Atualiza dashboards e painel de tickets
This commit is contained in:
parent
c66ffa6e0b
commit
4655c7570a
9 changed files with 483 additions and 420 deletions
|
|
@ -7,13 +7,12 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
|||
import { getTicketStatusLabel, getTicketStatusSummaryTone } from "@/lib/ticket-status-style"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { TicketCustomFieldsSection } from "@/components/tickets/ticket-custom-fields"
|
||||
|
||||
interface TicketDetailsPanelProps {
|
||||
ticket: TicketWithDetails
|
||||
}
|
||||
|
||||
type SummaryTone = "default" | "info" | "warning" | "success" | "muted" | "danger"
|
||||
type SummaryTone = "default" | "info" | "warning" | "success" | "muted" | "danger" | "primary"
|
||||
|
||||
const priorityLabel: Record<TicketWithDetails["priority"], string> = {
|
||||
LOW: "Baixa",
|
||||
|
|
@ -49,12 +48,20 @@ function formatMinutes(value?: number | null) {
|
|||
return `${value} min`
|
||||
}
|
||||
|
||||
type SummaryChipConfig = {
|
||||
key: string
|
||||
label: string
|
||||
value: string
|
||||
tone: SummaryTone
|
||||
labelClassName?: string
|
||||
}
|
||||
|
||||
export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
||||
const isAvulso = Boolean(ticket.company?.isAvulso)
|
||||
const companyLabel = ticket.company?.name ?? (isAvulso ? "Cliente avulso" : "Sem empresa vinculada")
|
||||
|
||||
const summaryChips = useMemo(() => {
|
||||
const chips: Array<{ key: string; label: string; value: string; tone: SummaryTone }> = [
|
||||
const chips: SummaryChipConfig[] = [
|
||||
{
|
||||
key: "queue",
|
||||
label: "Fila",
|
||||
|
|
@ -87,11 +94,12 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
},
|
||||
]
|
||||
if (ticket.formTemplateLabel) {
|
||||
chips.push({
|
||||
chips.splice(Math.min(chips.length, 5), 0, {
|
||||
key: "formTemplate",
|
||||
label: "Tipo de solicitação",
|
||||
label: "Fluxo",
|
||||
value: ticket.formTemplateLabel,
|
||||
tone: "info",
|
||||
tone: "primary",
|
||||
labelClassName: "text-white",
|
||||
})
|
||||
}
|
||||
return chips
|
||||
|
|
@ -117,7 +125,7 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
<div className="space-y-1">
|
||||
<CardTitle className="text-lg font-semibold text-neutral-900">Detalhes</CardTitle>
|
||||
<CardDescription className="text-sm text-neutral-500">
|
||||
Resumo do ticket, métricas de SLA e tempo dedicado pela equipe.
|
||||
Resumo do ticket, métricas de SLA, tempo dedicado e campos personalizados.
|
||||
</CardDescription>
|
||||
</div>
|
||||
{isAvulso ? (
|
||||
|
|
@ -131,8 +139,8 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
<section className="space-y-3">
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Resumo</h3>
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
{summaryChips.map(({ key, label, value, tone }) => (
|
||||
<SummaryChip key={key} label={label} value={value} tone={tone} />
|
||||
{summaryChips.map(({ key, label, value, tone, labelClassName }) => (
|
||||
<SummaryChip key={key} label={label} value={value} tone={tone} labelClassName={labelClassName} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -190,8 +198,6 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<TicketCustomFieldsSection ticket={ticket} />
|
||||
|
||||
<section className="space-y-3">
|
||||
<h3 className="text-sm font-semibold text-neutral-900">Tempo por agente</h3>
|
||||
{agentTotals.length > 0 ? (
|
||||
|
|
@ -255,7 +261,17 @@ export function TicketDetailsPanel({ ticket }: TicketDetailsPanelProps) {
|
|||
)
|
||||
}
|
||||
|
||||
function SummaryChip({ label, value, tone = "default" }: { label: string; value: string; tone?: SummaryTone }) {
|
||||
function SummaryChip({
|
||||
label,
|
||||
value,
|
||||
tone = "default",
|
||||
labelClassName,
|
||||
}: {
|
||||
label: string
|
||||
value: string
|
||||
tone?: SummaryTone
|
||||
labelClassName?: string
|
||||
}) {
|
||||
const toneClasses: Record<SummaryTone, string> = {
|
||||
default: "border-slate-200 bg-white text-neutral-900",
|
||||
info: "border-sky-200 bg-sky-50 text-sky-900",
|
||||
|
|
@ -263,11 +279,12 @@ function SummaryChip({ label, value, tone = "default" }: { label: string; value:
|
|||
success: "border-emerald-200 bg-emerald-50 text-emerald-800",
|
||||
muted: "border-slate-200 bg-slate-50 text-neutral-600",
|
||||
danger: "border-rose-200 bg-rose-50 text-rose-700",
|
||||
primary: "border-black bg-black text-white",
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("rounded-xl border px-3 py-2 shadow-sm", toneClasses[tone])}>
|
||||
<p className="text-[11px] font-semibold uppercase tracking-wide text-neutral-500">{label}</p>
|
||||
<p className={cn("text-[11px] font-semibold uppercase tracking-wide text-neutral-500", labelClassName)}>{label}</p>
|
||||
<p className="mt-1 truncate text-sm font-semibold text-current">{value}</p>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue