chore: add select

This commit is contained in:
2026-03-06 18:21:33 +01:00
parent a66f570df4
commit e14a1eb4b8
3 changed files with 347 additions and 237 deletions
+147 -74
View File
@@ -28,7 +28,6 @@ import type { AdminStackParamList } from "../../navigation/types";
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";
@@ -55,6 +54,7 @@ export default function OrdersScreen() {
const [filter, setFilter] = useState("all");
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
const [openMenuId, setOpenMenuId] = useState<number | null>(null);
const [assignModal, setAssignModal] = useState<{
visible: boolean;
commandId: number | null;
@@ -243,11 +243,47 @@ export default function OrdersScreen() {
alignItems: "center",
marginBottom: spacing.s,
},
actions: {
selectBtn: {
flexDirection: "row",
flexWrap: "wrap",
gap: spacing.s,
alignItems: "center",
justifyContent: "space-between",
marginTop: spacing.m,
paddingHorizontal: spacing.m,
paddingVertical: spacing.s,
backgroundColor: colors.bgPrimary,
borderRadius: borderRadius.sm,
borderWidth: 1,
borderColor: colors.border,
},
selectBtnText: {
color: colors.textSecondary,
fontSize: fontSize.sm,
},
dropdown: {
marginTop: 2,
backgroundColor: colors.bgCard,
borderRadius: borderRadius.sm,
borderWidth: 1,
borderColor: colors.border,
overflow: "hidden",
},
dropdownItem: {
flexDirection: "row",
alignItems: "center",
gap: spacing.s,
paddingHorizontal: spacing.m,
paddingVertical: spacing.m,
borderBottomWidth: 1,
borderBottomColor: colors.border,
},
dropdownItemLast: { borderBottomWidth: 0 },
dropdownText: {
color: colors.textWhite,
fontSize: fontSize.sm,
},
dropdownTextDanger: {
color: colors.error,
fontSize: fontSize.sm,
},
empty: {
color: colors.textMuted,
@@ -313,80 +349,117 @@ export default function OrdersScreen() {
[colors],
);
const renderOrder = ({ item }: { item: CommandResponse }) => (
<Card style={{ marginBottom: spacing.m }}>
<TouchableOpacity
onPress={() =>
navigation.navigate("OrderDetail", { orderId: item.id })
}
activeOpacity={0.7}
>
<View style={styles.row}>
<Text style={styles.orderId}>#{item.id}</Text>
<StatusBadge status={item.status} />
</View>
<Text style={styles.cardText}>Client: {item.username}</Text>
<Text style={styles.cardText}>Adresse: {item.adresse}</Text>
<Text style={styles.cardText}>
Total: {item.total_prix.toFixed(2)}
</Text>
{item.livreur_assign && (
const renderOrder = ({ item }: { item: CommandResponse }) => {
const isOpen = openMenuId === item.id;
const isDone = ["approved", "cancelled"].includes(item.status);
type Action = {
label: string;
icon: keyof typeof Ionicons.glyphMap;
onPress: () => void;
danger?: boolean;
condition?: boolean;
};
const actions: Action[] = [
{
label: "Voir items",
icon: "receipt-outline",
onPress: () => { setOpenMenuId(null); openItems(item.id); },
},
{
label: "Le client est là",
icon: "notifications-outline",
onPress: () => { setOpenMenuId(null); handleNotifyClient(item.id); },
condition: !isDone,
},
{
label: "Assigner livreur",
icon: "bicycle-outline",
onPress: () => { setOpenMenuId(null); openAssignModal(item.id); },
condition: !isDone,
},
{
label: "Passer en route",
icon: "car-outline",
onPress: () => { setOpenMenuId(null); handleStatusUpdate(item.id, "en_route"); },
condition: item.status === "assigned",
},
{
label: "Confirmer réception",
icon: "checkmark-circle-outline",
onPress: () => { setOpenMenuId(null); handleConfirmReception(item.id); },
condition: item.status === "livre",
},
{
label: "Supprimer",
icon: "trash-outline",
onPress: () => { setOpenMenuId(null); handleDelete(item.id); },
danger: true,
},
].filter((a) => a.condition !== false);
return (
<Card style={{ marginBottom: spacing.m }}>
<TouchableOpacity
onPress={() => navigation.navigate("OrderDetail", { orderId: item.id })}
activeOpacity={0.7}
>
<View style={styles.row}>
<Text style={styles.orderId}>#{item.id}</Text>
<StatusBadge status={item.status} />
</View>
<Text style={styles.cardText}>Client: {item.username}</Text>
<Text style={styles.cardText}>Adresse: {item.adresse}</Text>
<Text style={styles.cardText}>
Livreur: {item.livreur_assign}
Total: {item.total_prix.toFixed(2)}
</Text>
)}
<Text style={styles.cardDate}>
{new Date(item.created_at).toLocaleString("fr-FR")}
</Text>
</TouchableOpacity>
<View style={styles.actions}>
<Button
title="Voir items"
onPress={() => openItems(item.id)}
size="sm"
variant="primary"
/>
{!["approved", "cancelled"].includes(item.status) && (
<Button
title="Le client est là"
onPress={() => handleNotifyClient(item.id)}
size="sm"
variant="warning"
{item.livreur_assign && (
<Text style={styles.cardText}>Livreur: {item.livreur_assign}</Text>
)}
<Text style={styles.cardDate}>
{new Date(item.created_at).toLocaleString("fr-FR")}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.selectBtn}
onPress={() => setOpenMenuId(isOpen ? null : item.id)}
>
<Text style={styles.selectBtnText}>Actions</Text>
<Ionicons
name={isOpen ? "chevron-up" : "chevron-down"}
size={14}
color={colors.textSecondary}
/>
</TouchableOpacity>
{isOpen && (
<View style={styles.dropdown}>
{actions.map((action, index) => (
<TouchableOpacity
key={action.label}
style={[
styles.dropdownItem,
index === actions.length - 1 && styles.dropdownItemLast,
]}
onPress={action.onPress}
>
<Ionicons
name={action.icon}
size={16}
color={action.danger ? colors.error : colors.accent}
/>
<Text style={action.danger ? styles.dropdownTextDanger : styles.dropdownText}>
{action.label}
</Text>
</TouchableOpacity>
))}
</View>
)}
{!["approved", "cancelled"].includes(item.status) && (
<Button
title="Assigner"
onPress={() => openAssignModal(item.id)}
size="sm"
variant="secondary"
/>
)}
{item.status === "assigned" && (
<Button
title="En route"
onPress={() => handleStatusUpdate(item.id, "en_route")}
size="sm"
variant="secondary"
/>
)}
{item.status === "livre" && (
<Button
title="Confirmer"
onPress={() => handleConfirmReception(item.id)}
size="sm"
variant="success"
/>
)}
<Button
title="Supprimer"
onPress={() => handleDelete(item.id)}
size="sm"
variant="danger"
/>
</View>
</Card>
);
</Card>
);
};
if (loading) return <LoadingSpinner message="Chargement commandes..." />;