diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketDetailSkeleton.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketDetailSkeleton.tsx
index 714c079..08eae16 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketDetailSkeleton.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketDetailSkeleton.tsx
@@ -1,5 +1,6 @@
'use client';
+import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
function OverviewSkeletonField() {
@@ -53,50 +54,61 @@ export function TicketDetailSkeleton() {
-
-
+
+
-
-
+
+
{Array.from({ length: 8 }).map((_, index) => (
))}
-
-
+
+
-
+
+
-
+
+
);
diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketHistoryCard.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketHistoryCard.tsx
index ea1c1a5..3bd4ef8 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketHistoryCard.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketHistoryCard.tsx
@@ -2,6 +2,7 @@
import { History, MessageSquareText } from 'lucide-react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import type { TicketDetail, TicketHistoryItem, TicketStatus } from '@/types';
import { formatDate } from '@/utils/date';
@@ -93,31 +94,33 @@ export function TicketHistoryCard({ ticket }: { ticket: TicketDetail }) {
const history = ticket.history ?? [];
return (
-
-
-
-
+
+
+
+
Audit & Lifecycle Timeline
-
-
+
+
- {history.length ? (
-
- {history.map((item, index) => (
-
- ))}
-
- ) : (
-
-
- No timeline entries yet
-
-
- )}
-
+
+ {history.length ? (
+
+ {history.map((item, index) => (
+
+ ))}
+
+ ) : (
+
+
+ No timeline entries yet
+
+
+ )}
+
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketOverviewCard.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketOverviewCard.tsx
index 1643209..3735edd 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketOverviewCard.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketOverviewCard.tsx
@@ -1,5 +1,12 @@
'use client';
+import {
+ Card,
+ CardContent,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from '@/components/ui/card';
import type { TicketActor, TicketDetail } from '@/types';
import { formatDate } from '@/utils/date';
@@ -78,19 +85,19 @@ export function TicketOverviewCard({ ticket }: { ticket: TicketDetail }) {
const detectionCount = ticket.ai_result?.detection_count;
return (
-
-
-
Overview
-
+
+
+ Overview
+
-
+
{detectionCount != null ? `${detectionCount} Occurrences` : '-'}
-
+
{ticket.chainage_name}
@@ -103,13 +110,13 @@ export function TicketOverviewCard({ ticket }: { ticket: TicketDetail }) {
{formatCreatedDate(ticket.timestamps.created_at)}
-
+
{ticket.ai_result?.completed_at ? (
-
+
AI analysis completed {formatDate(ticket.ai_result.completed_at)}
-
+
) : null}
-
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/TicketRepairReportCard.tsx b/src/app/(modules)/ticket/[ticketId]/components/TicketRepairReportCard.tsx
index 5db9f75..342324f 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/TicketRepairReportCard.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/TicketRepairReportCard.tsx
@@ -2,6 +2,7 @@
import { ImageIcon } from 'lucide-react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import type { TicketDetail } from '@/types';
import { RepairProofImagesGrid } from './repair-report/RepairProofImagesGrid';
@@ -21,17 +22,21 @@ export function TicketRepairReportCard({ ticket }: { ticket: TicketDetail }) {
-
-
-
- Repair Images
-
+
+
+
+
+ Repair Images
+
+
-
-
+
+
+
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/actions/ClosedTicketAction.tsx b/src/app/(modules)/ticket/[ticketId]/components/actions/ClosedTicketAction.tsx
index d0777c2..e8aad22 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/actions/ClosedTicketAction.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/actions/ClosedTicketAction.tsx
@@ -98,13 +98,13 @@ export function ClosedTicketAction({ ticket }: { ticket: TicketDetail }) {
const reviewedAt = reviewer?.reviewed_at ?? getClosedAt(ticket);
return (
-
-
+
+
Resolution Details
Review record for {ticket.id}
-
+
-
+
{title}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairReportPanel.tsx b/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairReportPanel.tsx
index b884944..2f8f70e 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairReportPanel.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairReportPanel.tsx
@@ -1,7 +1,8 @@
'use client';
-import { FileText, MessageSquareQuote, BadgeCheck } from 'lucide-react';
+import { FileText, MessageSquareQuote } from 'lucide-react';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import type { TicketDetail } from '@/types';
import {
@@ -38,67 +39,70 @@ export function RepairReportPanel({ ticket }: { ticket: TicketDetail }) {
if (!repair) {
return (
-
-
-
-
Repair Report
-
-
-
+
+
+
+
+ Repair Report
+
+
+
+
+
+
);
}
return (
-
-
-
+
+
+
Repair Report
-
+
{repair.submitted_at ? (
-
+
Completed {formatRepairDate(repair.submitted_at)}
) : null}
-
+
-
-
-
-
+
+
+
+
+
-
-
Repair Summary
- {repair.notes?.trim() ? (
- <>
+
+
Repair Summary
+ {repair.notes?.trim() ? (
- {/*
-
- Self-certified by {getPersonLabel(ticket.worker)}
-
*/}
- >
- ) : (
-
- )}
-
-
+ ) : (
+
+ )}
+
+
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairVideoComparison.tsx b/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairVideoComparison.tsx
index 60c8b07..cf00314 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairVideoComparison.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/repair-report/RepairVideoComparison.tsx
@@ -3,6 +3,7 @@
import { ShieldCheck } from 'lucide-react';
import { ProtectedVideoPlayer } from '@/components/media/ProtectedVideoPlayer';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import type { TicketDetail } from '@/types';
export function RepairVideoComparison({ ticket }: { ticket: TicketDetail }) {
@@ -10,13 +11,15 @@ export function RepairVideoComparison({ ticket }: { ticket: TicketDetail }) {
const repairVideoUrl = ticket.repair?.proof_video_url ?? null;
return (
-
-
-
- Repair Verification
-
+
+
+
+
+ Repair Verification
+
+
-
+
-
-
+
+
);
}
diff --git a/src/app/(modules)/ticket/[ticketId]/components/repair-report/repairReportUtils.tsx b/src/app/(modules)/ticket/[ticketId]/components/repair-report/repairReportUtils.tsx
index 5235c58..0108762 100644
--- a/src/app/(modules)/ticket/[ticketId]/components/repair-report/repairReportUtils.tsx
+++ b/src/app/(modules)/ticket/[ticketId]/components/repair-report/repairReportUtils.tsx
@@ -33,7 +33,7 @@ export function ReportSurface({
className?: string;
}) {
return (
-
+
{children}
);
diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx
index 3d8a3c1..b570017 100644
--- a/src/components/ui/card.tsx
+++ b/src/components/ui/card.tsx
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<'div'>) {
) {
) {
return (
);
@@ -65,7 +65,7 @@ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
return (
);
@@ -75,7 +75,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
return (
);
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
index b463afd..3b66ad1 100644
--- a/src/components/ui/tabs.tsx
+++ b/src/components/ui/tabs.tsx
@@ -65,9 +65,9 @@ function TabsTrigger({
data-slot="tabs-trigger"
className={cn(
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
- "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
- "data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground",
- "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
+ "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
+ "data-[state=active]:border-primary data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-primary dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground",
+ "after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:-bottom-1.25 group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
className
)}
{...props}
diff --git a/src/constants/defectClassStatus.ts b/src/constants/defectClassStatus.ts
new file mode 100644
index 0000000..50d00a4
--- /dev/null
+++ b/src/constants/defectClassStatus.ts
@@ -0,0 +1,35 @@
+import type { TicketDefectClassTicketStatus } from '@/types';
+
+export const DEFECT_CLASS_STATUS_CONFIG: Record<
+ TicketDefectClassTicketStatus,
+ {
+ label: string;
+ badgeClassName: string;
+ }
+> = {
+ unassigned: {
+ label: 'Unassigned',
+ badgeClassName:
+ 'bg-zinc-500/15 text-zinc-600 dark:bg-zinc-500/20 dark:text-zinc-300',
+ },
+ assigned: {
+ label: 'Assigned',
+ badgeClassName:
+ 'bg-red-500/15 text-red-600 dark:bg-red-500/20 dark:text-red-400',
+ },
+ under_review: {
+ label: 'Under Review',
+ badgeClassName:
+ 'bg-violet-500/15 text-violet-600 dark:bg-violet-500/20 dark:text-violet-400',
+ },
+ approved: {
+ label: 'Approved',
+ badgeClassName:
+ 'bg-emerald-500/15 text-emerald-600 dark:bg-emerald-500/20 dark:text-emerald-400',
+ },
+ rejected: {
+ label: 'Rejected',
+ badgeClassName:
+ 'bg-orange-500/15 text-orange-600 dark:bg-orange-500/20 dark:text-orange-400',
+ },
+};