feat(tickets): add unassigned issue triage to ticket details

- embed detection previews within work assignments
- allow discarding only unassigned detections
- improve ticket detail labels, counts, and layout
This commit is contained in:
2026-08-07 15:31:47 +05:30
parent c8899c191e
commit 47697b4421
9 changed files with 177 additions and 74 deletions

View File

@@ -20,9 +20,11 @@ import type { TicketActor, TicketAssignmentSummary } from '@/types';
import { formatDate } from '@/utils/date';
import { useTicketAssignmentsQuery } from '../../hooks/useTicketQueries';
import { TicketDetectionPreview } from './TicketDetectionPreview';
interface TicketAssignmentsCardProps {
ticketId: string;
videoId?: string | null;
initialAssignments?: TicketAssignmentSummary[];
selectedAssignmentId?: number;
onAssignmentChange: (assignmentId: number) => void;
@@ -87,7 +89,7 @@ function AssignmentProgress({
);
}
function AssignmentLot({
function AssignmentOverview({
assignment,
}: {
assignment: TicketAssignmentSummary;
@@ -109,7 +111,7 @@ function AssignmentLot({
<div className="min-w-0 space-y-4 rounded-lg border p-3 sm:p-4">
<div className="min-w-0">
<p className="mb-2 text-xs font-medium text-muted-foreground">
Lot {assignment.id}
Assignment {assignment.id}
</p>
<PersonInfo person={worker} />
</div>
@@ -138,6 +140,7 @@ function AssignmentLot({
export function TicketAssignmentsCard({
ticketId,
videoId,
initialAssignments,
selectedAssignmentId,
onAssignmentChange,
@@ -173,14 +176,17 @@ export function TicketAssignmentsCard({
<div className="min-w-0">
<CardTitle className="flex items-center gap-2">
<BriefcaseBusiness className="size-5 text-primary" />
Assignment lots
Work Assignments
</CardTitle>
<CardDescription className="mt-1">
Live ownership, criteria, and repair progress for this ticket.
Issues grouped by assignee, scope, and repair progress.
</CardDescription>
</div>
{assignmentsQuery.data ? (
<Badge variant="default">{assignments.length}</Badge>
<Badge variant="default">
{assignments.length}{' '}
{assignments.length === 1 ? 'Assignment' : 'Assignments'}
</Badge>
) : null}
</div>
</CardHeader>
@@ -195,7 +201,7 @@ export function TicketAssignmentsCard({
) : assignmentsQuery.isError ? (
<div className="rounded-lg border border-dashed p-6 text-center">
<p className="text-sm font-medium">
Unable to load assignment lots.
Unable to load work assignments.
</p>
<Button
type="button"
@@ -210,7 +216,7 @@ export function TicketAssignmentsCard({
) : selectedAssignment ? (
<div className="min-w-0 space-y-3">
<nav
aria-label="Assignment lots"
aria-label="Work assignments"
className="w-full max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain touch-pan-x"
>
<div
@@ -239,7 +245,7 @@ export function TicketAssignmentsCard({
)}
onClick={() => onAssignmentChange(assignment.id)}
>
Lot {assignment.id}
Assignment {assignment.id}
</button>
);
})}
@@ -252,14 +258,23 @@ export function TicketAssignmentsCard({
aria-labelledby={`assignment-tab-${activeAssignmentId}`}
className="min-w-0"
>
<AssignmentLot assignment={selectedAssignment} />
<AssignmentOverview assignment={selectedAssignment} />
{videoId ? (
<div className={'mt-4 border-t pt-4'}>
<TicketDetectionPreview
ticketId={ticketId}
videoId={videoId}
assignmentId={selectedAssignment.id}
/>
</div>
) : null}
</div>
</div>
) : (
<div className="rounded-lg border border-dashed px-4 py-8 text-center">
<p className="text-sm font-medium">No assignments yet</p>
<p className="text-sm font-medium">No work assignments yet</p>
<p className="mt-1 text-sm text-muted-foreground">
Assignment lots will appear here after work is allocated.
Work assignments will appear here after issues are allocated.
</p>
</div>
)}