From 68829dc72b788f73447668bef0f721b5a1fc8b64 Mon Sep 17 00:00:00 2001 From: "santasri.pachhal" Date: Mon, 13 Jul 2026 19:27:54 +0530 Subject: [PATCH] feat(tickets): add detection discard workflow --- .../components/DetectionDiscardDialog.tsx | 161 ++++++++++++++++++ .../TicketClassDetectionPreview.tsx | 41 ++++- .../components/TicketDefectClassTabs.tsx | 1 + .../ticket/hooks/useTicketQueries.ts | 43 ++++- .../(modules)/ticket/queries/ticketKeys.ts | 4 +- src/constants/apiRoutes.ts | 3 + src/services/api/detection.service.ts | 21 +++ src/services/api/index.ts | 1 + src/types/detection.ts | 24 +++ 9 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 src/app/(modules)/ticket/[ticketId]/components/DetectionDiscardDialog.tsx create mode 100644 src/services/api/detection.service.ts diff --git a/src/app/(modules)/ticket/[ticketId]/components/DetectionDiscardDialog.tsx b/src/app/(modules)/ticket/[ticketId]/components/DetectionDiscardDialog.tsx new file mode 100644 index 0000000..aa286a2 --- /dev/null +++ b/src/app/(modules)/ticket/[ticketId]/components/DetectionDiscardDialog.tsx @@ -0,0 +1,161 @@ +'use client'; + +import { useState, type FormEvent } from 'react'; +import { Loader2, Trash2 } from 'lucide-react'; + +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Label } from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Textarea } from '@/components/ui/textarea'; +import type { DetectionDiscardReason, DiscardDetectionPayload } from '@/types'; + +const DISCARD_REASON_OPTIONS: Array<{ + value: DetectionDiscardReason; + label: string; +}> = [ + { value: 'not_a_defect', label: 'Not a defect' }, + { value: 'wrong_class', label: 'Wrong classification' }, + { value: 'duplicate', label: 'Duplicate detection' }, + { value: 'poor_image_quality', label: 'Poor image quality' }, + { value: 'incorrect_location', label: 'Incorrect location' }, + { value: 'already_repaired', label: 'Already repaired' }, + { value: 'other', label: 'Other' }, +]; + +interface DetectionDiscardDialogProps { + open: boolean; + detectionLabel: string; + isPending: boolean; + onOpenChange: (open: boolean) => void; + onSubmit: (payload: DiscardDetectionPayload) => Promise; +} + +export function DetectionDiscardDialog({ + open, + detectionLabel, + isPending, + onOpenChange, + onSubmit, +}: DetectionDiscardDialogProps) { + const [reason, setReason] = useState(''); + const [comment, setComment] = useState(''); + + const resetForm = () => { + setReason(''); + setComment(''); + }; + + const handleOpenChange = (nextOpen: boolean) => { + if (isPending) return; + + if (!nextOpen) resetForm(); + onOpenChange(nextOpen); + }; + + const handleSubmit = async (event: FormEvent) => { + event.preventDefault(); + if (!reason || isPending) return; + + try { + await onSubmit({ + reason, + comment: comment.trim() || undefined, + }); + resetForm(); + } catch { + // The mutation displays the request error and keeps the dialog open. + } + }; + + return ( + + +
+ + Discard detection + + Remove {detectionLabel} from this ticket and record why the AI + result is incorrect. + + + + +
+ + +
+ +
+
+ + + Optional | {comment.length}/500 + +
+