'use client'; import { useEffect, useMemo, useState } from 'react'; import { AlertTriangle, ChevronLeft, ChevronRight, ImageIcon, Trash2, } from 'lucide-react'; import DetectionLocationMap from '@/components/map/detectionLocationMap'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Skeleton } from '@/components/ui/skeleton'; import AnnotatedDetectionImage from '@/components/video/annotatedDetectionImage'; import { getDefectVisual } from '@/constants/defectVisualConfig'; import { cn } from '@/lib/utils'; import type { DetectionRepairProof } from '@/types'; import { useDiscardDetectionMutation, useTicketClassDetectionsQuery, } from '../../hooks/useTicketQueries'; import { DetectionDiscardDialog } from './DetectionDiscardDialog'; import { RepairProofGallery } from './repair/RepairProofGallery'; import { RepairSubmittedBanner } from './repair/RepairSubmittedBanner'; interface TicketClassDetectionPreviewProps { ticketId: string; videoId?: string | null; defectClassName: string; displayName: string; totalCount?: number; } function DetectionMetadataBar({ items, }: { items: { label: string; value: string | number }[]; }) { return (
{items.map((item, index) => (

{item.label}

{item.value}
))}
); } function DetectionRepairProofPanel({ repairProof, }: { repairProof: DetectionRepairProof; }) { if (!repairProof.submitted) { return null; } return (

Repair Proof

{repairProof.submitted_at ? ( ) : null}

Repair Notes

{repairProof.notes?.trim() || 'No repair notes provided.'}

); } function TicketClassDetectionPreviewSkeleton() { return ( <>
{Array.from({ length: 3 }).map((_, index) => (
))}
); } export function TicketClassDetectionPreview({ ticketId, videoId, defectClassName, displayName, totalCount, }: TicketClassDetectionPreviewProps) { const [currentIndex, setCurrentIndex] = useState(0); const [isDiscardDialogOpen, setIsDiscardDialogOpen] = useState(false); const visual = getDefectVisual(defectClassName); const IssueIcon = visual.icon; useEffect(() => { setCurrentIndex(0); }, [defectClassName]); const queryParams = useMemo( () => ({ class_name: defectClassName, skip: currentIndex, limit: 1, sort: 'timestamp_asc', }), [currentIndex, defectClassName], ); const detectionsQuery = useTicketClassDetectionsQuery( videoId ?? undefined, queryParams, ); const discardMutation = useDiscardDetectionMutation( ticketId, videoId ?? undefined, defectClassName, ); const detectionResult = detectionsQuery.data; const activeDetection = detectionResult?.items[0]; const detectionCount = detectionResult?.total ?? totalCount ?? 0; useEffect(() => { if (detectionCount === 0 && currentIndex !== 0) { setCurrentIndex(0); return; } if (detectionCount > 0 && currentIndex > detectionCount - 1) { setCurrentIndex(detectionCount - 1); } }, [currentIndex, detectionCount]); const isNavigationDisabled = detectionCount === 0 || detectionsQuery.isLoading; return (

{displayName}

{detectionCount} Detections

Review detections in ascending timestamp order.

{detectionCount === 0 ? '0 of 0' : `${currentIndex + 1} of ${detectionCount}`}
{detectionsQuery.isLoading && !detectionsQuery.data ? ( ) : detectionsQuery.isError ? (

Failed to load detection preview.

) : !activeDetection || !detectionResult ? (
No detections are available for this issue.
) : ( <>

Detection Image

{activeDetection.repair_proof ? ( ) : null}
{ await discardMutation.mutateAsync({ detectionId: activeDetection.detection.id, payload, }); setIsDiscardDialogOpen(false); }} /> )}
); }