import { mutation, query } from "./_generated/server"; import { v } from "convex/values"; import { requireAdmin } from "./rbac"; export const list = query({ args: { tenantId: v.string(), viewerId: v.id("users") }, handler: async (ctx, { tenantId, viewerId }) => { await requireAdmin(ctx, viewerId, tenantId); const invites = await ctx.db .query("userInvites") .withIndex("by_tenant", (q) => q.eq("tenantId", tenantId)) .collect(); return invites .sort((a, b) => (b.createdAt ?? 0) - (a.createdAt ?? 0)) .map((invite) => ({ id: invite._id, inviteId: invite.inviteId, email: invite.email, name: invite.name ?? null, role: invite.role, status: invite.status, token: invite.token, expiresAt: invite.expiresAt, createdAt: invite.createdAt, createdById: invite.createdById ?? null, acceptedAt: invite.acceptedAt ?? null, acceptedById: invite.acceptedById ?? null, revokedAt: invite.revokedAt ?? null, revokedById: invite.revokedById ?? null, revokedReason: invite.revokedReason ?? null, })); }, }); export const sync = mutation({ args: { tenantId: v.string(), inviteId: v.string(), email: v.string(), name: v.optional(v.string()), role: v.string(), status: v.string(), token: v.string(), expiresAt: v.number(), createdAt: v.number(), createdById: v.optional(v.string()), acceptedAt: v.optional(v.number()), acceptedById: v.optional(v.string()), revokedAt: v.optional(v.number()), revokedById: v.optional(v.string()), revokedReason: v.optional(v.string()), }, handler: async (ctx, args) => { const existing = await ctx.db .query("userInvites") .withIndex("by_invite", (q) => q.eq("tenantId", args.tenantId).eq("inviteId", args.inviteId)) .first(); if (!existing) { const id = await ctx.db.insert("userInvites", { tenantId: args.tenantId, inviteId: args.inviteId, email: args.email, name: args.name, role: args.role, status: args.status, token: args.token, expiresAt: args.expiresAt, createdAt: args.createdAt, createdById: args.createdById, acceptedAt: args.acceptedAt, acceptedById: args.acceptedById, revokedAt: args.revokedAt, revokedById: args.revokedById, revokedReason: args.revokedReason, }); return await ctx.db.get(id); } await ctx.db.patch(existing._id, { email: args.email, name: args.name, role: args.role, status: args.status, token: args.token, expiresAt: args.expiresAt, createdAt: args.createdAt, createdById: args.createdById, acceptedAt: args.acceptedAt, acceptedById: args.acceptedById, revokedAt: args.revokedAt, revokedById: args.revokedById, revokedReason: args.revokedReason, }); return await ctx.db.get(existing._id); }, }); export const remove = mutation({ args: { tenantId: v.string(), inviteId: v.string() }, handler: async (ctx, { tenantId, inviteId }) => { const existing = await ctx.db .query("userInvites") .withIndex("by_invite", (q) => q.eq("tenantId", tenantId).eq("inviteId", inviteId)) .first(); if (existing) { await ctx.db.delete(existing._id); } }, });