11'use client'
22
3- import { useEffect , useRef , useCallback } from 'react' // Removed useState
3+ import { useEffect , useRef , useCallback } from 'react'
44import mapboxgl from 'mapbox-gl'
55import MapboxDraw from '@mapbox/mapbox-gl-draw'
66import * as turf from '@turf/turf'
@@ -9,12 +9,24 @@ import 'react-toastify/dist/ReactToastify.css'
99import 'mapbox-gl/dist/mapbox-gl.css'
1010import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
1111import { useMapToggle , MapToggleEnum } from '../map-toggle-context'
12- import { useMapData } from './map-data-context' ; // Add this import
13- import { useMapLoading } from '../map-loading-context' ; // Import useMapLoading
12+ import { useMapData } from './map-data-context' ;
13+ import { useMapLoading } from '../map-loading-context' ;
1414import { useMap } from './map-context'
15+ import { FeatureCollection } from 'geojson'
1516
1617mapboxgl . accessToken = process . env . NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN as string ;
1718
19+ interface MapFeedback {
20+ success : boolean ;
21+ currentCenter : [ number , number ] ;
22+ currentZoom : number ;
23+ currentPitch : number ;
24+ currentBearing : number ;
25+ currentBounds ?: [ [ number , number ] , [ number , number ] ] ;
26+ error ?: string ;
27+ timestamp : number ;
28+ }
29+
1830export const Mapbox : React . FC < { position ?: { latitude : number ; longitude : number ; } } > = ( { position } ) => {
1931 const mapContainer = useRef < HTMLDivElement > ( null )
2032 const map = useRef < mapboxgl . Map | null > ( null )
@@ -30,16 +42,16 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
3042 const initializedRef = useRef < boolean > ( false )
3143 const currentMapCenterRef = useRef < { center : [ number , number ] ; zoom : number ; pitch : number } > ( { center : [ position ?. longitude ?? 0 , position ?. latitude ?? 0 ] , zoom : 2 , pitch : 0 } ) ;
3244 const drawingFeatures = useRef < any > ( null )
33- const { mapType, setMapType } = useMapToggle ( ) // Get setMapType
34- const { mapData, setMapData } = useMapData ( ) ; // Consume the new context, get setMapData
35- const { setIsMapLoaded } = useMapLoading ( ) ; // Get setIsMapLoaded from context
45+ const { mapType, setMapType } = useMapToggle ( )
46+ const { mapData, setMapData } = useMapData ( ) ;
47+ const { setIsMapLoaded } = useMapLoading ( ) ;
3648 const previousMapTypeRef = useRef < MapToggleEnum | null > ( null )
3749
3850 // Refs for long-press functionality
3951 const longPressTimerRef = useRef < NodeJS . Timeout | null > ( null ) ;
4052 const isMouseDownRef = useRef < boolean > ( false ) ;
4153
42- // const [isMapLoaded, setIsMapLoaded] = useState(false); // Removed local state
54+ const isDebug = process . env . NODE_ENV !== 'production' ;
4355
4456 // Formats the area or distance for display
4557 const formatMeasurement = useCallback ( ( value : number , isArea = true ) => {
@@ -97,17 +109,12 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
97109 el . style . borderRadius = '4px'
98110 el . style . fontSize = '12px'
99111 el . style . fontWeight = 'bold'
100- el . style . color = '#333333' // Added darker color
112+ el . style . color = '#333333'
101113 el . style . boxShadow = '0 2px 4px rgba(0,0,0,0.2)'
102114 el . style . pointerEvents = 'none'
103115 el . textContent = formattedArea
104116
105117 // Add marker for the label
106-
107-
108-
109-
110-
111118 if ( map . current ) {
112119 const marker = new mapboxgl . Marker ( { element : el } )
113120 . setLngLat ( coordinates as [ number , number ] )
@@ -136,7 +143,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
136143 el . style . borderRadius = '4px'
137144 el . style . fontSize = '12px'
138145 el . style . fontWeight = 'bold'
139- el . style . color = '#333333' // Added darker color
146+ el . style . color = '#333333'
140147 el . style . boxShadow = '0 2px 4px rgba(0,0,0,0.2)'
141148 el . style . pointerEvents = 'none'
142149 el . textContent = formattedLength
@@ -547,11 +554,6 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
547554 updateMapPosition ( lat , lng ) ;
548555 }
549556 }
550- // TODO: Handle mapData.mapFeature for drawing routes, polygons, etc. in a future step.
551- // For example:
552- // if (mapData.mapFeature && mapData.mapFeature.route_geometry && typeof drawRoute === 'function') {
553- // drawRoute(mapData.mapFeature.route_geometry); // Implement drawRoute function if needed
554- // }
555557 } , [ mapData . targetPosition , mapData . mapFeature , updateMapPosition ] ) ;
556558
557559 // Effect to handle GeoJSON data updates
@@ -563,12 +565,13 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
563565
564566 // If GeoJSON data is present, add or update the source and layers
565567 if ( mapData . geojson ) {
568+ const geojsonData = mapData . geojson as FeatureCollection ;
566569 if ( source ) {
567- ( source as mapboxgl . GeoJSONSource ) . setData ( mapData . geojson as any ) ;
570+ ( source as mapboxgl . GeoJSONSource ) . setData ( geojsonData ) ;
568571 } else {
569572 mapInstance . addSource ( 'geojson-data' , {
570573 type : 'geojson' ,
571- data : mapData . geojson as any ,
574+ data : geojsonData ,
572575 } ) ;
573576
574577 // Add layer for points
@@ -607,26 +610,28 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
607610
608611 // Effect to execute map commands with feedback
609612 useEffect ( ( ) => {
610- console . log ( '🗺️ Map commands useEffect triggered:' , {
611- hasMap : ! ! map . current ,
612- hasCommands : ! ! mapData . mapCommands ,
613- commandCount : mapData . mapCommands ?. length || 0 ,
614- commands : mapData . mapCommands ,
615- } ) ;
613+ if ( isDebug ) {
614+ console . log ( '🗺️ Map commands useEffect triggered:' , {
615+ hasMap : ! ! map . current ,
616+ hasCommands : ! ! mapData . mapCommands ,
617+ commandCount : mapData . mapCommands ?. length || 0 ,
618+ commands : mapData . mapCommands ,
619+ } ) ;
620+ }
616621
617622 if ( ! map . current || ! mapData . mapCommands || mapData . mapCommands . length === 0 ) {
618- console . log ( '⚠️ Skipping command execution - missing map or commands' ) ;
623+ if ( isDebug ) console . log ( '⚠️ Skipping command execution - missing map or commands' ) ;
619624 return ;
620625 }
621626
622627 const mapInstance = map . current ;
623628 let executionError : string | undefined ;
624629
625- console . log ( `🗺️ Executing ${ mapData . mapCommands . length } map commands...` ) ;
630+ if ( isDebug ) console . log ( `🗺️ Executing ${ mapData . mapCommands . length } map commands...` ) ;
626631
627632 try {
628633 mapData . mapCommands . forEach ( ( command , idx ) => {
629- console . log ( `🗺️ Executing command ${ idx + 1 } /${ mapData . mapCommands ! . length } : ${ command . command } ` , command . params ) ;
634+ if ( isDebug ) console . log ( `🗺️ Executing command ${ idx + 1 } /${ mapData . mapCommands ! . length } : ${ command . command } ` , command . params ) ;
630635 switch ( command . command ) {
631636 case 'flyTo' :
632637 mapInstance . flyTo ( command . params ) ;
@@ -669,14 +674,28 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
669674 }
670675 } ) ;
671676
677+ // Guard flag to ensure feedbackHandler only runs once
678+ let handled = false ;
679+ let fallbackTimeoutId : NodeJS . Timeout | null = null ;
680+
672681 // Capture feedback after commands complete
673682 const feedbackHandler = ( ) => {
683+ if ( handled ) return ;
684+ handled = true ;
685+
686+ if ( fallbackTimeoutId ) {
687+ clearTimeout ( fallbackTimeoutId ) ;
688+ }
689+
690+ // Clean up event listener
691+ mapInstance . off ( 'moveend' , feedbackHandler ) ;
692+
674693 const center = mapInstance . getCenter ( ) ;
675694 const bounds = mapInstance . getBounds ( ) ;
676695
677- const feedback : any = {
696+ const feedback : MapFeedback = {
678697 success : ! executionError ,
679- currentCenter : [ center . lng , center . lat ] as [ number , number ] ,
698+ currentCenter : [ center . lng , center . lat ] ,
680699 currentZoom : mapInstance . getZoom ( ) ,
681700 currentPitch : mapInstance . getPitch ( ) ,
682701 currentBearing : mapInstance . getBearing ( ) ,
@@ -688,10 +707,10 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
688707 feedback . currentBounds = [
689708 [ bounds . getWest ( ) , bounds . getSouth ( ) ] ,
690709 [ bounds . getEast ( ) , bounds . getNorth ( ) ]
691- ] as [ [ number , number ] , [ number , number ] ] ;
710+ ] ;
692711 }
693712
694- console . log ( '📍 Map feedback:' , feedback ) ;
713+ if ( isDebug ) console . log ( '📍 Map feedback:' , feedback ) ;
695714
696715 // Send feedback via callback if provided
697716 if ( mapData . feedbackCallback ) {
@@ -710,24 +729,28 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
710729 mapInstance . once ( 'moveend' , feedbackHandler ) ;
711730
712731 // Fallback timeout in case moveend doesn't fire
713- setTimeout ( ( ) => {
732+ // Increased timeout to allow for animation start
733+ fallbackTimeoutId = setTimeout ( ( ) => {
714734 if ( mapInstance . isMoving && mapInstance . isMoving ( ) ) {
715735 return ; // Still moving, wait for moveend
716736 }
717737 // If not moving, trigger feedback immediately
718- mapInstance . off ( 'moveend' , feedbackHandler ) ;
719738 feedbackHandler ( ) ;
720- } , 100 ) ;
739+ } , 500 ) ;
721740
722741 } catch ( error ) {
723742 executionError = error instanceof Error ? error . message : 'Unknown execution error' ;
724743 console . error ( '❌ Map command execution error:' , error ) ;
725744
726745 // Send error feedback
727- const errorFeedback = {
746+ const errorFeedback : MapFeedback = {
728747 success : false ,
729748 error : executionError ,
730749 timestamp : Date . now ( ) ,
750+ currentCenter : [ mapInstance . getCenter ( ) . lng , mapInstance . getCenter ( ) . lat ] ,
751+ currentZoom : mapInstance . getZoom ( ) ,
752+ currentPitch : mapInstance . getPitch ( ) ,
753+ currentBearing : mapInstance . getBearing ( )
731754 } ;
732755
733756 if ( mapData . feedbackCallback ) {
@@ -741,7 +764,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
741764 } ) ) ;
742765 }
743766
744- } , [ mapData . mapCommands , mapData . feedbackCallback , setMapData ] ) ;
767+ } , [ mapData . mapCommands , mapData . feedbackCallback , setMapData , isDebug ] ) ;
745768
746769 // Long-press handlers
747770 const handleMouseDown = useCallback ( ( ) => {
@@ -770,14 +793,11 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
770793
771794 // Cleanup for the main useEffect
772795 useEffect ( ( ) => {
773- // ... existing useEffect logic ...
774796 return ( ) => {
775- // ... existing cleanup logic ...
776- if ( longPressTimerRef . current ) { // Cleanup timer on component unmount
797+ if ( longPressTimerRef . current ) {
777798 clearTimeout ( longPressTimerRef . current ) ;
778799 longPressTimerRef . current = null ;
779800 }
780- // ... existing cleanup logic for map and geolocation ...
781801 if ( map . current ) {
782802 map . current . off ( 'moveend' , captureMapCenter )
783803
@@ -811,7 +831,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
811831 handleUserInteraction ,
812832 startRotation ,
813833 stopRotation ,
814- mapType , // mapType is already here, good.
834+ mapType ,
815835 updateMeasurementLabels ,
816836 setupGeolocationWatcher ,
817837 captureMapCenter ,
@@ -828,7 +848,7 @@ export const Mapbox: React.FC<{ position?: { latitude: number; longitude: number
828848 className = "h-full w-full overflow-hidden rounded-l-lg"
829849 onMouseDown = { handleMouseDown }
830850 onMouseUp = { handleMouseUp }
831- onMouseLeave = { handleMouseUp } // Clear timer if mouse leaves container while pressed
851+ onMouseLeave = { handleMouseUp }
832852 />
833853 </ div >
834854 )
0 commit comments