feat: implement drain issue

This commit is contained in:
2026-03-19 13:12:02 +05:30
parent 8510bd9f32
commit 32b2c3c6ab
8 changed files with 122 additions and 90 deletions

View File

@@ -5,6 +5,7 @@ import dynamic from 'next/dynamic';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Loader2, Milestone } from 'lucide-react';
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'), {
@@ -78,20 +79,6 @@ export function DashboardMap({
// Filter detections with valid GPS coordinates
const validDetections = detections.filter((d) => d.latitude && d.longitude);
// Count detections by category
const counts = {
defected_sign_board: validDetections.filter(
(d) => d.type?.toLowerCase() === 'defected_sign_board',
).length,
pothole: validDetections.filter((d) => d.type?.toLowerCase() === 'pothole').length,
road_crack: validDetections.filter((d) => d.type?.toLowerCase() === 'road_crack').length,
damaged_road_marking: validDetections.filter(
(d) => d.type?.toLowerCase() === 'damaged_road_marking',
).length,
good_sign_board: validDetections.filter((d) => d.type?.toLowerCase() === 'good_sign_board')
.length,
};
return (
<Card className={`overflow-hidden ${className}`}>
<CardHeader className="pb-2">
@@ -104,42 +91,30 @@ export function DashboardMap({
<CardTitle className="text-base font-bold">Detection Map</CardTitle>
<p className="text-xs text-muted-foreground">
{isLoading
? 'Loading...'
: `${validDetections.length} detections with GPS coordinates`}
? 'Loading...'
: `${validDetections.length} detections with GPS coordinates`}
</p>
</div>
</div>
{/* Compact Color Legend */}
{/* Dynamic Color Legend */}
<div className="flex flex-wrap items-center justify-end gap-x-4 gap-y-1 text-[10px] max-w-[60%]">
<div className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-red-500" />
<span className="text-muted-foreground font-medium">Potholes ({counts.pothole})</span>
</div>
<div className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-blue-500" />
<span className="text-muted-foreground font-medium">
Defected Signs ({counts.defected_sign_board})
</span>
</div>
<div className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-amber-500" />
<span className="text-muted-foreground font-medium">
Cracks ({counts.road_crack})
</span>
</div>
<div className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-indigo-500" />
<span className="text-muted-foreground font-medium">
Markings ({counts.damaged_road_marking})
</span>
</div>
<div className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full bg-emerald-500" />
<span className="text-muted-foreground font-medium">
Good Signs ({counts.good_sign_board})
</span>
</div>
{Object.values(DETECTION_TYPES).map((type) => {
const count = validDetections.filter(
(d) => (d.type || d.class || '').toLowerCase() === type.id.toLowerCase()
).length;
if (count === 0 && (type.id.includes('culvert') || type.id === 'drain_issue')) return null;
return (
<div key={type.id} className="flex items-center gap-1">
<div className="w-2.5 h-2.5 rounded-full" style={{ backgroundColor: type.color }} />
<span className="text-muted-foreground font-medium">
{type.label} ({count})
</span>
</div>
);
})}
</div>
</div>
</CardHeader>

View File

@@ -4,6 +4,7 @@ import { Activity, Film } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { DetectionLogEntry } from '@/types';
import { DETECTION_TYPES } from '@/constants/detectionModeConfig';
interface DetectionLogsProps {
logs: DetectionLogEntry[];
@@ -41,26 +42,31 @@ const DetectionLogs = ({ logs, onSeek }: DetectionLogsProps) => {
<span className="text-xs text-muted-foreground/80">{log.videoTime}</span>
</div>
<div className="space-y-4">
{log.detections.map((d, j) => (
<div key={`${d.id}-${j}`} className="space-y-1">
<div className="text-[13px] font-bold">
{(d.type || '').replace(/ /g, '_')} ID: {d.id} | Confidence:{' '}
{(d.confidence * 100).toFixed(1)}%
{log.detections.map((d, j) => {
const typeId = (d.type || '').toLowerCase();
const typeConfig = DETECTION_TYPES[typeId];
const label = typeConfig ? typeConfig.label : typeId.replace(/_/g, ' ');
return (
<div key={`${d.id}-${j}`} className="space-y-1">
<div className="text-[13px] font-bold">
{label} ID: {d.id} | Confidence: {(d.confidence * 100).toFixed(1)}%
</div>
{d.bbox && (
<div className="text-[12px] text-muted-foreground/80 font-medium">
Coordinates: ({Math.round(d.bbox.x1)}, {Math.round(d.bbox.y1)}){' '}
<span className="text-muted-foreground/40"></span> (
{Math.round(d.bbox.x2)}, {Math.round(d.bbox.y2)})
</div>
)}
{d.latitude && (
<div className="text-[12px] text-muted-foreground/80 font-medium">
GPS: {d.latitude.toFixed(8)}, {d.longitude?.toFixed(8)}
</div>
)}
</div>
{d.bbox && (
<div className="text-[12px] text-muted-foreground/80 font-medium">
Coordinates: ({Math.round(d.bbox.x1)}, {Math.round(d.bbox.y1)}){' '}
<span className="text-muted-foreground/40"></span> (
{Math.round(d.bbox.x2)}, {Math.round(d.bbox.y2)})
</div>
)}
{d.latitude && (
<div className="text-[12px] text-muted-foreground/80 font-medium">
GPS: {d.latitude.toFixed(8)}, {d.longitude?.toFixed(8)}
</div>
)}
</div>
))}
);
})}
</div>
</div>
))