feat: custom fields improvements

This commit is contained in:
Esdras Renan 2025-11-06 14:05:51 -03:00
parent 9495b54a28
commit 0f0f367b3a
11 changed files with 1290 additions and 12 deletions

View file

@ -0,0 +1,89 @@
import { format } from "date-fns"
import { ptBR } from "date-fns/locale"
export type TicketCustomFieldRecord = Record<
string,
{
label: string
type: string
value?: unknown
displayValue?: string
}
>
export type TicketCustomFieldEntry = {
key: string
label: string
type: string
value: unknown
displayValue?: string
formattedValue: string
}
function formatBoolean(value: unknown): string {
if (value === null || value === undefined) return "—"
return value === true || String(value).toLowerCase() === "true" ? "Sim" : "Não"
}
function formatDate(value: unknown): string {
if (value === null || value === undefined) return "—"
const date =
typeof value === "number"
? Number.isFinite(value)
? new Date(value)
: null
: typeof value === "string" && value.trim().length > 0
? new Date(value)
: null
if (!date || Number.isNaN(date.getTime())) return "—"
return format(date, "dd/MM/yyyy", { locale: ptBR })
}
function formatNumber(value: unknown): string {
if (value === null || value === undefined || value === "") return "—"
const numeric = typeof value === "number" ? value : Number(String(value).replace(",", "."))
if (!Number.isFinite(numeric)) return String(value)
return new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 2 }).format(numeric)
}
function formatFallback(value: unknown): string {
if (value === null || value === undefined) return "—"
if (typeof value === "string" && value.trim().length === 0) return "—"
return String(value)
}
export function formatTicketCustomFieldValue(entry: {
type: string
value?: unknown
displayValue?: string
}): string {
if (entry.displayValue && entry.displayValue.trim().length > 0) {
return entry.displayValue
}
switch ((entry.type ?? "").toLowerCase()) {
case "boolean":
return formatBoolean(entry.value)
case "date":
return formatDate(entry.value)
case "number":
return formatNumber(entry.value)
default:
return formatFallback(entry.value)
}
}
export function mapTicketCustomFields(
record: TicketCustomFieldRecord | undefined | null
): TicketCustomFieldEntry[] {
if (!record) return []
return Object.entries(record)
.map(([key, field]) => ({
key,
label: field.label,
type: field.type,
value: field.value ?? null,
displayValue: field.displayValue,
formattedValue: formatTicketCustomFieldValue(field),
}))
.sort((a, b) => a.label.localeCompare(b.label, "pt-BR"))
}

View file

@ -18,4 +18,5 @@ export const TICKET_TIMELINE_LABELS: Record<string, string> = {
CSAT_RECEIVED: "CSAT recebido",
CSAT_RATED: "CSAT avaliado",
TICKET_LINKED: "Chamado vinculado",
CUSTOM_FIELDS_UPDATED: "Campos personalizados atualizados",
};