chore: fix comming soon
This commit is contained in:
@@ -9,7 +9,11 @@ import {
|
|||||||
StatusBar,
|
StatusBar,
|
||||||
Alert,
|
Alert,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useRoute, useNavigation, type RouteProp } from "@react-navigation/native";
|
import {
|
||||||
|
useRoute,
|
||||||
|
useNavigation,
|
||||||
|
type RouteProp,
|
||||||
|
} from "@react-navigation/native";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps";
|
import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps";
|
||||||
import { spacing, fontSize, borderRadius } from "../../theme";
|
import { spacing, fontSize, borderRadius } from "../../theme";
|
||||||
@@ -87,7 +91,9 @@ export default function OrderDetailScreen() {
|
|||||||
try {
|
try {
|
||||||
const res = await getCommandByID(orderId);
|
const res = await getCommandByID(orderId);
|
||||||
setCommand(res.command);
|
setCommand(res.command);
|
||||||
} catch { /* ignore */ }
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
}, 20000);
|
}, 20000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, [orderId]);
|
}, [orderId]);
|
||||||
@@ -176,7 +182,10 @@ export default function OrderDetailScreen() {
|
|||||||
const handleNotifyClient = async () => {
|
const handleNotifyClient = async () => {
|
||||||
try {
|
try {
|
||||||
await notifyClientToDescend(orderId);
|
await notifyClientToDescend(orderId);
|
||||||
showSuccess("Notification envoyée", "Le client a été prévenu de descendre");
|
showSuccess(
|
||||||
|
"Notification envoyée",
|
||||||
|
"Le client a été prévenu de descendre",
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showError("Erreur", e.message);
|
showError("Erreur", e.message);
|
||||||
}
|
}
|
||||||
@@ -773,7 +782,7 @@ export default function OrderDetailScreen() {
|
|||||||
)}
|
)}
|
||||||
{!["approved", "cancelled"].includes(command.status) && (
|
{!["approved", "cancelled"].includes(command.status) && (
|
||||||
<Button
|
<Button
|
||||||
title="Le client est là"
|
title="Le livreur est là"
|
||||||
onPress={handleNotifyClient}
|
onPress={handleNotifyClient}
|
||||||
variant="warning"
|
variant="warning"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -823,9 +832,17 @@ export default function OrderDetailScreen() {
|
|||||||
</View>
|
</View>
|
||||||
<ScrollView showsVerticalScrollIndicator={false}>
|
<ScrollView showsVerticalScrollIndicator={false}>
|
||||||
{items.map((item: any) => (
|
{items.map((item: any) => (
|
||||||
<View key={item.id} style={styles.itemsModalCard}>
|
<View
|
||||||
|
key={item.id}
|
||||||
|
style={styles.itemsModalCard}
|
||||||
|
>
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={[styles.itemName, { flex: 1 }]}>
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.itemName,
|
||||||
|
{ flex: 1 },
|
||||||
|
]}
|
||||||
|
>
|
||||||
{item.produit ?? item.product_name}
|
{item.produit ?? item.product_name}
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -834,7 +851,8 @@ export default function OrderDetailScreen() {
|
|||||||
setShowItemsModal(false);
|
setShowItemsModal(false);
|
||||||
handleDeleteItem(
|
handleDeleteItem(
|
||||||
item.id,
|
item.id,
|
||||||
item.produit ?? item.product_name,
|
item.produit ??
|
||||||
|
item.product_name,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ export default function OrdersScreen() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const [filter, setFilter] = useState("all");
|
const [filter, setFilter] = useState("all");
|
||||||
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
const { alert, showError, showSuccess, showConfirm, hideAlert } =
|
||||||
|
useAlert();
|
||||||
|
|
||||||
const [openMenuId, setOpenMenuId] = useState<number | null>(null);
|
const [openMenuId, setOpenMenuId] = useState<number | null>(null);
|
||||||
const [assignModal, setAssignModal] = useState<{
|
const [assignModal, setAssignModal] = useState<{
|
||||||
@@ -162,7 +163,10 @@ export default function OrdersScreen() {
|
|||||||
const handleNotifyClient = async (commandId: number) => {
|
const handleNotifyClient = async (commandId: number) => {
|
||||||
try {
|
try {
|
||||||
await notifyClientToDescend(commandId);
|
await notifyClientToDescend(commandId);
|
||||||
showSuccess("Notification envoyée", "Le client a été prévenu de descendre");
|
showSuccess(
|
||||||
|
"Notification envoyée",
|
||||||
|
"Le client a été prévenu de descendre",
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showError("Erreur", e.message);
|
showError("Erreur", e.message);
|
||||||
}
|
}
|
||||||
@@ -191,15 +195,25 @@ export default function OrdersScreen() {
|
|||||||
const handleProposeAddress = async () => {
|
const handleProposeAddress = async () => {
|
||||||
if (!addressModal.commandId || !addressModal.input.trim()) return;
|
if (!addressModal.commandId || !addressModal.input.trim()) return;
|
||||||
try {
|
try {
|
||||||
await proposeAddressChangeAdmin(addressModal.commandId, addressModal.input.trim());
|
await proposeAddressChangeAdmin(
|
||||||
|
addressModal.commandId,
|
||||||
|
addressModal.input.trim(),
|
||||||
|
);
|
||||||
setAddressModal({ visible: false, commandId: null, input: "" });
|
setAddressModal({ visible: false, commandId: null, input: "" });
|
||||||
showSuccess("Proposition envoyée", "Le client a été notifié de la nouvelle adresse proposée");
|
showSuccess(
|
||||||
|
"Proposition envoyée",
|
||||||
|
"Le client a été notifié de la nouvelle adresse proposée",
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showError("Erreur", e.message);
|
showError("Erreur", e.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteItem = (commandId: number, itemId: number, itemName: string) => {
|
const handleDeleteItem = (
|
||||||
|
commandId: number,
|
||||||
|
itemId: number,
|
||||||
|
itemName: string,
|
||||||
|
) => {
|
||||||
showConfirm(
|
showConfirm(
|
||||||
"Supprimer l'article",
|
"Supprimer l'article",
|
||||||
`Supprimer "${itemName}" de la commande #${commandId} ?`,
|
`Supprimer "${itemName}" de la commande #${commandId} ?`,
|
||||||
@@ -429,54 +443,83 @@ export default function OrdersScreen() {
|
|||||||
condition?: boolean;
|
condition?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions: Action[] = ([
|
const actions: Action[] = (
|
||||||
|
[
|
||||||
{
|
{
|
||||||
label: "Voir items",
|
label: "Voir items",
|
||||||
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); openItems(item.id); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
openItems(item.id);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Proposer adresse",
|
label: "Proposer adresse",
|
||||||
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); setAddressModal({ visible: true, commandId: item.id, input: "" }); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
setAddressModal({
|
||||||
|
visible: true,
|
||||||
|
commandId: item.id,
|
||||||
|
input: "",
|
||||||
|
});
|
||||||
|
},
|
||||||
condition: !isDone,
|
condition: !isDone,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Le client est là",
|
label: "Le livreur est là",
|
||||||
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); handleNotifyClient(item.id); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
handleNotifyClient(item.id);
|
||||||
|
},
|
||||||
condition: !isDone,
|
condition: !isDone,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Assigner livreur",
|
label: "Assigner livreur",
|
||||||
icon: "bicycle-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "bicycle-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); openAssignModal(item.id); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
openAssignModal(item.id);
|
||||||
|
},
|
||||||
condition: !isDone,
|
condition: !isDone,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Passer en route",
|
label: "Passer en route",
|
||||||
icon: "car-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "car-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); handleStatusUpdate(item.id, "en_route"); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
handleStatusUpdate(item.id, "en_route");
|
||||||
|
},
|
||||||
condition: item.status === "assigned",
|
condition: item.status === "assigned",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Confirmer réception",
|
label: "Confirmer réception",
|
||||||
icon: "checkmark-circle-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "checkmark-circle-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); handleConfirmReception(item.id); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
handleConfirmReception(item.id);
|
||||||
|
},
|
||||||
condition: item.status === "livre",
|
condition: item.status === "livre",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Supprimer",
|
label: "Supprimer",
|
||||||
icon: "trash-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "trash-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); handleDelete(item.id); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
handleDelete(item.id);
|
||||||
|
},
|
||||||
danger: true,
|
danger: true,
|
||||||
},
|
},
|
||||||
] as Action[]).filter((a) => a.condition !== false);
|
] as Action[]
|
||||||
|
).filter((a) => a.condition !== false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card style={{ marginBottom: spacing.m }}>
|
<Card style={{ marginBottom: spacing.m }}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => navigation.navigate("OrderDetail", { orderId: item.id })}
|
onPress={() =>
|
||||||
|
navigation.navigate("OrderDetail", { orderId: item.id })
|
||||||
|
}
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
>
|
>
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
@@ -489,7 +532,9 @@ export default function OrdersScreen() {
|
|||||||
Total: {item.total_prix.toFixed(2)} €
|
Total: {item.total_prix.toFixed(2)} €
|
||||||
</Text>
|
</Text>
|
||||||
{item.livreur_assign && (
|
{item.livreur_assign && (
|
||||||
<Text style={styles.cardText}>Livreur: {item.livreur_assign}</Text>
|
<Text style={styles.cardText}>
|
||||||
|
Livreur: {item.livreur_assign}
|
||||||
|
</Text>
|
||||||
)}
|
)}
|
||||||
<Text style={styles.cardDate}>
|
<Text style={styles.cardDate}>
|
||||||
{new Date(item.created_at).toLocaleString("fr-FR")}
|
{new Date(item.created_at).toLocaleString("fr-FR")}
|
||||||
@@ -515,16 +560,27 @@ export default function OrdersScreen() {
|
|||||||
key={action.label}
|
key={action.label}
|
||||||
style={[
|
style={[
|
||||||
styles.dropdownItem,
|
styles.dropdownItem,
|
||||||
index === actions.length - 1 && styles.dropdownItemLast,
|
index === actions.length - 1 &&
|
||||||
|
styles.dropdownItemLast,
|
||||||
]}
|
]}
|
||||||
onPress={action.onPress}
|
onPress={action.onPress}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={action.icon}
|
name={action.icon}
|
||||||
size={16}
|
size={16}
|
||||||
color={action.danger ? colors.danger : colors.accent}
|
color={
|
||||||
|
action.danger
|
||||||
|
? colors.danger
|
||||||
|
: colors.accent
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Text style={action.danger ? styles.dropdownTextDanger : styles.dropdownText}>
|
<Text
|
||||||
|
style={
|
||||||
|
action.danger
|
||||||
|
? styles.dropdownTextDanger
|
||||||
|
: styles.dropdownText
|
||||||
|
}
|
||||||
|
>
|
||||||
{action.label}
|
{action.label}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -588,7 +644,10 @@ export default function OrdersScreen() {
|
|||||||
title={`Commande #${itemsModal.commandId}`}
|
title={`Commande #${itemsModal.commandId}`}
|
||||||
icon="receipt-outline"
|
icon="receipt-outline"
|
||||||
>
|
>
|
||||||
<ScrollView showsVerticalScrollIndicator={false} bounces={false}>
|
<ScrollView
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
bounces={false}
|
||||||
|
>
|
||||||
{(itemsModal.commandInfo || itemsModal.clientInfo) && (
|
{(itemsModal.commandInfo || itemsModal.clientInfo) && (
|
||||||
<View style={styles.modalSummary}>
|
<View style={styles.modalSummary}>
|
||||||
{itemsModal.clientInfo?.username && (
|
{itemsModal.clientInfo?.username && (
|
||||||
@@ -638,8 +697,12 @@ export default function OrdersScreen() {
|
|||||||
{item.produit ?? item.product_name}
|
{item.produit ?? item.product_name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.itemMeta}>
|
<Text style={styles.itemMeta}>
|
||||||
Qté: {item.quantite ?? item.quantity} ·{" "}
|
Qté:{" "}
|
||||||
{(item.prix ?? item.price)?.toFixed(2)} €
|
{item.quantite ?? item.quantity} ·{" "}
|
||||||
|
{(item.prix ?? item.price)?.toFixed(
|
||||||
|
2,
|
||||||
|
)}{" "}
|
||||||
|
€
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -648,7 +711,8 @@ export default function OrdersScreen() {
|
|||||||
handleDeleteItem(
|
handleDeleteItem(
|
||||||
itemsModal.commandId!,
|
itemsModal.commandId!,
|
||||||
item.id,
|
item.id,
|
||||||
item.produit ?? item.product_name,
|
item.produit ??
|
||||||
|
item.product_name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -699,7 +763,13 @@ export default function OrdersScreen() {
|
|||||||
{/* Modal proposition adresse */}
|
{/* Modal proposition adresse */}
|
||||||
<Modal
|
<Modal
|
||||||
visible={addressModal.visible}
|
visible={addressModal.visible}
|
||||||
onClose={() => setAddressModal({ visible: false, commandId: null, input: "" })}
|
onClose={() =>
|
||||||
|
setAddressModal({
|
||||||
|
visible: false,
|
||||||
|
commandId: null,
|
||||||
|
input: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
title={`Proposer adresse — commande #${addressModal.commandId}`}
|
title={`Proposer adresse — commande #${addressModal.commandId}`}
|
||||||
icon="location-outline"
|
icon="location-outline"
|
||||||
>
|
>
|
||||||
@@ -708,14 +778,18 @@ export default function OrdersScreen() {
|
|||||||
placeholder="Nouvelle adresse..."
|
placeholder="Nouvelle adresse..."
|
||||||
placeholderTextColor={colors.textMuted}
|
placeholderTextColor={colors.textMuted}
|
||||||
value={addressModal.input}
|
value={addressModal.input}
|
||||||
onChangeText={(t) => setAddressModal((prev) => ({ ...prev, input: t }))}
|
onChangeText={(t) =>
|
||||||
|
setAddressModal((prev) => ({ ...prev, input: t }))
|
||||||
|
}
|
||||||
multiline
|
multiline
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.addressConfirmBtn}
|
style={styles.addressConfirmBtn}
|
||||||
onPress={handleProposeAddress}
|
onPress={handleProposeAddress}
|
||||||
>
|
>
|
||||||
<Text style={styles.addressConfirmText}>Envoyer la proposition</Text>
|
<Text style={styles.addressConfirmText}>
|
||||||
|
Envoyer la proposition
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ export default function OrdersScreen() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const [openMenuId, setOpenMenuId] = useState<number | null>(null);
|
const [openMenuId, setOpenMenuId] = useState<number | null>(null);
|
||||||
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
const { alert, showError, showSuccess, showConfirm, hideAlert } =
|
||||||
|
useAlert();
|
||||||
const [itemsModal, setItemsModal] = useState<{
|
const [itemsModal, setItemsModal] = useState<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
commandId: number | null;
|
commandId: number | null;
|
||||||
@@ -77,7 +78,9 @@ export default function OrdersScreen() {
|
|||||||
commandId: number | null;
|
commandId: number | null;
|
||||||
input: string;
|
input: string;
|
||||||
}>({ visible: false, commandId: null, input: "" });
|
}>({ visible: false, commandId: null, input: "" });
|
||||||
const [livreurs, setLivreurs] = useState<{ id: number; username: string }[]>([]);
|
const [livreurs, setLivreurs] = useState<
|
||||||
|
{ id: number; username: string }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -148,7 +151,10 @@ export default function OrdersScreen() {
|
|||||||
setOpenMenuId(null);
|
setOpenMenuId(null);
|
||||||
try {
|
try {
|
||||||
await notifyClientToDescendCabine(commandId);
|
await notifyClientToDescendCabine(commandId);
|
||||||
showSuccess("Notification envoyée", "Le client a été prévenu de descendre");
|
showSuccess(
|
||||||
|
"Notification envoyée",
|
||||||
|
"Le client a été prévenu de descendre",
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showError("Erreur", e.message);
|
showError("Erreur", e.message);
|
||||||
}
|
}
|
||||||
@@ -157,9 +163,15 @@ export default function OrdersScreen() {
|
|||||||
const handleProposeAddress = async () => {
|
const handleProposeAddress = async () => {
|
||||||
if (!addressModal.commandId || !addressModal.input.trim()) return;
|
if (!addressModal.commandId || !addressModal.input.trim()) return;
|
||||||
try {
|
try {
|
||||||
await proposeAddressChangeCabine(addressModal.commandId, addressModal.input.trim());
|
await proposeAddressChangeCabine(
|
||||||
|
addressModal.commandId,
|
||||||
|
addressModal.input.trim(),
|
||||||
|
);
|
||||||
setAddressModal({ visible: false, commandId: null, input: "" });
|
setAddressModal({ visible: false, commandId: null, input: "" });
|
||||||
showSuccess("Proposition envoyée", "Le client a été notifié de la nouvelle adresse proposée");
|
showSuccess(
|
||||||
|
"Proposition envoyée",
|
||||||
|
"Le client a été notifié de la nouvelle adresse proposée",
|
||||||
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
showError("Erreur", e.message);
|
showError("Erreur", e.message);
|
||||||
}
|
}
|
||||||
@@ -205,7 +217,10 @@ export default function OrdersScreen() {
|
|||||||
const handleAssign = async (livreurUsername: string) => {
|
const handleAssign = async (livreurUsername: string) => {
|
||||||
if (!assignModal.commandId) return;
|
if (!assignModal.commandId) return;
|
||||||
try {
|
try {
|
||||||
await assignDeliveryPersonByCabine(assignModal.commandId, livreurUsername);
|
await assignDeliveryPersonByCabine(
|
||||||
|
assignModal.commandId,
|
||||||
|
livreurUsername,
|
||||||
|
);
|
||||||
setAssignModal({ visible: false, commandId: null });
|
setAssignModal({ visible: false, commandId: null });
|
||||||
await loadData();
|
await loadData();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -412,7 +427,8 @@ export default function OrdersScreen() {
|
|||||||
condition?: boolean;
|
condition?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions: Action[] = ([
|
const actions: Action[] = (
|
||||||
|
[
|
||||||
{
|
{
|
||||||
label: "Voir items",
|
label: "Voir items",
|
||||||
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "receipt-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
@@ -421,10 +437,17 @@ export default function OrdersScreen() {
|
|||||||
{
|
{
|
||||||
label: "Proposer adresse",
|
label: "Proposer adresse",
|
||||||
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "location-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => { setOpenMenuId(null); setAddressModal({ visible: true, commandId: item.id, input: "" }); },
|
onPress: () => {
|
||||||
|
setOpenMenuId(null);
|
||||||
|
setAddressModal({
|
||||||
|
visible: true,
|
||||||
|
commandId: item.id,
|
||||||
|
input: "",
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Le client est là",
|
label: "Le livreur est là",
|
||||||
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
|
icon: "notifications-outline" as keyof typeof Ionicons.glyphMap,
|
||||||
onPress: () => handleNotifyClient(item.id),
|
onPress: () => handleNotifyClient(item.id),
|
||||||
},
|
},
|
||||||
@@ -445,7 +468,8 @@ export default function OrdersScreen() {
|
|||||||
onPress: () => handleDelete(item.id),
|
onPress: () => handleDelete(item.id),
|
||||||
danger: true,
|
danger: true,
|
||||||
},
|
},
|
||||||
] as Action[]).filter((a) => a.condition !== false);
|
] as Action[]
|
||||||
|
).filter((a) => a.condition !== false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card style={{ marginBottom: spacing.m }}>
|
<Card style={{ marginBottom: spacing.m }}>
|
||||||
@@ -478,14 +502,19 @@ export default function OrdersScreen() {
|
|||||||
key={action.label}
|
key={action.label}
|
||||||
style={[
|
style={[
|
||||||
styles.dropdownItem,
|
styles.dropdownItem,
|
||||||
index === actions.length - 1 && styles.dropdownItemLast,
|
index === actions.length - 1 &&
|
||||||
|
styles.dropdownItemLast,
|
||||||
]}
|
]}
|
||||||
onPress={action.onPress}
|
onPress={action.onPress}
|
||||||
>
|
>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={action.icon}
|
name={action.icon}
|
||||||
size={16}
|
size={16}
|
||||||
color={action.danger ? colors.danger : colors.accent}
|
color={
|
||||||
|
action.danger
|
||||||
|
? colors.danger
|
||||||
|
: colors.accent
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Text
|
<Text
|
||||||
style={
|
style={
|
||||||
@@ -504,7 +533,9 @@ export default function OrdersScreen() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const readyCount = itemsModal.items.filter((i) => i.status === "ready").length;
|
const readyCount = itemsModal.items.filter(
|
||||||
|
(i) => i.status === "ready",
|
||||||
|
).length;
|
||||||
const totalCount = itemsModal.items.length;
|
const totalCount = itemsModal.items.length;
|
||||||
const progress = totalCount > 0 ? readyCount / totalCount : 0;
|
const progress = totalCount > 0 ? readyCount / totalCount : 0;
|
||||||
|
|
||||||
@@ -535,12 +566,19 @@ export default function OrdersScreen() {
|
|||||||
title={`Commande #${itemsModal.commandId}`}
|
title={`Commande #${itemsModal.commandId}`}
|
||||||
icon="receipt-outline"
|
icon="receipt-outline"
|
||||||
>
|
>
|
||||||
<ScrollView showsVerticalScrollIndicator={false} bounces={false}>
|
<ScrollView
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
bounces={false}
|
||||||
|
>
|
||||||
{(itemsModal.commandInfo || itemsModal.clientInfo) && (
|
{(itemsModal.commandInfo || itemsModal.clientInfo) && (
|
||||||
<View style={styles.modalSummary}>
|
<View style={styles.modalSummary}>
|
||||||
{itemsModal.clientInfo?.username && (
|
{itemsModal.clientInfo?.username && (
|
||||||
<View style={styles.modalSummaryRow}>
|
<View style={styles.modalSummaryRow}>
|
||||||
<Ionicons name="person-outline" size={14} color={colors.textMuted} />
|
<Ionicons
|
||||||
|
name="person-outline"
|
||||||
|
size={14}
|
||||||
|
color={colors.textMuted}
|
||||||
|
/>
|
||||||
<Text style={styles.modalSummaryText}>
|
<Text style={styles.modalSummaryText}>
|
||||||
{itemsModal.clientInfo.prenom}{" "}
|
{itemsModal.clientInfo.prenom}{" "}
|
||||||
{itemsModal.clientInfo.nom} ·{" "}
|
{itemsModal.clientInfo.nom} ·{" "}
|
||||||
@@ -548,17 +586,26 @@ export default function OrdersScreen() {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{(itemsModal.commandInfo?.address || itemsModal.commandInfo?.adresse) && (
|
{(itemsModal.commandInfo?.address ||
|
||||||
|
itemsModal.commandInfo?.adresse) && (
|
||||||
<View style={styles.modalSummaryRow}>
|
<View style={styles.modalSummaryRow}>
|
||||||
<Ionicons name="location-outline" size={14} color={colors.textMuted} />
|
<Ionicons
|
||||||
|
name="location-outline"
|
||||||
|
size={14}
|
||||||
|
color={colors.textMuted}
|
||||||
|
/>
|
||||||
<Text style={styles.modalSummaryText}>
|
<Text style={styles.modalSummaryText}>
|
||||||
{itemsModal.commandInfo.address || itemsModal.commandInfo.adresse}
|
{itemsModal.commandInfo.address ||
|
||||||
|
itemsModal.commandInfo.adresse}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
{itemsModal.commandInfo?.total_prix != null && (
|
{itemsModal.commandInfo?.total_prix != null && (
|
||||||
<Text style={styles.modalTotal}>
|
<Text style={styles.modalTotal}>
|
||||||
{Number(itemsModal.commandInfo.total_prix).toFixed(2)} €
|
{Number(
|
||||||
|
itemsModal.commandInfo.total_prix,
|
||||||
|
).toFixed(2)}{" "}
|
||||||
|
€
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
@@ -576,7 +623,9 @@ export default function OrdersScreen() {
|
|||||||
{
|
{
|
||||||
width: `${progress * 100}%`,
|
width: `${progress * 100}%`,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
progress === 1 ? STATUS_COLORS.ready : colors.info,
|
progress === 1
|
||||||
|
? STATUS_COLORS.ready
|
||||||
|
: colors.info,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
@@ -585,30 +634,51 @@ export default function OrdersScreen() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{itemsModal.items.map((item: any, index: number) => {
|
{itemsModal.items.map((item: any, index: number) => {
|
||||||
const statusColor = STATUS_COLORS[item.status] || colors.textMuted;
|
const statusColor =
|
||||||
|
STATUS_COLORS[item.status] || colors.textMuted;
|
||||||
return (
|
return (
|
||||||
<View key={item.id} style={styles.itemCard}>
|
<View key={item.id} style={styles.itemCard}>
|
||||||
<View style={[styles.itemCardAccent, { backgroundColor: statusColor }]} />
|
<View
|
||||||
|
style={[
|
||||||
|
styles.itemCardAccent,
|
||||||
|
{ backgroundColor: statusColor },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<View style={styles.itemCardBody}>
|
<View style={styles.itemCardBody}>
|
||||||
<View style={styles.itemIndex}>
|
<View style={styles.itemIndex}>
|
||||||
<Text style={styles.itemIndexText}>{index + 1}</Text>
|
<Text style={styles.itemIndexText}>
|
||||||
|
{index + 1}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.itemInfo}>
|
<View style={styles.itemInfo}>
|
||||||
<Text style={styles.itemName}>
|
<Text style={styles.itemName}>
|
||||||
{item.produit ?? item.product_name}
|
{item.produit ?? item.product_name}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.itemMeta}>
|
<Text style={styles.itemMeta}>
|
||||||
Qté: {item.quantite ?? item.quantity} ·{" "}
|
Qté:{" "}
|
||||||
{(item.prix ?? item.price)?.toFixed(2)} €
|
{item.quantite ?? item.quantity} ·{" "}
|
||||||
|
{(item.prix ?? item.price)?.toFixed(
|
||||||
|
2,
|
||||||
|
)}{" "}
|
||||||
|
€
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.itemStatusRow}>
|
<View style={styles.itemStatusRow}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name={STATUS_ICONS[item.status] || "ellipse-outline"}
|
name={
|
||||||
|
STATUS_ICONS[item.status] ||
|
||||||
|
"ellipse-outline"
|
||||||
|
}
|
||||||
size={13}
|
size={13}
|
||||||
color={statusColor}
|
color={statusColor}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.itemStatusText, { color: statusColor }]}>
|
<Text
|
||||||
{STATUS_LABELS[item.status] || item.status}
|
style={[
|
||||||
|
styles.itemStatusText,
|
||||||
|
{ color: statusColor },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{STATUS_LABELS[item.status] ||
|
||||||
|
item.status}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@@ -625,7 +695,9 @@ export default function OrdersScreen() {
|
|||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
visible={assignModal.visible}
|
visible={assignModal.visible}
|
||||||
onClose={() => setAssignModal({ visible: false, commandId: null })}
|
onClose={() =>
|
||||||
|
setAssignModal({ visible: false, commandId: null })
|
||||||
|
}
|
||||||
title={`Assigner commande #${assignModal.commandId}`}
|
title={`Assigner commande #${assignModal.commandId}`}
|
||||||
icon="bicycle-outline"
|
icon="bicycle-outline"
|
||||||
>
|
>
|
||||||
@@ -635,7 +707,11 @@ export default function OrdersScreen() {
|
|||||||
style={styles.livreurItem}
|
style={styles.livreurItem}
|
||||||
onPress={() => handleAssign(l.username)}
|
onPress={() => handleAssign(l.username)}
|
||||||
>
|
>
|
||||||
<Ionicons name="person-outline" size={20} color={colors.accent} />
|
<Ionicons
|
||||||
|
name="person-outline"
|
||||||
|
size={20}
|
||||||
|
color={colors.accent}
|
||||||
|
/>
|
||||||
<Text style={styles.livreurName}>{l.username}</Text>
|
<Text style={styles.livreurName}>{l.username}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
))}
|
))}
|
||||||
@@ -647,7 +723,13 @@ export default function OrdersScreen() {
|
|||||||
{/* Modal proposition adresse */}
|
{/* Modal proposition adresse */}
|
||||||
<Modal
|
<Modal
|
||||||
visible={addressModal.visible}
|
visible={addressModal.visible}
|
||||||
onClose={() => setAddressModal({ visible: false, commandId: null, input: "" })}
|
onClose={() =>
|
||||||
|
setAddressModal({
|
||||||
|
visible: false,
|
||||||
|
commandId: null,
|
||||||
|
input: "",
|
||||||
|
})
|
||||||
|
}
|
||||||
title={`Proposer adresse — commande #${addressModal.commandId}`}
|
title={`Proposer adresse — commande #${addressModal.commandId}`}
|
||||||
icon="location-outline"
|
icon="location-outline"
|
||||||
>
|
>
|
||||||
@@ -656,14 +738,18 @@ export default function OrdersScreen() {
|
|||||||
placeholder="Nouvelle adresse..."
|
placeholder="Nouvelle adresse..."
|
||||||
placeholderTextColor={colors.textMuted}
|
placeholderTextColor={colors.textMuted}
|
||||||
value={addressModal.input}
|
value={addressModal.input}
|
||||||
onChangeText={(t) => setAddressModal((prev) => ({ ...prev, input: t }))}
|
onChangeText={(t) =>
|
||||||
|
setAddressModal((prev) => ({ ...prev, input: t }))
|
||||||
|
}
|
||||||
multiline
|
multiline
|
||||||
/>
|
/>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.addressConfirmBtn}
|
style={styles.addressConfirmBtn}
|
||||||
onPress={handleProposeAddress}
|
onPress={handleProposeAddress}
|
||||||
>
|
>
|
||||||
<Text style={styles.addressConfirmText}>Envoyer la proposition</Text>
|
<Text style={styles.addressConfirmText}>
|
||||||
|
Envoyer la proposition
|
||||||
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
|
|||||||
@@ -94,9 +94,15 @@ export default function ProductsScreen() {
|
|||||||
}, [selectedCategory]);
|
}, [selectedCategory]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const catObj = categories.find((c) => c.name === selectedCategory);
|
||||||
|
if (catObj?.is_coming_soon) {
|
||||||
|
setLoading(false);
|
||||||
|
setProducts([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
fetchProducts();
|
fetchProducts();
|
||||||
}, [fetchProducts]);
|
}, [selectedCategory, categories, fetchProducts]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (carouselRef.current && products.length > 0) {
|
if (carouselRef.current && products.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user