From ff674d5bb5696c83a8a2e63e6a11a286f91642b5 Mon Sep 17 00:00:00 2001 From: esdrasrenan Date: Sun, 5 Oct 2025 14:36:57 -0300 Subject: [PATCH] feat: refine tickets table indicators Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- web/src/components/tickets/priority-pill.tsx | 2 +- web/src/components/tickets/tickets-table.tsx | 96 +++++++++++++++----- 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/web/src/components/tickets/priority-pill.tsx b/web/src/components/tickets/priority-pill.tsx index baabfdb..3eebdad 100644 --- a/web/src/components/tickets/priority-pill.tsx +++ b/web/src/components/tickets/priority-pill.tsx @@ -3,7 +3,7 @@ import { Badge } from "@/components/ui/badge" import { cn } from "@/lib/utils" import { PriorityIcon, priorityStyles } from "@/components/tickets/priority-select" -const baseClass = "inline-flex items-center gap-1.5 rounded-full px-3 py-0.5 text-xs font-semibold" +const baseClass = "inline-flex h-9 items-center gap-2 rounded-full px-3 text-sm font-semibold" export function TicketPriorityPill({ priority }: { priority: TicketPriority }) { const styles = priorityStyles[priority] diff --git a/web/src/components/tickets/tickets-table.tsx b/web/src/components/tickets/tickets-table.tsx index 5f666ed..1eb7d5d 100644 --- a/web/src/components/tickets/tickets-table.tsx +++ b/web/src/components/tickets/tickets-table.tsx @@ -4,9 +4,10 @@ import { useEffect, useState } from "react" import { useRouter } from "next/navigation" import { formatDistanceToNow } from "date-fns" import { ptBR } from "date-fns/locale" +import { type LucideIcon, Code, FileText, Mail, MessageCircle, MessageSquare, Phone } from "lucide-react" import { tickets as ticketsMock } from "@/lib/mocks/tickets" -import type { Ticket } from "@/lib/schemas/ticket" +import type { Ticket, TicketChannel, TicketStatus } from "@/lib/schemas/ticket" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Card, CardContent } from "@/components/ui/card" @@ -20,10 +21,10 @@ import { TableHeader, TableRow, } from "@/components/ui/table" -import { TicketPriorityPill } from "@/components/tickets/priority-pill" -import { TicketStatusBadge } from "@/components/tickets/status-badge" +import { PrioritySelect } from "@/components/tickets/priority-select" +import { cn } from "@/lib/utils" -const channelLabel: Record = { +const channelLabel: Record = { EMAIL: "E-mail", WHATSAPP: "WhatsApp", CHAT: "Chat", @@ -32,13 +33,39 @@ const channelLabel: Record = { MANUAL: "Manual", } +const channelIcon: Record = { + EMAIL: Mail, + WHATSAPP: MessageCircle, + CHAT: MessageSquare, + PHONE: Phone, + API: Code, + MANUAL: FileText, +} + const cellClass = "px-6 py-5 align-top text-sm text-neutral-700 first:pl-8 last:pr-8" -const queueBadgeClass = "inline-flex items-center rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold text-neutral-700" -const channelBadgeClass = "inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-xs font-semibold text-neutral-700" -const categoryBadgeClass = "inline-flex items-center gap-1 rounded-full border border-[#00e8ff]/50 bg-[#00e8ff]/10 px-2.5 py-0.5 text-[11px] font-semibold text-[#02414d]" +const channelIconBadgeClass = "inline-flex size-8 items-center justify-center rounded-full border border-slate-200 bg-slate-50 text-neutral-700" +const categoryChipClass = "inline-flex items-center gap-1 rounded-full bg-slate-200/60 px-2.5 py-1 text-[11px] font-medium text-neutral-700" const tableRowClass = "group border-b border-slate-100 text-sm transition-colors hover:bg-slate-100/70 last:border-none" +const statusLabel: Record = { + NEW: "Novo", + OPEN: "Aberto", + PENDING: "Pendente", + ON_HOLD: "Em espera", + RESOLVED: "Resolvido", + CLOSED: "Fechado", +} + +const statusTone: Record = { + NEW: "text-slate-700", + OPEN: "text-sky-700", + PENDING: "text-amber-700", + ON_HOLD: "text-violet-700", + RESOLVED: "text-emerald-700", + CLOSED: "text-slate-600", +} + function formatDuration(ms?: number) { if (!ms || ms <= 0) return "—" const totalSeconds = Math.floor(ms / 1000) @@ -143,7 +170,10 @@ export function TicketsTable({ tickets = ticketsMock }: TicketsTableProps) { - {tickets.map((ticket) => ( + {tickets.map((ticket) => { + const ChannelIcon = channelIcon[ticket.channel] ?? MessageCircle + + return ( {ticket.summary ?? "Sem resumo"} -
+
{ticket.requester.name} - - {ticket.category - ? `${ticket.category.name}${ticket.subcategory ? ` • ${ticket.subcategory.name}` : ""}` - : "Sem categoria"} - + {ticket.category ? ( + + {ticket.category.name} + {ticket.subcategory ? • {ticket.subcategory.name} : null} + + ) : ( + Sem categoria + )}
- + + {statusLabel[ticket.status]} + {ticket.metrics?.timeWaitingMinutes ? ( Em espera há {ticket.metrics.timeWaitingMinutes} min @@ -226,7 +273,8 @@ export function TicketsTable({ tickets = ticketsMock }: TicketsTableProps) { - ))} + ) + })} {tickets.length === 0 && (