import React, { useRef, useEffect, useCallback, forwardRef, useImperativeHandle, } from "react"; import { StyleSheet } from "react-native"; import { WebView } from "react-native-webview"; const TOMTOM_API_KEY = "MERY8I7LMeYVSLKO5WuV73W9rKJpBLoB"; export interface TomTomMarker { id: string; latitude: number; longitude: number; color: string; label?: string; description?: string; isSelected?: boolean; } export interface TomTomRoute { coordinates: { latitude: number; longitude: number }[]; color?: string; } export interface TomTomDestination { latitude: number; longitude: number; color?: string; } export interface TomTomMapRef { fitAllMarkers: () => void; fitToCoordinates: ( coords: { latitude: number; longitude: number }[], ) => void; } interface TomTomMapProps { style?: any; markers?: TomTomMarker[]; route?: TomTomRoute | null; destination?: TomTomDestination | null; initialCenter?: { latitude: number; longitude: number }; initialZoom?: number; onMarkerPress?: (markerId: string) => void; } const TomTomMap = forwardRef( ( { style, markers = [], route, destination, initialCenter, initialZoom = 12, 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( `handleMessage(${json}); true;`, ); } else { pendingMessages.current.push(json); } }, []); useImperativeHandle( ref, () => ({ fitAllMarkers: () => sendMessage({ type: "fitAll" }), fitToCoordinates: (coords) => sendMessage({ type: "fitCoords", coords }), }), [sendMessage], ); useEffect(() => { sendMessage({ type: "updateMarkers", markers }); }, [markers, sendMessage]); useEffect(() => { sendMessage({ type: "updateRoute", route: route || null, destination: destination || null, }); }, [route, destination, sendMessage]); const onMessage = useCallback( (event: any) => { try { const data = JSON.parse(event.nativeEvent.data); if (data.type === "ready") { isReady.current = true; // flush pending for (const msg of pendingMessages.current) { webViewRef.current?.injectJavaScript( `handleMessage(${msg}); true;`, ); } pendingMessages.current = []; // Auto fit markers after ready + flush setTimeout(() => { sendMessage({ type: "fitAll" }); }, 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); return ( ); }, ); function buildHtml( center: { latitude: number; longitude: number }, zoom: number, ) { return `
`; } const styles = StyleSheet.create({ map: { flex: 1 }, }); export default TomTomMap;