diff --git a/frontend-admin/src/screens/admin/OrderDetailScreen.tsx b/frontend-admin/src/screens/admin/OrderDetailScreen.tsx index 5a01986b..8f2f15ea 100644 --- a/frontend-admin/src/screens/admin/OrderDetailScreen.tsx +++ b/frontend-admin/src/screens/admin/OrderDetailScreen.tsx @@ -6,7 +6,6 @@ import { ScrollView, TouchableOpacity, Modal, - StatusBar, Alert, useWindowDimensions, } from "react-native"; @@ -16,7 +15,7 @@ import { type RouteProp, } from "@react-navigation/native"; import { Ionicons } from "@expo/vector-icons"; -import MapView, { Marker, Polyline, PROVIDER_DEFAULT } from "react-native-maps"; +import TomTomMap, { type TomTomMapRef, type TomTomMarker } from "../../components/TomTomMap"; import { spacing, fontSize, borderRadius } from "../../theme"; import { useTheme } from "../../context/ThemeContext"; import { @@ -30,7 +29,7 @@ import { deleteCommandItem, deleteCommand, } from "../../api/api_admin"; -import { geocodeAddress, calculateRoute } from "../../api/tomtom"; +import { calculateRoute, geocodeAddress } from "../../api/tomtom"; import type { RouteInfo, LatLng } from "../../api/tomtom"; import type { AdminStackParamList } from "../../navigation/types"; import StatusBadge from "../../components/StatusBadge"; @@ -55,11 +54,12 @@ export default function OrderDetailScreen() { const [showItemsModal, setShowItemsModal] = useState(false); // Map / tracking - const mapRef = useRef(null); - const fullscreenMapRef = useRef(null); + const mapRef = useRef(null); + const fullscreenMapRef = useRef(null); const [mapFullscreen, setMapFullscreen] = useState(false); const [livreurCoords, setLivreurCoords] = useState(null); const [destCoords, setDestCoords] = useState(null); + const [livreurMarkers, setLivreurMarkers] = useState([]); const [routeInfo, setRouteInfo] = useState(null); const [mapLoading, setMapLoading] = useState(false); const { alert, showError, showSuccess, hideAlert } = useAlert(); @@ -99,13 +99,21 @@ export default function OrderDetailScreen() { return () => clearInterval(interval); }, [orderId]); + // Rejoue la route sur la carte fullscreen quand elle s'ouvre + useEffect(() => { + if (mapFullscreen && livreurCoords && destCoords) { + setTimeout(() => { + fullscreenMapRef.current?.calcRoute(livreurCoords, destCoords); + }, 600); + } + }, [mapFullscreen]); + const loadLivreurRoute = async ( livreurUsername: string, deliveryAddress: string, ) => { setMapLoading(true); try { - // Get livreur location const details = await getDeliveryPersonDetails(livreurUsername); const loc = details?.location; if (!loc?.latitude || !loc?.longitude) { @@ -113,24 +121,26 @@ export default function OrderDetailScreen() { return; } - const origin: LatLng = { + const origin: LatLng = { latitude: loc.latitude, longitude: loc.longitude }; + setLivreurCoords(origin); + setLivreurMarkers([{ + id: livreurUsername, latitude: loc.latitude, longitude: loc.longitude, - }; - setLivreurCoords(origin); + color: "#22c55e", + label: livreurUsername, + description: "Livreur", + }]); - // Geocode destination + // Dessine la route sur la carte et récupère les infos (distance/durée) const dest = await geocodeAddress(deliveryAddress); - if (!dest) { - setMapLoading(false); - return; - } - setDestCoords(dest); - - // Calculate route - const result = await calculateRoute(origin, dest); - if (result) { - setRouteInfo(result.route); + if (dest) { + setDestCoords(dest); + const result = await calculateRoute(origin, dest); + if (result) { + setRouteInfo(result.route); + mapRef.current?.calcRoute(origin, dest); + } } } catch { /* silent */ @@ -138,27 +148,6 @@ export default function OrderDetailScreen() { setMapLoading(false); }; - const fitMapToRoute = (ref: React.RefObject) => { - if (ref.current && livreurCoords && destCoords) { - ref.current.fitToCoordinates( - [ - { - latitude: livreurCoords.latitude, - longitude: livreurCoords.longitude, - }, - { - latitude: destCoords.latitude, - longitude: destCoords.longitude, - }, - ], - { - edgePadding: { top: 80, right: 60, bottom: 80, left: 60 }, - animated: true, - }, - ); - } - }; - const handleValidate = async () => { try { await validateCommand(orderId); @@ -316,39 +305,6 @@ export default function OrderDetailScreen() { }, map: { width: "100%", height: MAP_HEIGHT }, - driverMarkerOuter: { - width: 34, - height: 34, - borderRadius: 17, - backgroundColor: colors.success + "40", - justifyContent: "center", - alignItems: "center", - }, - driverMarkerInner: { - width: 26, - height: 26, - borderRadius: 13, - backgroundColor: colors.success, - justifyContent: "center", - alignItems: "center", - }, - destMarkerOuter: { - width: 30, - height: 30, - borderRadius: 15, - backgroundColor: colors.danger + "40", - justifyContent: "center", - alignItems: "center", - }, - destMarkerInner: { - width: 22, - height: 22, - borderRadius: 11, - backgroundColor: colors.danger, - justifyContent: "center", - alignItems: "center", - }, - routeOverlay: { position: "absolute", top: spacing.s, @@ -552,16 +508,21 @@ export default function OrderDetailScreen() { ); // Groupement des items par product_id - const productGroups = (items ?? []).reduce>((acc, item) => { - const key = String(item.product_id || item.produit); - if (!acc[key]) acc[key] = []; - acc[key].push(item); - return acc; - }, {}); + const productGroups = (items ?? []).reduce>( + (acc, item) => { + const key = String(item.product_id || item.produit); + if (!acc[key]) acc[key] = []; + acc[key].push(item); + return acc; + }, + {}, + ); const groupedList = Object.values(productGroups); // Récapitulatif par catégorie - const categoryTotals = (items ?? []).reduce>((acc, item) => { + const categoryTotals = (items ?? []).reduce< + Record + >((acc, item) => { const cat = item.category || "Autre"; if (!acc[cat]) acc[cat] = { qty: 0, total: 0 }; acc[cat].qty += item.quantite ?? 0; @@ -590,74 +551,21 @@ export default function OrderDetailScreen() { visible={mapFullscreen} animationType="fade" onRequestClose={() => setMapFullscreen(false)} - statusBarTranslucent > -