feat(ticket): support defect-class ticket workflows

This commit is contained in:
2026-06-26 00:50:52 +05:30
parent 8665762ba2
commit 1f8ca87bd0
21 changed files with 343 additions and 70 deletions

View File

@@ -0,0 +1,100 @@
'use client';
import { useEffect, useMemo, useState } from 'react';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { CheckCircle2 } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { useTicketDefectClassesQuery } from '../../hooks/useTicketQueries';
interface TicketDefectClassTabsProps {
ticketId: string;
}
export function TicketDefectClassTabs({
ticketId,
}: TicketDefectClassTabsProps) {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const defectClassParam = searchParams.get('defect_class');
const defectClassesQuery = useTicketDefectClassesQuery(ticketId);
const defectClasses = useMemo(
() => defectClassesQuery.data?.defect_classes ?? [],
[defectClassesQuery.data?.defect_classes],
);
const [selectedClass, setSelectedClass] = useState<string>();
useEffect(() => {
if (!defectClasses.length) return;
const hasUrlClass = defectClasses.some(
(item) => item.class_name === defectClassParam,
);
setSelectedClass((current) => {
if (hasUrlClass) return defectClassParam ?? undefined;
return current &&
defectClasses.some((item) => item.class_name === current)
? current
: defectClasses[0].class_name;
});
}, [defectClassParam, defectClasses]);
const handleClassChange = (className: string) => {
const nextParams = new URLSearchParams(searchParams.toString());
nextParams.set('defect_class', className);
setSelectedClass(className);
console.log(className);
router.replace(`${pathname}?${nextParams.toString()}`, { scroll: false });
};
if (defectClassesQuery.isLoading) {
return (
<Card>
<CardContent className="flex flex-col gap-2">
{Array.from({ length: 3 }).map((_, index) => (
<div
key={index}
className="h-9 w-full animate-pulse rounded-full bg-muted"
/>
))}
</CardContent>
</Card>
);
}
if (defectClassesQuery.isError || !defectClasses.length || !selectedClass) {
return null;
}
return (
<Tabs
value={selectedClass}
onValueChange={handleClassChange}
orientation="vertical"
className="w-full"
>
<Card className="w-full py-0">
<CardContent className="py-4">
<TabsList className="flex h-auto w-full flex-col items-stretch gap-2 bg-transparent p-0">
{defectClasses.map((item) => (
<TabsTrigger
key={item.class_name}
value={item.class_name}
className="group h-9 w-full flex-none justify-start gap-2 rounded-full border border-border bg-muted/50 px-3 text-sm text-muted-foreground shadow-none after:hidden data-[state=active]:border-border data-[state=active]:bg-muted data-[state=active]:font-medium data-[state=active]:text-foreground"
>
<CheckCircle2 className="size-3.5 shrink-0 text-muted-foreground group-data-[state=active]:text-foreground" />
{item.display_name}
</TabsTrigger>
))}
</TabsList>
</CardContent>
</Card>
</Tabs>
);
}