Align ticket status colors across views
This commit is contained in:
parent
296e02cf0c
commit
6702811f4a
6 changed files with 110 additions and 89 deletions
|
|
@ -11,20 +11,7 @@ import { useAuth } from "@/lib/auth-client"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Card, CardContent, CardHeader } from "@/components/ui/card"
|
import { Card, CardContent, CardHeader } from "@/components/ui/card"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
import { getTicketStatusBadgeClass, getTicketStatusLabel } from "@/lib/ticket-status-style"
|
||||||
const statusLabel: Record<Ticket["status"], string> = {
|
|
||||||
PENDING: "Pendente",
|
|
||||||
AWAITING_ATTENDANCE: "Em andamento",
|
|
||||||
PAUSED: "Pausado",
|
|
||||||
RESOLVED: "Resolvido",
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusTone: Record<Ticket["status"], string> = {
|
|
||||||
PENDING: "border border-slate-200 bg-slate-100 text-slate-700",
|
|
||||||
AWAITING_ATTENDANCE: "border border-sky-200 bg-sky-100 text-sky-700",
|
|
||||||
PAUSED: "border border-amber-200 bg-[#fff3c4] text-[#7a5901]",
|
|
||||||
RESOLVED: "border border-emerald-200 bg-emerald-100 text-emerald-700",
|
|
||||||
}
|
|
||||||
|
|
||||||
const priorityLabel: Record<Ticket["priority"], string> = {
|
const priorityLabel: Record<Ticket["priority"], string> = {
|
||||||
LOW: "Baixa",
|
LOW: "Baixa",
|
||||||
|
|
@ -67,8 +54,8 @@ export function PortalTicketCard({ ticket }: PortalTicketCardProps) {
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-end gap-2 text-right">
|
<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])}>
|
<Badge className={cn("rounded-full px-3 py-1 text-xs font-semibold uppercase", getTicketStatusBadgeClass(ticket.status))}>
|
||||||
{statusLabel[ticket.status]}
|
{getTicketStatusLabel(ticket.status)}
|
||||||
</Badge>
|
</Badge>
|
||||||
{!isCustomer ? (
|
{!isCustomer ? (
|
||||||
<Badge className={cn("rounded-full px-3 py-1 text-xs font-semibold uppercase", priorityTone[ticket.priority])}>
|
<Badge className={cn("rounded-full px-3 py-1 text-xs font-semibold uppercase", priorityTone[ticket.priority])}>
|
||||||
|
|
@ -86,7 +73,7 @@ export function PortalTicketCard({ ticket }: PortalTicketCardProps) {
|
||||||
) : null}
|
) : null}
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<span className="text-xs uppercase tracking-wide text-neutral-500">Status</span>
|
<span className="text-xs uppercase tracking-wide text-neutral-500">Status</span>
|
||||||
<span className="font-medium text-neutral-800">{statusLabel[ticket.status]}</span>
|
<span className="font-medium text-neutral-800">{getTicketStatusLabel(ticket.status)}</span>
|
||||||
</div>
|
</div>
|
||||||
{ticket.assignee ? (
|
{ticket.assignee ? (
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import type { TicketWithDetails } from "@/lib/schemas/ticket"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
import { getTicketStatusLabel, getTicketStatusSummaryTone } from "@/lib/ticket-status-style"
|
||||||
|
|
||||||
interface TicketDetailsPanelProps {
|
interface TicketDetailsPanelProps {
|
||||||
ticket: TicketWithDetails
|
ticket: TicketWithDetails
|
||||||
|
|
@ -13,20 +14,6 @@ interface TicketDetailsPanelProps {
|
||||||
|
|
||||||
type SummaryTone = "default" | "info" | "warning" | "success" | "muted" | "danger"
|
type SummaryTone = "default" | "info" | "warning" | "success" | "muted" | "danger"
|
||||||
|
|
||||||
const statusLabel: Record<TicketWithDetails["status"], string> = {
|
|
||||||
PENDING: "Pendente",
|
|
||||||
AWAITING_ATTENDANCE: "Em andamento",
|
|
||||||
PAUSED: "Pausado",
|
|
||||||
RESOLVED: "Resolvido",
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusTone: Record<TicketWithDetails["status"], SummaryTone> = {
|
|
||||||
PENDING: "muted",
|
|
||||||
AWAITING_ATTENDANCE: "info",
|
|
||||||
PAUSED: "warning",
|
|
||||||
RESOLVED: "success",
|
|
||||||
}
|
|
||||||
|
|
||||||
const priorityLabel: Record<TicketWithDetails["priority"], string> = {
|
const priorityLabel: Record<TicketWithDetails["priority"], string> = {
|
||||||
LOW: "Baixa",
|
LOW: "Baixa",
|
||||||
MEDIUM: "Média",
|
MEDIUM: "Média",
|
||||||
|
|
@ -82,8 +69,8 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
||||||
{
|
{
|
||||||
key: "status",
|
key: "status",
|
||||||
label: "Status",
|
label: "Status",
|
||||||
value: statusLabel[ticket.status] ?? ticket.status,
|
value: getTicketStatusLabel(ticket.status) ?? ticket.status,
|
||||||
tone: statusTone[ticket.status] ?? "default",
|
tone: getTicketStatusSummaryTone(ticket.status) as SummaryTone,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "priority",
|
key: "priority",
|
||||||
|
|
|
||||||
|
|
@ -5,30 +5,17 @@ import { formatDistanceToNowStrict } from "date-fns"
|
||||||
import { ptBR } from "date-fns/locale"
|
import { ptBR } from "date-fns/locale"
|
||||||
import { LayoutGrid } from "lucide-react"
|
import { LayoutGrid } from "lucide-react"
|
||||||
|
|
||||||
import type { Ticket, TicketStatus } from "@/lib/schemas/ticket"
|
import type { Ticket } from "@/lib/schemas/ticket"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyTitle } from "@/components/ui/empty"
|
import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyTitle } from "@/components/ui/empty"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { TicketPriorityPill } from "@/components/tickets/priority-pill"
|
import { TicketPriorityPill } from "@/components/tickets/priority-pill"
|
||||||
|
import { getTicketStatusChipClass, getTicketStatusLabel } from "@/lib/ticket-status-style"
|
||||||
|
|
||||||
type TicketsBoardProps = {
|
type TicketsBoardProps = {
|
||||||
tickets: Ticket[]
|
tickets: Ticket[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusLabel: Record<TicketStatus, string> = {
|
|
||||||
PENDING: "Pendente",
|
|
||||||
AWAITING_ATTENDANCE: "Em andamento",
|
|
||||||
PAUSED: "Pausado",
|
|
||||||
RESOLVED: "Resolvido",
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusChipClass: Record<TicketStatus, string> = {
|
|
||||||
PENDING: "bg-amber-100 text-amber-800 ring-1 ring-amber-200",
|
|
||||||
AWAITING_ATTENDANCE: "bg-sky-100 text-sky-700 ring-1 ring-sky-200",
|
|
||||||
PAUSED: "bg-violet-100 text-violet-700 ring-1 ring-violet-200",
|
|
||||||
RESOLVED: "bg-emerald-100 text-emerald-700 ring-1 ring-emerald-200",
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatUpdated(date: Date) {
|
function formatUpdated(date: Date) {
|
||||||
return formatDistanceToNowStrict(date, { addSuffix: true, locale: ptBR })
|
return formatDistanceToNowStrict(date, { addSuffix: true, locale: ptBR })
|
||||||
}
|
}
|
||||||
|
|
@ -71,10 +58,10 @@ export function TicketsBoard({ tickets }: TicketsBoardProps) {
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-xs font-semibold transition",
|
"inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-xs font-semibold transition",
|
||||||
statusChipClass[ticket.status],
|
getTicketStatusChipClass(ticket.status),
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{statusLabel[ticket.status]}
|
{getTicketStatusLabel(ticket.status)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs font-semibold uppercase tracking-wide text-neutral-400">
|
<span className="text-xs font-semibold uppercase tracking-wide text-neutral-400">
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { format, formatDistanceToNowStrict } from "date-fns"
|
||||||
import { ptBR } from "date-fns/locale"
|
import { ptBR } from "date-fns/locale"
|
||||||
import { type LucideIcon, Code, FileText, Mail, MessageCircle, MessageSquare, Phone } from "lucide-react"
|
import { type LucideIcon, Code, FileText, Mail, MessageCircle, MessageSquare, Phone } from "lucide-react"
|
||||||
|
|
||||||
import type { Ticket, TicketChannel, TicketStatus } from "@/lib/schemas/ticket"
|
import type { Ticket, TicketChannel } from "@/lib/schemas/ticket"
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
|
|
@ -23,6 +23,7 @@ import {
|
||||||
import { PrioritySelect } from "@/components/tickets/priority-select"
|
import { PrioritySelect } from "@/components/tickets/priority-select"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import { deriveServerOffset, toServerTimestamp } from "@/components/tickets/ticket-timer.utils"
|
import { deriveServerOffset, toServerTimestamp } from "@/components/tickets/ticket-timer.utils"
|
||||||
|
import { getTicketStatusLabel, getTicketStatusTextClass } from "@/lib/ticket-status-style"
|
||||||
|
|
||||||
const channelLabel: Record<TicketChannel, string> = {
|
const channelLabel: Record<TicketChannel, string> = {
|
||||||
EMAIL: "E-mail",
|
EMAIL: "E-mail",
|
||||||
|
|
@ -48,20 +49,6 @@ const categoryChipClass = "inline-flex items-center gap-1 rounded-full bg-slate-
|
||||||
const tableRowClass =
|
const tableRowClass =
|
||||||
"group border-b border-slate-100 text-sm transition-colors hover:bg-slate-100/70 last:border-none"
|
"group border-b border-slate-100 text-sm transition-colors hover:bg-slate-100/70 last:border-none"
|
||||||
|
|
||||||
const statusLabel: Record<TicketStatus, string> = {
|
|
||||||
PENDING: "Pendente",
|
|
||||||
AWAITING_ATTENDANCE: "Em andamento",
|
|
||||||
PAUSED: "Pausado",
|
|
||||||
RESOLVED: "Resolvido",
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusTone: Record<TicketStatus, string> = {
|
|
||||||
PENDING: "text-slate-700",
|
|
||||||
AWAITING_ATTENDANCE: "text-sky-700",
|
|
||||||
PAUSED: "text-violet-700",
|
|
||||||
RESOLVED: "text-emerald-700",
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDuration(ms?: number) {
|
function formatDuration(ms?: number) {
|
||||||
if (!ms || ms <= 0) return "—"
|
if (!ms || ms <= 0) return "—"
|
||||||
const totalSeconds = Math.floor(ms / 1000)
|
const totalSeconds = Math.floor(ms / 1000)
|
||||||
|
|
@ -267,8 +254,11 @@ export function TicketsTable({ tickets }: TicketsTableProps) {
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className={`${cellClass} pl-6 sm:pl-10 xl:pl-14`}>
|
<TableCell className={`${cellClass} pl-6 sm:pl-10 xl:pl-14`}>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<span className={cn("text-sm font-semibold break-words leading-tight max-w-[140px] sm:max-w-[180px] lg:max-w-[210px]", statusTone[ticket.status])}>
|
<span className={cn(
|
||||||
{statusLabel[ticket.status]}
|
"text-sm font-semibold break-words leading-tight max-w-[140px] sm:max-w-[180px] lg:max-w-[210px]",
|
||||||
|
getTicketStatusTextClass(ticket.status)
|
||||||
|
)}>
|
||||||
|
{getTicketStatusLabel(ticket.status)}
|
||||||
</span>
|
</span>
|
||||||
{ticket.metrics?.timeWaitingMinutes ? (
|
{ticket.metrics?.timeWaitingMinutes ? (
|
||||||
<span className="text-xs text-neutral-500">
|
<span className="text-xs text-neutral-500">
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import { Button } from "@/components/ui/button"
|
||||||
import { Separator } from "@/components/ui/separator"
|
import { Separator } from "@/components/ui/separator"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||||
|
import { getTicketStatusDotClass, getTicketStatusLabel } from "@/lib/ticket-status-style"
|
||||||
import {
|
import {
|
||||||
Bold,
|
Bold,
|
||||||
Italic,
|
Italic,
|
||||||
|
|
@ -115,20 +116,6 @@ type TicketMentionAttributes = Record<string, unknown>
|
||||||
const TICKET_MENTION_FALLBACK_STATUS = "PENDING"
|
const TICKET_MENTION_FALLBACK_STATUS = "PENDING"
|
||||||
const TICKET_MENTION_FALLBACK_PRIORITY = "MEDIUM"
|
const TICKET_MENTION_FALLBACK_PRIORITY = "MEDIUM"
|
||||||
|
|
||||||
const statusLabels: Record<string, string> = {
|
|
||||||
PENDING: "Pendente",
|
|
||||||
AWAITING_ATTENDANCE: "Em andamento",
|
|
||||||
PAUSED: "Pausado",
|
|
||||||
RESOLVED: "Resolvido",
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusTone: Record<string, string> = {
|
|
||||||
PENDING: "bg-amber-400",
|
|
||||||
AWAITING_ATTENDANCE: "bg-sky-500",
|
|
||||||
PAUSED: "bg-violet-500",
|
|
||||||
RESOLVED: "bg-emerald-500",
|
|
||||||
}
|
|
||||||
|
|
||||||
function toPlainString(value: unknown): string {
|
function toPlainString(value: unknown): string {
|
||||||
if (value === null || value === undefined) return ""
|
if (value === null || value === undefined) return ""
|
||||||
return String(value)
|
return String(value)
|
||||||
|
|
@ -162,11 +149,11 @@ function updateTicketMentionNodeElements(elements: TicketMentionNodeElements, at
|
||||||
const displayedReference = referenceLabel ? `#${referenceLabel}` : "#"
|
const displayedReference = referenceLabel ? `#${referenceLabel}` : "#"
|
||||||
const formattedSubject = normalized.subject ? formatMentionSubject(normalized.subject) : ""
|
const formattedSubject = normalized.subject ? formatMentionSubject(normalized.subject) : ""
|
||||||
const additionalClass = toPlainString(attrs.class ?? attrs.className)
|
const additionalClass = toPlainString(attrs.class ?? attrs.className)
|
||||||
const statusToneClass = statusTone[normalized.status] ?? "bg-slate-400"
|
const dotClass = getTicketStatusDotClass(normalized.status)
|
||||||
|
|
||||||
root.className = cn(TICKET_MENTION_BASE_CLASSES, additionalClass)
|
root.className = cn(TICKET_MENTION_BASE_CLASSES, additionalClass)
|
||||||
root.dataset.ticketMention = "true"
|
root.dataset.ticketMention = "true"
|
||||||
dotEl.className = cn(TICKET_MENTION_DOT_BASE_CLASSES, statusToneClass)
|
dotEl.className = cn(TICKET_MENTION_DOT_BASE_CLASSES, dotClass)
|
||||||
referenceEl.className = TICKET_MENTION_REF_CLASSES
|
referenceEl.className = TICKET_MENTION_REF_CLASSES
|
||||||
subjectEl.className = TICKET_MENTION_SUBJECT_CLASSES
|
subjectEl.className = TICKET_MENTION_SUBJECT_CLASSES
|
||||||
separatorEl.className = TICKET_MENTION_SEP_CLASSES
|
separatorEl.className = TICKET_MENTION_SEP_CLASSES
|
||||||
|
|
@ -244,8 +231,7 @@ function buildTicketMentionAnchorHtml(attrs: {
|
||||||
const url = attrs.url ?? ""
|
const url = attrs.url ?? ""
|
||||||
const displayedReference = reference || id
|
const displayedReference = reference || id
|
||||||
const formattedSubject = subject ? formatMentionSubject(subject) : ""
|
const formattedSubject = subject ? formatMentionSubject(subject) : ""
|
||||||
const dotToneClass = statusTone[status] ?? "bg-slate-400"
|
const dotClass = `${TICKET_MENTION_DOT_BASE_CLASSES} ${getTicketStatusDotClass(status)}`
|
||||||
const dotClass = `${TICKET_MENTION_DOT_BASE_CLASSES} ${dotToneClass}`
|
|
||||||
const title = formattedSubject ? `#${displayedReference} • ${formattedSubject}` : `#${displayedReference}`
|
const title = formattedSubject ? `#${displayedReference} • ${formattedSubject}` : `#${displayedReference}`
|
||||||
|
|
||||||
return `<a data-ticket-mention="true" data-ticket-id="${escapeHtml(id)}" data-ticket-reference="${escapeHtml(reference)}" data-ticket-status="${escapeHtml(status)}" data-ticket-priority="${escapeHtml(priority)}" data-ticket-subject="${escapeHtml(subject)}" status="${escapeHtml(status)}" href="${escapeHtml(url)}" class="${escapeHtml(TICKET_MENTION_BASE_CLASSES)}" rel="noopener noreferrer" target="_self" title="${escapeHtml(title)}"><span class="${escapeHtml(dotClass)}"></span><span class="${escapeHtml(TICKET_MENTION_REF_CLASSES)}">#${escapeHtml(displayedReference)}</span><span class="${escapeHtml(TICKET_MENTION_SEP_CLASSES)}">•</span><span class="${escapeHtml(TICKET_MENTION_SUBJECT_CLASSES)}">${escapeHtml(formattedSubject)}</span></a>`
|
return `<a data-ticket-mention="true" data-ticket-id="${escapeHtml(id)}" data-ticket-reference="${escapeHtml(reference)}" data-ticket-status="${escapeHtml(status)}" data-ticket-priority="${escapeHtml(priority)}" data-ticket-subject="${escapeHtml(subject)}" status="${escapeHtml(status)}" href="${escapeHtml(url)}" class="${escapeHtml(TICKET_MENTION_BASE_CLASSES)}" rel="noopener noreferrer" target="_self" title="${escapeHtml(title)}"><span class="${escapeHtml(dotClass)}"></span><span class="${escapeHtml(TICKET_MENTION_REF_CLASSES)}">#${escapeHtml(displayedReference)}</span><span class="${escapeHtml(TICKET_MENTION_SEP_CLASSES)}">•</span><span class="${escapeHtml(TICKET_MENTION_SUBJECT_CLASSES)}">${escapeHtml(formattedSubject)}</span></a>`
|
||||||
|
|
@ -424,8 +410,8 @@ function TicketMentionList({ items, command, onRegister }: TicketMentionSuggesti
|
||||||
<div className="max-h-72 min-w-[320px] space-y-1 overflow-y-auto p-2">
|
<div className="max-h-72 min-w-[320px] space-y-1 overflow-y-auto p-2">
|
||||||
{items.map((item, index) => {
|
{items.map((item, index) => {
|
||||||
const isActive = index === selectedIndex
|
const isActive = index === selectedIndex
|
||||||
const status = statusLabels[item.status] ?? item.status
|
const status = getTicketStatusLabel(item.status)
|
||||||
const statusDot = statusTone[item.status] ?? "bg-slate-400"
|
const statusDot = getTicketStatusDotClass(item.status)
|
||||||
const priority = priorityLabels[item.priority] ?? item.priority
|
const priority = priorityLabels[item.priority] ?? item.priority
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
@ -579,8 +565,7 @@ const TicketMentionExtension = Mention.extend({
|
||||||
const priority = String(HTMLAttributes.priority ?? HTMLAttributes["data-ticket-priority"] ?? "MEDIUM").toUpperCase()
|
const priority = String(HTMLAttributes.priority ?? HTMLAttributes["data-ticket-priority"] ?? "MEDIUM").toUpperCase()
|
||||||
const href = String(HTMLAttributes.url ?? HTMLAttributes.href ?? "#")
|
const href = String(HTMLAttributes.url ?? HTMLAttributes.href ?? "#")
|
||||||
const anchorClass = cn(TICKET_MENTION_BASE_CLASSES, toPlainString(HTMLAttributes.class ?? HTMLAttributes.className))
|
const anchorClass = cn(TICKET_MENTION_BASE_CLASSES, toPlainString(HTMLAttributes.class ?? HTMLAttributes.className))
|
||||||
const statusToneClass = statusTone[status] ?? "bg-slate-400"
|
const dotClass = cn(TICKET_MENTION_DOT_BASE_CLASSES, getTicketStatusDotClass(status))
|
||||||
const dotClass = cn(TICKET_MENTION_DOT_BASE_CLASSES, statusToneClass)
|
|
||||||
return [
|
return [
|
||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
85
src/lib/ticket-status-style.ts
Normal file
85
src/lib/ticket-status-style.ts
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
import type { TicketStatus } from "@/lib/schemas/ticket"
|
||||||
|
|
||||||
|
export type TicketStatusSummaryTone = "default" | "info" | "warning" | "success" | "muted" | "danger"
|
||||||
|
|
||||||
|
export type TicketStatusStyle = {
|
||||||
|
label: string
|
||||||
|
summaryTone: TicketStatusSummaryTone
|
||||||
|
chipClass: string
|
||||||
|
badgeClass: string
|
||||||
|
tableTextClass: string
|
||||||
|
dotClass: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const FALLBACK_STATUS: TicketStatus = "PENDING"
|
||||||
|
|
||||||
|
const META: Record<TicketStatus, TicketStatusStyle> = {
|
||||||
|
PENDING: {
|
||||||
|
label: "Pendente",
|
||||||
|
summaryTone: "muted",
|
||||||
|
chipClass: "bg-slate-100 text-neutral-700 ring-1 ring-slate-200",
|
||||||
|
badgeClass: "border border-slate-200 bg-slate-100 text-neutral-700",
|
||||||
|
tableTextClass: "text-neutral-600",
|
||||||
|
dotClass: "bg-slate-400",
|
||||||
|
},
|
||||||
|
AWAITING_ATTENDANCE: {
|
||||||
|
label: "Em andamento",
|
||||||
|
summaryTone: "info",
|
||||||
|
chipClass: "bg-sky-100 text-sky-700 ring-1 ring-sky-200",
|
||||||
|
badgeClass: "border border-sky-200 bg-sky-100 text-sky-700",
|
||||||
|
tableTextClass: "text-sky-700",
|
||||||
|
dotClass: "bg-sky-500",
|
||||||
|
},
|
||||||
|
PAUSED: {
|
||||||
|
label: "Pausado",
|
||||||
|
summaryTone: "warning",
|
||||||
|
chipClass: "bg-amber-100 text-amber-800 ring-1 ring-amber-200",
|
||||||
|
badgeClass: "border border-amber-200 bg-amber-50 text-amber-700",
|
||||||
|
tableTextClass: "text-amber-700",
|
||||||
|
dotClass: "bg-amber-400",
|
||||||
|
},
|
||||||
|
RESOLVED: {
|
||||||
|
label: "Resolvido",
|
||||||
|
summaryTone: "success",
|
||||||
|
chipClass: "bg-emerald-100 text-emerald-700 ring-1 ring-emerald-200",
|
||||||
|
badgeClass: "border border-emerald-200 bg-emerald-50 text-emerald-700",
|
||||||
|
tableTextClass: "text-emerald-700",
|
||||||
|
dotClass: "bg-emerald-500",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveMeta(status: TicketStatus | string | null | undefined): TicketStatusStyle {
|
||||||
|
if (!status) return META[FALLBACK_STATUS]
|
||||||
|
const normalized = status.toUpperCase() as TicketStatus
|
||||||
|
return META[normalized] ?? META[FALLBACK_STATUS]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusMeta(status: TicketStatus | string | null | undefined): TicketStatusStyle {
|
||||||
|
return resolveMeta(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusLabel(status: TicketStatus | string | null | undefined): string {
|
||||||
|
return resolveMeta(status).label
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusChipClass(status: TicketStatus | string | null | undefined): string {
|
||||||
|
return resolveMeta(status).chipClass
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusBadgeClass(status: TicketStatus | string | null | undefined): string {
|
||||||
|
return resolveMeta(status).badgeClass
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusTextClass(status: TicketStatus | string | null | undefined): string {
|
||||||
|
return resolveMeta(status).tableTextClass
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusDotClass(status: TicketStatus | string | null | undefined): string {
|
||||||
|
return resolveMeta(status).dotClass
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTicketStatusSummaryTone(status: TicketStatus | string | null | undefined): TicketStatusSummaryTone {
|
||||||
|
return resolveMeta(status).summaryTone
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TICKET_STATUS_META = META
|
||||||
Loading…
Add table
Add a link
Reference in a new issue