From 0abb425d51c44d87497e979b3828439c3b50707d Mon Sep 17 00:00:00 2001 From: esdrasrenan Date: Sun, 5 Oct 2025 02:16:53 -0300 Subject: [PATCH] feat: compact recent tickets panel on dashboard Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .../tickets/recent-tickets-panel.tsx | 135 ++++++++++++++---- 1 file changed, 110 insertions(+), 25 deletions(-) diff --git a/web/src/components/tickets/recent-tickets-panel.tsx b/web/src/components/tickets/recent-tickets-panel.tsx index 17d587b..a41b65f 100644 --- a/web/src/components/tickets/recent-tickets-panel.tsx +++ b/web/src/components/tickets/recent-tickets-panel.tsx @@ -1,32 +1,117 @@ -"use client"; +"use client" -import { useQuery } from "convex/react"; +import Link from "next/link" +import { formatDistanceToNow } from "date-fns" +import { ptBR } from "date-fns/locale" +import { useQuery } from "convex/react" // @ts-expect-error Convex runtime API lacks TS declarations -import { api } from "@/convex/_generated/api"; -import { DEFAULT_TENANT_ID } from "@/lib/constants"; -import { mapTicketsFromServerList } from "@/lib/mappers/ticket"; -import { TicketsTable } from "@/components/tickets/tickets-table"; +import { api } from "@/convex/_generated/api" +import { DEFAULT_TENANT_ID } from "@/lib/constants" +import { mapTicketsFromServerList } from "@/lib/mappers/ticket" +import type { Ticket } from "@/lib/schemas/ticket" +import { Badge } from "@/components/ui/badge" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Skeleton } from "@/components/ui/skeleton" +import { TicketPriorityPill } from "@/components/tickets/priority-pill" +import { TicketStatusBadge } from "@/components/tickets/status-badge" -export function RecentTicketsPanel() { - const ticketsRaw = useQuery(api.tickets.list, { tenantId: DEFAULT_TENANT_ID, limit: 10 }); - if (ticketsRaw === undefined) { - return ( -
-
- {Array.from({ length: 4 }).map((_, i) => ( -
-
-
-
- ))} +const metaBadgeClass = + "inline-flex items-center gap-1 rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-[11px] font-semibold text-neutral-700" + +const channelLabel: Record = { + EMAIL: "E-mail", + WHATSAPP: "WhatsApp", + CHAT: "Chat", + PHONE: "Telefone", + API: "API", + MANUAL: "Manual", +} + +function TicketRow({ ticket }: { ticket: Ticket }) { + return ( +
+
+
+
+ #{ticket.reference} + + {ticket.queue ?? "Sem fila"} + +
+
+ + {ticket.subject} + +

{ticket.summary ?? "Sem resumo"}

+
+
+ {ticket.requester.name} + + {formatDistanceToNow(ticket.updatedAt, { addSuffix: true, locale: ptBR })} +
+
+
+ + +
+ {channelLabel[ticket.channel] ?? ticket.channel} + {ticket.assignee?.name ?? "Sem responsável"} + {ticket.category ? ( + + {ticket.category.name} + {ticket.subcategory ? ` • ${ticket.subcategory.name}` : ""} + + ) : ( + Sem categoria + )} +
- ); - } - const tickets = mapTicketsFromServerList((ticketsRaw ?? []) as unknown[]); - return ( -
-
- ); + ) +} + +export function RecentTicketsPanel() { + const ticketsRaw = useQuery(api.tickets.list, { tenantId: DEFAULT_TENANT_ID, limit: 6 }) + + if (ticketsRaw === undefined) { + return ( + + + Últimos chamados + + + {Array.from({ length: 4 }).map((_, index) => ( +
+ + +
+ ))} +
+
+ ) + } + + const tickets = mapTicketsFromServerList((ticketsRaw ?? []) as unknown[]).slice(0, 6) + + return ( + + + Últimos chamados + + + + {tickets.length === 0 ? ( +
+ Nenhum ticket recente encontrado. +
+ ) : ( + tickets.map((ticket) => ) + )} +
+
+ ) }