114 lines
3.5 KiB
TypeScript
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();
|
|
}),
|
|
});
|