From 77cbb1d8d7109175b9aab8b182cb4df5d7aa1b60 Mon Sep 17 00:00:00 2001 From: Daniel Kirby Date: Thu, 25 Jun 2026 11:40:09 +0100 Subject: [PATCH] feat: build dashboard overview UI --- src/routes/dashboard/+page.svelte | 41 ++++++ src/routes/dashboard/activity-lists.svelte | 163 +++++++++++++++++++++ src/routes/dashboard/billing-trend.svelte | 55 +++++++ src/routes/dashboard/metric-cards.svelte | 77 ++++++++++ src/routes/dashboard/room-summary.svelte | 67 +++++++++ 5 files changed, 403 insertions(+) create mode 100644 src/routes/dashboard/activity-lists.svelte create mode 100644 src/routes/dashboard/billing-trend.svelte create mode 100644 src/routes/dashboard/metric-cards.svelte create mode 100644 src/routes/dashboard/room-summary.svelte diff --git a/src/routes/dashboard/+page.svelte b/src/routes/dashboard/+page.svelte index e69de29..5bc8b55 100644 --- a/src/routes/dashboard/+page.svelte +++ b/src/routes/dashboard/+page.svelte @@ -0,0 +1,41 @@ + + + + Dashboard | Clearity + + +
+
+

Dashboard

+

+ Operational overview for clients, contracts, bookings, rooms, and billing. +

+
+ + + +
+ + +
+ + + +

{data.meta.overdueInvoiceBasis}

+
diff --git a/src/routes/dashboard/activity-lists.svelte b/src/routes/dashboard/activity-lists.svelte new file mode 100644 index 0000000..a4966b0 --- /dev/null +++ b/src/routes/dashboard/activity-lists.svelte @@ -0,0 +1,163 @@ + + +
+ + + Upcoming bookings + Next room and service reservations. + + + + {#if upcomingBookings.length > 0} +
+ + + {#each upcomingBookings as booking (booking.id)} + + +
{booking.roomName}
+
{booking.clientName}
+
+ +
{formatDate(booking.startsAt, true)}
+
+ {formatValue(booking.serviceName)} +
+
+ + {booking.status} + +
+ {/each} +
+
+
+ {:else} + + + + No upcoming bookings + Future bookings will appear here. + + + {/if} +
+
+ + + + Contracts ending soon + Active contracts ending in the next 60 days. + + + + {#if contractsEndingSoon.length > 0} +
+ + + {#each contractsEndingSoon as contract (contract.id)} + + +
{contract.clientName}
+
+ {contract.roomNames.join(', ') || formatValue(contract.serviceName)} +
+
+ +
{formatDate(contract.endDate)}
+
+ {formatMoney(contract.licenseFeeGbp)} / month +
+
+
+ {/each} +
+
+
+ {:else} + + + + No near-term endings + Contracts ending soon will be listed here. + + + {/if} +
+
+ + + + Recent invoices + Latest generated billing output. + + + + {#if recentInvoices.length > 0} +
+ + + {#each recentInvoices as invoice (invoice.id)} + + +
{invoice.invoiceNumber}
+
{invoice.clientName}
+
+ +
{formatMoney(invoice.totalGbp)}
+
+ Issued {formatDate(invoice.issueDate)} +
+
+
+ {/each} +
+
+
+ {:else} + + + + No invoices yet + Generated invoices will appear here. + + + {/if} +
+
+
diff --git a/src/routes/dashboard/billing-trend.svelte b/src/routes/dashboard/billing-trend.svelte new file mode 100644 index 0000000..8726b50 --- /dev/null +++ b/src/routes/dashboard/billing-trend.svelte @@ -0,0 +1,55 @@ + + + + + Billing trend + Issued invoice totals over the last six months. + + + {#if hasValues} +
+ {#each records as record (record.month)} +
+
+
0 ? 4 : 0)}%`} + title={`${record.label}: ${formatMoney(record.totalGbp)}`} + >
+
+
+
{formatMoney(record.totalGbp)}
+
{record.label}
+
+
+ {/each} +
+ {:else} + + + + No issued invoices yet + Billing totals will appear once invoices are generated. + + + {/if} +
+
diff --git a/src/routes/dashboard/metric-cards.svelte b/src/routes/dashboard/metric-cards.svelte new file mode 100644 index 0000000..95a6882 --- /dev/null +++ b/src/routes/dashboard/metric-cards.svelte @@ -0,0 +1,77 @@ + + +
+ {#each cards as card (card.label)} + {@const Icon = card.icon} + + + + + {card.label} + + + +
{card.value}
+

{card.detail}

+
+
+ {/each} +
diff --git a/src/routes/dashboard/room-summary.svelte b/src/routes/dashboard/room-summary.svelte new file mode 100644 index 0000000..ba8d615 --- /dev/null +++ b/src/routes/dashboard/room-summary.svelte @@ -0,0 +1,67 @@ + + + + + Room inventory + Allocation is based on rooms linked to active contracts. + + + {#if metrics.totalRooms > 0} +
+
+ Allocated rooms + {metrics.allocatedRooms} / {metrics.totalRooms} +
+ +
+ +
+ + + + Type + Rooms + Allocated + Workstations + Sq ft. + + + + {#each summary.types as type (type.type)} + + {type.label} + {type.total} + {type.allocated} + {type.workstations || 'Not set'} + {type.sqFt || 'Not set'} + + {/each} + + +
+ {:else} + + + + No rooms configured + Add rooms before tracking inventory and allocation. + + + {/if} +
+