feat: add client workspace management
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
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 { bookings, clients, rooms, services } from '$lib/server/db/schema';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { bookingCreateSchema, bookingEditSchema } from '$lib/schemas/bookings.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
const [clientRows, roomRows, serviceRows] = await Promise.all([
|
||||
db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.orderBy(asc(clients.name)),
|
||||
db
|
||||
.select({ id: rooms.id, name: rooms.name })
|
||||
.from(rooms)
|
||||
.where(isNull(rooms.archivedAt))
|
||||
.orderBy(asc(rooms.name)),
|
||||
db
|
||||
.select({ id: services.id, name: services.name })
|
||||
.from(services)
|
||||
.where(isNull(services.archivedAt))
|
||||
.orderBy(asc(services.name))
|
||||
]);
|
||||
|
||||
return {
|
||||
clients: clientRows.map((client) => ({ label: client.name, value: client.id })),
|
||||
rooms: roomRows.map((room) => ({ label: room.name, value: room.id })),
|
||||
services: [
|
||||
{ label: 'No service', value: '' },
|
||||
...serviceRows.map((service) => ({ label: service.name, value: service.id }))
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
const records = await db
|
||||
.select()
|
||||
.from(bookings)
|
||||
.where(and(eq(bookings.clientId, params.id), isNull(bookings.archivedAt)))
|
||||
.orderBy(asc(bookings.startsAt));
|
||||
|
||||
return {
|
||||
records: records.map((record) => ({
|
||||
...record,
|
||||
formValues: {
|
||||
id: record.id,
|
||||
clientId: record.clientId ?? '',
|
||||
roomId: record.roomId ?? '',
|
||||
serviceId: record.serviceId ?? '',
|
||||
startsAt: record.startsAt ?? '',
|
||||
endsAt: record.endsAt ?? '',
|
||||
status: record.status ?? '',
|
||||
notes: record.notes ?? ''
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(bookingCreateSchema), {
|
||||
id: 'bookings-create'
|
||||
}),
|
||||
editForm: await superValidate(zod4(bookingEditSchema), { id: 'bookings-edit' }),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'bookings-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
const formData = await request.formData();
|
||||
formData.set('clientId', params.id);
|
||||
const form = await superValidate(formData, zod4(bookingCreateSchema), {
|
||||
id: 'bookings-create'
|
||||
});
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
|
||||
try {
|
||||
await db.insert(bookings).values({
|
||||
id: crypto.randomUUID(),
|
||||
clientId: form.data.clientId,
|
||||
roomId: form.data.roomId,
|
||||
serviceId: form.data.serviceId || null,
|
||||
startsAt: form.data.startsAt,
|
||||
endsAt: form.data.endsAt,
|
||||
status: form.data.status,
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date(),
|
||||
createdAt: new Date()
|
||||
});
|
||||
} catch {
|
||||
return message(form, 'Unable to create booking.', { status: 400 });
|
||||
}
|
||||
|
||||
return message(form, 'Booking created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
const formData = await request.formData();
|
||||
formData.set('clientId', params.id);
|
||||
const form = await superValidate(formData, zod4(bookingEditSchema), {
|
||||
id: 'bookings-edit'
|
||||
});
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
|
||||
try {
|
||||
await db
|
||||
.update(bookings)
|
||||
.set({
|
||||
clientId: form.data.clientId,
|
||||
roomId: form.data.roomId,
|
||||
serviceId: form.data.serviceId || null,
|
||||
startsAt: form.data.startsAt,
|
||||
endsAt: form.data.endsAt,
|
||||
status: form.data.status,
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id)));
|
||||
} catch {
|
||||
return message(form, 'Unable to update booking.', { status: 400 });
|
||||
}
|
||||
|
||||
return message(form, 'Booking updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'bookings-archive'
|
||||
});
|
||||
|
||||
if (!form.valid) return message(form, 'Booking id is required.', { status: 400 });
|
||||
|
||||
await db
|
||||
.update(bookings)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id)));
|
||||
|
||||
return message(form, 'Booking archived.');
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user