'use client'; import { useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Loader2, Milestone, Maximize2, Minimize2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Detection } from '@/types'; import { DETECTION_TYPES } from '@/constants/detectionModeConfig'; // Dynamically import the map to avoid SSR issues with Leaflet const DashboardMapContent = dynamic(() => import('./dashboard-map-content'), { ssr: false, loading: () => (
), }); interface DashboardMapProps { className?: string; selectedProjectId?: string | null; selectedPackageId?: string | null; selectedChainageId?: string | null; projectSummary?: any; } export function DashboardMap({ className, selectedProjectId, selectedPackageId, selectedChainageId, projectSummary, }: DashboardMapProps) { const [detections, setDetections] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [isMaximized, setIsMaximized] = useState(false); const [selectedTypes, setSelectedTypes] = useState([]); useEffect(() => { if (!projectSummary) { setDetections([]); setIsLoading(false); return; } try { setIsLoading(true); setError(null); const filteredDetections: Detection[] = []; const packagesToProcess = selectedPackageId && selectedPackageId !== 'all' ? { [selectedPackageId]: projectSummary.packages[selectedPackageId] } : projectSummary.packages || {}; for (const [pkgName, pkg] of Object.entries(packagesToProcess)) { if (!pkg) continue; const chainagesToProcess = selectedChainageId && selectedChainageId !== 'all' ? { [selectedChainageId]: (pkg as any).chainages?.[ selectedChainageId ], } : (pkg as any).chainages || {}; for (const [chnName, chn] of Object.entries(chainagesToProcess)) { if (!chn) continue; const chainageDetections = ((chn as any).detections || []).filter( (d: any) => (d.type || d.class || '').toLowerCase() !== 'good_sign_board', ); filteredDetections.push(...chainageDetections); } } setDetections(filteredDetections); } catch (err) { console.error('Failed to extract detections:', err); setError('Failed to load detection data'); } finally { setIsLoading(false); } }, [projectSummary, selectedPackageId, selectedChainageId]); // Handle detection type toggle const toggleType = (typeId: string) => { setSelectedTypes((prev) => { if (prev.includes(typeId)) { const next = prev.filter((id) => id !== typeId); return next.length === 0 ? [] : next; } else { return [...prev, typeId]; } }); }; // Filter detections with valid GPS coordinates and selected types const validDetections = detections.filter((d) => { const hasGps = d.latitude && d.longitude; if (!hasGps) return false; if (selectedTypes.length === 0) return true; const typeId = (d.type || d.class || '').toLowerCase(); return selectedTypes.includes(typeId); }); return ( {/* Top Right Actions */}
{/* Bottom Left Legend */}
{Object.values(DETECTION_TYPES).map((type) => { const typeId = type.id.toLowerCase(); const count = detections.filter( (d) => (d.type || d.class || '').toLowerCase() === typeId && d.latitude && d.longitude, ).length; if ( count === 0 && (type.id.includes('culvert') || type.id === 'drain_issue') ) return null; if (type.id === 'good_sign_board') return null; const isSelected = selectedTypes.length === 0 || selectedTypes.includes(typeId); return ( ); })}
{isLoading ? (
) : error ? (

{error}

) : validDetections.length === 0 ? (

No detections with GPS coordinates found

Process some videos to see detections on the map

) : ( )} {/* Bottom Left Label Overlay */}
); }