feat: scaffold tickets experience

This commit is contained in:
esdrasrenan 2025-09-18 23:30:50 -03:00
commit 2230590e57
79 changed files with 16055 additions and 0 deletions

View file

@ -0,0 +1,93 @@
import { format } from "date-fns"
import { ptBR } from "date-fns/locale"
import { IconAlertTriangle, IconClockHour4, IconTags } from "@tabler/icons-react"
import type { TicketWithDetails } from "@/lib/schemas/ticket"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
interface TicketDetailsPanelProps {
ticket: TicketWithDetails
}
export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
return (
<Card className="border-none shadow-none">
<CardHeader className="px-0">
<CardTitle className="text-lg font-semibold">Detalhes</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-4 px-0 text-sm text-muted-foreground">
<div className="space-y-1">
<p className="text-xs font-semibold uppercase">Fila</p>
<Badge variant="outline">{ticket.queue ?? "Sem fila"}</Badge>
</div>
<Separator />
<div className="space-y-2">
<p className="text-xs font-semibold uppercase">SLA</p>
{ticket.slaPolicy ? (
<div className="flex flex-col gap-2 rounded-lg border border-dashed bg-card px-3 py-2">
<span className="text-foreground">{ticket.slaPolicy.name}</span>
<div className="flex flex-col gap-1 text-xs text-muted-foreground">
{ticket.slaPolicy.targetMinutesToFirstResponse ? (
<span>
Resposta inicial: {ticket.slaPolicy.targetMinutesToFirstResponse} min
</span>
) : null}
{ticket.slaPolicy.targetMinutesToResolution ? (
<span>
Resolucao: {ticket.slaPolicy.targetMinutesToResolution} min
</span>
) : null}
</div>
</div>
) : (
<span>Sem politica atribuida.</span>
)}
</div>
<Separator />
<div className="space-y-2">
<p className="text-xs font-semibold uppercase">Metricas</p>
{ticket.metrics ? (
<div className="flex flex-col gap-2 text-xs text-muted-foreground">
<span className="flex items-center gap-2">
<IconClockHour4 className="size-3" /> Tempo aguardando: {ticket.metrics.timeWaitingMinutes ?? "-"} min
</span>
<span className="flex items-center gap-2">
<IconAlertTriangle className="size-3" /> Tempo aberto: {ticket.metrics.timeOpenedMinutes ?? "-"} min
</span>
</div>
) : (
<span>Sem dados de SLA ainda.</span>
)}
</div>
<Separator />
<div className="space-y-2">
<p className="text-xs font-semibold uppercase">Tags</p>
<div className="flex flex-wrap gap-2">
{ticket.tags?.length ? (
ticket.tags.map((tag) => (
<Badge key={tag} variant="outline" className="gap-1">
<IconTags className="size-3" /> {tag}
</Badge>
))
) : (
<span>Sem tags.</span>
)}
</div>
</div>
<Separator />
<div className="space-y-1">
<p className="text-xs font-semibold uppercase">Historico</p>
<div className="flex flex-col gap-1 text-xs text-muted-foreground">
<span>Criado: {format(ticket.createdAt, "dd/MM/yyyy HH:mm", { locale: ptBR })}</span>
<span>Atualizado: {format(ticket.updatedAt, "dd/MM/yyyy HH:mm", { locale: ptBR })}</span>
{ticket.resolvedAt ? (
<span>Resolvido: {format(ticket.resolvedAt, "dd/MM/yyyy HH:mm", { locale: ptBR })}</span>
) : null}
</div>
</div>
</CardContent>
</Card>
)
}