Files
clearity/src/routes/dashboard/contracts/+page.server.ts
T

84 lines
2.8 KiB
TypeScript

import { and, asc, eq, inArray, isNull } from 'drizzle-orm';
import { message, superValidate } from 'sveltekit-superforms/server';
import { zod4 } from 'sveltekit-superforms/adapters';
import { db } from '$lib/server/db';
import { contracts, contractRooms, clients, rooms, services } from '$lib/server/db/schema';
import { loadOrganizationContext } from '$lib/server/organizations';
import { archiveSchema } from '$lib/schemas/shared.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 }) => {
const { activeOrganizationId } = await loadOrganizationContext(locals);
const records = await db
.select({
contract: contracts,
serviceName: services.name
})
.from(contracts)
.leftJoin(services, eq(contracts.serviceId, services.id))
.where(and(eq(contracts.organizationId, activeOrganizationId), isNull(contracts.archivedAt)))
.orderBy(asc(contracts.startDate));
const contractIds = records.map((record) => record.contract.id);
const roomLinks =
contractIds.length > 0
? await db
.select({
contractId: contractRooms.contractId,
roomName: rooms.name
})
.from(contractRooms)
.innerJoin(rooms, eq(contractRooms.roomId, rooms.id))
.where(inArray(contractRooms.contractId, contractIds))
.orderBy(asc(rooms.name))
: [];
const roomNamesByContract = new Map<string, string[]>();
for (const link of roomLinks) {
const existing = roomNamesByContract.get(link.contractId) ?? [];
existing.push(link.roomName);
roomNamesByContract.set(link.contractId, existing);
}
return {
records: records.map((record) => ({
...record.contract,
roomName: (roomNamesByContract.get(record.contract.id) ?? []).join(', '),
serviceName: record.serviceName
})),
options: await loadOptions(activeOrganizationId),
archiveForm: await superValidate(zod4(archiveSchema), {
id: 'contracts-archive',
errors: false
})
};
};
export const actions: Actions = {
archive: async (event) => {
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
const form = await superValidate(event, zod4(archiveSchema), { id: 'contracts-archive' });
if (!form.valid) return message(form, 'Contract id is required.', { status: 400 });
await db
.update(contracts)
.set({ archivedAt: new Date(), updatedAt: new Date() })
.where(
and(eq(contracts.id, form.data.id), eq(contracts.organizationId, activeOrganizationId))
);
return message(form, 'Contract archived.');
}
};