feat(ticket): add paginated class detection preview with image and map

This commit is contained in:
2026-07-08 10:48:03 +05:30
parent fb9a654aea
commit 23186ffd29
11 changed files with 447 additions and 143 deletions

View File

@@ -1,8 +1,8 @@
import { getDefectVisual } from '@/constants/defectVisualConfig';
import type { DetectionResultLog } from '@/types';
import type { DetectionResultItem } from '@/types';
interface BoundingBoxOverlayProps {
detections: DetectionResultLog[];
detections: DetectionResultItem[];
videoWidth: number;
videoHeight: number;
}

View File

@@ -2,6 +2,7 @@
import dynamic from 'next/dynamic';
import { MapPin } from 'lucide-react';
import { cn } from '@/lib/utils';
import {
Card,
CardContent,
@@ -14,6 +15,12 @@ type DetectionLocationMapProps = {
latitude: number | null;
longitude: number | null;
label: string;
title?: string;
description?: string;
aspectRatio?: string;
showCoordinates?: boolean;
variant?: 'card' | 'plain';
className?: string;
};
type ClientDetectionLocationMapProps = {
@@ -70,44 +77,66 @@ export default function DetectionLocationMap({
latitude,
longitude,
label,
title = 'Detection Location',
description = 'Selected log GPS coordinates',
aspectRatio = '16 / 9',
showCoordinates = true,
variant = 'card',
className,
}: DetectionLocationMapProps) {
const mapContent =
latitude == null || longitude == null ? (
<div
className="flex items-center justify-center rounded-lg border border-dashed bg-muted/30 px-4 py-8 text-sm text-muted-foreground"
style={{ aspectRatio }}
>
Coordinates are unavailable for the selected log.
</div>
) : (
<>
{showCoordinates ? (
<div className="text-sm text-muted-foreground">
{latitude.toFixed(6)}, {longitude.toFixed(6)}
</div>
) : null}
<div
className="overflow-hidden rounded-lg border bg-muted"
style={{ aspectRatio }}
>
<ClientDetectionLocationMap
latitude={latitude}
longitude={longitude}
label={label}
/>
</div>
</>
);
if (variant === 'plain') {
return (
<div className={cn('space-y-2', className)}>
{title ? (
<p className="text-xs font-medium text-muted-foreground">{title}</p>
) : null}
{mapContent}
</div>
);
}
return (
<Card className="overflow-hidden">
<Card className={cn('overflow-hidden', className)}>
<CardHeader className="border-b pb-4">
<div className="flex items-center gap-3">
<div className="rounded bg-secondary p-2">
<MapPin className="h-5 w-5 text-primary" />
</div>
<div>
<CardTitle className="text-base font-semibold">
Detection Location
</CardTitle>
<CardDescription className="text-xs">
Selected log GPS coordinates
</CardDescription>
<CardTitle className="text-base font-semibold">{title}</CardTitle>
<CardDescription className="text-xs">{description}</CardDescription>
</div>
</div>
</CardHeader>
<CardContent className="space-y-4 pt-6">
{latitude == null || longitude == null ? (
<div className="rounded-lg border border-dashed bg-muted/30 px-4 py-8 text-sm text-muted-foreground">
Coordinates are unavailable for the selected log.
</div>
) : (
<>
<div className="text-sm text-muted-foreground">
{latitude.toFixed(6)}, {longitude.toFixed(6)}
</div>
<div className="h-72 overflow-hidden rounded-lg border bg-muted">
<ClientDetectionLocationMap
latitude={latitude}
longitude={longitude}
label={label}
/>
</div>
</>
)}
</CardContent>
<CardContent className="space-y-4 pt-6">{mapContent}</CardContent>
</Card>
);
}

View File

@@ -4,12 +4,12 @@ import { AlertTriangle, ImageIcon, Loader2 } from 'lucide-react';
import Image from 'next/image';
import { useProtectedMediaObjectUrl } from '@/hooks/useProtectedMedia';
import type { DetectionResultLog } from '@/types';
import type { DetectionResultItem } from '@/types';
import BoundingBoxOverlay from '@/components/annotation/boundingBoxOverlay';
interface AnnotatedDetectionImageProps {
detection?: DetectionResultLog;
detection?: DetectionResultItem;
videoWidth: number;
videoHeight: number;
}