Skip to content

Commit 4f989c2

Browse files
committed
fix: integrate geojsonEnricherV2 and refactor MapboxMap feedback handling
1 parent a74b7e8 commit 4f989c2

File tree

2 files changed

+70
-48
lines changed

2 files changed

+70
-48
lines changed

app/actions.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { VideoSearchSection } from '@/components/video-search-section'
3131
import { MapQueryHandler } from '@/components/map/map-query-handler' // Add this import
3232
import { LocationResponseHandler } from '@/components/map/location-response-handler'
3333
import { PartialRelated } from '@/lib/schema/related'
34+
import { geojsonEnricherV2 } from '@/lib/agents/geojson-enricher-v2'
3435

3536
// Removed mcp parameter from submit, as geospatialTool now handles its client.
3637
async function submit(formData?: FormData, skip?: boolean) {
@@ -74,7 +75,7 @@ async function submit(formData?: FormData, skip?: boolean) {
7475
...aiState.get(),
7576
messages: [
7677
...aiState.get().messages,
77-
{ id: nanoid(), role: 'user', content }
78+
{ id: nanoid(), role: 'user', content: JSON.stringify(content) }
7879
]
7980
});
8081
messages.push({ role: 'user', content });
@@ -384,8 +385,9 @@ async function submit(formData?: FormData, skip?: boolean) {
384385
if (!errorOccurred) {
385386
let locationResponse;
386387
try {
387-
const { composio } = await initializeComposioMapbox();
388-
locationResponse = await mapControlOrchestrator(answer, { mcpClient: composio });
388+
// Attempt to enrich the response with GeoJSON data
389+
locationResponse = await geojsonEnricherV2(answer);
390+
console.log('✨ Enrichment successful:', locationResponse);
389391
} catch (e) {
390392
console.error("Error during geojson enrichment:", e);
391393
// Fallback to a response without location data

components/map/mapbox-map.tsx

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useEffect, useRef, useCallback } from 'react' // Removed useState
3+
import { useEffect, useRef, useCallback } from 'react'
44
import mapboxgl from 'mapbox-gl'
55
import MapboxDraw from '@mapbox/mapbox-gl-draw'
66
import * as turf from '@turf/turf'
@@ -9,12 +9,24 @@ import 'react-toastify/dist/ReactToastify.css'
99
import 'mapbox-gl/dist/mapbox-gl.css'
1010
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
1111
import { 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';
1414
import { useMap } from './map-context'
15+
import { FeatureCollection } from 'geojson'
1516

1617
mapboxgl.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+
1830
export 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

Comments
 (0)