import { z } from 'zod' import { RoundType } from '@prisma/client' import { router, adminProcedure } from '../trpc' import { logAudit } from '@/server/utils/audit' export const roundTemplateRouter = router({ /** * List all round templates, optionally filtered by programId. */ list: adminProcedure .input( z.object({ programId: z.string().optional(), }).optional() ) .query(async ({ ctx, input }) => { return ctx.prisma.roundTemplate.findMany({ where: { ...(input?.programId ? { programId: input.programId } : {}), }, orderBy: { createdAt: 'desc' }, }) }), /** * Get a single template by ID. */ getById: adminProcedure .input(z.object({ id: z.string() })) .query(async ({ ctx, input }) => { const template = await ctx.prisma.roundTemplate.findUnique({ where: { id: input.id }, }) if (!template) { throw new Error('Template not found') } return template }), /** * Create a new round template from scratch. */ create: adminProcedure .input( z.object({ name: z.string().min(1).max(200), description: z.string().optional(), programId: z.string().optional(), roundType: z.nativeEnum(RoundType).default('EVALUATION'), criteriaJson: z.any(), settingsJson: z.any().optional(), assignmentConfig: z.any().optional(), }) ) .mutation(async ({ ctx, input }) => { const template = await ctx.prisma.roundTemplate.create({ data: { name: input.name, description: input.description, programId: input.programId, roundType: input.roundType, criteriaJson: input.criteriaJson, settingsJson: input.settingsJson ?? undefined, assignmentConfig: input.assignmentConfig ?? undefined, createdBy: ctx.user.id, }, }) try { await logAudit({ prisma: ctx.prisma, userId: ctx.user.id, action: 'CREATE_ROUND_TEMPLATE', entityType: 'RoundTemplate', entityId: template.id, detailsJson: { name: input.name }, }) } catch {} return template }), /** * Create a template from an existing round (snapshot). */ createFromRound: adminProcedure .input( z.object({ roundId: z.string(), name: z.string().min(1).max(200), description: z.string().optional(), }) ) .mutation(async ({ ctx, input }) => { // Fetch the round and its active evaluation form const round = await ctx.prisma.round.findUnique({ where: { id: input.roundId }, include: { evaluationForms: { where: { isActive: true }, take: 1, }, }, }) if (!round) { throw new Error('Round not found') } const form = round.evaluationForms[0] const criteriaJson = form?.criteriaJson ?? [] const template = await ctx.prisma.roundTemplate.create({ data: { name: input.name, description: input.description || `Snapshot of ${round.name}`, programId: round.programId, roundType: round.roundType, criteriaJson, settingsJson: round.settingsJson ?? undefined, createdBy: ctx.user.id, }, }) try { await logAudit({ prisma: ctx.prisma, userId: ctx.user.id, action: 'CREATE_ROUND_TEMPLATE_FROM_ROUND', entityType: 'RoundTemplate', entityId: template.id, detailsJson: { name: input.name, sourceRoundId: input.roundId }, }) } catch {} return template }), /** * Update a template. */ update: adminProcedure .input( z.object({ id: z.string(), name: z.string().min(1).max(200).optional(), description: z.string().optional(), programId: z.string().nullable().optional(), roundType: z.nativeEnum(RoundType).optional(), criteriaJson: z.any().optional(), settingsJson: z.any().optional(), assignmentConfig: z.any().optional(), }) ) .mutation(async ({ ctx, input }) => { const { id, ...data } = input const template = await ctx.prisma.roundTemplate.update({ where: { id }, data: { ...(data.name !== undefined ? { name: data.name } : {}), ...(data.description !== undefined ? { description: data.description } : {}), ...(data.programId !== undefined ? { programId: data.programId } : {}), ...(data.roundType !== undefined ? { roundType: data.roundType } : {}), ...(data.criteriaJson !== undefined ? { criteriaJson: data.criteriaJson } : {}), ...(data.settingsJson !== undefined ? { settingsJson: data.settingsJson } : {}), ...(data.assignmentConfig !== undefined ? { assignmentConfig: data.assignmentConfig } : {}), }, }) try { await logAudit({ prisma: ctx.prisma, userId: ctx.user.id, action: 'UPDATE_ROUND_TEMPLATE', entityType: 'RoundTemplate', entityId: id, detailsJson: { updatedFields: Object.keys(data) }, }) } catch {} return template }), /** * Delete a template. */ delete: adminProcedure .input(z.object({ id: z.string() })) .mutation(async ({ ctx, input }) => { await ctx.prisma.roundTemplate.delete({ where: { id: input.id }, }) try { await logAudit({ prisma: ctx.prisma, userId: ctx.user.id, action: 'DELETE_ROUND_TEMPLATE', entityType: 'RoundTemplate', entityId: input.id, }) } catch {} return { success: true } }), })