sistema-de-chamados/src/components/portal/portal-ticket-card.tsx

100 lines
4 KiB
TypeScript

"use client"
import { format } from "date-fns"
import { formatDistanceToNow } from "date-fns"
import { ptBR } from "date-fns/locale"
import Link from "next/link"
import { Tag } from "lucide-react"
import type { Ticket } from "@/lib/schemas/ticket"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardHeader } from "@/components/ui/card"
import { cn } from "@/lib/utils"
const statusLabel: Record<Ticket["status"], string> = {
PENDING: "Pendente",
AWAITING_ATTENDANCE: "Aguardando atendimento",
PAUSED: "Pausado",
RESOLVED: "Resolvido",
}
const statusTone: Record<Ticket["status"], string> = {
PENDING: "bg-slate-200 text-slate-800",
AWAITING_ATTENDANCE: "bg-sky-100 text-sky-700",
PAUSED: "bg-violet-100 text-violet-700",
RESOLVED: "bg-emerald-100 text-emerald-700",
}
const priorityLabel: Record<Ticket["priority"], string> = {
LOW: "Baixa",
MEDIUM: "Média",
HIGH: "Alta",
URGENT: "Urgente",
}
const priorityTone: Record<Ticket["priority"], string> = {
LOW: "bg-slate-100 text-slate-600",
MEDIUM: "bg-sky-100 text-sky-700",
HIGH: "bg-amber-100 text-amber-700",
URGENT: "bg-rose-100 text-rose-700",
}
interface PortalTicketCardProps {
ticket: Ticket
}
export function PortalTicketCard({ ticket }: PortalTicketCardProps) {
const updatedAgo = formatDistanceToNow(ticket.updatedAt, {
addSuffix: true,
locale: ptBR,
})
return (
<Link href={`/portal/tickets/${ticket.id}`} className="block">
<Card className="overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm transition hover:-translate-y-0.5 hover:shadow-md">
<CardHeader className="flex flex-row items-start justify-between gap-3 px-5 pb-3 pt-5">
<div>
<div className="flex items-center gap-2 text-sm text-neutral-500">
<span className="font-semibold text-neutral-900">#{ticket.reference}</span>
<span>&middot;</span>
<span>{format(ticket.createdAt, "dd/MM/yyyy")}</span>
</div>
<h3 className="mt-1 text-lg font-semibold text-neutral-900">{ticket.subject}</h3>
{ticket.summary ? (
<p className="mt-1 line-clamp-2 text-sm text-neutral-600">{ticket.summary}</p>
) : null}
</div>
<div className="flex flex-col items-end gap-2 text-right">
<Badge className={cn("rounded-full px-3 py-1 text-xs font-semibold uppercase", statusTone[ticket.status])}>
{statusLabel[ticket.status]}
</Badge>
<Badge className={cn("rounded-full px-3 py-1 text-xs font-semibold uppercase", priorityTone[ticket.priority])}>
{priorityLabel[ticket.priority]}
</Badge>
</div>
</CardHeader>
<CardContent className="flex flex-wrap items-center justify-between gap-4 border-t border-slate-100 px-5 py-4 text-sm text-neutral-600">
<div className="flex flex-col gap-1">
<span className="text-xs uppercase tracking-wide text-neutral-500">Fila</span>
<span className="font-medium text-neutral-800">{ticket.queue ?? "Sem fila"}</span>
</div>
<div className="flex flex-col gap-1">
<span className="text-xs uppercase tracking-wide text-neutral-500">Status</span>
<span className="font-medium text-neutral-800">{statusLabel[ticket.status]}</span>
</div>
<div className="flex flex-col gap-1">
<span className="text-xs uppercase tracking-wide text-neutral-500">Última atualização</span>
<span className="font-medium text-neutral-800">{updatedAgo}</span>
</div>
<div className="flex flex-col gap-1">
<span className="text-xs uppercase tracking-wide text-neutral-500">Categoria</span>
<span className="flex items-center gap-2 font-medium text-neutral-800">
<Tag className="size-4 text-neutral-500" />
{ticket.category?.name ?? "Não classificada"}
</span>
</div>
</CardContent>
</Card>
</Link>
)
}