wicked-eggs-push/apps/server/routers/contacts.ts
2026-05-13 12:18:03 +05:00

114 lines
3.5 KiB
TypeScript

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();
}),
});