diff --git a/web/convex/bootstrap.ts b/web/convex/bootstrap.ts index 0eadd01..6292237 100644 --- a/web/convex/bootstrap.ts +++ b/web/convex/bootstrap.ts @@ -4,10 +4,23 @@ import { v } from "convex/values"; export const ensureDefaults = mutation({ args: { tenantId: v.string() }, handler: async (ctx, { tenantId }) => { - const existing = await ctx.db + let existing = await ctx.db .query("queues") .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId)) .collect(); + existing = await Promise.all( + existing.map(async (queue) => { + if (queue.name === "Suporte N1" || queue.slug === "suporte-n1") { + await ctx.db.patch(queue._id, { name: "Chamados", slug: "chamados" }); + return (await ctx.db.get(queue._id)) ?? queue; + } + if (queue.name === "Suporte N2" || queue.slug === "suporte-n2") { + await ctx.db.patch(queue._id, { name: "Laboratório", slug: "laboratorio" }); + return (await ctx.db.get(queue._id)) ?? queue; + } + return queue; + }) + ); if (existing.length === 0) { const queues = [ { name: "Chamados", slug: "chamados" }, diff --git a/web/convex/queues.ts b/web/convex/queues.ts index fa5f975..9b5ace4 100644 --- a/web/convex/queues.ts +++ b/web/convex/queues.ts @@ -1,6 +1,20 @@ import { query } from "./_generated/server"; import { v } from "convex/values"; +const QUEUE_RENAME_LOOKUP: Record = { + "Suporte N1": "Chamados", + "suporte-n1": "Chamados", + "Suporte N2": "Laboratório", + "suporte-n2": "Laboratório", +}; + +function renameQueueString(value: string) { + const direct = QUEUE_RENAME_LOOKUP[value]; + if (direct) return direct; + const normalizedKey = value.replace(/\s+/g, "-").toLowerCase(); + return QUEUE_RENAME_LOOKUP[normalizedKey] ?? value; +} + export const summary = query({ args: { tenantId: v.string() }, handler: async (ctx, { tenantId }) => { @@ -15,7 +29,7 @@ export const summary = query({ const waiting = pending.filter((t) => t.status === "PENDING" || t.status === "ON_HOLD").length; const open = pending.filter((t) => t.status !== "RESOLVED" && t.status !== "CLOSED").length; const breached = 0; // Placeholder, SLAs later - return { id: qItem._id, name: qItem.name, pending: open, waiting, breached }; + return { id: qItem._id, name: renameQueueString(qItem.name), pending: open, waiting, breached }; }) ); return result; diff --git a/web/convex/seed.ts b/web/convex/seed.ts index 2498ab1..f6e9ff3 100644 --- a/web/convex/seed.ts +++ b/web/convex/seed.ts @@ -9,7 +9,7 @@ export const seedDemo = mutation({ .query("queues") .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId)) .collect(); - const queues = existingQueues.length + let queues = existingQueues.length ? existingQueues : await Promise.all( [ @@ -19,6 +19,21 @@ export const seedDemo = mutation({ ).then((ids) => Promise.all(ids.map((id) => ctx.db.get(id)))) ; + queues = await Promise.all( + queues.map(async (queue) => { + if (!queue) return queue; + if (queue.name === "Suporte N1" || queue.slug === "suporte-n1") { + await ctx.db.patch(queue._id, { name: "Chamados", slug: "chamados" }); + return (await ctx.db.get(queue._id)) ?? queue; + } + if (queue.name === "Suporte N2" || queue.slug === "suporte-n2") { + await ctx.db.patch(queue._id, { name: "Laboratório", slug: "laboratorio" }); + return (await ctx.db.get(queue._id)) ?? queue; + } + return queue; + }) + ); + // Ensure users async function ensureUser(name: string, email: string, role = "AGENT") { const found = await ctx.db diff --git a/web/convex/tickets.ts b/web/convex/tickets.ts index e609ff2..9ce81bd 100644 --- a/web/convex/tickets.ts +++ b/web/convex/tickets.ts @@ -4,6 +4,39 @@ import { Id, type Doc } from "./_generated/dataModel"; const PRIORITY_ORDER = ["URGENT", "HIGH", "MEDIUM", "LOW"] as const; +const QUEUE_RENAME_LOOKUP: Record = { + "Suporte N1": "Chamados", + "suporte-n1": "Chamados", + "Suporte N2": "Laboratório", + "suporte-n2": "Laboratório", +}; + +function renameQueueString(value?: string | null): string | null { + if (!value) return value ?? null; + const direct = QUEUE_RENAME_LOOKUP[value]; + if (direct) return direct; + const normalizedKey = value.replace(/\s+/g, "-").toLowerCase(); + return QUEUE_RENAME_LOOKUP[normalizedKey] ?? value; +} + +function normalizeQueueName(queue?: Doc<"queues"> | null): string | null { + if (!queue) return null; + const normalized = renameQueueString(queue.name); + if (normalized && normalized !== queue.name) { + return normalized; + } + if (queue.slug) { + const fromSlug = renameQueueString(queue.slug); + if (fromSlug) return fromSlug; + } + return normalized ?? queue.name; +} + +function normalizeTeams(teams?: string[] | null): string[] { + if (!teams) return []; + return teams.map((team) => renameQueueString(team) ?? team); +} + export const list = query({ args: { tenantId: v.string(), @@ -55,6 +88,7 @@ export const list = query({ const requester = (await ctx.db.get(t.requesterId)) as Doc<"users"> | null; const assignee = t.assigneeId ? ((await ctx.db.get(t.assigneeId)) as Doc<"users"> | null) : null; const queue = t.queueId ? ((await ctx.db.get(t.queueId)) as Doc<"queues"> | null) : null; + const queueName = normalizeQueueName(queue); const activeSession = t.activeSessionId ? await ctx.db.get(t.activeSessionId) : null; let categorySummary: { id: Id<"ticketCategories">; name: string } | null = null; let subcategorySummary: { id: Id<"ticketSubcategories">; name: string } | null = null; @@ -85,13 +119,13 @@ export const list = query({ status: t.status, priority: t.priority, channel: t.channel, - queue: queue?.name ?? null, + queue: queueName, requester: requester && { id: requester._id, name: requester.name, email: requester.email, avatarUrl: requester.avatarUrl, - teams: requester.teams ?? [], + teams: normalizeTeams(requester.teams), }, assignee: assignee ? { @@ -99,7 +133,7 @@ export const list = query({ name: assignee.name, email: assignee.email, avatarUrl: assignee.avatarUrl, - teams: assignee.teams ?? [], + teams: normalizeTeams(assignee.teams), } : null, slaPolicy: null, @@ -139,6 +173,7 @@ export const getById = query({ const requester = (await ctx.db.get(t.requesterId)) as Doc<"users"> | null; const assignee = t.assigneeId ? ((await ctx.db.get(t.assigneeId)) as Doc<"users"> | null) : null; const queue = t.queueId ? ((await ctx.db.get(t.queueId)) as Doc<"queues"> | null) : null; + const queueName = normalizeQueueName(queue); const category = t.categoryId ? await ctx.db.get(t.categoryId) : null; const subcategory = t.subcategoryId ? await ctx.db.get(t.subcategoryId) : null; const comments = await ctx.db @@ -191,13 +226,13 @@ export const getById = query({ status: t.status, priority: t.priority, channel: t.channel, - queue: queue?.name ?? null, + queue: queueName, requester: requester && { id: requester._id, name: requester.name, email: requester.email, avatarUrl: requester.avatarUrl, - teams: requester.teams ?? [], + teams: normalizeTeams(requester.teams), }, assignee: assignee ? { @@ -205,7 +240,7 @@ export const getById = query({ name: assignee.name, email: assignee.email, avatarUrl: assignee.avatarUrl, - teams: assignee.teams ?? [], + teams: normalizeTeams(assignee.teams), } : null, slaPolicy: null, @@ -242,12 +277,21 @@ export const getById = query({ }, description: undefined, customFields: {}, - timeline: timeline.map((ev) => ({ - id: ev._id, - type: ev.type, - payload: ev.payload, - createdAt: ev.createdAt, - })), + timeline: timeline.map((ev) => { + let payload = ev.payload; + if (ev.type === "QUEUE_CHANGED" && payload && typeof payload === "object" && "queueName" in payload) { + const normalized = renameQueueString((payload as { queueName?: string }).queueName ?? null); + if (normalized && normalized !== (payload as { queueName?: string }).queueName) { + payload = { ...payload, queueName: normalized }; + } + } + return { + id: ev._id, + type: ev.type, + payload, + createdAt: ev.createdAt, + }; + }), comments: commentsHydrated, }; }, @@ -451,10 +495,11 @@ export const changeQueue = mutation({ const now = Date.now(); await ctx.db.patch(ticketId, { queueId, updatedAt: now }); const queue = (await ctx.db.get(queueId)) as Doc<"queues"> | null; + const queueName = normalizeQueueName(queue); await ctx.db.insert("ticketEvents", { ticketId, type: "QUEUE_CHANGED", - payload: { queueId, queueName: queue?.name, actorId }, + payload: { queueId, queueName, actorId }, createdAt: now, }); },