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