import { z } from "zod"; import { router, publicProcedure } from "../trpc"; const ActivitiesTypeOptions = [ "Call", "Meeting", "Task", "Demo", ] as const; export const activitiesRouter = router({ getAll: publicProcedure .input( z.object({ dateFilter: z.enum(["all", "today", "thisWeek", "thisMonth"]).optional(), typeFilter: z.enum(["all", ...ActivitiesTypeOptions]).optional(), }).optional() ) .query(async ({ ctx, input }) => { let query = ctx.queryBuilder .selectFrom("activities") .select(["id", "name", "type", "plannedAt", "doneAt", "createdAt", "updatedAt"]) .with({ deal: qb => qb.select(["id", "name"]) }) .with({ notes: qb => qb.select(["id", "name"]) }); // Apply date filter if (input?.dateFilter && input.dateFilter !== "all") { if (input.dateFilter === "today") { query = query.where("plannedAt", "=", "today"); } else if (input.dateFilter === "thisWeek") { query = query.where("plannedAt", "isWithIn", "currentWeek"); } else if (input.dateFilter === "thisMonth") { query = query.where("plannedAt", "isWithIn", "currentMonth"); } } // Apply type filter if (input?.typeFilter && input.typeFilter !== "all") { query = query.where("type", "=", input.typeFilter); } return await query.orderBy("plannedAt", "desc").execute(); }), getByDeal: publicProcedure .input(z.object({ dealId: z.number() })) .query(async ({ ctx, input }) => { return await ctx.queryBuilder .selectFrom("activities") .select(["id", "name", "type", "plannedAt", "doneAt", "createdAt", "updatedAt"]) .with({ notes: qb => qb.select(["id", "name"]) }) .where("deal", "=", input.dealId) .orderBy("plannedAt", "asc") .execute(); }), getById: publicProcedure .input(z.object({ id: z.number() })) .query(async ({ ctx, input }) => { return await ctx.queryBuilder .selectFrom("activities") .select(["id", "name", "type", "plannedAt", "doneAt", "createdAt", "updatedAt"]) .with({ deal: qb => qb.select(["id", "name"]) }) .with({ notes: qb => qb.select(["id", "name"]) }) .where("id", "=", input.id) .executeTakeFirst(); }), create: publicProcedure .input( z.object({ name: z.string().min(1), deal: z.array(z.number()).optional(), plannedAt: z.string().optional(), doneAt: z.string().optional(), type: z.enum(ActivitiesTypeOptions).optional(), }) ) .mutation(async ({ ctx, input }) => { // Build values object with only defined fields const values: { name: string; deal?: number[]; plannedAt?: string; doneAt?: string; type?: string } = { name: input.name, }; if (input.deal) values.deal = input.deal; if (input.plannedAt) values.plannedAt = input.plannedAt; if (input.doneAt) values.doneAt = input.doneAt; if (input.type) values.type = input.type; return await ctx.queryBuilder .insertInto("activities") // eslint-disable-next-line @typescript-eslint/no-explicit-any .values(values as any) .executeTakeFirst(); }), update: publicProcedure .input( z.object({ id: z.number(), name: z.string().optional(), plannedAt: z.string().optional(), doneAt: z.string().optional(), notes: z.array(z.number()).optional(), type: z.enum(ActivitiesTypeOptions).optional(), }) ) .mutation(async ({ ctx, input }) => { const { id, ...data } = input; // Filter out undefined values const updateData = Object.fromEntries( Object.entries(data).filter(([, v]) => v !== undefined) ) as typeof data; return await ctx.queryBuilder .update("activities") .set(updateData) .where("id", "=", id) .execute(); }), complete: publicProcedure .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .update("activities") .set({ doneAt: new Date().toISOString() }) .where("id", "=", input.id) .execute(); }), uncomplete: publicProcedure .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .update("activities") .set({ doneAt: null as unknown as string }) .where("id", "=", input.id) .execute(); }), delete: publicProcedure .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .deleteFrom("activities") .where("id", "=", input.id) .execute(); }), });