import { ConvexError, v } from "convex/values"; import { mutation, query } from "./_generated/server"; import { requireStaff } from "./rbac"; function normalizeSlug(input?: string | null): string | undefined { if (!input) return undefined const trimmed = input.trim() if (!trimmed) return undefined const ascii = trimmed .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/[\u2013\u2014]/g, "-") const sanitized = ascii.replace(/[^\w\s-]/g, "").replace(/[_\s]+/g, "-") const collapsed = sanitized.replace(/-+/g, "-").toLowerCase() const normalized = collapsed.replace(/^-+|-+$/g, "") return normalized || undefined } export const list = query({ args: { tenantId: v.string(), viewerId: v.id("users") }, handler: async (ctx, { tenantId, viewerId }) => { await requireStaff(ctx, viewerId, tenantId) const companies = await ctx.db .query("companies") .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId)) .collect() return companies.map((c) => ({ id: c._id, name: c.name, slug: c.slug })) }, }) export const ensureProvisioned = mutation({ args: { tenantId: v.string(), slug: v.string(), name: v.string(), provisioningCode: v.string(), }, handler: async (ctx, { tenantId, slug, name, provisioningCode }) => { const normalizedSlug = normalizeSlug(slug) if (!normalizedSlug) { throw new ConvexError("Slug inválido") } const trimmedName = name.trim() if (!trimmedName) { throw new ConvexError("Nome inválido") } const existing = await ctx.db .query("companies") .withIndex("by_tenant_slug", (q) => q.eq("tenantId", tenantId).eq("slug", normalizedSlug)) .unique() if (existing) { if (existing.provisioningCode !== provisioningCode) { await ctx.db.patch(existing._id, { provisioningCode }) } return { id: existing._id, slug: existing.slug, name: existing.name, } } const now = Date.now() const id = await ctx.db.insert("companies", { tenantId, name: trimmedName, slug: normalizedSlug, provisioningCode, isAvulso: false, contractedHoursPerMonth: undefined, cnpj: undefined, domain: undefined, phone: undefined, description: undefined, address: undefined, createdAt: now, updatedAt: now, }) return { id, slug: normalizedSlug, name: trimmedName, } }, })