import { and, asc, eq, isNull } from 'drizzle-orm'; import { message, superValidate } from 'sveltekit-superforms/server'; import { zod4 } from 'sveltekit-superforms/adapters'; import { db } from '$lib/server/db'; import { contacts, clients } from '$lib/server/db/schema'; import { loadOrganizationContext } from '$lib/server/organizations'; import { archiveSchema } from '$lib/schemas/shared.schema'; import { contactCreateSchema, contactEditSchema } from '$lib/schemas/contacts.schema'; import type { Actions, PageServerLoad } from './$types'; async function loadOptions(organizationId: string) { const clientRows = await db .select({ id: clients.id, name: clients.name }) .from(clients) .where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt))) .orderBy(asc(clients.name)); return { clients: clientRows.map((client) => ({ label: client.name, value: client.id })) }; } export const load: PageServerLoad = async ({ locals, params }) => { const { activeOrganizationId } = await loadOrganizationContext(locals); const records = await db .select() .from(contacts) .where( and( eq(contacts.clientId, params.id), eq(contacts.organizationId, activeOrganizationId), isNull(contacts.archivedAt) ) ) .orderBy(asc(contacts.name)); return { records: records.map((record) => ({ ...record, formValues: { id: record.id, clientId: record.clientId ?? '', name: record.name ?? '', role: record.role ?? '', email: record.email ?? '', phone: record.phone ?? '', isPrimary: record.isPrimary ? 'true' : 'false', receivesInvoices: record.receivesInvoices ? 'true' : 'false', receivesContracts: record.receivesContracts ? 'true' : 'false' } })), options: await loadOptions(activeOrganizationId), createForm: await superValidate({ clientId: params.id }, zod4(contactCreateSchema), { id: 'contacts-create', errors: false }), editForm: await superValidate(zod4(contactEditSchema), { id: 'contacts-edit', errors: false }), archiveForm: await superValidate(zod4(archiveSchema), { id: 'contacts-archive', errors: false }) }; }; export const actions: Actions = { create: async ({ locals, params, request }) => { const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contactCreateSchema), { id: 'contacts-create' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); try { await db.insert(contacts).values({ id: crypto.randomUUID(), organizationId: activeOrganizationId, clientId: form.data.clientId, name: form.data.name, role: form.data.role || null, email: form.data.email || null, phone: form.data.phone || null, isPrimary: form.data.isPrimary === 'true', receivesInvoices: form.data.receivesInvoices === 'true', receivesContracts: form.data.receivesContracts === 'true', updatedAt: new Date(), createdAt: new Date() }); } catch { return message(form, 'Unable to create contact.', { status: 400 }); } return message(form, 'Contact created.'); }, edit: async ({ locals, params, request }) => { const { activeOrganizationId } = await loadOrganizationContext(locals); const formData = await request.formData(); formData.set('clientId', params.id); const form = await superValidate(formData, zod4(contactEditSchema), { id: 'contacts-edit' }); if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 }); try { await db .update(contacts) .set({ clientId: form.data.clientId, name: form.data.name, role: form.data.role || null, email: form.data.email || null, phone: form.data.phone || null, isPrimary: form.data.isPrimary === 'true', receivesInvoices: form.data.receivesInvoices === 'true', receivesContracts: form.data.receivesContracts === 'true', updatedAt: new Date() }) .where( and( eq(contacts.id, form.data.id), eq(contacts.clientId, params.id), eq(contacts.organizationId, activeOrganizationId) ) ); } catch { return message(form, 'Unable to update contact.', { status: 400 }); } return message(form, 'Contact updated.'); }, archive: async ({ locals, params, request }) => { const { activeOrganizationId } = await loadOrganizationContext(locals); const form = await superValidate(await request.formData(), zod4(archiveSchema), { id: 'contacts-archive' }); if (!form.valid) return message(form, 'Contact id is required.', { status: 400 }); await db .update(contacts) .set({ archivedAt: new Date(), updatedAt: new Date() }) .where( and( eq(contacts.id, form.data.id), eq(contacts.clientId, params.id), eq(contacts.organizationId, activeOrganizationId) ) ); return message(form, 'Contact archived.'); } };