feat: núcleo de tickets com Convex (CRUD, play, comentários com anexos) + auth placeholder; docs em AGENTS.md; toasts e updates otimistas; mapeadores Zod; refinos PT-BR e layout do painel de detalhes
This commit is contained in:
parent
2230590e57
commit
27b103cb46
97 changed files with 15117 additions and 15715 deletions
81
web/convex/seed.ts
Normal file
81
web/convex/seed.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { mutation } from "./_generated/server";
|
||||
|
||||
export const seedDemo = mutation({
|
||||
args: {},
|
||||
handler: async (ctx) => {
|
||||
const tenantId = "tenant-atlas";
|
||||
// Ensure queues
|
||||
const existingQueues = await ctx.db
|
||||
.query("queues")
|
||||
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
|
||||
.collect();
|
||||
const queues = existingQueues.length
|
||||
? existingQueues
|
||||
: await Promise.all(
|
||||
[
|
||||
{ name: "Suporte N1", slug: "suporte-n1" },
|
||||
{ name: "Suporte N2", slug: "suporte-n2" },
|
||||
].map((q) => ctx.db.insert("queues", { tenantId, name: q.name, slug: q.slug, teamId: undefined }))
|
||||
).then((ids) => Promise.all(ids.map((id) => ctx.db.get(id))))
|
||||
;
|
||||
|
||||
// Ensure users
|
||||
async function ensureUser(name: string, email: string, role = "AGENT") {
|
||||
const found = await ctx.db
|
||||
.query("users")
|
||||
.withIndex("by_tenant_email", (q) => q.eq("tenantId", tenantId).eq("email", email))
|
||||
.first();
|
||||
if (found) return found._id;
|
||||
return await ctx.db.insert("users", { tenantId, name, email, role, avatarUrl: `https://avatar.vercel.sh/${name.split(" ")[0]}` });
|
||||
}
|
||||
const anaId = await ensureUser("Ana Souza", "ana.souza@example.com");
|
||||
const brunoId = await ensureUser("Bruno Lima", "bruno.lima@example.com");
|
||||
const eduardaId = await ensureUser("Eduarda Rocha", "eduarda.rocha@example.com", "CUSTOMER");
|
||||
|
||||
// Seed a couple of tickets
|
||||
const now = Date.now();
|
||||
const newestRef = await ctx.db
|
||||
.query("tickets")
|
||||
.withIndex("by_tenant_reference", (q) => q.eq("tenantId", tenantId))
|
||||
.order("desc")
|
||||
.take(1);
|
||||
let ref = newestRef[0]?.reference ?? 41000;
|
||||
const queue1 = queues[0]!._id;
|
||||
const queue2 = queues[1]!._id;
|
||||
|
||||
const t1 = await ctx.db.insert("tickets", {
|
||||
tenantId,
|
||||
reference: ++ref,
|
||||
subject: "Erro 500 ao acessar portal do cliente",
|
||||
summary: "Clientes relatam erro intermitente no portal web",
|
||||
status: "OPEN",
|
||||
priority: "URGENT",
|
||||
channel: "EMAIL",
|
||||
queueId: queue1,
|
||||
requesterId: eduardaId,
|
||||
assigneeId: anaId,
|
||||
createdAt: now - 1000 * 60 * 60 * 5,
|
||||
updatedAt: now - 1000 * 60 * 10,
|
||||
tags: ["portal", "cliente"],
|
||||
});
|
||||
await ctx.db.insert("ticketEvents", { ticketId: t1, type: "CREATED", createdAt: now - 1000 * 60 * 60 * 5, payload: {} });
|
||||
|
||||
const t2 = await ctx.db.insert("tickets", {
|
||||
tenantId,
|
||||
reference: ++ref,
|
||||
subject: "Integração ERP parada",
|
||||
summary: "Webhook do ERP retornando timeout",
|
||||
status: "PENDING",
|
||||
priority: "HIGH",
|
||||
channel: "WHATSAPP",
|
||||
queueId: queue2,
|
||||
requesterId: eduardaId,
|
||||
assigneeId: brunoId,
|
||||
createdAt: now - 1000 * 60 * 60 * 8,
|
||||
updatedAt: now - 1000 * 60 * 30,
|
||||
tags: ["Integração", "erp"],
|
||||
});
|
||||
await ctx.db.insert("ticketEvents", { ticketId: t2, type: "CREATED", createdAt: now - 1000 * 60 * 60 * 8, payload: {} });
|
||||
},
|
||||
});
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue