refactor: scope dashboard records by organization
Attach clients, rooms, services, bookings, contacts, addresses, invoices, and contracts to organizations. Filter dashboard loads and related option lists by the active organization from the session. Ensure create, update, and archive actions only affect records in the active organization.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import { Separator } from '$lib/components/ui/separator/index.js';
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
|
||||
const { children } = $props();
|
||||
const { data, children } = $props();
|
||||
|
||||
type BreadcrumbItem = {
|
||||
label: string;
|
||||
@@ -79,7 +79,7 @@
|
||||
</script>
|
||||
|
||||
<Sidebar.Provider>
|
||||
<AppSidebar />
|
||||
<AppSidebar organizations={data.organizations} activeOrganization={data.activeOrganization} />
|
||||
<Sidebar.Inset>
|
||||
<header class="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<Sidebar.Trigger class="-ms-1" />
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { addresses, clients } 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() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -18,22 +19,24 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(addresses)
|
||||
.where(isNull(addresses.archivedAt))
|
||||
.where(and(eq(addresses.organizationId, activeOrganizationId), isNull(addresses.archivedAt)))
|
||||
.orderBy(asc(addresses.label));
|
||||
|
||||
return {
|
||||
records,
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'addresses-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'addresses-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Address id is required.', { status: 400 });
|
||||
@@ -41,7 +44,9 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(addresses)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(addresses.id, form.data.id));
|
||||
.where(
|
||||
and(eq(addresses.id, form.data.id), eq(addresses.organizationId, activeOrganizationId))
|
||||
);
|
||||
|
||||
return message(form, 'Address archived.');
|
||||
}
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const [clientRows, roomRows, serviceRows] = await Promise.all([
|
||||
db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name)),
|
||||
db
|
||||
.select({ id: rooms.id, name: rooms.name })
|
||||
.from(rooms)
|
||||
.where(isNull(rooms.archivedAt))
|
||||
.where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt)))
|
||||
.orderBy(asc(rooms.name)),
|
||||
db
|
||||
.select({ id: services.id, name: services.name })
|
||||
.from(services)
|
||||
.where(isNull(services.archivedAt))
|
||||
.where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt)))
|
||||
.orderBy(asc(services.name))
|
||||
]);
|
||||
|
||||
@@ -35,22 +36,24 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(bookings)
|
||||
.where(isNull(bookings.archivedAt))
|
||||
.where(and(eq(bookings.organizationId, activeOrganizationId), isNull(bookings.archivedAt)))
|
||||
.orderBy(asc(bookings.startsAt));
|
||||
|
||||
return {
|
||||
records,
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'bookings-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'bookings-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Booking id is required.', { status: 400 });
|
||||
@@ -58,7 +61,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(bookings)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(bookings.id, form.data.id));
|
||||
.where(and(eq(bookings.id, form.data.id), eq(bookings.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Booking archived.');
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { addresses, clients, contacts } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { clientEditSchema, clientOnboardingCreateSchema } from '$lib/schemas/clients.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, activeOrganizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -34,6 +36,7 @@ export const load: PageServerLoad = async () => {
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(clientOnboardingCreateSchema), {
|
||||
id: 'clients-create'
|
||||
});
|
||||
@@ -47,6 +50,7 @@ export const actions: Actions = {
|
||||
|
||||
await tx.insert(clients).values({
|
||||
id: clientId,
|
||||
organizationId: activeOrganizationId,
|
||||
name: form.data.name,
|
||||
type: form.data.type,
|
||||
status: form.data.status,
|
||||
@@ -58,6 +62,7 @@ export const actions: Actions = {
|
||||
|
||||
await tx.insert(contacts).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId,
|
||||
name: form.data.primaryContactName,
|
||||
role: form.data.primaryContactRole || null,
|
||||
@@ -71,6 +76,7 @@ export const actions: Actions = {
|
||||
|
||||
await tx.insert(addresses).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId,
|
||||
label: form.data.primaryAddressLabel,
|
||||
line1: form.data.primaryAddressLine1,
|
||||
@@ -92,6 +98,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
edit: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(clientEditSchema), { id: 'clients-edit' });
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
@@ -107,7 +114,7 @@ export const actions: Actions = {
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(eq(clients.id, form.data.id));
|
||||
.where(and(eq(clients.id, form.data.id), eq(clients.organizationId, activeOrganizationId)));
|
||||
} catch {
|
||||
return message(form, 'Unable to update client.', { status: 400 });
|
||||
}
|
||||
@@ -116,6 +123,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'clients-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Client id is required.', { status: 400 });
|
||||
@@ -123,7 +131,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(clients)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(clients.id, form.data.id));
|
||||
.where(and(eq(clients.id, form.data.id), eq(clients.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Client archived.');
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
rooms,
|
||||
services
|
||||
} from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { clientEditSchema } from '$lib/schemas/clients.schema';
|
||||
import type { LayoutServerLoad } from './$types';
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
@@ -30,22 +31,22 @@ function formValues(row: typeof clients.$inferSelect) {
|
||||
};
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const [clientRows, roomRows, serviceRows] = await Promise.all([
|
||||
db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name)),
|
||||
db
|
||||
.select({ id: rooms.id, name: rooms.name })
|
||||
.from(rooms)
|
||||
.where(isNull(rooms.archivedAt))
|
||||
.where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt)))
|
||||
.orderBy(asc(rooms.name)),
|
||||
db
|
||||
.select({ id: services.id, name: services.name })
|
||||
.from(services)
|
||||
.where(isNull(services.archivedAt))
|
||||
.where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt)))
|
||||
.orderBy(asc(services.name))
|
||||
]);
|
||||
|
||||
@@ -59,11 +60,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: LayoutServerLoad = async ({ params }) => {
|
||||
export const load: LayoutServerLoad = async ({ locals, params }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const [client] = await db
|
||||
.select()
|
||||
.from(clients)
|
||||
.where(and(eq(clients.id, params.id), isNull(clients.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(clients.id, params.id),
|
||||
eq(clients.organizationId, activeOrganizationId),
|
||||
isNull(clients.archivedAt)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (!client) error(404, 'Client not found');
|
||||
@@ -73,29 +81,59 @@ export const load: LayoutServerLoad = async ({ params }) => {
|
||||
db
|
||||
.select()
|
||||
.from(addresses)
|
||||
.where(and(eq(addresses.clientId, params.id), isNull(addresses.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(addresses.clientId, params.id),
|
||||
eq(addresses.organizationId, activeOrganizationId),
|
||||
isNull(addresses.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(addresses.label)),
|
||||
db
|
||||
.select()
|
||||
.from(contacts)
|
||||
.where(and(eq(contacts.clientId, params.id), isNull(contacts.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(contacts.clientId, params.id),
|
||||
eq(contacts.organizationId, activeOrganizationId),
|
||||
isNull(contacts.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(contacts.name)),
|
||||
db
|
||||
.select()
|
||||
.from(invoices)
|
||||
.where(and(eq(invoices.clientId, params.id), isNull(invoices.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(invoices.clientId, params.id),
|
||||
eq(invoices.organizationId, activeOrganizationId),
|
||||
isNull(invoices.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(invoices.invoiceNumber)),
|
||||
db
|
||||
.select()
|
||||
.from(contracts)
|
||||
.where(and(eq(contracts.clientId, params.id), isNull(contracts.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(contracts.clientId, params.id),
|
||||
eq(contracts.organizationId, activeOrganizationId),
|
||||
isNull(contracts.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(contracts.title)),
|
||||
db
|
||||
.select()
|
||||
.from(bookings)
|
||||
.where(and(eq(bookings.clientId, params.id), isNull(bookings.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(bookings.clientId, params.id),
|
||||
eq(bookings.organizationId, activeOrganizationId),
|
||||
isNull(bookings.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(bookings.startsAt)),
|
||||
loadOptions()
|
||||
loadOptions(activeOrganizationId)
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server';
|
||||
import { zod4 } from 'sveltekit-superforms/adapters';
|
||||
import { db } from '$lib/server/db';
|
||||
import { addresses, clients } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { addressCreateSchema, addressEditSchema } from '$lib/schemas/addresses.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -19,11 +20,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(addresses)
|
||||
.where(and(eq(addresses.clientId, params.id), isNull(addresses.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(addresses.clientId, params.id),
|
||||
eq(addresses.organizationId, activeOrganizationId),
|
||||
isNull(addresses.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(addresses.label));
|
||||
|
||||
return {
|
||||
@@ -42,7 +50,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
isPrimary: record.isPrimary ? 'true' : 'false'
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(addressCreateSchema), {
|
||||
id: 'addresses-create'
|
||||
}),
|
||||
@@ -52,7 +60,8 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
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(addressCreateSchema), {
|
||||
@@ -64,6 +73,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(addresses).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId: form.data.clientId,
|
||||
label: form.data.label,
|
||||
line1: form.data.line1,
|
||||
@@ -83,7 +93,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Address created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
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(addressEditSchema), { id: 'addresses-edit' });
|
||||
@@ -105,7 +116,13 @@ export const actions: Actions = {
|
||||
isPrimary: form.data.isPrimary === 'true',
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(addresses.id, form.data.id), eq(addresses.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(addresses.id, form.data.id),
|
||||
eq(addresses.clientId, params.id),
|
||||
eq(addresses.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
return message(form, 'Unable to update address.', { status: 400 });
|
||||
}
|
||||
@@ -113,7 +130,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Address updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
archive: async ({ locals, params, request }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'addresses-archive'
|
||||
});
|
||||
@@ -123,7 +141,13 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(addresses)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(addresses.id, form.data.id), eq(addresses.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(addresses.id, form.data.id),
|
||||
eq(addresses.clientId, params.id),
|
||||
eq(addresses.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
|
||||
return message(form, 'Address archived.');
|
||||
}
|
||||
|
||||
@@ -3,26 +3,27 @@ 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 { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { bookingCreateSchema, bookingEditSchema } from '$lib/schemas/bookings.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const [clientRows, roomRows, serviceRows] = await Promise.all([
|
||||
db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name)),
|
||||
db
|
||||
.select({ id: rooms.id, name: rooms.name })
|
||||
.from(rooms)
|
||||
.where(isNull(rooms.archivedAt))
|
||||
.where(and(eq(rooms.organizationId, organizationId), isNull(rooms.archivedAt)))
|
||||
.orderBy(asc(rooms.name)),
|
||||
db
|
||||
.select({ id: services.id, name: services.name })
|
||||
.from(services)
|
||||
.where(isNull(services.archivedAt))
|
||||
.where(and(eq(services.organizationId, organizationId), isNull(services.archivedAt)))
|
||||
.orderBy(asc(services.name))
|
||||
]);
|
||||
|
||||
@@ -36,11 +37,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(bookings)
|
||||
.where(and(eq(bookings.clientId, params.id), isNull(bookings.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(bookings.clientId, params.id),
|
||||
eq(bookings.organizationId, activeOrganizationId),
|
||||
isNull(bookings.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(bookings.startsAt));
|
||||
|
||||
return {
|
||||
@@ -57,7 +65,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
notes: record.notes ?? ''
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(bookingCreateSchema), {
|
||||
id: 'bookings-create'
|
||||
}),
|
||||
@@ -67,7 +75,8 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
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(bookingCreateSchema), {
|
||||
@@ -79,6 +88,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(bookings).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId: form.data.clientId,
|
||||
roomId: form.data.roomId,
|
||||
serviceId: form.data.serviceId || null,
|
||||
@@ -96,7 +106,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Booking created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
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(bookingEditSchema), {
|
||||
@@ -118,7 +129,13 @@ export const actions: Actions = {
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(bookings.id, form.data.id),
|
||||
eq(bookings.clientId, params.id),
|
||||
eq(bookings.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
return message(form, 'Unable to update booking.', { status: 400 });
|
||||
}
|
||||
@@ -126,7 +143,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Booking updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
archive: async ({ locals, params, request }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'bookings-archive'
|
||||
});
|
||||
@@ -136,7 +154,13 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(bookings)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(bookings.id, form.data.id), eq(bookings.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(bookings.id, form.data.id),
|
||||
eq(bookings.clientId, params.id),
|
||||
eq(bookings.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
|
||||
return message(form, 'Booking archived.');
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@ 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() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -19,11 +20,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
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), isNull(contacts.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(contacts.clientId, params.id),
|
||||
eq(contacts.organizationId, activeOrganizationId),
|
||||
isNull(contacts.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(contacts.name));
|
||||
|
||||
return {
|
||||
@@ -40,7 +48,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
notes: record.notes ?? ''
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(contactCreateSchema), {
|
||||
id: 'contacts-create'
|
||||
}),
|
||||
@@ -50,7 +58,8 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
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), {
|
||||
@@ -62,6 +71,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(contacts).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId: form.data.clientId,
|
||||
name: form.data.name,
|
||||
role: form.data.role || null,
|
||||
@@ -79,7 +89,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Contact created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
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' });
|
||||
@@ -99,7 +110,13 @@ export const actions: Actions = {
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(contacts.id, form.data.id), eq(contacts.clientId, params.id)));
|
||||
.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 });
|
||||
}
|
||||
@@ -107,7 +124,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Contact updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
archive: async ({ locals, params, request }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'contacts-archive'
|
||||
});
|
||||
@@ -117,7 +135,13 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(contacts)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(contacts.id, form.data.id), eq(contacts.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(contacts.id, form.data.id),
|
||||
eq(contacts.clientId, params.id),
|
||||
eq(contacts.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
|
||||
return message(form, 'Contact archived.');
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server';
|
||||
import { zod4 } from 'sveltekit-superforms/adapters';
|
||||
import { db } from '$lib/server/db';
|
||||
import { contracts, clients } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { contractCreateSchema, contractEditSchema } from '$lib/schemas/contracts.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -19,11 +20,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(contracts)
|
||||
.where(and(eq(contracts.clientId, params.id), isNull(contracts.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(contracts.clientId, params.id),
|
||||
eq(contracts.organizationId, activeOrganizationId),
|
||||
isNull(contracts.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(contracts.title));
|
||||
|
||||
return {
|
||||
@@ -40,7 +48,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
notes: record.notes ?? ''
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(contractCreateSchema), {
|
||||
id: 'contracts-create'
|
||||
}),
|
||||
@@ -50,7 +58,8 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
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(contractCreateSchema), {
|
||||
@@ -62,6 +71,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(contracts).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId: form.data.clientId,
|
||||
title: form.data.title,
|
||||
startDate: form.data.startDate,
|
||||
@@ -79,7 +89,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Contract created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
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(contractEditSchema), {
|
||||
@@ -101,7 +112,13 @@ export const actions: Actions = {
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(contracts.id, form.data.id), eq(contracts.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(contracts.id, form.data.id),
|
||||
eq(contracts.clientId, params.id),
|
||||
eq(contracts.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
return message(form, 'Unable to update contract.', { status: 400 });
|
||||
}
|
||||
@@ -109,7 +126,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Contract updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
archive: async ({ locals, params, request }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'contracts-archive'
|
||||
});
|
||||
@@ -119,7 +137,13 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(contracts)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(contracts.id, form.data.id), eq(contracts.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(contracts.id, form.data.id),
|
||||
eq(contracts.clientId, params.id),
|
||||
eq(contracts.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
|
||||
return message(form, 'Contract archived.');
|
||||
}
|
||||
|
||||
@@ -3,15 +3,16 @@ import { message, superValidate } from 'sveltekit-superforms/server';
|
||||
import { zod4 } from 'sveltekit-superforms/adapters';
|
||||
import { db } from '$lib/server/db';
|
||||
import { invoices, clients } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { invoiceCreateSchema, invoiceEditSchema } from '$lib/schemas/invoices.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -19,11 +20,18 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export const load: PageServerLoad = async ({ locals, params }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(invoices)
|
||||
.where(and(eq(invoices.clientId, params.id), isNull(invoices.archivedAt)))
|
||||
.where(
|
||||
and(
|
||||
eq(invoices.clientId, params.id),
|
||||
eq(invoices.organizationId, activeOrganizationId),
|
||||
isNull(invoices.archivedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(asc(invoices.invoiceNumber));
|
||||
|
||||
return {
|
||||
@@ -42,7 +50,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
notes: record.notes ?? ''
|
||||
}
|
||||
})),
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
createForm: await superValidate({ clientId: params.id }, zod4(invoiceCreateSchema), {
|
||||
id: 'invoices-create'
|
||||
}),
|
||||
@@ -52,7 +60,8 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async ({ params, request }) => {
|
||||
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(invoiceCreateSchema), {
|
||||
@@ -64,6 +73,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(invoices).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
clientId: form.data.clientId,
|
||||
invoiceNumber: form.data.invoiceNumber,
|
||||
issueDate: form.data.issueDate,
|
||||
@@ -83,7 +93,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Invoice created.');
|
||||
},
|
||||
|
||||
edit: async ({ params, request }) => {
|
||||
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(invoiceEditSchema), { id: 'invoices-edit' });
|
||||
@@ -105,7 +116,13 @@ export const actions: Actions = {
|
||||
notes: form.data.notes || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(and(eq(invoices.id, form.data.id), eq(invoices.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(invoices.id, form.data.id),
|
||||
eq(invoices.clientId, params.id),
|
||||
eq(invoices.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
return message(form, 'Unable to update invoice.', { status: 400 });
|
||||
}
|
||||
@@ -113,7 +130,8 @@ export const actions: Actions = {
|
||||
return message(form, 'Invoice updated.');
|
||||
},
|
||||
|
||||
archive: async ({ params, request }) => {
|
||||
archive: async ({ locals, params, request }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const form = await superValidate(await request.formData(), zod4(archiveSchema), {
|
||||
id: 'invoices-archive'
|
||||
});
|
||||
@@ -123,7 +141,13 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(invoices)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(and(eq(invoices.id, form.data.id), eq(invoices.clientId, params.id)));
|
||||
.where(
|
||||
and(
|
||||
eq(invoices.id, form.data.id),
|
||||
eq(invoices.clientId, params.id),
|
||||
eq(invoices.organizationId, activeOrganizationId)
|
||||
)
|
||||
);
|
||||
|
||||
return message(form, 'Invoice archived.');
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
async function loadOptions() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -18,22 +19,24 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(contacts)
|
||||
.where(isNull(contacts.archivedAt))
|
||||
.where(and(eq(contacts.organizationId, activeOrganizationId), isNull(contacts.archivedAt)))
|
||||
.orderBy(asc(contacts.name));
|
||||
|
||||
return {
|
||||
records,
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'contacts-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'contacts-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Contact id is required.', { status: 400 });
|
||||
@@ -41,7 +44,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(contacts)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(contacts.id, form.data.id));
|
||||
.where(and(eq(contacts.id, form.data.id), eq(contacts.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Contact archived.');
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { contracts, clients } 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() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -18,22 +19,24 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(contracts)
|
||||
.where(isNull(contracts.archivedAt))
|
||||
.where(and(eq(contracts.organizationId, activeOrganizationId), isNull(contracts.archivedAt)))
|
||||
.orderBy(asc(contracts.title));
|
||||
|
||||
return {
|
||||
records,
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'contracts-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
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 });
|
||||
@@ -41,7 +44,9 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(contracts)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(contracts.id, form.data.id));
|
||||
.where(
|
||||
and(eq(contracts.id, form.data.id), eq(contracts.organizationId, activeOrganizationId))
|
||||
);
|
||||
|
||||
return message(form, 'Contract archived.');
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { invoices, clients } 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() {
|
||||
async function loadOptions(organizationId: string) {
|
||||
const clientRows = await db
|
||||
.select({ id: clients.id, name: clients.name })
|
||||
.from(clients)
|
||||
.where(isNull(clients.archivedAt))
|
||||
.where(and(eq(clients.organizationId, organizationId), isNull(clients.archivedAt)))
|
||||
.orderBy(asc(clients.name));
|
||||
|
||||
return {
|
||||
@@ -18,22 +19,24 @@ async function loadOptions() {
|
||||
};
|
||||
}
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(invoices)
|
||||
.where(isNull(invoices.archivedAt))
|
||||
.where(and(eq(invoices.organizationId, activeOrganizationId), isNull(invoices.archivedAt)))
|
||||
.orderBy(asc(invoices.invoiceNumber));
|
||||
|
||||
return {
|
||||
records,
|
||||
options: await loadOptions(),
|
||||
options: await loadOptions(activeOrganizationId),
|
||||
archiveForm: await superValidate(zod4(archiveSchema), { id: 'invoices-archive' })
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'invoices-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Invoice id is required.', { status: 400 });
|
||||
@@ -41,7 +44,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(invoices)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(invoices.id, form.data.id));
|
||||
.where(and(eq(invoices.id, form.data.id), eq(invoices.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Invoice archived.');
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { rooms } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { roomCreateSchema, roomEditSchema } from '$lib/schemas/rooms.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(rooms)
|
||||
.where(isNull(rooms.archivedAt))
|
||||
.where(and(eq(rooms.organizationId, activeOrganizationId), isNull(rooms.archivedAt)))
|
||||
.orderBy(asc(rooms.name));
|
||||
|
||||
return {
|
||||
@@ -39,11 +41,13 @@ export const load: PageServerLoad = async () => {
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(roomCreateSchema), { id: 'rooms-create' });
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
|
||||
const sharedValues = {
|
||||
organizationId: activeOrganizationId,
|
||||
name: form.data.name,
|
||||
type: form.data.type,
|
||||
sqFt: null,
|
||||
@@ -96,6 +100,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
edit: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(roomEditSchema), { id: 'rooms-edit' });
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
@@ -140,7 +145,10 @@ export const actions: Actions = {
|
||||
};
|
||||
|
||||
try {
|
||||
await db.update(rooms).set(roomValues).where(eq(rooms.id, form.data.id));
|
||||
await db
|
||||
.update(rooms)
|
||||
.set(roomValues)
|
||||
.where(and(eq(rooms.id, form.data.id), eq(rooms.organizationId, activeOrganizationId)));
|
||||
} catch {
|
||||
return message(form, 'Unable to update room.', { status: 400 });
|
||||
}
|
||||
@@ -149,6 +157,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'rooms-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Room id is required.', { status: 400 });
|
||||
@@ -156,7 +165,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(rooms)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(rooms.id, form.data.id));
|
||||
.where(and(eq(rooms.id, form.data.id), eq(rooms.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Room archived.');
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import { asc, eq, isNull } from 'drizzle-orm';
|
||||
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 { services } from '$lib/server/db/schema';
|
||||
import { loadOrganizationContext } from '$lib/server/organizations';
|
||||
import { archiveSchema } from '$lib/schemas/shared.schema';
|
||||
import { serviceCreateSchema, serviceEditSchema } from '$lib/schemas/services.schema';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
export const load: PageServerLoad = async ({ locals }) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(locals);
|
||||
const records = await db
|
||||
.select()
|
||||
.from(services)
|
||||
.where(isNull(services.archivedAt))
|
||||
.where(and(eq(services.organizationId, activeOrganizationId), isNull(services.archivedAt)))
|
||||
.orderBy(asc(services.name));
|
||||
|
||||
return {
|
||||
@@ -34,6 +36,7 @@ export const load: PageServerLoad = async () => {
|
||||
|
||||
export const actions: Actions = {
|
||||
create: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(serviceCreateSchema), { id: 'services-create' });
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
@@ -41,6 +44,7 @@ export const actions: Actions = {
|
||||
try {
|
||||
await db.insert(services).values({
|
||||
id: crypto.randomUUID(),
|
||||
organizationId: activeOrganizationId,
|
||||
name: form.data.name,
|
||||
category: form.data.category || null,
|
||||
unit: form.data.unit,
|
||||
@@ -57,6 +61,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
edit: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(serviceEditSchema), { id: 'services-edit' });
|
||||
|
||||
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
|
||||
@@ -72,7 +77,9 @@ export const actions: Actions = {
|
||||
description: form.data.description || null,
|
||||
updatedAt: new Date()
|
||||
})
|
||||
.where(eq(services.id, form.data.id));
|
||||
.where(
|
||||
and(eq(services.id, form.data.id), eq(services.organizationId, activeOrganizationId))
|
||||
);
|
||||
} catch {
|
||||
return message(form, 'Unable to update service.', { status: 400 });
|
||||
}
|
||||
@@ -81,6 +88,7 @@ export const actions: Actions = {
|
||||
},
|
||||
|
||||
archive: async (event) => {
|
||||
const { activeOrganizationId } = await loadOrganizationContext(event.locals);
|
||||
const form = await superValidate(event, zod4(archiveSchema), { id: 'services-archive' });
|
||||
|
||||
if (!form.valid) return message(form, 'Service id is required.', { status: 400 });
|
||||
@@ -88,7 +96,7 @@ export const actions: Actions = {
|
||||
await db
|
||||
.update(services)
|
||||
.set({ archivedAt: new Date(), updatedAt: new Date() })
|
||||
.where(eq(services.id, form.data.id));
|
||||
.where(and(eq(services.id, form.data.id), eq(services.organizationId, activeOrganizationId)));
|
||||
|
||||
return message(form, 'Service archived.');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user