import { useState, useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; import { Package, MapPin, CheckCircle, Navigation, User, AlertCircle, MapPinned, ShoppingBag, BarChart3, Shield, } from "lucide-react"; import "./DeliveryDashboard.css"; import { getDeliveryPersonDetails, extractAdminUsernameFromToken, } from "../../api/api_admin"; import { getMyStatus, updateMyStatus, getMyQueue, getMyDeliveries, getDeliveryDetails, startDelivery, updateDeliveryStatus, updateMyLocation, isDeliveryAuthenticated, triggerPoliceAlert, endAlert, getMyAlerts, } from "../../api/api_delivery"; interface DeliveryStats { todayDeliveries: number; completedDeliveries: number; pendingDeliveries: number; approvedDeliveries: number; totalDeliveries: number; } interface OrderItem { produit: string; prix: number; quantite: number; } interface CurrentDelivery { id: number; orderNumber: string; customerName: string; customerPhone?: string; deliveryAddress: string; status: "assigned" | "picked_up" | "in_route"; distance: string; items?: OrderItem[]; totalPrice?: number; } interface LocationState { latitude: number | null; longitude: number | null; accuracy: number | null; lastUpdate: Date | null; permissionGranted: boolean; error: string | null; } interface AlertConfig { type: "success" | "error" | "warning" | "info"; title: string; message: string; onConfirm?: () => void; } function DeliveryDashboard() { const navigate = useNavigate(); const [stats, setStats] = useState({ todayDeliveries: 0, completedDeliveries: 0, pendingDeliveries: 0, approvedDeliveries: 0, totalDeliveries: 0, }); const [currentDelivery, setCurrentDelivery] = useState(null); const [loading, setLoading] = useState(true); const [deliveryPersonName, setDeliveryPersonName] = useState(""); const [isAvailable, setIsAvailable] = useState(true); const [currentStatus, setCurrentStatus] = useState< "available" | "busy" | "offline" >("offline"); const [location, setLocation] = useState({ latitude: null, longitude: null, accuracy: null, lastUpdate: null, permissionGranted: false, error: null, }); const [showLocationPrompt, setShowLocationPrompt] = useState(false); const watchIdRef = useRef(null); const [showAlert, setShowAlert] = useState(false); const [alertConfig, setAlertConfig] = useState({ type: "success", title: "", message: "", onConfirm: undefined, }); const [isAlertTriggered, setIsAlertTriggered] = useState(false); const [policeAlertLoading, setPoliceAlertLoading] = useState(false); useEffect(() => { const checkAuth = () => { if (!isDeliveryAuthenticated()) { console.log( "❌ [UserManagement] Cabine non authentifié, redirection vers /login-delivery/delivery", ); navigate("/login-delivery/delivery", { replace: true }); } }; checkAuth(); }, [navigate]); useEffect(() => { const authInterval = setInterval(() => { if (!isDeliveryAuthenticated()) { console.log( "❌ [UserManagement] Session cabine expirée, redirection vers /login-delivery/delivery", ); navigate("/login-delivery/delivery", { replace: true }); } }, 5000); return () => clearInterval(authInterval); }, [navigate]); const showStyledAlert = ( type: "success" | "error" | "warning" | "info", title: string, message: string, onConfirm?: () => void, ) => { setAlertConfig({ type, title, message, onConfirm }); setShowAlert(true); }; const requestLocationPermission = async () => { if (!navigator.geolocation) { console.error( "❌ [GEOLOCATION] Géolocalisation non supportée par ce navigateur", ); setLocation((prev) => ({ ...prev, error: "Géolocalisation non supportée par votre navigateur", })); return false; } try { console.log("📍 [GEOLOCATION] Demande de permission..."); const position = await new Promise( (resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject, { enableHighAccuracy: true, timeout: 10000, maximumAge: 0, }); }, ); console.log("✅ [GEOLOCATION] Permission accordée!", { lat: position.coords.latitude, lng: position.coords.longitude, accuracy: position.coords.accuracy, }); setLocation({ latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy, lastUpdate: new Date(), permissionGranted: true, error: null, }); setShowLocationPrompt(false); await updateLocationOnServer( position.coords.latitude, position.coords.longitude, ); startLocationTracking(); return true; } catch (error: any) { console.error("❌ [GEOLOCATION] Erreur permission:", error); let errorMessage = "Impossible d'accéder à votre position"; if (error.code === 1) { errorMessage = "Permission de géolocalisation refusée"; } else if (error.code === 2) { errorMessage = "Position indisponible"; } else if (error.code === 3) { errorMessage = "Délai d'attente dépassé"; } setLocation((prev) => ({ ...prev, error: errorMessage, permissionGranted: false, })); return false; } }; const updateLocationOnServer = async ( latitude: number, longitude: number, ) => { try { console.log("📡 [GEOLOCATION] Envoi position au serveur:", { latitude, longitude, }); const result = await updateMyLocation(latitude, longitude); if (!result.success) { console.error("❌ [GEOLOCATION] Erreur:", result.error); return; } console.log("✅ [GEOLOCATION] Position mise à jour sur le serveur"); if (result.status) { setCurrentStatus(result.status as any); setIsAvailable(result.status === "available"); } } catch (error) { console.error( "❌ [GEOLOCATION] Erreur mise à jour serveur:", error, ); } }; const startLocationTracking = () => { if (!navigator.geolocation) return; console.log("🎯 [GEOLOCATION] Démarrage du suivi continu..."); if (watchIdRef.current !== null) { navigator.geolocation.clearWatch(watchIdRef.current); } watchIdRef.current = navigator.geolocation.watchPosition( (position) => { console.log("📍 [GEOLOCATION] Position mise à jour:", { lat: position.coords.latitude, lng: position.coords.longitude, accuracy: position.coords.accuracy, }); setLocation({ latitude: position.coords.latitude, longitude: position.coords.longitude, accuracy: position.coords.accuracy, lastUpdate: new Date(), permissionGranted: true, error: null, }); updateLocationOnServer( position.coords.latitude, position.coords.longitude, ); }, (error) => { console.error("❌ [GEOLOCATION] Erreur suivi:", error); }, { enableHighAccuracy: true, timeout: 30000, maximumAge: 0, }, ); }; const stopLocationTracking = () => { if (watchIdRef.current !== null) { console.log("🛑 [GEOLOCATION] Arrêt du suivi"); navigator.geolocation.clearWatch(watchIdRef.current); watchIdRef.current = null; } }; useEffect(() => { const fetchDeliveryData = async () => { try { const username = extractAdminUsernameFromToken(); if (!username) { console.error( "❌ [DELIVERY_DASHBOARD] Username non trouvé", ); setLoading(false); return; } console.log( "🔍 [DELIVERY_DASHBOARD] Chargement données pour:", username, ); const statusResult = await getMyStatus(); if (statusResult.success && statusResult.status) { const status = statusResult.status.status; setCurrentStatus(status); setIsAvailable(status === "available"); console.log("✅ [DELIVERY_DASHBOARD] Statut:", status); } const queueResult = await getMyQueue(); // ✅ FIX: Vérification de queue_info avec optional chaining if (queueResult.success && queueResult.queue_info) { setStats((prev) => ({ ...prev, pendingDeliveries: queueResult.queue_info?.queue_size || 0, })); console.log( "✅ [DELIVERY_DASHBOARD] Queue:", queueResult.queue_info.queue_size, ); } const deliveriesResult = await getMyDeliveries(); if (deliveriesResult.success && deliveriesResult.deliveries) { const deliveries = deliveriesResult.deliveries; console.log( "✅ [DELIVERY_DASHBOARD] Livraisons:", deliveries, ); const completedToday = deliveries.filter((d: any) => { const isToday = new Date(d.updated_at).toDateString() === new Date().toDateString(); return d.status === "livre" && isToday; }).length; const totalCompleted = deliveries.filter( (d: any) => d.status === "livre", ).length; const approvedCount = deliveries.filter( (d: any) => d.status === "approved", ).length; console.log( `📊 [DELIVERY_DASHBOARD] Commandes approved: ${approvedCount}`, ); setStats((prev) => ({ ...prev, todayDeliveries: completedToday, completedDeliveries: totalCompleted, approvedDeliveries: approvedCount, totalDeliveries: deliveries.length, })); let currentDeliveryData = deliveries.find( (d: any) => d.status === "en_route", ); if (!currentDeliveryData) { currentDeliveryData = deliveries.find( (d: any) => d.status === "assigned", ); } if (currentDeliveryData) { console.log( "📦 [DELIVERY_DASHBOARD] Livraison en cours:", currentDeliveryData, ); const detailsResult = await getDeliveryDetails( currentDeliveryData.id, ); if (detailsResult.success && detailsResult.delivery) { const delivery = detailsResult.delivery.delivery; const clientInfo = detailsResult.delivery.client_info; setCurrentDelivery({ id: delivery.id, orderNumber: `CMD-${delivery.id}`, customerName: clientInfo?.nom ? `${clientInfo.nom} ${clientInfo.prenom || ""}`.trim() : clientInfo?.username || "Client", customerPhone: clientInfo?.telephone || "+33 X XX XX XX XX", deliveryAddress: delivery.adresse || "Adresse de livraison", status: delivery.status === "assigned" ? "assigned" : "in_route", distance: "N/A", // ✅ FIX: Cast to any pour accéder à items qui peut exister mais n'est pas typé items: (currentDeliveryData as any).items || [], totalPrice: currentDeliveryData.total_prix || 0, }); } } else { setCurrentDelivery(null); } } const details = await getDeliveryPersonDetails(username); // ✅ FIX: Cast to any car 'nom' n'existe pas dans le type mais peut exister dans la réponse setDeliveryPersonName((details as any).nom || details.username); // ✅ Vérifier les alertes actives au chargement const alertsResult = await getMyAlerts(); if (alertsResult.success && alertsResult.alerts) { const hasActiveAlert = alertsResult.alerts.some( (alert) => alert.status === "true", ); setIsAlertTriggered(hasActiveAlert); console.log( "📋 [DELIVERY_DASHBOARD] Alertes actives:", hasActiveAlert, ); } } catch (error) { console.error( "❌ [DELIVERY_DASHBOARD] Erreur chargement données:", error, ); } finally { setLoading(false); setTimeout(() => { setShowLocationPrompt(true); }, 1000); } }; fetchDeliveryData(); const refreshInterval = setInterval(() => { console.log( "🔄 [DELIVERY_DASHBOARD] Rafraîchissement automatique...", ); fetchDeliveryData(); }, 10000); return () => { stopLocationTracking(); clearInterval(refreshInterval); }; }, []); const handleStartDelivery = async () => { if (!currentDelivery) return; if (!location.latitude || !location.longitude) { showStyledAlert( "warning", "Position GPS requise", "Votre position GPS n'est pas disponible. Veuillez activer la géolocalisation pour démarrer la livraison.", ); return; } try { console.log( "📦 [DELIVERY_DASHBOARD] Démarrage de la livraison:", currentDelivery.id, ); const result = await startDelivery( currentDelivery.id, location.latitude, location.longitude, ); if (!result.success) { console.error("❌ [DELIVERY_DASHBOARD] Erreur:", result.error); showStyledAlert( "error", "Erreur", result.error || "Une erreur est survenue lors du démarrage de la livraison.", ); return; } console.log("✅ [DELIVERY_DASHBOARD] Livraison démarrée"); showStyledAlert( "success", "Livraison démarrée", "La livraison a été démarrée avec succès !", () => window.location.reload(), ); } catch (error) { console.error( "❌ [DELIVERY_DASHBOARD] Erreur démarrage livraison:", error, ); showStyledAlert( "error", "Erreur", "Une erreur est survenue lors du démarrage de la livraison.", ); } }; const handleCompleteDelivery = async () => { if (!currentDelivery) return; if (!location.latitude || !location.longitude) { showStyledAlert( "warning", "Position GPS requise", "Votre position GPS n'est pas disponible. Veuillez activer la géolocalisation pour valider la livraison.", ); return; } try { console.log( "✅ [DELIVERY_DASHBOARD] Marquage livraison comme terminée:", currentDelivery.id, ); const result = await updateDeliveryStatus( currentDelivery.id, "livre", location.latitude, location.longitude, ); if (!result.success) { console.error("❌ [DELIVERY_DASHBOARD] Erreur:", result.error); showStyledAlert( "error", "Erreur", result.error || "Une erreur est survenue lors de la validation de la livraison.", ); return; } console.log("✅ [DELIVERY_DASHBOARD] Livraison terminée"); showStyledAlert( "success", "Livraison terminée", "La livraison a été marquée comme terminée avec succès !", () => window.location.reload(), ); } catch (error) { console.error( "❌ [DELIVERY_DASHBOARD] Erreur complétion livraison:", error, ); showStyledAlert( "error", "Erreur", "Une erreur est survenue lors de la validation de la livraison.", ); } }; const handleNavigate = () => { if (currentDelivery) { const address = encodeURIComponent(currentDelivery.deliveryAddress); window.open( `https://www.google.com/maps/search/?api=1&query=${address}`, "_blank", ); } }; const toggleAvailability = async () => { try { const newStatus = isAvailable ? "offline" : "available"; console.log( `🔄 [DELIVERY_DASHBOARD] Changement statut: ${currentStatus} -> ${newStatus}`, ); const result = await updateMyStatus(newStatus); if (!result.success) { console.error("❌ [DELIVERY_DASHBOARD] Erreur:", result.error); showStyledAlert( "error", "Erreur", result.error || "Une erreur est survenue lors du changement de statut.", ); return; } console.log("✅ [DELIVERY_DASHBOARD] Statut mis à jour"); setIsAvailable(!isAvailable); setCurrentStatus(newStatus); } catch (error) { console.error( "❌ [DELIVERY_DASHBOARD] Erreur changement statut:", error, ); showStyledAlert( "error", "Erreur", "Une erreur est survenue lors du changement de statut.", ); } }; const handlePoliceAlert = async () => { if (policeAlertLoading) return; setPoliceAlertLoading(true); try { console.log("🚨 [POLICE_ALERT] Déclenchement alerte police..."); const result = await triggerPoliceAlert(); if (!result.success) { console.error("❌ [POLICE_ALERT] Erreur:", result.error); showStyledAlert( "error", "Erreur", result.error || "Impossible de déclencher l'alerte police.", ); return; } console.log("✅ [POLICE_ALERT] Alerte créée:", result); setIsAlertTriggered(true); showStyledAlert( "success", "Alerte Police Activée", "Votre alerte police a été transmise avec succès. Les autorités et votre équipe ont été notifiées.", ); // Vérifier les alertes actives pour mettre à jour l'état const alertsResult = await getMyAlerts(); if (alertsResult.success && alertsResult.alerts) { const hasActiveAlert = alertsResult.alerts.some( (alert) => alert.status === "true", ); setIsAlertTriggered(hasActiveAlert); } } catch (error) { console.error("❌ [POLICE_ALERT] Erreur:", error); showStyledAlert( "error", "Erreur", "Une erreur est survenue lors du déclenchement de l'alerte police.", ); } finally { setPoliceAlertLoading(false); } }; const handleEndPoliceAlert = async () => { if (policeAlertLoading) return; // Trouver l'alerte active const alertsResult = await getMyAlerts(); if (!alertsResult.success || !alertsResult.alerts) { showStyledAlert( "error", "Erreur", "Impossible de récupérer les alertes actives.", ); return; } const activeAlert = alertsResult.alerts.find( (alert) => alert.status === "true", ); if (!activeAlert) { showStyledAlert( "warning", "Aucune alerte active", "Il n'y a pas d'alerte police active à terminer.", ); return; } setPoliceAlertLoading(true); try { console.log( "🔚 [END_POLICE_ALERT] Fin d'alerte police:", activeAlert.id, ); const result = await endAlert(activeAlert.id); if (!result.success) { console.error("❌ [END_POLICE_ALERT] Erreur:", result.error); showStyledAlert( "error", "Erreur", result.error || "Impossible de terminer l'alerte police.", ); return; } console.log("✅ [END_POLICE_ALERT] Alerte terminée:", result); setIsAlertTriggered(false); showStyledAlert( "success", "Alerte Police Terminée", "Votre alerte police a été désactivée avec succès.", ); } catch (error) { console.error("❌ [END_POLICE_ALERT] Erreur:", error); showStyledAlert( "error", "Erreur", "Une erreur est survenue lors de la désactivation de l'alerte police.", ); } finally { setPoliceAlertLoading(false); } }; if (loading) { return (

Chargement de votre tableau de bord...

); } return (
{/* Modal de demande de géolocalisation */} {showLocationPrompt && !location.permissionGranted && (

Activer la localisation

Pour vous assigner des livraisons et suivre vos déplacements en temps réel, nous avons besoin d'accéder à votre position GPS.

{location.error && (

⚠️ {location.error}

)}
)} {/* Modal d'alerte stylisée */} {showAlert && (
setShowAlert(false)} >
e.stopPropagation()} >
{alertConfig.type === "success" && ( )} {alertConfig.type === "error" && ( )} {alertConfig.type === "warning" && ( )} {alertConfig.type === "info" && ( )}

{alertConfig.title}

{alertConfig.message}

)} {/* Header */}

Tableau de Bord Livreur

Gérez vos livraisons efficacement

Bonjour, {deliveryPersonName}!
{isAvailable ? "Disponible" : "Hors ligne"}
{location.permissionGranted && location.latitude && location.longitude && (
GPS actif
)} {!location.permissionGranted && (
setShowLocationPrompt(true)} > GPS désactivé
)} {/* Bouton Alerte Police - Un seul bouton à la fois */} {!isAlertTriggered ? ( ) : ( )}
{/* Stats Cards */}

Complétées

{stats.completedDeliveries}

Approved

{stats.approvedDeliveries}

navigate("/delivery/stats")} style={{ cursor: "pointer" }} >

Voir Statistiques

Détails

navigate("/delivery/alerts")} style={{ cursor: "pointer" }} >

Alertes

Détails

{/* Current Delivery Section */}

Livraison en Cours

{stats.pendingDeliveries > 0 && (
{stats.pendingDeliveries} livraison {stats.pendingDeliveries > 1 ? "s" : ""} en file d'attente
)}
{currentDelivery ? (

Détails de la Livraison

{currentDelivery.status === "assigned" && ( <> Assignée )} {currentDelivery.status === "in_route" && ( <> En Route )}

N° Commande

{currentDelivery.orderNumber}

Client

{currentDelivery.customerName}

Adresse

{currentDelivery.deliveryAddress}

{/* Section Produits */} {currentDelivery.items && currentDelivery.items.length > 0 && (

Produits à livrer

{currentDelivery.items.map( (item, index) => (

{item.produit}

Quantité:{" "} {item.quantite}

{item.prix.toFixed(2)} €

), )}
Total de la commande {currentDelivery.totalPrice?.toFixed( 2, )}{" "} €
)}
{currentDelivery.status === "assigned" && ( )} {currentDelivery.status === "in_route" && ( )}
) : (

Aucune livraison en cours

Les commandes vous seront assignées automatiquement selon votre proximité
)}
); } export default DeliveryDashboard;