import { z } from "zod"; import { router, publicProcedure } from "../trpc"; export const contactsRouter = router({ getAll: publicProcedure.query(async ({ ctx }) => { return await ctx.queryBuilder .selectFrom("contacts") .select(["id", "firstName", "lastName", "mail", "phone1", "phone2", "notes", "createdAt", "updatedAt"]) .orderBy("createdAt", "desc") .execute(); }), search: publicProcedure .input(z.object({ query: z.string(), limit: z.number().default(5) })) .query(async ({ ctx, input }) => { const searchTerm = input.query.trim(); // If no search term, return recent contacts if (!searchTerm) { return await ctx.queryBuilder .selectFrom("contacts") .select(["id", "firstName", "lastName", "mail"]) .orderBy("createdAt", "desc") .limit(input.limit) .execute(); } // Search by firstName, lastName, or mail using orWhere return await ctx.queryBuilder .selectFrom("contacts") .select(["id", "firstName", "lastName", "mail"]) .where("firstName", "contains", searchTerm) .orWhere("lastName", "contains", searchTerm) .orWhere("mail", "contains", searchTerm) .orderBy("createdAt", "desc") .limit(input.limit) .execute(); }), getById: publicProcedure .input(z.object({ id: z.number() })) .query(async ({ ctx, input }) => { return await ctx.queryBuilder .selectFrom("contacts") .select(["id", "firstName", "lastName", "mail", "phone1", "phone2", "notes", "createdAt", "updatedAt"]) .with({ company: qb => qb.select(["id", "name", "website"]) }) .where("id", "=", input.id) .executeTakeFirst(); }), create: publicProcedure .input( z.object({ firstName: z.string().min(1), lastName: z.string().min(1), mail: z.string().email().optional().or(z.literal("")), phone1: z.string().optional(), phone2: z.string().optional(), notes: z.string().optional(), company: z.array(z.number()).optional(), }) ) .mutation(async ({ ctx, input }) => { // Filter out empty mail const values = { ...input, mail: input.mail || undefined, }; return await ctx.queryBuilder .insertInto("contacts") .values(values) .executeTakeFirst(); }), update: publicProcedure .input( z.object({ id: z.number(), firstName: z.string().optional(), lastName: z.string().optional(), mail: z.string().email().optional().or(z.literal("")), phone1: z.string().optional(), phone2: z.string().optional(), notes: z.string().optional(), company: z.array(z.number()).optional(), }) ) .mutation(async ({ ctx, input }) => { const { id, ...data } = input; // Filter out undefined values and empty mail const updateData = Object.fromEntries( Object.entries(data).filter(([key, v]) => { if (v === undefined) return false; if (key === "mail" && v === "") return false; return true; }) ) as typeof data; return await ctx.queryBuilder .update("contacts") .set(updateData) .where("id", "=", id) .execute(); }), delete: publicProcedure .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { return await ctx.queryBuilder .deleteFrom("contacts") .where("id", "=", input.id) .execute(); }), });