chore: reorganize project structure and ensure default queues
This commit is contained in:
parent
854887f499
commit
1cccb852a5
201 changed files with 417 additions and 838 deletions
|
|
@ -1,138 +0,0 @@
|
|||
import { mutation, query } from "./_generated/server";
|
||||
import type { MutationCtx, QueryCtx } from "./_generated/server";
|
||||
import { ConvexError, v } from "convex/values";
|
||||
import type { Id } from "./_generated/dataModel";
|
||||
|
||||
import { requireAdmin } from "./rbac";
|
||||
|
||||
function normalizeName(value: string) {
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
type AnyCtx = QueryCtx | MutationCtx;
|
||||
|
||||
async function ensureUniqueName(ctx: AnyCtx, tenantId: string, name: string, excludeId?: Id<"slaPolicies">) {
|
||||
const existing = await ctx.db
|
||||
.query("slaPolicies")
|
||||
.withIndex("by_tenant_name", (q) => q.eq("tenantId", tenantId).eq("name", name))
|
||||
.first();
|
||||
if (existing && (!excludeId || existing._id !== excludeId)) {
|
||||
throw new ConvexError("Já existe uma política SLA com este nome");
|
||||
}
|
||||
}
|
||||
|
||||
export const list = query({
|
||||
args: { tenantId: v.string(), viewerId: v.id("users") },
|
||||
handler: async (ctx, { tenantId, viewerId }) => {
|
||||
await requireAdmin(ctx, viewerId, tenantId);
|
||||
const items = await ctx.db
|
||||
.query("slaPolicies")
|
||||
.withIndex("by_tenant_name", (q) => q.eq("tenantId", tenantId))
|
||||
.collect();
|
||||
|
||||
return items.map((policy) => ({
|
||||
id: policy._id,
|
||||
name: policy.name,
|
||||
description: policy.description ?? "",
|
||||
timeToFirstResponse: policy.timeToFirstResponse ?? null,
|
||||
timeToResolution: policy.timeToResolution ?? null,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
export const create = mutation({
|
||||
args: {
|
||||
tenantId: v.string(),
|
||||
actorId: v.id("users"),
|
||||
name: v.string(),
|
||||
description: v.optional(v.string()),
|
||||
timeToFirstResponse: v.optional(v.number()),
|
||||
timeToResolution: v.optional(v.number()),
|
||||
},
|
||||
handler: async (ctx, { tenantId, actorId, name, description, timeToFirstResponse, timeToResolution }) => {
|
||||
await requireAdmin(ctx, actorId, tenantId);
|
||||
const trimmed = normalizeName(name);
|
||||
if (trimmed.length < 2) {
|
||||
throw new ConvexError("Informe um nome válido para a política");
|
||||
}
|
||||
await ensureUniqueName(ctx, tenantId, trimmed);
|
||||
if (timeToFirstResponse !== undefined && timeToFirstResponse < 0) {
|
||||
throw new ConvexError("Tempo para primeira resposta deve ser positivo");
|
||||
}
|
||||
if (timeToResolution !== undefined && timeToResolution < 0) {
|
||||
throw new ConvexError("Tempo para resolução deve ser positivo");
|
||||
}
|
||||
|
||||
const id = await ctx.db.insert("slaPolicies", {
|
||||
tenantId,
|
||||
name: trimmed,
|
||||
description,
|
||||
timeToFirstResponse,
|
||||
timeToResolution,
|
||||
});
|
||||
return id;
|
||||
},
|
||||
});
|
||||
|
||||
export const update = mutation({
|
||||
args: {
|
||||
policyId: v.id("slaPolicies"),
|
||||
tenantId: v.string(),
|
||||
actorId: v.id("users"),
|
||||
name: v.string(),
|
||||
description: v.optional(v.string()),
|
||||
timeToFirstResponse: v.optional(v.number()),
|
||||
timeToResolution: v.optional(v.number()),
|
||||
},
|
||||
handler: async (ctx, { policyId, tenantId, actorId, name, description, timeToFirstResponse, timeToResolution }) => {
|
||||
await requireAdmin(ctx, actorId, tenantId);
|
||||
const policy = await ctx.db.get(policyId);
|
||||
if (!policy || policy.tenantId !== tenantId) {
|
||||
throw new ConvexError("Política não encontrada");
|
||||
}
|
||||
const trimmed = normalizeName(name);
|
||||
if (trimmed.length < 2) {
|
||||
throw new ConvexError("Informe um nome válido para a política");
|
||||
}
|
||||
if (timeToFirstResponse !== undefined && timeToFirstResponse < 0) {
|
||||
throw new ConvexError("Tempo para primeira resposta deve ser positivo");
|
||||
}
|
||||
if (timeToResolution !== undefined && timeToResolution < 0) {
|
||||
throw new ConvexError("Tempo para resolução deve ser positivo");
|
||||
}
|
||||
await ensureUniqueName(ctx, tenantId, trimmed, policyId);
|
||||
|
||||
await ctx.db.patch(policyId, {
|
||||
name: trimmed,
|
||||
description,
|
||||
timeToFirstResponse,
|
||||
timeToResolution,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const remove = mutation({
|
||||
args: {
|
||||
policyId: v.id("slaPolicies"),
|
||||
tenantId: v.string(),
|
||||
actorId: v.id("users"),
|
||||
},
|
||||
handler: async (ctx, { policyId, tenantId, actorId }) => {
|
||||
await requireAdmin(ctx, actorId, tenantId);
|
||||
const policy = await ctx.db.get(policyId);
|
||||
if (!policy || policy.tenantId !== tenantId) {
|
||||
throw new ConvexError("Política não encontrada");
|
||||
}
|
||||
|
||||
const ticketLinked = await ctx.db
|
||||
.query("tickets")
|
||||
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
|
||||
.filter((q) => q.eq(q.field("slaPolicyId"), policyId))
|
||||
.first();
|
||||
if (ticketLinked) {
|
||||
throw new ConvexError("Remova a associação de tickets antes de excluir a política");
|
||||
}
|
||||
|
||||
await ctx.db.delete(policyId);
|
||||
},
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue