feat(ticket): refine repair report and history timeline UI

This commit is contained in:
2026-06-19 11:22:41 +05:30
parent 8c3d19a429
commit a567a52e26
27 changed files with 1550 additions and 363 deletions

View File

@@ -0,0 +1,92 @@
'use client';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import type { TicketActor, TicketDetail } from '@/types';
import { TicketStatusBadge } from '../../components/TicketStatusBadge';
function formatDate(value: string | null | undefined) {
if (!value) return '-';
return new Intl.DateTimeFormat('en-IN', {
dateStyle: 'medium',
timeStyle: 'short',
}).format(new Date(value));
}
function OverviewMeta({
label,
value,
}: {
label: string;
value: string | number | null | undefined;
}) {
return (
<div className="space-y-1">
<p className="text-xs text-muted-foreground">{label}</p>
<p className="text-sm font-medium">{value ?? '-'}</p>
</div>
);
}
function PersonMeta({
label,
person,
}: {
label: string;
person: TicketActor | null | undefined;
}) {
return (
<div className="space-y-1">
<p className="text-xs text-muted-foreground">{label}</p>
{person ? (
<div className="min-w-0">
<p className="truncate text-sm font-medium">{person.name || '-'}</p>
{person.email && (
<p className="truncate text-xs text-muted-foreground">
{person.email}
</p>
)}
</div>
) : (
<p className="text-sm font-medium">-</p>
)}
</div>
);
}
export function TicketOverviewCard({ ticket }: { ticket: TicketDetail }) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-4">
<CardTitle className="text-base">Overview</CardTitle>
<TicketStatusBadge status={ticket.status} />
</CardHeader>
<CardContent className="space-y-6">
<div className="grid gap-5 md:grid-cols-[180px_minmax(0,1fr)]">
<div className="space-y-1">
<p className="text-xs text-muted-foreground">AI Detections</p>
<p className="text-3xl font-semibold leading-none">
{ticket.ai_result?.detection_count ?? '-'}
</p>
<p className="text-xs text-muted-foreground">
Completed {formatDate(ticket.ai_result?.completed_at)}
</p>
</div>
<div className="grid gap-4 sm:grid-cols-2">
<PersonMeta label="Uploaded By" person={ticket.uploader} />
<PersonMeta label="Assigned To" person={ticket.worker} />
<PersonMeta
label="Assigned By"
person={ticket.worker?.assigned_by}
/>
<OverviewMeta
label="Assigned At"
value={formatDate(ticket.worker?.assigned_at)}
/>
</div>
</div>
</CardContent>
</Card>
);
}