"use client" import { useEffect } from "react" import { MapContainer, TileLayer, Polyline, CircleMarker, Popup, useMap } from "react-leaflet" import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { LatLngBounds, LatLng } from "leaflet" import "leaflet/dist/leaflet.css" type Detection = { id: number type: string class: string confidence: number latitude: number longitude: number frame_number: number } type MapModalProps = { open: boolean onClose: () => void detections: Detection[] detectionType: "pothole-detection" | "sign-board-detection" | "pot-sign-detection" } // Component to auto-fit map bounds to show all markers function FitBounds({ bounds }: { bounds: LatLngBounds }) { const map = useMap() useEffect(() => { if (!map || !bounds.isValid()) return // Small delay to ensure the container dimensions are fully calculated (prevents _leaflet_pos error) const timer = setTimeout(() => { map.invalidateSize() map.fitBounds(bounds, { padding: [50, 50], maxZoom: 16, animate: true }) }, 200) return () => clearTimeout(timer) }, [bounds, map]) return null } export default function MapModal({ open, onClose, detections, detectionType }: MapModalProps) { // Filter detections with valid GPS coordinates const validDetections = detections.filter(d => d.latitude && d.longitude) if (validDetections.length === 0) { return ( Detection Map No GPS coordinates available for detections ) } // Extract route coordinates (start to end) const routeCoordinates: [number, number][] = validDetections.map(d => [d.latitude, d.longitude]) // Calculate bounds to fit all markers const bounds = new LatLngBounds( new LatLng(routeCoordinates[0][0], routeCoordinates[0][1]), new LatLng(routeCoordinates[0][0], routeCoordinates[0][1]) ) routeCoordinates.forEach(coord => bounds.extend(new LatLng(coord[0], coord[1]))) // Center point (middle of route) const center: [number, number] = [ (bounds.getNorth() + bounds.getSouth()) / 2, (bounds.getEast() + bounds.getWest()) / 2 ] const isCombined = detectionType === "pot-sign-detection" const isPothole = detectionType === "pothole-detection" return ( {isCombined ? "Pothole & Signboard" : isPothole ? "Pothole" : "Signboard"} Detection Map {validDetections.length} detection{validDetections.length !== 1 ? "s" : ""} with GPS coordinates {/* Route line */} {/* Detection markers */} {validDetections.map((detection, idx) => { const type = (detection.type || "").toLowerCase() let markerColor = "#64748b" // Default Slate let strokeColor = "#475569" if (type === "pothole") { markerColor = "#ef4444" strokeColor = "#b91c1c" } else if (type === "defected_sign_board") { markerColor = "#3b82f6" strokeColor = "#1d4ed8" } else if (type === "road_crack") { markerColor = "#f59e0b" strokeColor = "#b45309" } else if (type === "damaged_road_marking") { markerColor = "#6366f1" strokeColor = "#4338ca" } else if (type === "good_sign_board") { markerColor = "#10b981" strokeColor = "#047857" } return ( {(detection.type || "").replace(/_/g, " ")} #{detection.id} Frame: {detection.frame_number} Confidence: {(detection.confidence * 100).toFixed(1)}% {detection.latitude.toFixed(6)}, {detection.longitude.toFixed(6)} ) })} {/* Auto-fit bounds */} ) }
{validDetections.length} detection{validDetections.length !== 1 ? "s" : ""} with GPS coordinates