feat(tickets): add repair proof status filter for class issues

This commit is contained in:
2026-07-21 19:24:40 +05:30
parent 830883c6b7
commit 76c87811d8
8 changed files with 172 additions and 146 deletions

View File

@@ -1,7 +1,13 @@
'use client';
import { useEffect, useMemo, useState } from 'react';
import { AlertTriangle, ChevronLeft, ChevronRight, Trash2 } from 'lucide-react';
import {
AlertTriangle,
ChevronLeft,
ChevronRight,
ImageIcon,
Trash2,
} from 'lucide-react';
import DetectionLocationMap from '@/components/map/detectionLocationMap';
import { Badge } from '@/components/ui/badge';
@@ -10,12 +16,15 @@ 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;
@@ -54,6 +63,44 @@ function DetectionMetadataBar({
);
}
function DetectionRepairProofPanel({
repairProof,
}: {
repairProof: DetectionRepairProof;
}) {
if (!repairProof.submitted) {
return null;
}
return (
<section className="space-y-4 rounded-lg border bg-muted/20 p-4">
<div className="flex items-center gap-2">
<ImageIcon className="size-5 text-primary" />
<h4 className="font-semibold">Repair Proof</h4>
</div>
{repairProof.submitted_at ? (
<RepairSubmittedBanner
submittedAt={repairProof.submitted_at}
submitterName="Ticket Worker"
/>
) : null}
<RepairProofGallery
imageUrls={repairProof.proof_image_urls}
maxVisibleImages={4}
/>
<div className="space-y-1.5">
<p className="text-xs font-semibold text-foreground">Repair Notes</p>
<p className="text-sm leading-relaxed whitespace-pre-wrap text-muted-foreground">
{repairProof.notes?.trim() || 'No repair notes provided.'}
</p>
</div>
</section>
);
}
function TicketClassDetectionPreviewSkeleton() {
return (
<>
@@ -131,12 +178,6 @@ export function TicketClassDetectionPreview({
const detectionResult = detectionsQuery.data;
const activeDetection = detectionResult?.items[0];
const detectionCount = detectionResult?.total ?? totalCount ?? 0;
const mediaAspectRatio =
detectionResult &&
detectionResult.video_width > 0 &&
detectionResult.video_height > 0
? `${detectionResult.video_width} / ${detectionResult.video_height}`
: '16 / 9';
useEffect(() => {
if (detectionCount === 0 && currentIndex !== 0) {
@@ -249,11 +290,13 @@ export function TicketClassDetectionPreview({
<div className="grid grid-cols-1 items-start gap-4 xl:grid-cols-2">
<div className="min-w-0 space-y-2">
<p className="text-muted-foreground">Detection Image</p>
<div className="overflow-hidden rounded-lg">
<div className="w-full overflow-hidden rounded-lg">
<AnnotatedDetectionImage
detection={activeDetection}
videoWidth={detectionResult.video_width}
videoHeight={detectionResult.video_height}
aspectRatio="16 / 9"
enableLightbox
/>
</div>
</div>
@@ -265,7 +308,7 @@ export function TicketClassDetectionPreview({
label={`${displayName} - Frame ${activeDetection.frame.number}`}
title="Location on Map"
variant="plain"
aspectRatio={mediaAspectRatio}
aspectRatio="16 / 9"
showCoordinates={false}
/>
</div>
@@ -287,6 +330,12 @@ export function TicketClassDetectionPreview({
]}
/>
{activeDetection.repair_proof ? (
<DetectionRepairProofPanel
repairProof={activeDetection.repair_proof}
/>
) : null}
<div className="flex justify-end">
<Button
type="button"