'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 ? (
) : validDetections.length === 0 ? (
No detections with GPS coordinates found
Process some videos to see detections on the map
) : (
)}
{/* Bottom Left Label Overlay */}
);
}