import React, { useRef, useEffect, useCallback, forwardRef, useImperativeHandle, } from "react"; import { StyleSheet } from "react-native"; import { WebView } from "react-native-webview"; import { geocodeAddress, calculateRoute } from "../api/tomtom"; const TOMTOM_API_KEY = "MERY8I7LMeYVSLKO5WuV73W9rKJpBLoB"; export interface TomTomMarker { id: string; latitude: number; longitude: number; color: string; label?: string; description?: string; isSelected?: boolean; } export interface TomTomMapRef { fitAllMarkers: () => void; fitToCoordinates: ( coords: { latitude: number; longitude: number }[], ) => void; calcRoute: ( origin: { latitude: number; longitude: number }, destination: { latitude: number; longitude: number }, ) => void; calcRouteFromAddress: ( origin: { latitude: number; longitude: number }, address: string, ) => void; clearRoute: () => void; } interface TomTomMapProps { style?: any; markers?: TomTomMarker[]; initialCenter?: { latitude: number; longitude: number }; initialZoom?: number; onMarkerPress?: (markerId: string) => void; } const TomTomMap = forwardRef( ( { style, markers = [], initialCenter, initialZoom = 14, onMarkerPress, }, ref, ) => { const webViewRef = useRef(null); const isReady = useRef(false); const pendingMessages = useRef([]); const sendMessage = useCallback((msg: object) => { const json = JSON.stringify(msg); if (isReady.current) { webViewRef.current?.injectJavaScript( `(function(){ try { handleMessage(${json}); } catch(e) {} })(); true;`, ); } else { pendingMessages.current.push(json); } }, []); useImperativeHandle( ref, () => ({ fitAllMarkers: () => sendMessage({ type: "fitAll" }), fitToCoordinates: (coords) => sendMessage({ type: "fitCoords", coords }), clearRoute: () => sendMessage({ type: "clearRoute" }), calcRoute: (origin, dest) => { calculateRoute(origin, dest).then((result) => { if (result) { sendMessage({ type: "drawRoute", coordinates: result.route.coordinates, destination: dest, }); } else { // Fallback: ligne droite sendMessage({ type: "drawRoute", coordinates: [origin, dest], destination: dest, }); } }).catch(() => { sendMessage({ type: "drawRoute", coordinates: [origin, dest], destination: dest, }); }); }, calcRouteFromAddress: async (origin, address) => { try { const dest = await geocodeAddress(address); if (!dest) return; const result = await calculateRoute(origin, dest); if (result) { sendMessage({ type: "drawRoute", coordinates: result.route.coordinates, destination: dest, }); } else { sendMessage({ type: "drawRoute", coordinates: [origin, dest], destination: dest, }); } } catch { /* silent */ } }, }), [sendMessage], ); useEffect(() => { sendMessage({ type: "updateMarkers", markers }); }, [markers, sendMessage]); const onMessage = useCallback( (event: any) => { try { const data = JSON.parse(event.nativeEvent.data); if (data.type === "ready") { isReady.current = true; // Rejouer les messages en attente const pending = pendingMessages.current.slice(); pendingMessages.current = []; for (const msg of pending) { webViewRef.current?.injectJavaScript( `(function(){ try { handleMessage(${msg}); } catch(e) {} })(); true;`, ); } // Fit sur tous les markers après un court délai setTimeout(() => { webViewRef.current?.injectJavaScript( `(function(){ try { handleMessage(${JSON.stringify({ type: "fitAll" })}); } catch(e) {} })(); true;`, ); }, 500); } else if (data.type === "markerPress" && onMarkerPress) { onMarkerPress(data.id); } } catch { /* ignore */ } }, [onMarkerPress], ); const center = initialCenter || (markers.length > 0 ? { latitude: markers[0].latitude, longitude: markers[0].longitude, } : { latitude: 48.8566, longitude: 2.3522 }); const html = buildHtml(center, initialZoom, TOMTOM_API_KEY); return ( ); }, ); function buildHtml( center: { latitude: number; longitude: number }, zoom: number, apiKey: string, ) { return `
`; } const styles = StyleSheet.create({ map: { flex: 1 }, }); export default TomTomMap;