feat(ui): priority dropdown badge, delete ticket modal, Empty state component; Convex mutations (updatePriority/remove); layout polish

- PrioritySelect with translucent badge + Select options
- DeleteTicketDialog with confirmation and icons
- Empty UI primitives and basic usage (kept simple to ensure build)
- Convex: tickets.updatePriority & tickets.remove
- Header: integrate priority select, delete action, avatar-rich assignee select
This commit is contained in:
esdrasrenan 2025-10-04 14:56:16 -03:00
parent ea60c3b841
commit 97ca2b3b54
5 changed files with 222 additions and 3 deletions

View file

@ -333,6 +333,21 @@ export const changeQueue = mutation({
},
});
export const updatePriority = mutation({
args: { ticketId: v.id("tickets"), priority: v.string(), actorId: v.id("users") },
handler: async (ctx, { ticketId, priority, actorId }) => {
const now = Date.now();
await ctx.db.patch(ticketId, { priority, updatedAt: now });
const pt: Record<string, string> = { LOW: "Baixa", MEDIUM: "Média", HIGH: "Alta", URGENT: "Urgente" };
await ctx.db.insert("ticketEvents", {
ticketId,
type: "PRIORITY_CHANGED",
payload: { to: priority, toLabel: pt[priority] ?? priority, actorId },
createdAt: now,
});
},
});
export const playNext = mutation({
args: {
tenantId: v.string(),
@ -422,3 +437,30 @@ export const playNext = mutation({
}
},
});
export const remove = mutation({
args: { ticketId: v.id("tickets"), actorId: v.id("users") },
handler: async (ctx, { ticketId, actorId }) => {
// delete comments (and attachments)
const comments = await ctx.db
.query("ticketComments")
.withIndex("by_ticket", (q) => q.eq("ticketId", ticketId))
.collect();
for (const c of comments) {
for (const att of c.attachments ?? []) {
try { await ctx.storage.delete(att.storageId); } catch {}
}
await ctx.db.delete(c._id);
}
// delete events
const events = await ctx.db
.query("ticketEvents")
.withIndex("by_ticket", (q) => q.eq("ticketId", ticketId))
.collect();
for (const ev of events) await ctx.db.delete(ev._id);
// delete ticket
await ctx.db.delete(ticketId);
// (optional) event is moot after deletion
return true;
},
});