diff --git a/src/lib/server/services/assets.ts b/src/lib/server/services/assets.ts index 9a6ef65..ee5a832 100644 --- a/src/lib/server/services/assets.ts +++ b/src/lib/server/services/assets.ts @@ -1,4 +1,4 @@ -import { and, asc, desc, eq, isNull, or, sql } from 'drizzle-orm'; +import { and, asc, desc, eq, inArray, isNull, or, sql } from 'drizzle-orm'; import { db } from '$lib/server/db/client'; import { assets, @@ -292,7 +292,10 @@ export async function appendAssetLog( export interface AssetListOptions { companyId: string; typeSlug?: string; + /** Restrict to a single property. Mutually exclusive with `propertyIds`. */ propertyId?: string; + /** Restrict to assets at any of these properties (e.g. a property tree). */ + propertyIds?: string[]; projectId?: string; roomId?: string; q?: string; @@ -302,7 +305,11 @@ export interface AssetListOptions { export async function listAssets(opts: AssetListOptions) { const where = [eq(assets.companyId, opts.companyId), isNull(assets.deletedAt)]; - if (opts.propertyId) where.push(eq(assets.currentPropertyId, opts.propertyId)); + if (opts.propertyIds && opts.propertyIds.length > 0) { + where.push(inArray(assets.currentPropertyId, opts.propertyIds)); + } else if (opts.propertyId) { + where.push(eq(assets.currentPropertyId, opts.propertyId)); + } if (opts.projectId) where.push(eq(assets.currentProjectId, opts.projectId)); if (opts.roomId) where.push(eq(assets.currentRoomId, opts.roomId)); if (opts.typeSlug) { diff --git a/src/routes/(app)/properties/[id]/+layout.svelte b/src/routes/(app)/properties/[id]/+layout.svelte index 6f980b1..5a3b09e 100644 --- a/src/routes/(app)/properties/[id]/+layout.svelte +++ b/src/routes/(app)/properties/[id]/+layout.svelte @@ -15,6 +15,8 @@ { href: `/properties/${data.property.id}/assets`, label: 'Assets' }, { href: `/properties/${data.property.id}/accounts`, label: 'Accounts' }, { href: `/properties/${data.property.id}/expenses`, label: 'Expenses' }, + { href: `/properties/${data.property.id}/maintenance`, label: 'Maintenance' }, + { href: `/properties/${data.property.id}/todos`, label: 'Todos' }, { href: `/properties/${data.property.id}/documents`, label: 'Documents' } ]); diff --git a/src/routes/(app)/properties/[id]/assets/+page.server.ts b/src/routes/(app)/properties/[id]/assets/+page.server.ts index 6e3f999..d773bec 100644 --- a/src/routes/(app)/properties/[id]/assets/+page.server.ts +++ b/src/routes/(app)/properties/[id]/assets/+page.server.ts @@ -1,9 +1,14 @@ import { error } from '@sveltejs/kit'; import { listAssets } from '$lib/server/services/assets'; +import { getDescendantIds } from '$lib/server/services/properties'; import type { PageServerLoad } from './$types'; -export const load: PageServerLoad = async ({ locals, params }) => { +export const load: PageServerLoad = async ({ locals, params, url }) => { if (!locals.company) throw error(401); - const rows = await listAssets({ companyId: locals.company.id, propertyId: params.id }); - return { assets: rows }; + const includeDescendants = url.searchParams.get('descendants') === '1'; + const propertyIds = includeDescendants + ? await getDescendantIds(locals.company.id, params.id) + : [params.id]; + const rows = await listAssets({ companyId: locals.company.id, propertyIds }); + return { assets: rows, includeDescendants, descendantCount: propertyIds.length }; }; diff --git a/src/routes/(app)/properties/[id]/assets/+page.svelte b/src/routes/(app)/properties/[id]/assets/+page.svelte index bad23bd..d55f371 100644 --- a/src/routes/(app)/properties/[id]/assets/+page.svelte +++ b/src/routes/(app)/properties/[id]/assets/+page.svelte @@ -1,6 +1,7 @@
{data.assets.length} asset{data.assets.length === 1 ? '' : 's'} at this property.
+{data.assets.length} asset{data.assets.length === 1 ? '' : 's'}{data.includeDescendants ? ' across the property tree' : ' at this property'}.
+ Add asset| Schedule | +Asset | +Interval | +Next due | +Status | +
|---|---|---|---|---|
| {s.name} | ++ {s.assetName} + | +every {s.intervalValue} {s.intervalUnit} | ++ {s.kind === 'time' ? fmtDate(s.nextDueAt) : `${s.nextDueUsage ?? '—'} ${s.intervalUnit}`} + | ++ {#if !s.active} + paused + {:else if isOverdue} + overdue + {:else} + active + {/if} + | +
{e.notes}
+ {/if} +