chore: add modal detail

This commit is contained in:
2026-03-02 14:47:39 +01:00
parent d78a5743a1
commit 81128def9f
@@ -48,6 +48,7 @@ import TomTomMap, {
TomTomMapRef,
TomTomMarker,
} from "../../components/TomTomMap";
import DetailsModal from "../../components/ui/Modal";
import {
setupDeliveryNotificationChannel,
registerForPushNotificationsAsync,
@@ -72,6 +73,9 @@ const STATUS_LABELS: Record<string, string> = {
interface EnrichedDelivery extends DeliveryItem {
clientName?: string;
clientPhone?: string;
clientUsername?: string;
clientNom?: string;
clientPrenom?: string;
items?: Array<{ produit: string; quantite: number; prix: number }>;
}
@@ -108,6 +112,7 @@ export default function DashboardScreen() {
// Notifications
const [unreadNotifCount, setUnreadNotifCount] = useState(0);
const [detailsDelivery, setDetailsDelivery] = useState<EnrichedDelivery | null>(null);
const pushTokenRef = useRef<string | null>(null);
const STATUS_COLORS: Record<string, string> = useMemo(
@@ -240,6 +245,9 @@ export default function DashboardScreen() {
? `${client.prenom || ""} ${client.nom}`.trim()
: client?.username || undefined,
clientPhone: client?.telephone || undefined,
clientUsername: client?.username || undefined,
clientNom: client?.nom || undefined,
clientPrenom: client?.prenom || undefined,
items:
detail.delivery?.items ||
(d as any).items ||
@@ -641,12 +649,21 @@ export default function DashboardScreen() {
</TouchableOpacity>
)}
<TouchableOpacity
style={styles.detailsBtn}
onPress={() => setDetailsDelivery(item)}
activeOpacity={0.7}
>
<Ionicons name="list-outline" size={16} color={colors.accent} />
<Text style={styles.detailsBtnText}>Détails</Text>
</TouchableOpacity>
{(item.status === "pending" || item.status === "assigned") && (
<Button
title="Démarrer la livraison"
onPress={() => handleStartDelivery(item.id)}
style={{
marginTop: spacing.m,
marginTop: spacing.s,
backgroundColor: colors.success,
}}
/>
@@ -657,7 +674,7 @@ export default function DashboardScreen() {
title="Terminer la livraison"
onPress={() => handleCompleteDelivery(item.id)}
style={{
marginTop: spacing.m,
marginTop: spacing.s,
backgroundColor: colors.accent,
}}
/>
@@ -1288,6 +1305,102 @@ export default function DashboardScreen() {
fontSize: fontSize.sm,
fontFamily: "monospace",
},
// Bouton détails
detailsBtn: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: spacing.xs,
borderWidth: 1,
borderColor: colors.accent,
paddingVertical: spacing.s,
borderRadius: borderRadius.sm,
marginTop: spacing.m,
},
detailsBtnText: {
color: colors.accent,
fontSize: fontSize.sm,
fontWeight: "600",
},
// Modal détails
detailSection: { marginBottom: spacing.m },
detailSectionTitle: {
color: colors.textWhite,
fontSize: fontSize.sm,
fontWeight: "700",
marginBottom: spacing.s,
},
detailRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingVertical: spacing.xs,
borderBottomWidth: 1,
borderBottomColor: colors.borderSubtle,
},
detailLabel: {
color: colors.textMuted,
fontSize: fontSize.sm,
},
detailValue: {
color: colors.textWhite,
fontSize: fontSize.sm,
fontWeight: "600",
},
detailDivider: {
height: 1,
backgroundColor: colors.border,
marginBottom: spacing.m,
},
detailProductRow: {
flexDirection: "row",
alignItems: "center",
paddingVertical: spacing.s,
borderBottomWidth: 1,
borderBottomColor: colors.borderSubtle,
},
detailProductName: {
color: colors.textWhite,
fontSize: fontSize.sm,
fontWeight: "600",
},
detailProductQty: {
color: colors.textMuted,
fontSize: fontSize.xs,
marginTop: 2,
},
detailProductPrice: {
color: colors.success,
fontSize: fontSize.sm,
fontWeight: "700",
},
detailEmpty: {
color: colors.textMuted,
fontSize: fontSize.sm,
textAlign: "center",
paddingVertical: spacing.m,
},
detailTotalRow: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginTop: spacing.m,
paddingTop: spacing.m,
borderTopWidth: 1,
borderTopColor: colors.border,
},
detailTotalLabel: {
color: colors.textSecondary,
fontSize: fontSize.md,
fontWeight: "700",
},
detailTotalValue: {
color: colors.textWhite,
fontSize: fontSize.lg,
fontWeight: "700",
},
notifBadgeBar: {
flexDirection: "row",
alignItems: "center",
@@ -1480,6 +1593,79 @@ export default function DashboardScreen() {
</View>
</Modal>
{/* ── Modal détails commande ── */}
<DetailsModal
visible={detailsDelivery !== null}
onClose={() => setDetailsDelivery(null)}
title={`Commande #${detailsDelivery?.id}`}
icon="receipt-outline"
iconColor={colors.accent}
>
<ScrollView showsVerticalScrollIndicator={false}>
{/* Infos client */}
<View style={styles.detailSection}>
<Text style={styles.detailSectionTitle}>
<Ionicons name="person-outline" size={14} color={colors.accent} />
{" "}Client
</Text>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>Pseudo</Text>
<Text style={styles.detailValue}>
{detailsDelivery?.clientUsername || "—"}
</Text>
</View>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>Prénom</Text>
<Text style={styles.detailValue}>
{detailsDelivery?.clientPrenom || "—"}
</Text>
</View>
<View style={styles.detailRow}>
<Text style={styles.detailLabel}>Nom</Text>
<Text style={styles.detailValue}>
{detailsDelivery?.clientNom || "—"}
</Text>
</View>
</View>
{/* Séparateur */}
<View style={styles.detailDivider} />
{/* Produits */}
<Text style={styles.detailSectionTitle}>
<Ionicons name="bag-outline" size={14} color={colors.success} />
{" "}Produits
</Text>
{detailsDelivery?.items && detailsDelivery.items.length > 0 ? (
detailsDelivery.items.map((prod, idx) => (
<View key={idx} style={styles.detailProductRow}>
<View style={{ flex: 1 }}>
<Text style={styles.detailProductName}>
{prod.produit}
</Text>
<Text style={styles.detailProductQty}>
Quantité : {prod.quantite}
</Text>
</View>
<Text style={styles.detailProductPrice}>
{(prod.prix ?? 0).toFixed(2)}
</Text>
</View>
))
) : (
<Text style={styles.detailEmpty}>Aucun produit</Text>
)}
{/* Total */}
<View style={styles.detailTotalRow}>
<Text style={styles.detailTotalLabel}>Total</Text>
<Text style={styles.detailTotalValue}>
{detailsDelivery?.total_prix ?? 0}
</Text>
</View>
</ScrollView>
</DetailsModal>
{/* ── Badge notifications ── */}
{unreadNotifCount > 0 && (
<View style={styles.notifBadgeBar}>