import { z } from "zod"; import { router, publicProcedure } from "../trpc"; const DealsPhaseOptions = [ "New", "Demo scheduled", "Contract signed", "Lost", ] as const; // Create a Zod enum from the phase options const phaseEnum = z.enum(DealsPhaseOptions); export const dealsRouter = router({ getAll: publicProcedure.query(async ({ ctx }) => { return await ctx.queryBuilder .selectFrom("deals") .select(["id", "name", "phase", "createdAt", "updatedAt"]) .with({ mainContact: qb => qb.select(["id", "firstName", "lastName", "mail"]) }) .orderBy("createdAt", "desc") .execute(); }), getById: publicProcedure .input(z.object({ id: z.number() })) .query(async ({ ctx, input }) => { // Get the deal with all fields including links const deal = await ctx.queryBuilder .selectFrom("deals") .select(["id", "name", "phase", "createdAt", "updatedAt"]) .with({ mainContact: qb => qb.select(["id", "firstName", "lastName", "mail"]) }) .where("id", "=", input.id) .executeTakeFirst(); return deal; }), search: publicProcedure .input(z.object({ query: z.string(), limit: z.number().optional() })) .query(async ({ ctx, input }) => { let query = ctx.queryBuilder .selectFrom("deals") .select(["id", "name", "phase"]); if (input.query.trim()) { query = query.where("name", "contains", input.query); } return await query .orderBy("name", "asc") .execute(); }), // Get detailed deal info with contact and company for details page getDetails: publicProcedure .input(z.object({ id: z.number() })) .query(async ({ ctx, input }) => { // Get the deal with contact info const deal = await ctx.queryBuilder .selectFrom("deals") .select(["id", "name", "phase", "lostReason", "createdAt", "updatedAt"]) .with({ mainContact: qb => qb.select(["id", "firstName", "lastName", "mail", "phone1", "phone2", "notes"]) .with({ company: companyQb => companyQb.select(["id", "name", "website", "notes"]) }) }) .with({ activities: qb => qb.select(["id", "name", "type", "plannedAt", "doneAt", "createdAt"]) .with({ notes: notesQb => notesQb.select(["id", "name", "createdAt"]) }) }) .where("id", "=", input.id) .executeTakeFirst(); return deal; }), create: publicProcedure .input( z.object({ name: z.string().min(1), phase: phaseEnum.default("New"), mainContact: z.array(z.number()).optional(), }) ) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .insertInto("deals") .values(input) .executeTakeFirst(); }), update: publicProcedure .input( z.object({ id: z.number(), name: z.string().optional(), phase: phaseEnum.optional(), mainContact: z.array(z.number()).optional(), }) ) .mutation(async ({ ctx, input }) => { const { id, ...data } = input; // Filter out undefined values to avoid overwriting with undefined const updateData = Object.fromEntries( Object.entries(data).filter(([, v]) => v !== undefined) ) as typeof data; return await ctx.queryBuilder .update("deals") .set(updateData) .where("id", "=", id) .execute(); }), delete: publicProcedure .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .deleteFrom("deals") .where("id", "=", input.id) .execute(); }), });