chore: add modal detail
This commit is contained in:
@@ -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}>
|
||||
|
||||
Reference in New Issue
Block a user