feat: dispositivos e ajustes de csat e relatórios

This commit is contained in:
codex-bot 2025-11-03 19:29:50 -03:00
parent 25d2a9b062
commit e0ef66555d
86 changed files with 5811 additions and 992 deletions

View file

@ -65,6 +65,11 @@ const serverTicketSchema = z.object({
tags: z.array(z.string()).default([]).optional(),
lastTimelineEntry: z.string().nullable().optional(),
metrics: z.any().nullable().optional(),
csatScore: z.number().nullable().optional(),
csatMaxScore: z.number().nullable().optional(),
csatComment: z.string().nullable().optional(),
csatRatedAt: z.number().nullable().optional(),
csatRatedBy: z.string().nullable().optional(),
category: z
.object({
id: z.string(),
@ -154,9 +159,17 @@ const serverTicketWithDetailsSchema = serverTicketSchema.extend({
});
export function mapTicketFromServer(input: unknown) {
const s = serverTicketSchema.parse(input);
const {
csatScore,
csatMaxScore,
csatComment,
csatRatedAt,
csatRatedBy,
...base
} = serverTicketSchema.parse(input);
const s = { csatScore, csatMaxScore, csatComment, csatRatedAt, csatRatedBy, ...base };
const ui = {
...s,
...base,
status: normalizeTicketStatus(s.status),
company: s.company
? { id: s.company.id, name: s.company.name, isAvulso: s.company.isAvulso ?? false }
@ -179,6 +192,11 @@ export function mapTicketFromServer(input: unknown) {
dueAt: s.dueAt ? new Date(s.dueAt) : null,
firstResponseAt: s.firstResponseAt ? new Date(s.firstResponseAt) : null,
resolvedAt: s.resolvedAt ? new Date(s.resolvedAt) : null,
csatScore: typeof csatScore === "number" ? csatScore : null,
csatMaxScore: typeof csatMaxScore === "number" ? csatMaxScore : null,
csatComment: typeof csatComment === "string" && csatComment.trim().length > 0 ? csatComment.trim() : null,
csatRatedAt: csatRatedAt ? new Date(csatRatedAt) : null,
csatRatedBy: csatRatedBy ?? null,
workSummary: s.workSummary
? {
totalWorkedMs: s.workSummary.totalWorkedMs,
@ -211,7 +229,15 @@ export function mapTicketsFromServerList(arr: unknown[]) {
}
export function mapTicketWithDetailsFromServer(input: unknown) {
const s = serverTicketWithDetailsSchema.parse(input);
const {
csatScore,
csatMaxScore,
csatComment,
csatRatedAt,
csatRatedBy,
...base
} = serverTicketWithDetailsSchema.parse(input);
const s = { csatScore, csatMaxScore, csatComment, csatRatedAt, csatRatedBy, ...base };
const customFields = Object.entries(s.customFields ?? {}).reduce<
Record<string, { label: string; type: string; value?: unknown; displayValue?: string }>
>(
@ -231,47 +257,52 @@ export function mapTicketWithDetailsFromServer(input: unknown) {
{}
);
const ui = {
...s,
...base,
customFields,
status: normalizeTicketStatus(s.status),
category: s.category ?? undefined,
subcategory: s.subcategory ?? undefined,
lastTimelineEntry: s.lastTimelineEntry ?? undefined,
updatedAt: new Date(s.updatedAt),
createdAt: new Date(s.createdAt),
dueAt: s.dueAt ? new Date(s.dueAt) : null,
firstResponseAt: s.firstResponseAt ? new Date(s.firstResponseAt) : null,
resolvedAt: s.resolvedAt ? new Date(s.resolvedAt) : null,
company: s.company ? { id: s.company.id, name: s.company.name, isAvulso: s.company.isAvulso ?? false } : undefined,
machine: s.machine
status: normalizeTicketStatus(base.status),
category: base.category ?? undefined,
subcategory: base.subcategory ?? undefined,
lastTimelineEntry: base.lastTimelineEntry ?? undefined,
updatedAt: new Date(base.updatedAt),
createdAt: new Date(base.createdAt),
dueAt: base.dueAt ? new Date(base.dueAt) : null,
firstResponseAt: base.firstResponseAt ? new Date(base.firstResponseAt) : null,
resolvedAt: base.resolvedAt ? new Date(base.resolvedAt) : null,
csatScore: typeof csatScore === "number" ? csatScore : null,
csatMaxScore: typeof csatMaxScore === "number" ? csatMaxScore : null,
csatComment: typeof csatComment === "string" && csatComment.trim().length > 0 ? csatComment.trim() : null,
csatRatedAt: csatRatedAt ? new Date(csatRatedAt) : null,
csatRatedBy: csatRatedBy ?? null,
company: base.company ? { id: base.company.id, name: base.company.name, isAvulso: base.company.isAvulso ?? false } : undefined,
machine: base.machine
? {
id: s.machine.id ?? null,
hostname: s.machine.hostname ?? null,
persona: s.machine.persona ?? null,
assignedUserName: s.machine.assignedUserName ?? null,
assignedUserEmail: s.machine.assignedUserEmail ?? null,
status: s.machine.status ?? null,
id: base.machine.id ?? null,
hostname: base.machine.hostname ?? null,
persona: base.machine.persona ?? null,
assignedUserName: base.machine.assignedUserName ?? null,
assignedUserEmail: base.machine.assignedUserEmail ?? null,
status: base.machine.status ?? null,
}
: null,
timeline: s.timeline.map((e) => ({ ...e, createdAt: new Date(e.createdAt) })),
comments: s.comments.map((c) => ({
timeline: base.timeline.map((e) => ({ ...e, createdAt: new Date(e.createdAt) })),
comments: base.comments.map((c) => ({
...c,
createdAt: new Date(c.createdAt),
updatedAt: new Date(c.updatedAt),
})),
workSummary: s.workSummary
workSummary: base.workSummary
? {
totalWorkedMs: s.workSummary.totalWorkedMs,
internalWorkedMs: s.workSummary.internalWorkedMs ?? 0,
externalWorkedMs: s.workSummary.externalWorkedMs ?? 0,
serverNow: s.workSummary.serverNow,
activeSession: s.workSummary.activeSession
totalWorkedMs: base.workSummary.totalWorkedMs,
internalWorkedMs: base.workSummary.internalWorkedMs ?? 0,
externalWorkedMs: base.workSummary.externalWorkedMs ?? 0,
serverNow: base.workSummary.serverNow,
activeSession: base.workSummary.activeSession
? {
...s.workSummary.activeSession,
startedAt: new Date(s.workSummary.activeSession.startedAt),
...base.workSummary.activeSession,
startedAt: new Date(base.workSummary.activeSession.startedAt),
}
: null,
perAgentTotals: (s.workSummary.perAgentTotals ?? []).map((item) => ({
perAgentTotals: (base.workSummary.perAgentTotals ?? []).map((item) => ({
agentId: item.agentId,
agentName: item.agentName ?? null,
agentEmail: item.agentEmail ?? null,