diff --git a/components/map/mapbox-map.tsx b/components/map/mapbox-map.tsx index 3dd390cd..69b601b9 100644 --- a/components/map/mapbox-map.tsx +++ b/components/map/mapbox-map.tsx @@ -20,6 +20,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number const map = useRef(null) const { setMap } = useMap() const drawRef = useRef(null) + const navControlRef = useRef(null) const rotationFrameRef = useRef(null) const polygonLabelsRef = useRef<{ [id: string]: mapboxgl.Marker }>({}) const lineLabelsRef = useRef<{ [id: string]: mapboxgl.Marker }>({}) @@ -34,6 +35,11 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number const { mapData, setMapData } = useMapData(); // Consume the new context, get setMapData const { setIsMapLoaded } = useMapLoading(); // Get setIsMapLoaded from context const previousMapTypeRef = useRef(null) + const mapTypeRef = useRef(mapType) + + useEffect(() => { + mapTypeRef.current = mapType + }, [mapType]) // Refs for long-press functionality const longPressTimerRef = useRef(null); @@ -221,7 +227,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number }) }) setTimeout(() => { - if (mapType === MapToggleEnum.RealTimeMode) { + if (mapTypeRef.current === MapToggleEnum.RealTimeMode) { startRotation() } isUpdatingPositionRef.current = false @@ -231,7 +237,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number isUpdatingPositionRef.current = false } } - }, [mapType, startRotation, stopRotation]) + }, [startRotation, stopRotation]) // Set up drawing tools const setupDrawingTools = useCallback(() => { @@ -295,7 +301,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number geolocationWatchIdRef.current = null } - if (mapType !== MapToggleEnum.RealTimeMode) return + if (mapTypeRef.current !== MapToggleEnum.RealTimeMode) return if (!navigator.geolocation) { toast('Geolocation is not supported by your browser') @@ -312,7 +318,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number } geolocationWatchIdRef.current = navigator.geolocation.watchPosition(success, error) - }, [mapType, updateMapPosition]) + }, [updateMapPosition]) // Capture map center changes const captureMapCenter = useCallback(() => { @@ -367,7 +373,23 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number if (mapType === MapToggleEnum.DrawingMode) { // If switching to drawing mode, setup drawing tools setupDrawingTools() + + // Setup zoom controls if not already present + if (!navControlRef.current) { + navControlRef.current = new mapboxgl.NavigationControl(); + map.current.addControl(navControlRef.current, 'top-left'); + } } else { + // Remove zoom controls if present + if (navControlRef.current) { + try { + map.current.removeControl(navControlRef.current); + navControlRef.current = null; + } catch (e) { + console.log('Error removing navigation control:', e); + } + } + // If switching from drawing mode, remove drawing tools but save features if (drawRef.current) { // Save current drawings before removing control @@ -436,10 +458,6 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number preserveDrawingBuffer: true }) - if (window.innerWidth > 768) { - map.current.addControl(new mapboxgl.NavigationControl(), 'top-left') - } - // Register event listeners map.current.on('moveend', captureMapCenter) map.current.on('mousedown', handleUserInteraction) @@ -472,13 +490,17 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number }, }) - // Initialize drawing tools based on initial mode - if (mapType === MapToggleEnum.DrawingMode) { + // Initial setup for the current mode + if (mapTypeRef.current === MapToggleEnum.DrawingMode) { setupDrawingTools() + if (!navControlRef.current) { + navControlRef.current = new mapboxgl.NavigationControl(); + map.current.addControl(navControlRef.current, 'top-left'); + } } // If not in real-time mode, start rotation - if (mapType !== MapToggleEnum.RealTimeMode) { + if (mapTypeRef.current !== MapToggleEnum.RealTimeMode) { startRotation() } @@ -489,6 +511,10 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number } return () => { + if (longPressTimerRef.current) { + clearTimeout(longPressTimerRef.current); + } + if (map.current) { map.current.off('moveend', captureMapCenter) @@ -498,10 +524,20 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number map.current.off('draw.delete', updateMeasurementLabels) map.current.off('draw.update', updateMeasurementLabels) map.current.removeControl(drawRef.current) + drawRef.current = null } catch (e) { console.log('Draw control already removed') } } + + if (navControlRef.current) { + try { + map.current.removeControl(navControlRef.current) + navControlRef.current = null + } catch (e) { + console.log('Navigation control already removed') + } + } // Clean up any existing labels Object.values(polygonLabelsRef.current).forEach(marker => marker.remove()) @@ -520,16 +556,16 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number } } }, [ - handleUserInteraction, - startRotation, - stopRotation, - mapType, - updateMeasurementLabels, - setupGeolocationWatcher, - captureMapCenter, - setupDrawingTools, + captureMapCenter, + handleUserInteraction, setIsMapLoaded, - setMap + setMap, + setupDrawingTools, + setupGeolocationWatcher, + startRotation, + stopRotation, + updateMeasurementLabels + // Removed position, mapData.cameraState and mapType to avoid map recreation ]) // Handle position updates from props @@ -547,11 +583,6 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number updateMapPosition(lat, lng); } } - // TODO: Handle mapData.mapFeature for drawing routes, polygons, etc. in a future step. - // For example: - // if (mapData.mapFeature && mapData.mapFeature.route_geometry && typeof drawRoute === 'function') { - // drawRoute(mapData.mapFeature.route_geometry); // Implement drawRoute function if needed - // } }, [mapData.targetPosition, mapData.mapFeature, updateMapPosition]); // Long-press handlers @@ -579,58 +610,6 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number } }, []); - // Cleanup for the main useEffect - useEffect(() => { - // ... existing useEffect logic ... - return () => { - // ... existing cleanup logic ... - if (longPressTimerRef.current) { // Cleanup timer on component unmount - clearTimeout(longPressTimerRef.current); - longPressTimerRef.current = null; - } - // ... existing cleanup logic for map and geolocation ... - if (map.current) { - map.current.off('moveend', captureMapCenter) - - if (drawRef.current) { - try { - map.current.off('draw.create', updateMeasurementLabels) - map.current.off('draw.delete', updateMeasurementLabels) - map.current.off('draw.update', updateMeasurementLabels) - map.current.removeControl(drawRef.current) - } catch (e) { - console.log('Draw control already removed') - } - } - - Object.values(polygonLabelsRef.current).forEach(marker => marker.remove()) - Object.values(lineLabelsRef.current).forEach(marker => marker.remove()) - - stopRotation() - setIsMapLoaded(false) - setMap(null) - map.current.remove() - map.current = null - } - - if (geolocationWatchIdRef.current !== null) { - navigator.geolocation.clearWatch(geolocationWatchIdRef.current) - geolocationWatchIdRef.current = null - } - }; - }, [ - handleUserInteraction, - startRotation, - stopRotation, - mapType, // mapType is already here, good. - updateMeasurementLabels, - setupGeolocationWatcher, - captureMapCenter, - setupDrawingTools, - setIsMapLoaded, - setMap - ]); - return (
diff --git a/tests/map.spec.ts b/tests/map.spec.ts index 5d6aa972..1047d3e1 100644 --- a/tests/map.spec.ts +++ b/tests/map.spec.ts @@ -35,6 +35,10 @@ test.describe('Map functionality', () => { return; } + // Switch to drawing mode to make zoom controls visible + await page.click('[data-testid="map-toggle"]'); + await page.click('[data-testid="map-mode-draw"]'); + const hasMap = await page.evaluate(() => Boolean((window as any).map)); if (!hasMap) test.skip(true, 'Map instance not available on window for E2E');