159 lines
4.9 KiB
TypeScript
159 lines
4.9 KiB
TypeScript
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.');
|
|
}
|
|
};
|