feat: checklists em tickets + automações

- Adiciona checklist no ticket (itens obrigatórios/opcionais) e bloqueia encerramento com pendências\n- Cria templates de checklist (globais/por empresa) + tela em /settings/checklists\n- Nova ação de automação: aplicar template de checklist\n- Corrige crash do Select (value vazio), warnings de Dialog e dimensionamento de charts\n- Ajusta SMTP (STARTTLS) e melhora teste de integração
This commit is contained in:
esdrasrenan 2025-12-13 20:51:47 -03:00
parent 4306b0504d
commit 88a9ef454e
27 changed files with 2685 additions and 226 deletions

View file

@ -81,6 +81,22 @@ const serverTicketSchema = z.object({
queue: z.string().nullable(),
formTemplate: z.string().nullable().optional(),
formTemplateLabel: z.string().nullable().optional(),
checklist: z
.array(
z.object({
id: z.string(),
text: z.string(),
done: z.boolean(),
required: z.boolean().optional(),
templateId: z.string().optional(),
templateItemId: z.string().optional(),
createdAt: z.number().optional(),
createdBy: z.string().optional(),
doneAt: z.number().optional(),
doneBy: z.string().optional(),
}),
)
.optional(),
requester: serverUserSchema,
assignee: serverUserSchema.nullable(),
company: z
@ -227,6 +243,10 @@ export function mapTicketFromServer(input: unknown) {
...base
} = serverTicketSchema.parse(input);
const s = { csatScore, csatMaxScore, csatComment, csatRatedAt, csatRatedBy, ...base };
const checklist = (s.checklist ?? []).map((item) => ({
...item,
required: item.required ?? true,
}));
const slaSnapshot = s.slaSnapshot
? {
categoryId: s.slaSnapshot.categoryId ? String(s.slaSnapshot.categoryId) : undefined,
@ -243,6 +263,7 @@ export function mapTicketFromServer(input: unknown) {
const ui = {
...base,
status: normalizeTicketStatus(s.status),
checklist,
company: s.company
? { id: s.company.id, name: s.company.name, isAvulso: s.company.isAvulso ?? false }
: undefined,
@ -325,6 +346,10 @@ export function mapTicketWithDetailsFromServer(input: unknown) {
...base
} = serverTicketWithDetailsSchema.parse(input);
const s = { csatScore, csatMaxScore, csatComment, csatRatedAt, csatRatedBy, ...base };
const checklist = (s.checklist ?? []).map((item) => ({
...item,
required: item.required ?? true,
}));
const slaSnapshot = s.slaSnapshot
? {
categoryId: s.slaSnapshot.categoryId ? String(s.slaSnapshot.categoryId) : undefined,
@ -360,6 +385,7 @@ export function mapTicketWithDetailsFromServer(input: unknown) {
...base,
customFields,
status: normalizeTicketStatus(base.status),
checklist,
category: base.category ?? undefined,
subcategory: base.subcategory ?? undefined,
lastTimelineEntry: base.lastTimelineEntry ?? undefined,