diff --git a/frontend-admin/src/screens/admin/OrdersScreen.tsx b/frontend-admin/src/screens/admin/OrdersScreen.tsx index 31661f5e..2ca2dbb8 100644 --- a/frontend-admin/src/screens/admin/OrdersScreen.tsx +++ b/frontend-admin/src/screens/admin/OrdersScreen.tsx @@ -6,6 +6,7 @@ import { FlatList, TouchableOpacity, RefreshControl, + ScrollView, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { useNavigation } from "@react-navigation/native"; @@ -17,6 +18,10 @@ import { getAvailableDeliveryPersons, assignDeliveryPerson, updateCommandStatus, + getCommandItems, + notifyClientToDescend, + confirmReceptionAdmin, + deleteCommand, } from "../../api/api_admin"; import type { CommandResponse } from "../../api/types"; import type { AdminStackParamList } from "../../navigation/types"; @@ -24,6 +29,7 @@ import StatusBadge from "../../components/StatusBadge"; import LoadingSpinner from "../../components/ui/LoadingSpinner"; import Modal from "../../components/ui/Modal"; import Button from "../../components/ui/Button"; +import Card from "../../components/ui/Card"; import AlertModal from "../../components/ui/AlertModal"; import { useAlert } from "../../hooks/useAlert"; @@ -47,12 +53,27 @@ export default function OrdersScreen() { const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [filter, setFilter] = useState("all"); + const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert(); + const [assignModal, setAssignModal] = useState<{ visible: boolean; commandId: number | null; }>({ visible: false, commandId: null }); const [livreurs, setLivreurs] = useState([]); - const { alert, showError, hideAlert } = useAlert(); + + const [itemsModal, setItemsModal] = useState<{ + visible: boolean; + commandId: number | null; + items: any[]; + commandInfo: any; + clientInfo: any; + }>({ + visible: false, + commandId: null, + items: [], + commandInfo: null, + clientInfo: null, + }); const loadData = useCallback(async () => { try { @@ -105,6 +126,75 @@ export default function OrdersScreen() { } }; + const openItems = async (commandId: number) => { + try { + const result = await getCommandItems(commandId); + setItemsModal({ + visible: true, + commandId, + items: result.items, + commandInfo: result.command_info, + clientInfo: result.client_info, + }); + } catch (e: any) { + showError("Erreur", e.message); + } + }; + + const closeItemsModal = () => + setItemsModal({ + visible: false, + commandId: null, + items: [], + commandInfo: null, + clientInfo: null, + }); + + const handleNotifyClient = async (commandId: number) => { + try { + await notifyClientToDescend(commandId); + showSuccess("Notification envoyée", "Le client a été prévenu de descendre"); + } catch (e: any) { + showError("Erreur", e.message); + } + }; + + const handleConfirmReception = (commandId: number) => { + showConfirm( + "Confirmer la commande", + `Confirmer la réception de la commande #${commandId} ?`, + async () => { + try { + const res = await confirmReceptionAdmin(commandId); + showSuccess( + "Réception confirmée", + `${res.points_earned} point(s) attribués au client ${res.client_username}`, + ); + await loadData(); + } catch (e: any) { + showError("Erreur", e.message); + } + }, + "Confirmer", + ); + }; + + const handleDelete = (commandId: number) => { + showConfirm( + "Supprimer", + `Supprimer la commande #${commandId} ?`, + async () => { + try { + await deleteCommand(commandId); + await loadData(); + } catch (e: any) { + showError("Erreur", e.message); + } + }, + "Supprimer", + ); + }; + const styles = useMemo( () => StyleSheet.create({ @@ -132,25 +222,6 @@ export default function OrdersScreen() { fontSize: fontSize.sm, }, filterTextActive: { color: colors.textWhite }, - card: { - backgroundColor: colors.bgCard, - borderRadius: borderRadius.md, - padding: spacing.l, - marginBottom: spacing.m, - borderWidth: 1, - borderColor: colors.borderLight, - }, - cardHeader: { - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", - marginBottom: spacing.s, - }, - orderId: { - fontSize: fontSize.lg, - fontWeight: "bold", - color: colors.textWhite, - }, cardText: { color: colors.textSecondary, fontSize: fontSize.sm, @@ -161,8 +232,20 @@ export default function OrdersScreen() { fontSize: fontSize.xs, marginTop: spacing.s, }, + orderId: { + fontSize: fontSize.lg, + fontWeight: "bold", + color: colors.textWhite, + }, + row: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: spacing.s, + }, actions: { flexDirection: "row", + flexWrap: "wrap", gap: spacing.s, marginTop: spacing.m, }, @@ -182,42 +265,101 @@ export default function OrdersScreen() { gap: spacing.m, }, livreurName: { color: colors.textWhite, fontSize: fontSize.md }, + + // Modal items + modalSummary: { + backgroundColor: colors.bgCard, + borderRadius: borderRadius.sm, + padding: spacing.m, + marginBottom: spacing.m, + gap: spacing.xs, + }, + modalSummaryRow: { + flexDirection: "row", + alignItems: "center", + gap: spacing.s, + }, + modalSummaryText: { + color: colors.textSecondary, + fontSize: fontSize.sm, + flex: 1, + }, + modalTotal: { + color: colors.accent, + fontSize: fontSize.md, + fontWeight: "700", + marginTop: spacing.xs, + }, + itemCard: { + backgroundColor: colors.bgCard, + borderRadius: borderRadius.sm, + marginBottom: spacing.s, + overflow: "hidden", + }, + itemCardBody: { + padding: spacing.m, + }, + itemName: { + color: colors.textWhite, + fontSize: fontSize.md, + fontWeight: "600", + marginBottom: 2, + }, + itemMeta: { + color: colors.textMuted, + fontSize: fontSize.xs, + }, }), [colors], ); const renderOrder = ({ item }: { item: CommandResponse }) => ( - - navigation.navigate("OrderDetail", { orderId: item.id }) - } - activeOpacity={0.7} - > - - #{item.id} - - - Client: {item.username} - Adresse: {item.adresse} - - Total: {item.total_prix.toFixed(2)} € - - {item.livreur_assign && ( + + + navigation.navigate("OrderDetail", { orderId: item.id }) + } + activeOpacity={0.7} + > + + #{item.id} + + + Client: {item.username} + Adresse: {item.adresse} - Livreur: {item.livreur_assign} + Total: {item.total_prix.toFixed(2)} € - )} - - {new Date(item.created_at).toLocaleString("fr-FR")} - + {item.livreur_assign && ( + + Livreur: {item.livreur_assign} + + )} + + {new Date(item.created_at).toLocaleString("fr-FR")} + + +