@burdenoff/microfe-assethandler 2026.826.8 → 2026.826.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAgNA,wBAAgB,oBAAoB,gCA2pBnC"}
1
+ {"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,oBAAoB,gCA8pBnC"}
@@ -8,14 +8,15 @@ import { StatTile as s } from "../components/StatTile.js";
8
8
  import { ChartCard as c } from "../components/ChartCard.js";
9
9
  import "../components/index.js";
10
10
  import { downloadCsv as l } from "../utils/csv.js";
11
- import { useMemo as u, useState as ee } from "react";
12
- import { Activity as te, DollarSign as ne, Download as d, FileBarChart2 as re, Percent as f, Printer as p, TrendingDown as m, Wallet as ie, Wrench as ae } from "lucide-react";
13
- import { gql as h } from "@apollo/client";
14
- import { useQuery as oe } from "@apollo/client/react";
15
- import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
16
- import { Button as y, GlassCard as b, GradientText as x, IllustratedEmptyState as S, PagePurpose as C, Select as w, SelectContent as T, SelectItem as E, SelectTrigger as se, SelectValue as ce, Tabs as le, TabsContent as D, TabsList as ue, TabsTrigger as O } from "@burdenoff/fe-libs/ui";
11
+ import { buildAssignmentCoverageSlices as ee } from "../utils/utilization.js";
12
+ import { useMemo as u, useState as te } from "react";
13
+ import { Activity as ne, DollarSign as re, Download as d, FileBarChart2 as ie, Percent as f, Printer as p, TrendingDown as m, Wallet as h, Wrench as g } from "lucide-react";
14
+ import { gql as _ } from "@apollo/client";
15
+ import { useQuery as ae } from "@apollo/client/react";
16
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
17
+ import { Button as x, GlassCard as S, GradientText as C, IllustratedEmptyState as w, PagePurpose as oe, Select as se, SelectContent as ce, SelectItem as T, SelectTrigger as E, SelectValue as le, Tabs as ue, TabsContent as D, TabsList as de, TabsTrigger as O } from "@burdenoff/fe-libs/ui";
17
18
  //#region src/assethandler/pages/ReportsDashboardPage.tsx
18
- var de = h`
19
+ var fe = _`
19
20
  query AssetHandlerReports($registerFilter: AssetRegisterFilterInput) {
20
21
  assetRegister(filter: $registerFilter, pagination: { limit: 1000 }) {
21
22
  id
@@ -64,7 +65,7 @@ var de = h`
64
65
  }
65
66
  }
66
67
  }
67
- `, fe = [
68
+ `, pe = [
68
69
  "ACTIVE",
69
70
  "INACTIVE",
70
71
  "MAINTENANCE",
@@ -78,7 +79,7 @@ var de = h`
78
79
  neutral: "bg-bg-sunken text-text-secondary"
79
80
  };
80
81
  function A({ tone: e, children: t }) {
81
- return /* @__PURE__ */ _("span", {
82
+ return /* @__PURE__ */ y("span", {
82
83
  className: n("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize", k[e]),
83
84
  children: t
84
85
  });
@@ -91,16 +92,16 @@ var j = (e) => {
91
92
  return t === "completed" ? "success" : t === "in_progress" || t === "scheduled" ? "info" : t === "overdue" || t === "cancelled" ? "error" : "neutral";
92
93
  };
93
94
  function N({ rows: e = 6, cols: t }) {
94
- return /* @__PURE__ */ _(g, { children: Array.from({ length: e }).map((e, n) => /* @__PURE__ */ _("tr", {
95
+ return /* @__PURE__ */ y(v, { children: Array.from({ length: e }).map((e, n) => /* @__PURE__ */ y("tr", {
95
96
  className: "border-b border-border-seam/60",
96
- children: Array.from({ length: t }).map((e, t) => /* @__PURE__ */ _("td", {
97
+ children: Array.from({ length: t }).map((e, t) => /* @__PURE__ */ y("td", {
97
98
  className: "p-3",
98
- children: /* @__PURE__ */ _("div", { className: "h-4 w-full max-w-[120px] animate-pulse rounded bg-bg-sunken" })
99
+ children: /* @__PURE__ */ y("div", { className: "h-4 w-full max-w-[120px] animate-pulse rounded bg-bg-sunken" })
99
100
  }, t))
100
101
  }, n)) });
101
102
  }
102
103
  function P() {
103
- let { format: n, compact: h } = t(), { assets: k } = e(), [P, F] = ee("all"), { data: I, loading: L } = oe(de, {
104
+ let { format: n, compact: _ } = t(), { assets: k } = e(), [P, F] = te("all"), { data: I, loading: L } = ae(fe, {
104
105
  variables: { registerFilter: P === "all" ? null : { status: P } },
105
106
  fetchPolicy: "cache-and-network",
106
107
  errorPolicy: "all"
@@ -111,7 +112,7 @@ function P() {
111
112
  }, [k]), U = o(R, {
112
113
  pageSize: 12,
113
114
  resetKey: P
114
- }), W = o(z, { pageSize: 12 }), G = B?.totalAssetValue ?? 0, K = B?.totalDepreciation ?? 0, pe = G + K > 0 ? K / (G + K) * 100 : 0, q = u(() => {
115
+ }), W = o(z, { pageSize: 12 }), G = B?.totalAssetValue ?? 0, K = B?.totalDepreciation ?? 0, me = G + K > 0 ? K / (G + K) * 100 : 0, q = u(() => {
115
116
  let e = /* @__PURE__ */ new Map();
116
117
  for (let t of R) {
117
118
  let n = t.currentValue ?? t.purchaseValue ?? 0;
@@ -124,35 +125,22 @@ function P() {
124
125
  category: e,
125
126
  value: t
126
127
  })).sort((e, t) => t.value - e.value).slice(0, 12);
127
- }, [R]), me = u(() => (V?.byStatus ?? []).map((e) => ({
128
+ }, [R]), J = u(() => (V?.byStatus ?? []).map((e) => ({
128
129
  name: e.status.toLowerCase(),
129
130
  value: e.count
130
- })).filter((e) => e.value > 0), [V]), he = u(() => V ? [
131
- {
132
- name: "Assigned",
133
- value: V.assignedAssets
134
- },
135
- {
136
- name: "Unassigned",
137
- value: V.unassignedAssets
138
- },
139
- {
140
- name: "Idle",
141
- value: V.idleAssets
142
- }
143
- ].filter((e) => e.value > 0) : [], [V]), J = u(() => [{
131
+ })).filter((e) => e.value > 0), [V]), he = u(() => V ? ee(V.assignedAssets, V.unassignedAssets, V.idleAssets) : [], [V]), Y = u(() => [{
144
132
  name: "Current value",
145
133
  value: G
146
134
  }, {
147
135
  name: "Accumulated depreciation",
148
136
  value: K
149
- }].filter((e) => e.value > 0), [G, K]), Y = u(() => B ? [{
137
+ }].filter((e) => e.value > 0), [G, K]), X = u(() => B ? [{
150
138
  metric: "Allocated",
151
139
  value: B.budgetAllocated
152
140
  }, {
153
141
  metric: "Spent",
154
142
  value: B.budgetSpent
155
- }] : [], [B]), X = u(() => {
143
+ }] : [], [B]), Z = u(() => {
156
144
  let e = /* @__PURE__ */ new Map();
157
145
  for (let t of z) {
158
146
  let n = t.actualCost ?? t.estimatedCost ?? 0;
@@ -165,7 +153,7 @@ function P() {
165
153
  type: e[0],
166
154
  cost: e[1]
167
155
  })).sort((e, t) => t.cost - e.cost);
168
- }, [z]), Z = () => {
156
+ }, [z]), ge = () => {
169
157
  l(`asset-register-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, [
170
158
  "Asset Number",
171
159
  "Name",
@@ -189,7 +177,7 @@ function P() {
189
177
  e.totalCostOfOwnership ?? "",
190
178
  e.purchaseDate ? new Date(e.purchaseDate).toISOString().slice(0, 10) : ""
191
179
  ]));
192
- }, ge = () => {
180
+ }, _e = () => {
193
181
  l(`maintenance-log-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, [
194
182
  "Title",
195
183
  "Asset",
@@ -211,7 +199,7 @@ function P() {
211
199
  e.estimatedCost ?? "",
212
200
  e.actualCost ?? ""
213
201
  ]));
214
- }, _e = () => {
202
+ }, ve = () => {
215
203
  B && l(`financial-summary-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, ["Metric", "Value"], [
216
204
  ["Total asset value", B.totalAssetValue],
217
205
  ["Total depreciation", B.totalDepreciation],
@@ -222,7 +210,7 @@ function P() {
222
210
  ["Invoices outstanding (count)", B.invoicesOutstandingCount],
223
211
  ["Transaction expense", B.transactionExpense]
224
212
  ]);
225
- }, ve = () => {
213
+ }, ye = () => {
226
214
  V && l(`utilization-report-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, ["Metric", "Value"], [
227
215
  ["Total assets", V.totalAssets],
228
216
  ["Assigned assets", V.assignedAssets],
@@ -231,85 +219,85 @@ function P() {
231
219
  ["Overdue assignments", V.overdueAssignments],
232
220
  ...V.byStatus.map((e) => [`Status: ${e.status}`, e.count])
233
221
  ]);
234
- }, Q = L && R.length === 0, $ = L && z.length === 0, ye = /* @__PURE__ */ v(g, { children: [/* @__PURE__ */ v(y, {
222
+ }, Q = L && R.length === 0, $ = L && z.length === 0, be = /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ b(x, {
235
223
  size: "sm",
236
- onClick: Z,
224
+ onClick: ge,
237
225
  disabled: R.length === 0,
238
- children: [/* @__PURE__ */ _(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
239
- }), /* @__PURE__ */ v(y, {
226
+ children: [/* @__PURE__ */ y(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
227
+ }), /* @__PURE__ */ b(x, {
240
228
  size: "sm",
241
229
  variant: "outline",
242
230
  onClick: () => window.print(),
243
- children: [/* @__PURE__ */ _(p, { className: "mr-2 h-4 w-4" }), "Print"]
231
+ children: [/* @__PURE__ */ y(p, { className: "mr-2 h-4 w-4" }), "Print"]
244
232
  })] });
245
- return /* @__PURE__ */ v("div", {
233
+ return /* @__PURE__ */ b("div", {
246
234
  className: "space-y-6 p-4 sm:p-6",
247
235
  children: [
248
- /* @__PURE__ */ v("div", {
236
+ /* @__PURE__ */ b("div", {
249
237
  className: "flex flex-col gap-5 xl:flex-row xl:items-end xl:justify-between",
250
- children: [/* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("h1", {
238
+ children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
251
239
  className: "text-2xl font-bold sm:text-3xl",
252
- children: /* @__PURE__ */ _(x, { children: "Reports" })
253
- }), /* @__PURE__ */ _("p", {
240
+ children: /* @__PURE__ */ y(C, { children: "Reports" })
241
+ }), /* @__PURE__ */ y("p", {
254
242
  className: "mt-1 max-w-xl text-sm text-text-secondary",
255
243
  children: "Registers and summaries built from live asset, finance and maintenance data."
256
- })] }), /* @__PURE__ */ v("div", {
244
+ })] }), /* @__PURE__ */ b("div", {
257
245
  className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
258
246
  children: [
259
- /* @__PURE__ */ _(s, {
247
+ /* @__PURE__ */ y(s, {
260
248
  label: "Total asset value",
261
249
  value: G,
262
250
  format: (e) => n(e),
263
- icon: ne,
251
+ icon: re,
264
252
  hero: !0
265
253
  }),
266
- /* @__PURE__ */ _(s, {
254
+ /* @__PURE__ */ y(s, {
267
255
  label: "Total depreciation",
268
256
  value: K,
269
257
  format: (e) => n(e),
270
258
  icon: m
271
259
  }),
272
- /* @__PURE__ */ _(s, {
260
+ /* @__PURE__ */ y(s, {
273
261
  label: "Depreciated",
274
- value: pe,
262
+ value: me,
275
263
  format: (e) => `${e.toFixed(2)}%`,
276
264
  icon: f
277
265
  })
278
266
  ]
279
267
  })]
280
268
  }),
281
- /* @__PURE__ */ _(C, { children: "Pull the numbers you need for audits, finance reviews and planning. Every register below is generated from live records — export any of them to CSV or print the page for sign-off." }),
282
- /* @__PURE__ */ v(le, {
269
+ /* @__PURE__ */ y(oe, { children: "Pull the numbers you need for audits, finance reviews and planning. Every register below is generated from live records — export any of them to CSV or print the page for sign-off." }),
270
+ /* @__PURE__ */ b(ue, {
283
271
  defaultValue: "register",
284
272
  children: [
285
- /* @__PURE__ */ v(ue, {
273
+ /* @__PURE__ */ b(de, {
286
274
  className: "max-w-full justify-start overflow-x-auto",
287
275
  children: [
288
- /* @__PURE__ */ v(O, {
276
+ /* @__PURE__ */ b(O, {
289
277
  value: "register",
290
- children: [/* @__PURE__ */ _(re, { className: "mr-1.5 h-4 w-4" }), "Asset Register"]
278
+ children: [/* @__PURE__ */ y(ie, { className: "mr-1.5 h-4 w-4" }), "Asset Register"]
291
279
  }),
292
- /* @__PURE__ */ v(O, {
280
+ /* @__PURE__ */ b(O, {
293
281
  value: "financial",
294
- children: [/* @__PURE__ */ _(ie, { className: "mr-1.5 h-4 w-4" }), "Financial Summary"]
282
+ children: [/* @__PURE__ */ y(h, { className: "mr-1.5 h-4 w-4" }), "Financial Summary"]
295
283
  }),
296
- /* @__PURE__ */ v(O, {
284
+ /* @__PURE__ */ b(O, {
297
285
  value: "maintenance",
298
- children: [/* @__PURE__ */ _(ae, { className: "mr-1.5 h-4 w-4" }), "Maintenance Log"]
286
+ children: [/* @__PURE__ */ y(g, { className: "mr-1.5 h-4 w-4" }), "Maintenance Log"]
299
287
  }),
300
- /* @__PURE__ */ v(O, {
288
+ /* @__PURE__ */ b(O, {
301
289
  value: "utilization",
302
- children: [/* @__PURE__ */ _(te, { className: "mr-1.5 h-4 w-4" }), "Utilization"]
290
+ children: [/* @__PURE__ */ y(ne, { className: "mr-1.5 h-4 w-4" }), "Utilization"]
303
291
  })
304
292
  ]
305
293
  }),
306
- /* @__PURE__ */ v(D, {
294
+ /* @__PURE__ */ b(D, {
307
295
  value: "register",
308
296
  className: "mt-4 space-y-4",
309
- children: [q.length > 0 ? /* @__PURE__ */ _(c, {
297
+ children: [q.length > 0 ? /* @__PURE__ */ y(c, {
310
298
  title: "Asset value by category",
311
299
  subtitle: "Current book value aggregated from the register",
312
- children: /* @__PURE__ */ _(r, {
300
+ children: /* @__PURE__ */ y(r, {
313
301
  data: q,
314
302
  xKey: "category",
315
303
  series: [{
@@ -318,122 +306,122 @@ function P() {
318
306
  }],
319
307
  orientation: "horizontal",
320
308
  height: Math.max(200, q.length * 34),
321
- valueFormat: h,
309
+ valueFormat: _,
322
310
  categoryWidth: 128,
323
311
  ariaLabel: "Current asset value by category"
324
312
  })
325
- }) : null, /* @__PURE__ */ v(b, {
313
+ }) : null, /* @__PURE__ */ b(S, {
326
314
  treatment: "glass",
327
315
  className: "overflow-hidden border-border-seam",
328
316
  children: [
329
- /* @__PURE__ */ v("div", {
317
+ /* @__PURE__ */ b("div", {
330
318
  className: "flex flex-col gap-3 border-b border-border-seam p-4 sm:flex-row sm:items-center sm:justify-between",
331
- children: [/* @__PURE__ */ v("div", {
319
+ children: [/* @__PURE__ */ b("div", {
332
320
  className: "flex items-center gap-3",
333
- children: [/* @__PURE__ */ _("h3", {
321
+ children: [/* @__PURE__ */ y("h3", {
334
322
  className: "text-base font-semibold text-text-primary",
335
323
  children: "Asset Register"
336
- }), /* @__PURE__ */ v(w, {
324
+ }), /* @__PURE__ */ b(se, {
337
325
  value: P,
338
326
  onValueChange: F,
339
- children: [/* @__PURE__ */ _(se, {
327
+ children: [/* @__PURE__ */ y(E, {
340
328
  className: "h-8 w-40",
341
- children: /* @__PURE__ */ _(ce, { placeholder: "Filter by status" })
342
- }), /* @__PURE__ */ v(T, { children: [/* @__PURE__ */ _(E, {
329
+ children: /* @__PURE__ */ y(le, { placeholder: "Filter by status" })
330
+ }), /* @__PURE__ */ b(ce, { children: [/* @__PURE__ */ y(T, {
343
331
  value: "all",
344
332
  children: "All statuses"
345
- }), fe.map((e) => /* @__PURE__ */ _(E, {
333
+ }), pe.map((e) => /* @__PURE__ */ y(T, {
346
334
  value: e,
347
335
  className: "capitalize",
348
336
  children: e.toLowerCase()
349
337
  }, e))] })]
350
338
  })]
351
- }), /* @__PURE__ */ _("div", {
339
+ }), /* @__PURE__ */ y("div", {
352
340
  className: "flex flex-wrap gap-2",
353
- children: ye
341
+ children: be
354
342
  })]
355
343
  }),
356
- /* @__PURE__ */ _("div", {
344
+ /* @__PURE__ */ y("div", {
357
345
  className: "hidden overflow-x-auto md:block",
358
- children: /* @__PURE__ */ v("table", {
346
+ children: /* @__PURE__ */ b("table", {
359
347
  className: "w-full min-w-[860px] text-sm",
360
- children: [/* @__PURE__ */ _("thead", { children: /* @__PURE__ */ v("tr", {
348
+ children: [/* @__PURE__ */ y("thead", { children: /* @__PURE__ */ b("tr", {
361
349
  className: "border-b border-border-seam bg-bg-sunken/50 text-left",
362
350
  children: [
363
- /* @__PURE__ */ _("th", {
351
+ /* @__PURE__ */ y("th", {
364
352
  className: "p-3 font-medium",
365
353
  children: "Asset"
366
354
  }),
367
- /* @__PURE__ */ _("th", {
355
+ /* @__PURE__ */ y("th", {
368
356
  className: "p-3 font-medium",
369
357
  children: "Category"
370
358
  }),
371
- /* @__PURE__ */ _("th", {
359
+ /* @__PURE__ */ y("th", {
372
360
  className: "p-3 font-medium",
373
361
  children: "Status"
374
362
  }),
375
- /* @__PURE__ */ _("th", {
363
+ /* @__PURE__ */ y("th", {
376
364
  className: "p-3 font-medium",
377
365
  children: "Department"
378
366
  }),
379
- /* @__PURE__ */ _("th", {
367
+ /* @__PURE__ */ y("th", {
380
368
  className: "p-3 text-right font-medium",
381
369
  children: "Purchase"
382
370
  }),
383
- /* @__PURE__ */ _("th", {
371
+ /* @__PURE__ */ y("th", {
384
372
  className: "p-3 text-right font-medium",
385
373
  children: "Current"
386
374
  }),
387
- /* @__PURE__ */ _("th", {
375
+ /* @__PURE__ */ y("th", {
388
376
  className: "p-3 text-right font-medium",
389
377
  children: "Depreciation"
390
378
  }),
391
- /* @__PURE__ */ _("th", {
379
+ /* @__PURE__ */ y("th", {
392
380
  className: "p-3 text-right font-medium",
393
381
  children: "TCO"
394
382
  })
395
383
  ]
396
- }) }), /* @__PURE__ */ _("tbody", { children: Q ? /* @__PURE__ */ _(N, { cols: 8 }) : U.pageItems.map((e) => /* @__PURE__ */ v("tr", {
384
+ }) }), /* @__PURE__ */ y("tbody", { children: Q ? /* @__PURE__ */ y(N, { cols: 8 }) : U.pageItems.map((e) => /* @__PURE__ */ b("tr", {
397
385
  className: "border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40",
398
386
  children: [
399
- /* @__PURE__ */ v("td", {
387
+ /* @__PURE__ */ b("td", {
400
388
  className: "p-3",
401
- children: [/* @__PURE__ */ _("p", {
389
+ children: [/* @__PURE__ */ y("p", {
402
390
  className: "font-medium",
403
391
  children: e.name
404
- }), /* @__PURE__ */ _("p", {
392
+ }), /* @__PURE__ */ y("p", {
405
393
  className: "text-xs text-text-secondary",
406
394
  children: e.assetNumber
407
395
  })]
408
396
  }),
409
- /* @__PURE__ */ _("td", {
397
+ /* @__PURE__ */ y("td", {
410
398
  className: "p-3 capitalize",
411
399
  children: e.category.replace(/_/g, " ")
412
400
  }),
413
- /* @__PURE__ */ _("td", {
401
+ /* @__PURE__ */ y("td", {
414
402
  className: "p-3",
415
- children: /* @__PURE__ */ _(A, {
403
+ children: /* @__PURE__ */ y(A, {
416
404
  tone: j(e.status),
417
405
  children: e.status.toLowerCase()
418
406
  })
419
407
  }),
420
- /* @__PURE__ */ _("td", {
408
+ /* @__PURE__ */ y("td", {
421
409
  className: "p-3",
422
410
  children: e.department || "—"
423
411
  }),
424
- /* @__PURE__ */ _("td", {
412
+ /* @__PURE__ */ y("td", {
425
413
  className: "p-3 text-right tabular-nums",
426
414
  children: n(e.purchaseValue)
427
415
  }),
428
- /* @__PURE__ */ _("td", {
416
+ /* @__PURE__ */ y("td", {
429
417
  className: "p-3 text-right tabular-nums",
430
418
  children: n(e.currentValue)
431
419
  }),
432
- /* @__PURE__ */ _("td", {
420
+ /* @__PURE__ */ y("td", {
433
421
  className: "p-3 text-right tabular-nums",
434
422
  children: n(e.accumulatedDepreciation)
435
423
  }),
436
- /* @__PURE__ */ _("td", {
424
+ /* @__PURE__ */ y("td", {
437
425
  className: "p-3 text-right tabular-nums",
438
426
  children: n(e.totalCostOfOwnership)
439
427
  })
@@ -441,43 +429,43 @@ function P() {
441
429
  }, e.id)) })]
442
430
  })
443
431
  }),
444
- /* @__PURE__ */ _("div", {
432
+ /* @__PURE__ */ y("div", {
445
433
  className: "divide-y divide-border-seam/60 md:hidden",
446
- children: Q ? /* @__PURE__ */ _("div", {
434
+ children: Q ? /* @__PURE__ */ y("div", {
447
435
  className: "space-y-3 p-4",
448
- children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ _("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
449
- }) : U.pageItems.map((e) => /* @__PURE__ */ v("div", {
436
+ children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ y("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
437
+ }) : U.pageItems.map((e) => /* @__PURE__ */ b("div", {
450
438
  className: "p-4",
451
- children: [/* @__PURE__ */ v("div", {
439
+ children: [/* @__PURE__ */ b("div", {
452
440
  className: "flex items-start justify-between gap-2",
453
- children: [/* @__PURE__ */ v("div", {
441
+ children: [/* @__PURE__ */ b("div", {
454
442
  className: "min-w-0",
455
- children: [/* @__PURE__ */ _("p", {
443
+ children: [/* @__PURE__ */ y("p", {
456
444
  className: "truncate font-medium",
457
445
  children: e.name
458
- }), /* @__PURE__ */ _("p", {
446
+ }), /* @__PURE__ */ y("p", {
459
447
  className: "text-xs text-text-secondary",
460
448
  children: e.assetNumber
461
449
  })]
462
- }), /* @__PURE__ */ _(A, {
450
+ }), /* @__PURE__ */ y(A, {
463
451
  tone: j(e.status),
464
452
  children: e.status.toLowerCase()
465
453
  })]
466
- }), /* @__PURE__ */ v("div", {
454
+ }), /* @__PURE__ */ b("div", {
467
455
  className: "mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-text-secondary",
468
456
  children: [
469
- /* @__PURE__ */ _("span", { children: "Category" }),
470
- /* @__PURE__ */ _("span", {
457
+ /* @__PURE__ */ y("span", { children: "Category" }),
458
+ /* @__PURE__ */ y("span", {
471
459
  className: "text-right capitalize text-text-primary",
472
460
  children: e.category.replace(/_/g, " ")
473
461
  }),
474
- /* @__PURE__ */ _("span", { children: "Current value" }),
475
- /* @__PURE__ */ _("span", {
462
+ /* @__PURE__ */ y("span", { children: "Current value" }),
463
+ /* @__PURE__ */ y("span", {
476
464
  className: "text-right tabular-nums text-text-primary",
477
465
  children: n(e.currentValue)
478
466
  }),
479
- /* @__PURE__ */ _("span", { children: "Depreciation" }),
480
- /* @__PURE__ */ _("span", {
467
+ /* @__PURE__ */ y("span", { children: "Depreciation" }),
468
+ /* @__PURE__ */ y("span", {
481
469
  className: "text-right tabular-nums text-text-primary",
482
470
  children: n(e.accumulatedDepreciation)
483
471
  })
@@ -485,13 +473,13 @@ function P() {
485
473
  })]
486
474
  }, e.id))
487
475
  }),
488
- R.length === 0 && !L ? /* @__PURE__ */ _(S, {
476
+ R.length === 0 && !L ? /* @__PURE__ */ y(w, {
489
477
  illustration: "empty-data",
490
478
  title: "No assets in the register",
491
479
  description: "Register assets with financial details and they will appear here."
492
- }) : /* @__PURE__ */ _("div", {
480
+ }) : /* @__PURE__ */ y("div", {
493
481
  className: "px-3",
494
- children: /* @__PURE__ */ _(a, {
482
+ children: /* @__PURE__ */ y(a, {
495
483
  page: U.page,
496
484
  pageCount: U.pageCount,
497
485
  rangeStart: U.rangeStart,
@@ -507,70 +495,70 @@ function P() {
507
495
  ]
508
496
  })]
509
497
  }),
510
- /* @__PURE__ */ v(D, {
498
+ /* @__PURE__ */ b(D, {
511
499
  value: "financial",
512
500
  className: "mt-4 space-y-4",
513
501
  children: [
514
- /* @__PURE__ */ _("div", {
502
+ /* @__PURE__ */ y("div", {
515
503
  className: "flex justify-end",
516
- children: /* @__PURE__ */ v(y, {
504
+ children: /* @__PURE__ */ b(x, {
517
505
  size: "sm",
518
- onClick: _e,
506
+ onClick: ve,
519
507
  disabled: !B,
520
- children: [/* @__PURE__ */ _(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
508
+ children: [/* @__PURE__ */ y(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
521
509
  })
522
510
  }),
523
- /* @__PURE__ */ v("div", {
511
+ /* @__PURE__ */ b("div", {
524
512
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
525
513
  children: [
526
- /* @__PURE__ */ _(s, {
514
+ /* @__PURE__ */ y(s, {
527
515
  label: "Total asset value",
528
516
  value: G,
529
517
  format: (e) => n(e)
530
518
  }),
531
- /* @__PURE__ */ _(s, {
519
+ /* @__PURE__ */ y(s, {
532
520
  label: "Total depreciation",
533
521
  value: K,
534
522
  format: (e) => n(e)
535
523
  }),
536
- /* @__PURE__ */ _(s, {
524
+ /* @__PURE__ */ y(s, {
537
525
  label: "Maintenance spend",
538
526
  value: B?.totalMaintenanceSpend ?? 0,
539
527
  format: (e) => n(e)
540
528
  }),
541
- /* @__PURE__ */ _(s, {
529
+ /* @__PURE__ */ y(s, {
542
530
  label: "Transaction expense",
543
531
  value: B?.transactionExpense ?? 0,
544
532
  format: (e) => n(e)
545
533
  }),
546
- /* @__PURE__ */ _(s, {
534
+ /* @__PURE__ */ y(s, {
547
535
  label: "Budget allocated",
548
536
  value: B?.budgetAllocated ?? 0,
549
537
  format: (e) => n(e)
550
538
  }),
551
- /* @__PURE__ */ _(s, {
539
+ /* @__PURE__ */ y(s, {
552
540
  label: "Budget spent",
553
541
  value: B?.budgetSpent ?? 0,
554
542
  format: (e) => n(e)
555
543
  }),
556
- /* @__PURE__ */ _(s, {
544
+ /* @__PURE__ */ y(s, {
557
545
  label: "Invoices outstanding",
558
546
  value: B?.invoicesOutstanding ?? 0,
559
547
  format: (e) => n(e)
560
548
  }),
561
- /* @__PURE__ */ _(s, {
549
+ /* @__PURE__ */ y(s, {
562
550
  label: "Outstanding invoices",
563
551
  value: B?.invoicesOutstandingCount ?? 0
564
552
  })
565
553
  ]
566
554
  }),
567
- /* @__PURE__ */ v("div", {
555
+ /* @__PURE__ */ b("div", {
568
556
  className: "grid gap-4 lg:grid-cols-2",
569
- children: [Y.length > 0 && (B?.budgetAllocated || B?.budgetSpent) ? /* @__PURE__ */ _(c, {
557
+ children: [X.length > 0 && (B?.budgetAllocated || B?.budgetSpent) ? /* @__PURE__ */ y(c, {
570
558
  title: "Budget utilization",
571
559
  subtitle: "Allocated against spend",
572
- children: /* @__PURE__ */ _(r, {
573
- data: Y,
560
+ children: /* @__PURE__ */ y(r, {
561
+ data: X,
574
562
  xKey: "metric",
575
563
  series: [{
576
564
  key: "value",
@@ -578,15 +566,15 @@ function P() {
578
566
  }],
579
567
  orientation: "horizontal",
580
568
  height: 200,
581
- valueFormat: h,
569
+ valueFormat: _,
582
570
  categoryWidth: 96,
583
571
  ariaLabel: "Budget allocated versus spent"
584
572
  })
585
- }) : null, J.length > 0 ? /* @__PURE__ */ _(c, {
573
+ }) : null, Y.length > 0 ? /* @__PURE__ */ y(c, {
586
574
  title: "Value vs depreciation",
587
575
  subtitle: "Current book value against accumulated depreciation",
588
- children: /* @__PURE__ */ _(i, {
589
- data: J,
576
+ children: /* @__PURE__ */ y(i, {
577
+ data: Y,
590
578
  centerLabel: "Original cost",
591
579
  centerValue: G + K,
592
580
  valueFormat: (e) => n(e),
@@ -597,99 +585,99 @@ function P() {
597
585
  })
598
586
  ]
599
587
  }),
600
- /* @__PURE__ */ v(D, {
588
+ /* @__PURE__ */ b(D, {
601
589
  value: "maintenance",
602
590
  className: "mt-4 space-y-4",
603
591
  children: [
604
- /* @__PURE__ */ _("div", {
592
+ /* @__PURE__ */ y("div", {
605
593
  className: "flex justify-end",
606
- children: /* @__PURE__ */ v(y, {
594
+ children: /* @__PURE__ */ b(x, {
607
595
  size: "sm",
608
- onClick: ge,
596
+ onClick: _e,
609
597
  disabled: z.length === 0,
610
- children: [/* @__PURE__ */ _(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
598
+ children: [/* @__PURE__ */ y(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
611
599
  })
612
600
  }),
613
- X.length > 0 ? /* @__PURE__ */ _(c, {
601
+ Z.length > 0 ? /* @__PURE__ */ y(c, {
614
602
  title: "Maintenance spend by type",
615
603
  subtitle: "Actual cost, falling back to estimates",
616
- children: /* @__PURE__ */ _(r, {
617
- data: X,
604
+ children: /* @__PURE__ */ y(r, {
605
+ data: Z,
618
606
  xKey: "type",
619
607
  series: [{
620
608
  key: "cost",
621
609
  label: "Spend"
622
610
  }],
623
611
  orientation: "horizontal",
624
- height: Math.max(180, X.length * 34),
625
- valueFormat: h,
612
+ height: Math.max(180, Z.length * 34),
613
+ valueFormat: _,
626
614
  categoryWidth: 128,
627
615
  ariaLabel: "Maintenance spend by type"
628
616
  })
629
617
  }) : null,
630
- /* @__PURE__ */ v(b, {
618
+ /* @__PURE__ */ b(S, {
631
619
  treatment: "glass",
632
620
  className: "overflow-hidden border-border-seam",
633
621
  children: [
634
- /* @__PURE__ */ _("div", {
622
+ /* @__PURE__ */ y("div", {
635
623
  className: "hidden overflow-x-auto md:block",
636
- children: /* @__PURE__ */ v("table", {
624
+ children: /* @__PURE__ */ b("table", {
637
625
  className: "w-full min-w-[720px] text-sm",
638
- children: [/* @__PURE__ */ _("thead", { children: /* @__PURE__ */ v("tr", {
626
+ children: [/* @__PURE__ */ y("thead", { children: /* @__PURE__ */ b("tr", {
639
627
  className: "border-b border-border-seam bg-bg-sunken/50 text-left",
640
628
  children: [
641
- /* @__PURE__ */ _("th", {
629
+ /* @__PURE__ */ y("th", {
642
630
  className: "p-3 font-medium",
643
631
  children: "Work"
644
632
  }),
645
- /* @__PURE__ */ _("th", {
633
+ /* @__PURE__ */ y("th", {
646
634
  className: "p-3 font-medium",
647
635
  children: "Asset"
648
636
  }),
649
- /* @__PURE__ */ _("th", {
637
+ /* @__PURE__ */ y("th", {
650
638
  className: "p-3 font-medium",
651
639
  children: "Type"
652
640
  }),
653
- /* @__PURE__ */ _("th", {
641
+ /* @__PURE__ */ y("th", {
654
642
  className: "p-3 font-medium",
655
643
  children: "Status"
656
644
  }),
657
- /* @__PURE__ */ _("th", {
645
+ /* @__PURE__ */ y("th", {
658
646
  className: "p-3 font-medium",
659
647
  children: "Completed"
660
648
  }),
661
- /* @__PURE__ */ _("th", {
649
+ /* @__PURE__ */ y("th", {
662
650
  className: "p-3 text-right font-medium",
663
651
  children: "Actual Cost"
664
652
  })
665
653
  ]
666
- }) }), /* @__PURE__ */ _("tbody", { children: $ ? /* @__PURE__ */ _(N, { cols: 6 }) : W.pageItems.map((e) => /* @__PURE__ */ v("tr", {
654
+ }) }), /* @__PURE__ */ y("tbody", { children: $ ? /* @__PURE__ */ y(N, { cols: 6 }) : W.pageItems.map((e) => /* @__PURE__ */ b("tr", {
667
655
  className: "border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40",
668
656
  children: [
669
- /* @__PURE__ */ _("td", {
657
+ /* @__PURE__ */ y("td", {
670
658
  className: "p-3 font-medium",
671
659
  children: e.title
672
660
  }),
673
- /* @__PURE__ */ _("td", {
661
+ /* @__PURE__ */ y("td", {
674
662
  className: "p-3",
675
663
  children: H.get(e.assetId) ?? e.assetId
676
664
  }),
677
- /* @__PURE__ */ _("td", {
665
+ /* @__PURE__ */ y("td", {
678
666
  className: "p-3 capitalize",
679
667
  children: e.type.replace(/_/g, " ")
680
668
  }),
681
- /* @__PURE__ */ _("td", {
669
+ /* @__PURE__ */ y("td", {
682
670
  className: "p-3",
683
- children: /* @__PURE__ */ _(A, {
671
+ children: /* @__PURE__ */ y(A, {
684
672
  tone: M(e.status),
685
673
  children: e.status.replace(/_/g, " ").toLowerCase()
686
674
  })
687
675
  }),
688
- /* @__PURE__ */ _("td", {
676
+ /* @__PURE__ */ y("td", {
689
677
  className: "p-3 text-xs text-text-secondary",
690
678
  children: e.completedAt ? new Date(e.completedAt).toLocaleDateString() : "—"
691
679
  }),
692
- /* @__PURE__ */ _("td", {
680
+ /* @__PURE__ */ y("td", {
693
681
  className: "p-3 text-right tabular-nums",
694
682
  children: n(e.actualCost)
695
683
  })
@@ -697,31 +685,31 @@ function P() {
697
685
  }, e.id)) })]
698
686
  })
699
687
  }),
700
- /* @__PURE__ */ _("div", {
688
+ /* @__PURE__ */ y("div", {
701
689
  className: "divide-y divide-border-seam/60 md:hidden",
702
- children: $ ? /* @__PURE__ */ _("div", {
690
+ children: $ ? /* @__PURE__ */ y("div", {
703
691
  className: "space-y-3 p-4",
704
- children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ _("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
705
- }) : W.pageItems.map((e) => /* @__PURE__ */ v("div", {
692
+ children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ y("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
693
+ }) : W.pageItems.map((e) => /* @__PURE__ */ b("div", {
706
694
  className: "p-4",
707
- children: [/* @__PURE__ */ v("div", {
695
+ children: [/* @__PURE__ */ b("div", {
708
696
  className: "flex items-start justify-between gap-2",
709
- children: [/* @__PURE__ */ _("p", {
697
+ children: [/* @__PURE__ */ y("p", {
710
698
  className: "min-w-0 flex-1 truncate font-medium",
711
699
  children: e.title
712
- }), /* @__PURE__ */ _(A, {
700
+ }), /* @__PURE__ */ y(A, {
713
701
  tone: M(e.status),
714
702
  children: e.status.replace(/_/g, " ").toLowerCase()
715
703
  })]
716
- }), /* @__PURE__ */ v("div", {
704
+ }), /* @__PURE__ */ b("div", {
717
705
  className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-text-secondary",
718
706
  children: [
719
- /* @__PURE__ */ _("span", {
707
+ /* @__PURE__ */ y("span", {
720
708
  className: "capitalize",
721
709
  children: e.type.replace(/_/g, " ")
722
710
  }),
723
- /* @__PURE__ */ v("span", { children: ["· ", H.get(e.assetId) ?? e.assetId] }),
724
- e.actualCost == null ? null : /* @__PURE__ */ _("span", {
711
+ /* @__PURE__ */ b("span", { children: ["· ", H.get(e.assetId) ?? e.assetId] }),
712
+ e.actualCost == null ? null : /* @__PURE__ */ y("span", {
725
713
  className: "ml-auto tabular-nums text-text-primary",
726
714
  children: n(e.actualCost)
727
715
  })
@@ -729,13 +717,13 @@ function P() {
729
717
  })]
730
718
  }, e.id))
731
719
  }),
732
- z.length === 0 && !L ? /* @__PURE__ */ _(S, {
720
+ z.length === 0 && !L ? /* @__PURE__ */ y(w, {
733
721
  illustration: "empty-data",
734
722
  title: "No maintenance records",
735
723
  description: "Logged maintenance work will appear here once scheduled or completed."
736
- }) : /* @__PURE__ */ _("div", {
724
+ }) : /* @__PURE__ */ y("div", {
737
725
  className: "px-3",
738
- children: /* @__PURE__ */ _(a, {
726
+ children: /* @__PURE__ */ y(a, {
739
727
  page: W.page,
740
728
  pageCount: W.pageCount,
741
729
  rangeStart: W.rangeStart,
@@ -752,39 +740,39 @@ function P() {
752
740
  })
753
741
  ]
754
742
  }),
755
- /* @__PURE__ */ v(D, {
743
+ /* @__PURE__ */ b(D, {
756
744
  value: "utilization",
757
745
  className: "mt-4 space-y-4",
758
746
  children: [
759
- /* @__PURE__ */ _("div", {
747
+ /* @__PURE__ */ y("div", {
760
748
  className: "flex justify-end",
761
- children: /* @__PURE__ */ v(y, {
749
+ children: /* @__PURE__ */ b(x, {
762
750
  size: "sm",
763
- onClick: ve,
751
+ onClick: ye,
764
752
  disabled: !V,
765
- children: [/* @__PURE__ */ _(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
753
+ children: [/* @__PURE__ */ y(d, { className: "mr-2 h-4 w-4" }), "Export CSV"]
766
754
  })
767
755
  }),
768
- /* @__PURE__ */ v("div", {
756
+ /* @__PURE__ */ b("div", {
769
757
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-5",
770
758
  children: [
771
- /* @__PURE__ */ _(s, {
759
+ /* @__PURE__ */ y(s, {
772
760
  label: "Total assets",
773
761
  value: V?.totalAssets ?? 0
774
762
  }),
775
- /* @__PURE__ */ _(s, {
763
+ /* @__PURE__ */ y(s, {
776
764
  label: "Assigned",
777
765
  value: V?.assignedAssets ?? 0
778
766
  }),
779
- /* @__PURE__ */ _(s, {
767
+ /* @__PURE__ */ y(s, {
780
768
  label: "Unassigned",
781
769
  value: V?.unassignedAssets ?? 0
782
770
  }),
783
- /* @__PURE__ */ _(s, {
784
- label: "Idle",
771
+ /* @__PURE__ */ y(s, {
772
+ label: "Active unassigned",
785
773
  value: V?.idleAssets ?? 0
786
774
  }),
787
- /* @__PURE__ */ _(s, {
775
+ /* @__PURE__ */ y(s, {
788
776
  label: "Overdue assignments",
789
777
  value: V?.overdueAssignments ?? 0,
790
778
  delta: V && V.overdueAssignments > 0 ? "Attention" : void 0,
@@ -792,23 +780,23 @@ function P() {
792
780
  })
793
781
  ]
794
782
  }),
795
- /* @__PURE__ */ v("div", {
783
+ /* @__PURE__ */ b("div", {
796
784
  className: "grid gap-4 lg:grid-cols-2",
797
- children: [/* @__PURE__ */ _(c, {
785
+ children: [/* @__PURE__ */ y(c, {
798
786
  title: "Assets by status",
799
787
  subtitle: "Distribution across lifecycle states",
800
- children: /* @__PURE__ */ _(i, {
801
- data: me,
788
+ children: /* @__PURE__ */ y(i, {
789
+ data: J,
802
790
  centerLabel: "Assets",
803
791
  centerValue: V?.totalAssets ?? 0,
804
792
  height: 240,
805
793
  emptyLabel: "No status data available.",
806
794
  ariaLabel: "Assets by status"
807
795
  })
808
- }), /* @__PURE__ */ _(c, {
796
+ }), /* @__PURE__ */ y(c, {
809
797
  title: "Assignment coverage",
810
- subtitle: "Assigned, unassigned and idle assets",
811
- children: /* @__PURE__ */ _(i, {
798
+ subtitle: "Mutually exclusive assigned, active-unassigned and other-unassigned assets",
799
+ children: /* @__PURE__ */ y(i, {
812
800
  data: he,
813
801
  centerLabel: "Assets",
814
802
  centerValue: V?.totalAssets ?? 0,
@@ -1 +1 @@
1
- {"version":3,"file":"ReportsDashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport {\n Button,\n GlassCard,\n GradientText,\n PagePurpose,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Download,\n Printer,\n FileBarChart2,\n Wallet,\n Wrench,\n Activity,\n DollarSign,\n TrendingDown,\n Percent,\n} from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n StatTile,\n ChartCard,\n BarsChart,\n DonutChart,\n type DonutSlice,\n} from '../components';\nimport { downloadCsv } from '../utils/csv';\nimport { cn } from '../utils/cn';\n\n// ─── Query result shapes ──────────────────────────────────────────\ninterface RegisterAsset {\n id: string;\n assetNumber: string;\n name: string;\n category: string;\n status: string;\n department?: string | null;\n purchaseValue?: number | null;\n currentValue?: number | null;\n accumulatedDepreciation?: number | null;\n totalCostOfOwnership?: number | null;\n purchaseDate?: string | null;\n}\n\ninterface FinancialSummary {\n totalAssetValue: number;\n totalDepreciation: number;\n totalMaintenanceSpend: number;\n budgetAllocated: number;\n budgetSpent: number;\n invoicesOutstanding: number;\n invoicesOutstandingCount: number;\n transactionExpense: number;\n}\n\ninterface MaintenanceLogRecord {\n id: string;\n assetId: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n scheduledAt?: string | null;\n completedAt?: string | null;\n estimatedCost?: number | null;\n actualCost?: number | null;\n}\n\ninterface UtilizationReport {\n totalAssets: number;\n assignedAssets: number;\n unassignedAssets: number;\n idleAssets: number;\n overdueAssignments: number;\n byStatus: { status: string; count: number }[];\n}\n\nconst REPORTS_QUERY = gql`\n query AssetHandlerReports($registerFilter: AssetRegisterFilterInput) {\n assetRegister(filter: $registerFilter, pagination: { limit: 1000 }) {\n id\n assetNumber\n name\n category\n status\n department\n purchaseValue\n currentValue\n accumulatedDepreciation\n totalCostOfOwnership\n purchaseDate\n }\n financialSummary {\n totalAssetValue\n totalDepreciation\n totalMaintenanceSpend\n budgetAllocated\n budgetSpent\n invoicesOutstanding\n invoicesOutstandingCount\n transactionExpense\n }\n maintenanceLog(pagination: { limit: 1000 }) {\n id\n assetId\n title\n type\n status\n priority\n scheduledAt\n completedAt\n estimatedCost\n actualCost\n }\n utilizationReport {\n totalAssets\n assignedAssets\n unassignedAssets\n idleAssets\n overdueAssignments\n byStatus {\n status\n count\n }\n }\n }\n`;\n\ninterface ReportsResult {\n assetRegister: RegisterAsset[];\n financialSummary: FinancialSummary;\n maintenanceLog: MaintenanceLogRecord[];\n utilizationReport: UtilizationReport;\n}\n\nconst ASSET_STATUSES = ['ACTIVE', 'INACTIVE', 'MAINTENANCE', 'RETIRED', 'DISPOSED'] as const;\n\n// ─── Presentation helpers ─────────────────────────────────────────\ntype Tone = 'success' | 'warning' | 'error' | 'info' | 'neutral';\n\nconst PILL_TONE: Record<Tone, string> = {\n success: 'bg-status-success-subtle text-status-success-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n error: 'bg-status-error-subtle text-status-error-text',\n info: 'bg-status-info-subtle text-status-info-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n};\n\nfunction StatusPill({ tone, children }: { tone: Tone; children: ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize',\n PILL_TONE[tone]\n )}\n >\n {children}\n </span>\n );\n}\n\nconst assetStatusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'active') return 'success';\n if (s === 'maintenance') return 'warning';\n if (s === 'retired' || s === 'disposed') return 'error';\n return 'neutral';\n};\n\nconst maintenanceStatusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'completed') return 'success';\n if (s === 'in_progress' || s === 'scheduled') return 'info';\n if (s === 'overdue' || s === 'cancelled') return 'error';\n return 'neutral';\n};\n\nfunction SkeletonRows({ rows = 6, cols }: { rows?: number; cols: number }) {\n return (\n <>\n {Array.from({ length: rows }).map((_, r) => (\n <tr key={r} className=\"border-b border-border-seam/60\">\n {Array.from({ length: cols }).map((_, c) => (\n <td key={c} className=\"p-3\">\n <div className=\"h-4 w-full max-w-[120px] animate-pulse rounded bg-bg-sunken\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n );\n}\n\nexport function ReportsDashboardPage() {\n const { format: money, compact: compactUsd } = useAssetMoney();\n const { assets } = useAssetHandlerStore();\n const [statusFilter, setStatusFilter] = useState<string>('all');\n\n const { data, loading } = useQuery<ReportsResult>(REPORTS_QUERY, {\n variables: {\n registerFilter: statusFilter === 'all' ? null : { status: statusFilter },\n },\n fetchPolicy: 'cache-and-network',\n errorPolicy: 'all',\n });\n\n const register = useMemo(() => data?.assetRegister ?? [], [data]);\n const maintenance = useMemo(() => data?.maintenanceLog ?? [], [data]);\n const summary = data?.financialSummary;\n const utilization = data?.utilizationReport;\n\n const assetNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const asset of assets) map.set(asset.id, asset.name);\n return map;\n }, [assets]);\n\n const registerPage = usePagination(register, { pageSize: 12, resetKey: statusFilter });\n const maintenancePage = usePagination(maintenance, { pageSize: 12 });\n\n // ─── Header KPI figures (real, from financialSummary) ───\n const totalAssetValue = summary?.totalAssetValue ?? 0;\n const totalDepreciation = summary?.totalDepreciation ?? 0;\n const depreciationPct =\n totalAssetValue + totalDepreciation > 0\n ? (totalDepreciation / (totalAssetValue + totalDepreciation)) * 100\n : 0;\n\n // ─── Chart aggregations (real data only) ───\n const categoryValue = useMemo(() => {\n const map = new Map<string, number>();\n for (const a of register) {\n const value = a.currentValue ?? a.purchaseValue ?? 0;\n if (value > 0) {\n const key = a.category.replace(/_/g, ' ');\n map.set(key, (map.get(key) ?? 0) + value);\n }\n }\n return Array.from(map, ([category, value]) => ({ category, value }))\n .sort((a, b) => b.value - a.value)\n .slice(0, 12);\n }, [register]);\n\n const statusSlices = useMemo<DonutSlice[]>(\n () =>\n (utilization?.byStatus ?? [])\n .map((s) => ({ name: s.status.toLowerCase(), value: s.count }))\n .filter((s) => s.value > 0),\n [utilization]\n );\n\n const coverageSlices = useMemo<DonutSlice[]>(() => {\n if (!utilization) return [];\n return [\n { name: 'Assigned', value: utilization.assignedAssets },\n { name: 'Unassigned', value: utilization.unassignedAssets },\n { name: 'Idle', value: utilization.idleAssets },\n ].filter((s) => s.value > 0);\n }, [utilization]);\n\n const valueSlices = useMemo<DonutSlice[]>(() => {\n const slices = [\n { name: 'Current value', value: totalAssetValue },\n { name: 'Accumulated depreciation', value: totalDepreciation },\n ].filter((s) => s.value > 0);\n return slices;\n }, [totalAssetValue, totalDepreciation]);\n\n const budgetBars = useMemo(() => {\n if (!summary) return [];\n return [\n { metric: 'Allocated', value: summary.budgetAllocated },\n { metric: 'Spent', value: summary.budgetSpent },\n ];\n }, [summary]);\n\n const maintenanceSpendByType = useMemo(() => {\n const map = new Map<string, number>();\n for (const m of maintenance) {\n const cost = m.actualCost ?? m.estimatedCost ?? 0;\n if (cost > 0) {\n const key = m.type.replace(/_/g, ' ');\n map.set(key, (map.get(key) ?? 0) + cost);\n }\n }\n return Array.from(map, (entry) => ({ type: entry[0], cost: entry[1] })).sort(\n (a, b) => b.cost - a.cost\n );\n }, [maintenance]);\n\n // ─── Exports (unchanged behaviour) ───\n const exportRegister = () => {\n downloadCsv(\n `asset-register-${new Date().toISOString().slice(0, 10)}`,\n [\n 'Asset Number',\n 'Name',\n 'Category',\n 'Status',\n 'Department',\n 'Purchase Value',\n 'Current Value',\n 'Accumulated Depreciation',\n 'Total Cost of Ownership',\n 'Purchase Date',\n ],\n register.map((a) => [\n a.assetNumber,\n a.name,\n a.category,\n a.status,\n a.department ?? '',\n a.purchaseValue ?? '',\n a.currentValue ?? '',\n a.accumulatedDepreciation ?? '',\n a.totalCostOfOwnership ?? '',\n a.purchaseDate ? new Date(a.purchaseDate).toISOString().slice(0, 10) : '',\n ])\n );\n };\n\n const exportMaintenance = () => {\n downloadCsv(\n `maintenance-log-${new Date().toISOString().slice(0, 10)}`,\n [\n 'Title',\n 'Asset',\n 'Type',\n 'Status',\n 'Priority',\n 'Scheduled',\n 'Completed',\n 'Estimated Cost',\n 'Actual Cost',\n ],\n maintenance.map((m) => [\n m.title,\n assetNameById.get(m.assetId) ?? m.assetId,\n m.type,\n m.status,\n m.priority,\n m.scheduledAt ? new Date(m.scheduledAt).toISOString().slice(0, 10) : '',\n m.completedAt ? new Date(m.completedAt).toISOString().slice(0, 10) : '',\n m.estimatedCost ?? '',\n m.actualCost ?? '',\n ])\n );\n };\n\n const exportFinancial = () => {\n if (!summary) return;\n downloadCsv(\n `financial-summary-${new Date().toISOString().slice(0, 10)}`,\n ['Metric', 'Value'],\n [\n ['Total asset value', summary.totalAssetValue],\n ['Total depreciation', summary.totalDepreciation],\n ['Total maintenance spend', summary.totalMaintenanceSpend],\n ['Budget allocated', summary.budgetAllocated],\n ['Budget spent', summary.budgetSpent],\n ['Invoices outstanding', summary.invoicesOutstanding],\n ['Invoices outstanding (count)', summary.invoicesOutstandingCount],\n ['Transaction expense', summary.transactionExpense],\n ]\n );\n };\n\n const exportUtilization = () => {\n if (!utilization) return;\n downloadCsv(\n `utilization-report-${new Date().toISOString().slice(0, 10)}`,\n ['Metric', 'Value'],\n [\n ['Total assets', utilization.totalAssets],\n ['Assigned assets', utilization.assignedAssets],\n ['Unassigned assets', utilization.unassignedAssets],\n ['Idle assets', utilization.idleAssets],\n ['Overdue assignments', utilization.overdueAssignments],\n ...utilization.byStatus.map((s): [string, number] => [`Status: ${s.status}`, s.count]),\n ]\n );\n };\n\n const registerLoading = loading && register.length === 0;\n const maintenanceLoading = loading && maintenance.length === 0;\n\n const registerActions = (\n <>\n <Button size=\"sm\" onClick={exportRegister} disabled={register.length === 0}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => window.print()}>\n <Printer className=\"mr-2 h-4 w-4\" />\n Print\n </Button>\n </>\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n {/* ─── Header with persistent finance KPI strip ─── */}\n <div className=\"flex flex-col gap-5 xl:flex-row xl:items-end xl:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold sm:text-3xl\">\n <GradientText>Reports</GradientText>\n </h1>\n <p className=\"mt-1 max-w-xl text-sm text-text-secondary\">\n Registers and summaries built from live asset, finance and maintenance data.\n </p>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatTile\n label=\"Total asset value\"\n value={totalAssetValue}\n format={(v) => money(v)}\n icon={DollarSign}\n hero\n />\n <StatTile\n label=\"Total depreciation\"\n value={totalDepreciation}\n format={(v) => money(v)}\n icon={TrendingDown}\n />\n <StatTile\n label=\"Depreciated\"\n value={depreciationPct}\n format={(v) => `${v.toFixed(2)}%`}\n icon={Percent}\n />\n </div>\n </div>\n\n <PagePurpose>\n Pull the numbers you need for audits, finance reviews and planning. Every register below is\n generated from live records — export any of them to CSV or print the page for sign-off.\n </PagePurpose>\n\n <Tabs defaultValue=\"register\">\n <TabsList className=\"max-w-full justify-start overflow-x-auto\">\n <TabsTrigger value=\"register\">\n <FileBarChart2 className=\"mr-1.5 h-4 w-4\" />\n Asset Register\n </TabsTrigger>\n <TabsTrigger value=\"financial\">\n <Wallet className=\"mr-1.5 h-4 w-4\" />\n Financial Summary\n </TabsTrigger>\n <TabsTrigger value=\"maintenance\">\n <Wrench className=\"mr-1.5 h-4 w-4\" />\n Maintenance Log\n </TabsTrigger>\n <TabsTrigger value=\"utilization\">\n <Activity className=\"mr-1.5 h-4 w-4\" />\n Utilization\n </TabsTrigger>\n </TabsList>\n\n {/* ─── Asset Register ─── */}\n <TabsContent value=\"register\" className=\"mt-4 space-y-4\">\n {categoryValue.length > 0 ? (\n <ChartCard\n title=\"Asset value by category\"\n subtitle=\"Current book value aggregated from the register\"\n >\n <BarsChart\n data={categoryValue}\n xKey=\"category\"\n series={[{ key: 'value', label: 'Current value' }]}\n orientation=\"horizontal\"\n height={Math.max(200, categoryValue.length * 34)}\n valueFormat={compactUsd}\n categoryWidth={128}\n ariaLabel=\"Current asset value by category\"\n />\n </ChartCard>\n ) : null}\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n <div className=\"flex flex-col gap-3 border-b border-border-seam p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <h3 className=\"text-base font-semibold text-text-primary\">Asset Register</h3>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"h-8 w-40\">\n <SelectValue placeholder=\"Filter by status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n {ASSET_STATUSES.map((status) => (\n <SelectItem key={status} value={status} className=\"capitalize\">\n {status.toLowerCase()}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-wrap gap-2\">{registerActions}</div>\n </div>\n\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-left\">\n <th className=\"p-3 font-medium\">Asset</th>\n <th className=\"p-3 font-medium\">Category</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Department</th>\n <th className=\"p-3 text-right font-medium\">Purchase</th>\n <th className=\"p-3 text-right font-medium\">Current</th>\n <th className=\"p-3 text-right font-medium\">Depreciation</th>\n <th className=\"p-3 text-right font-medium\">TCO</th>\n </tr>\n </thead>\n <tbody>\n {registerLoading ? (\n <SkeletonRows cols={8} />\n ) : (\n registerPage.pageItems.map((a) => (\n <tr\n key={a.id}\n className=\"border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40\"\n >\n <td className=\"p-3\">\n <p className=\"font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetNumber}</p>\n </td>\n <td className=\"p-3 capitalize\">{a.category.replace(/_/g, ' ')}</td>\n <td className=\"p-3\">\n <StatusPill tone={assetStatusTone(a.status)}>\n {a.status.toLowerCase()}\n </StatusPill>\n </td>\n <td className=\"p-3\">{a.department || '—'}</td>\n <td className=\"p-3 text-right tabular-nums\">{money(a.purchaseValue)}</td>\n <td className=\"p-3 text-right tabular-nums\">{money(a.currentValue)}</td>\n <td className=\"p-3 text-right tabular-nums\">\n {money(a.accumulatedDepreciation)}\n </td>\n <td className=\"p-3 text-right tabular-nums\">\n {money(a.totalCostOfOwnership)}\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* Mobile cards */}\n <div className=\"divide-y divide-border-seam/60 md:hidden\">\n {registerLoading ? (\n <div className=\"space-y-3 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 animate-pulse rounded bg-bg-sunken\" />\n ))}\n </div>\n ) : (\n registerPage.pageItems.map((a) => (\n <div key={a.id} className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetNumber}</p>\n </div>\n <StatusPill tone={assetStatusTone(a.status)}>\n {a.status.toLowerCase()}\n </StatusPill>\n </div>\n <div className=\"mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <span>Category</span>\n <span className=\"text-right capitalize text-text-primary\">\n {a.category.replace(/_/g, ' ')}\n </span>\n <span>Current value</span>\n <span className=\"text-right tabular-nums text-text-primary\">\n {money(a.currentValue)}\n </span>\n <span>Depreciation</span>\n <span className=\"text-right tabular-nums text-text-primary\">\n {money(a.accumulatedDepreciation)}\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n\n {register.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets in the register\"\n description=\"Register assets with financial details and they will appear here.\"\n />\n ) : (\n <div className=\"px-3\">\n <Pagination\n page={registerPage.page}\n pageCount={registerPage.pageCount}\n rangeStart={registerPage.rangeStart}\n rangeEnd={registerPage.rangeEnd}\n totalItems={registerPage.totalItems}\n canPrev={registerPage.canPrev}\n canNext={registerPage.canNext}\n onPrev={registerPage.prevPage}\n onNext={registerPage.nextPage}\n itemLabel=\"assets\"\n />\n </div>\n )}\n </GlassCard>\n </TabsContent>\n\n {/* ─── Financial Summary ─── */}\n <TabsContent value=\"financial\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportFinancial} disabled={!summary}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile label=\"Total asset value\" value={totalAssetValue} format={(v) => money(v)} />\n <StatTile\n label=\"Total depreciation\"\n value={totalDepreciation}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Maintenance spend\"\n value={summary?.totalMaintenanceSpend ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Transaction expense\"\n value={summary?.transactionExpense ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Budget allocated\"\n value={summary?.budgetAllocated ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Budget spent\"\n value={summary?.budgetSpent ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Invoices outstanding\"\n value={summary?.invoicesOutstanding ?? 0}\n format={(v) => money(v)}\n />\n <StatTile label=\"Outstanding invoices\" value={summary?.invoicesOutstandingCount ?? 0} />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n {budgetBars.length > 0 && (summary?.budgetAllocated || summary?.budgetSpent) ? (\n <ChartCard title=\"Budget utilization\" subtitle=\"Allocated against spend\">\n <BarsChart\n data={budgetBars}\n xKey=\"metric\"\n series={[{ key: 'value', label: 'Amount' }]}\n orientation=\"horizontal\"\n height={200}\n valueFormat={compactUsd}\n categoryWidth={96}\n ariaLabel=\"Budget allocated versus spent\"\n />\n </ChartCard>\n ) : null}\n {valueSlices.length > 0 ? (\n <ChartCard\n title=\"Value vs depreciation\"\n subtitle=\"Current book value against accumulated depreciation\"\n >\n <DonutChart\n data={valueSlices}\n centerLabel=\"Original cost\"\n centerValue={totalAssetValue + totalDepreciation}\n valueFormat={(v) => money(v)}\n height={220}\n ariaLabel=\"Current value versus accumulated depreciation\"\n />\n </ChartCard>\n ) : null}\n </div>\n </TabsContent>\n\n {/* ─── Maintenance Log ─── */}\n <TabsContent value=\"maintenance\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportMaintenance} disabled={maintenance.length === 0}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n\n {maintenanceSpendByType.length > 0 ? (\n <ChartCard\n title=\"Maintenance spend by type\"\n subtitle=\"Actual cost, falling back to estimates\"\n >\n <BarsChart\n data={maintenanceSpendByType}\n xKey=\"type\"\n series={[{ key: 'cost', label: 'Spend' }]}\n orientation=\"horizontal\"\n height={Math.max(180, maintenanceSpendByType.length * 34)}\n valueFormat={compactUsd}\n categoryWidth={128}\n ariaLabel=\"Maintenance spend by type\"\n />\n </ChartCard>\n ) : null}\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[720px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-left\">\n <th className=\"p-3 font-medium\">Work</th>\n <th className=\"p-3 font-medium\">Asset</th>\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Completed</th>\n <th className=\"p-3 text-right font-medium\">Actual Cost</th>\n </tr>\n </thead>\n <tbody>\n {maintenanceLoading ? (\n <SkeletonRows cols={6} />\n ) : (\n maintenancePage.pageItems.map((m) => (\n <tr\n key={m.id}\n className=\"border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40\"\n >\n <td className=\"p-3 font-medium\">{m.title}</td>\n <td className=\"p-3\">{assetNameById.get(m.assetId) ?? m.assetId}</td>\n <td className=\"p-3 capitalize\">{m.type.replace(/_/g, ' ')}</td>\n <td className=\"p-3\">\n <StatusPill tone={maintenanceStatusTone(m.status)}>\n {m.status.replace(/_/g, ' ').toLowerCase()}\n </StatusPill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {m.completedAt ? new Date(m.completedAt).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3 text-right tabular-nums\">{money(m.actualCost)}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* Mobile cards */}\n <div className=\"divide-y divide-border-seam/60 md:hidden\">\n {maintenanceLoading ? (\n <div className=\"space-y-3 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 animate-pulse rounded bg-bg-sunken\" />\n ))}\n </div>\n ) : (\n maintenancePage.pageItems.map((m) => (\n <div key={m.id} className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"min-w-0 flex-1 truncate font-medium\">{m.title}</p>\n <StatusPill tone={maintenanceStatusTone(m.status)}>\n {m.status.replace(/_/g, ' ').toLowerCase()}\n </StatusPill>\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span className=\"capitalize\">{m.type.replace(/_/g, ' ')}</span>\n <span>· {assetNameById.get(m.assetId) ?? m.assetId}</span>\n {m.actualCost != null ? (\n <span className=\"ml-auto tabular-nums text-text-primary\">\n {money(m.actualCost)}\n </span>\n ) : null}\n </div>\n </div>\n ))\n )}\n </div>\n\n {maintenance.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No maintenance records\"\n description=\"Logged maintenance work will appear here once scheduled or completed.\"\n />\n ) : (\n <div className=\"px-3\">\n <Pagination\n page={maintenancePage.page}\n pageCount={maintenancePage.pageCount}\n rangeStart={maintenancePage.rangeStart}\n rangeEnd={maintenancePage.rangeEnd}\n totalItems={maintenancePage.totalItems}\n canPrev={maintenancePage.canPrev}\n canNext={maintenancePage.canNext}\n onPrev={maintenancePage.prevPage}\n onNext={maintenancePage.nextPage}\n itemLabel=\"records\"\n />\n </div>\n )}\n </GlassCard>\n </TabsContent>\n\n {/* ─── Utilization ─── */}\n <TabsContent value=\"utilization\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportUtilization} disabled={!utilization}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-5\">\n <StatTile label=\"Total assets\" value={utilization?.totalAssets ?? 0} />\n <StatTile label=\"Assigned\" value={utilization?.assignedAssets ?? 0} />\n <StatTile label=\"Unassigned\" value={utilization?.unassignedAssets ?? 0} />\n <StatTile label=\"Idle\" value={utilization?.idleAssets ?? 0} />\n <StatTile\n label=\"Overdue assignments\"\n value={utilization?.overdueAssignments ?? 0}\n delta={utilization && utilization.overdueAssignments > 0 ? 'Attention' : undefined}\n deltaTone=\"negative\"\n />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Assets by status\" subtitle=\"Distribution across lifecycle states\">\n <DonutChart\n data={statusSlices}\n centerLabel=\"Assets\"\n centerValue={utilization?.totalAssets ?? 0}\n height={240}\n emptyLabel=\"No status data available.\"\n ariaLabel=\"Assets by status\"\n />\n </ChartCard>\n <ChartCard title=\"Assignment coverage\" subtitle=\"Assigned, unassigned and idle assets\">\n <DonutChart\n data={coverageSlices}\n centerLabel=\"Assets\"\n centerValue={utilization?.totalAssets ?? 0}\n height={240}\n emptyLabel=\"No coverage data available.\"\n ariaLabel=\"Assignment coverage\"\n />\n </ChartCard>\n </div>\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReportsDashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"sourcesContent":["import { useMemo, useState, type ReactNode } from 'react';\nimport { useAssetMoney } from '../providers/AssetHandlerProvider';\nimport {\n Button,\n GlassCard,\n GradientText,\n PagePurpose,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Download,\n Printer,\n FileBarChart2,\n Wallet,\n Wrench,\n Activity,\n DollarSign,\n TrendingDown,\n Percent,\n} from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n StatTile,\n ChartCard,\n BarsChart,\n DonutChart,\n type DonutSlice,\n} from '../components';\nimport { downloadCsv } from '../utils/csv';\nimport { cn } from '../utils/cn';\nimport { buildAssignmentCoverageSlices } from '../utils/utilization';\n\n// ─── Query result shapes ──────────────────────────────────────────\ninterface RegisterAsset {\n id: string;\n assetNumber: string;\n name: string;\n category: string;\n status: string;\n department?: string | null;\n purchaseValue?: number | null;\n currentValue?: number | null;\n accumulatedDepreciation?: number | null;\n totalCostOfOwnership?: number | null;\n purchaseDate?: string | null;\n}\n\ninterface FinancialSummary {\n totalAssetValue: number;\n totalDepreciation: number;\n totalMaintenanceSpend: number;\n budgetAllocated: number;\n budgetSpent: number;\n invoicesOutstanding: number;\n invoicesOutstandingCount: number;\n transactionExpense: number;\n}\n\ninterface MaintenanceLogRecord {\n id: string;\n assetId: string;\n title: string;\n type: string;\n status: string;\n priority: string;\n scheduledAt?: string | null;\n completedAt?: string | null;\n estimatedCost?: number | null;\n actualCost?: number | null;\n}\n\ninterface UtilizationReport {\n totalAssets: number;\n assignedAssets: number;\n unassignedAssets: number;\n idleAssets: number;\n overdueAssignments: number;\n byStatus: { status: string; count: number }[];\n}\n\nconst REPORTS_QUERY = gql`\n query AssetHandlerReports($registerFilter: AssetRegisterFilterInput) {\n assetRegister(filter: $registerFilter, pagination: { limit: 1000 }) {\n id\n assetNumber\n name\n category\n status\n department\n purchaseValue\n currentValue\n accumulatedDepreciation\n totalCostOfOwnership\n purchaseDate\n }\n financialSummary {\n totalAssetValue\n totalDepreciation\n totalMaintenanceSpend\n budgetAllocated\n budgetSpent\n invoicesOutstanding\n invoicesOutstandingCount\n transactionExpense\n }\n maintenanceLog(pagination: { limit: 1000 }) {\n id\n assetId\n title\n type\n status\n priority\n scheduledAt\n completedAt\n estimatedCost\n actualCost\n }\n utilizationReport {\n totalAssets\n assignedAssets\n unassignedAssets\n idleAssets\n overdueAssignments\n byStatus {\n status\n count\n }\n }\n }\n`;\n\ninterface ReportsResult {\n assetRegister: RegisterAsset[];\n financialSummary: FinancialSummary;\n maintenanceLog: MaintenanceLogRecord[];\n utilizationReport: UtilizationReport;\n}\n\nconst ASSET_STATUSES = ['ACTIVE', 'INACTIVE', 'MAINTENANCE', 'RETIRED', 'DISPOSED'] as const;\n\n// ─── Presentation helpers ─────────────────────────────────────────\ntype Tone = 'success' | 'warning' | 'error' | 'info' | 'neutral';\n\nconst PILL_TONE: Record<Tone, string> = {\n success: 'bg-status-success-subtle text-status-success-text',\n warning: 'bg-status-warning-subtle text-status-warning-text',\n error: 'bg-status-error-subtle text-status-error-text',\n info: 'bg-status-info-subtle text-status-info-text',\n neutral: 'bg-bg-sunken text-text-secondary',\n};\n\nfunction StatusPill({ tone, children }: { tone: Tone; children: ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize',\n PILL_TONE[tone]\n )}\n >\n {children}\n </span>\n );\n}\n\nconst assetStatusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'active') return 'success';\n if (s === 'maintenance') return 'warning';\n if (s === 'retired' || s === 'disposed') return 'error';\n return 'neutral';\n};\n\nconst maintenanceStatusTone = (status: string): Tone => {\n const s = status.toLowerCase();\n if (s === 'completed') return 'success';\n if (s === 'in_progress' || s === 'scheduled') return 'info';\n if (s === 'overdue' || s === 'cancelled') return 'error';\n return 'neutral';\n};\n\nfunction SkeletonRows({ rows = 6, cols }: { rows?: number; cols: number }) {\n return (\n <>\n {Array.from({ length: rows }).map((_, r) => (\n <tr key={r} className=\"border-b border-border-seam/60\">\n {Array.from({ length: cols }).map((_, c) => (\n <td key={c} className=\"p-3\">\n <div className=\"h-4 w-full max-w-[120px] animate-pulse rounded bg-bg-sunken\" />\n </td>\n ))}\n </tr>\n ))}\n </>\n );\n}\n\nexport function ReportsDashboardPage() {\n const { format: money, compact: compactUsd } = useAssetMoney();\n const { assets } = useAssetHandlerStore();\n const [statusFilter, setStatusFilter] = useState<string>('all');\n\n const { data, loading } = useQuery<ReportsResult>(REPORTS_QUERY, {\n variables: {\n registerFilter: statusFilter === 'all' ? null : { status: statusFilter },\n },\n fetchPolicy: 'cache-and-network',\n errorPolicy: 'all',\n });\n\n const register = useMemo(() => data?.assetRegister ?? [], [data]);\n const maintenance = useMemo(() => data?.maintenanceLog ?? [], [data]);\n const summary = data?.financialSummary;\n const utilization = data?.utilizationReport;\n\n const assetNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const asset of assets) map.set(asset.id, asset.name);\n return map;\n }, [assets]);\n\n const registerPage = usePagination(register, { pageSize: 12, resetKey: statusFilter });\n const maintenancePage = usePagination(maintenance, { pageSize: 12 });\n\n // ─── Header KPI figures (real, from financialSummary) ───\n const totalAssetValue = summary?.totalAssetValue ?? 0;\n const totalDepreciation = summary?.totalDepreciation ?? 0;\n const depreciationPct =\n totalAssetValue + totalDepreciation > 0\n ? (totalDepreciation / (totalAssetValue + totalDepreciation)) * 100\n : 0;\n\n // ─── Chart aggregations (real data only) ───\n const categoryValue = useMemo(() => {\n const map = new Map<string, number>();\n for (const a of register) {\n const value = a.currentValue ?? a.purchaseValue ?? 0;\n if (value > 0) {\n const key = a.category.replace(/_/g, ' ');\n map.set(key, (map.get(key) ?? 0) + value);\n }\n }\n return Array.from(map, ([category, value]) => ({ category, value }))\n .sort((a, b) => b.value - a.value)\n .slice(0, 12);\n }, [register]);\n\n const statusSlices = useMemo<DonutSlice[]>(\n () =>\n (utilization?.byStatus ?? [])\n .map((s) => ({ name: s.status.toLowerCase(), value: s.count }))\n .filter((s) => s.value > 0),\n [utilization]\n );\n\n const coverageSlices = useMemo<DonutSlice[]>(() => {\n if (!utilization) return [];\n return buildAssignmentCoverageSlices(\n utilization.assignedAssets,\n utilization.unassignedAssets,\n utilization.idleAssets\n );\n }, [utilization]);\n\n const valueSlices = useMemo<DonutSlice[]>(() => {\n const slices = [\n { name: 'Current value', value: totalAssetValue },\n { name: 'Accumulated depreciation', value: totalDepreciation },\n ].filter((s) => s.value > 0);\n return slices;\n }, [totalAssetValue, totalDepreciation]);\n\n const budgetBars = useMemo(() => {\n if (!summary) return [];\n return [\n { metric: 'Allocated', value: summary.budgetAllocated },\n { metric: 'Spent', value: summary.budgetSpent },\n ];\n }, [summary]);\n\n const maintenanceSpendByType = useMemo(() => {\n const map = new Map<string, number>();\n for (const m of maintenance) {\n const cost = m.actualCost ?? m.estimatedCost ?? 0;\n if (cost > 0) {\n const key = m.type.replace(/_/g, ' ');\n map.set(key, (map.get(key) ?? 0) + cost);\n }\n }\n return Array.from(map, (entry) => ({ type: entry[0], cost: entry[1] })).sort(\n (a, b) => b.cost - a.cost\n );\n }, [maintenance]);\n\n // ─── Exports (unchanged behaviour) ───\n const exportRegister = () => {\n downloadCsv(\n `asset-register-${new Date().toISOString().slice(0, 10)}`,\n [\n 'Asset Number',\n 'Name',\n 'Category',\n 'Status',\n 'Department',\n 'Purchase Value',\n 'Current Value',\n 'Accumulated Depreciation',\n 'Total Cost of Ownership',\n 'Purchase Date',\n ],\n register.map((a) => [\n a.assetNumber,\n a.name,\n a.category,\n a.status,\n a.department ?? '',\n a.purchaseValue ?? '',\n a.currentValue ?? '',\n a.accumulatedDepreciation ?? '',\n a.totalCostOfOwnership ?? '',\n a.purchaseDate ? new Date(a.purchaseDate).toISOString().slice(0, 10) : '',\n ])\n );\n };\n\n const exportMaintenance = () => {\n downloadCsv(\n `maintenance-log-${new Date().toISOString().slice(0, 10)}`,\n [\n 'Title',\n 'Asset',\n 'Type',\n 'Status',\n 'Priority',\n 'Scheduled',\n 'Completed',\n 'Estimated Cost',\n 'Actual Cost',\n ],\n maintenance.map((m) => [\n m.title,\n assetNameById.get(m.assetId) ?? m.assetId,\n m.type,\n m.status,\n m.priority,\n m.scheduledAt ? new Date(m.scheduledAt).toISOString().slice(0, 10) : '',\n m.completedAt ? new Date(m.completedAt).toISOString().slice(0, 10) : '',\n m.estimatedCost ?? '',\n m.actualCost ?? '',\n ])\n );\n };\n\n const exportFinancial = () => {\n if (!summary) return;\n downloadCsv(\n `financial-summary-${new Date().toISOString().slice(0, 10)}`,\n ['Metric', 'Value'],\n [\n ['Total asset value', summary.totalAssetValue],\n ['Total depreciation', summary.totalDepreciation],\n ['Total maintenance spend', summary.totalMaintenanceSpend],\n ['Budget allocated', summary.budgetAllocated],\n ['Budget spent', summary.budgetSpent],\n ['Invoices outstanding', summary.invoicesOutstanding],\n ['Invoices outstanding (count)', summary.invoicesOutstandingCount],\n ['Transaction expense', summary.transactionExpense],\n ]\n );\n };\n\n const exportUtilization = () => {\n if (!utilization) return;\n downloadCsv(\n `utilization-report-${new Date().toISOString().slice(0, 10)}`,\n ['Metric', 'Value'],\n [\n ['Total assets', utilization.totalAssets],\n ['Assigned assets', utilization.assignedAssets],\n ['Unassigned assets', utilization.unassignedAssets],\n ['Idle assets', utilization.idleAssets],\n ['Overdue assignments', utilization.overdueAssignments],\n ...utilization.byStatus.map((s): [string, number] => [`Status: ${s.status}`, s.count]),\n ]\n );\n };\n\n const registerLoading = loading && register.length === 0;\n const maintenanceLoading = loading && maintenance.length === 0;\n\n const registerActions = (\n <>\n <Button size=\"sm\" onClick={exportRegister} disabled={register.length === 0}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={() => window.print()}>\n <Printer className=\"mr-2 h-4 w-4\" />\n Print\n </Button>\n </>\n );\n\n return (\n <div className=\"space-y-6 p-4 sm:p-6\">\n {/* ─── Header with persistent finance KPI strip ─── */}\n <div className=\"flex flex-col gap-5 xl:flex-row xl:items-end xl:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold sm:text-3xl\">\n <GradientText>Reports</GradientText>\n </h1>\n <p className=\"mt-1 max-w-xl text-sm text-text-secondary\">\n Registers and summaries built from live asset, finance and maintenance data.\n </p>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n <StatTile\n label=\"Total asset value\"\n value={totalAssetValue}\n format={(v) => money(v)}\n icon={DollarSign}\n hero\n />\n <StatTile\n label=\"Total depreciation\"\n value={totalDepreciation}\n format={(v) => money(v)}\n icon={TrendingDown}\n />\n <StatTile\n label=\"Depreciated\"\n value={depreciationPct}\n format={(v) => `${v.toFixed(2)}%`}\n icon={Percent}\n />\n </div>\n </div>\n\n <PagePurpose>\n Pull the numbers you need for audits, finance reviews and planning. Every register below is\n generated from live records — export any of them to CSV or print the page for sign-off.\n </PagePurpose>\n\n <Tabs defaultValue=\"register\">\n <TabsList className=\"max-w-full justify-start overflow-x-auto\">\n <TabsTrigger value=\"register\">\n <FileBarChart2 className=\"mr-1.5 h-4 w-4\" />\n Asset Register\n </TabsTrigger>\n <TabsTrigger value=\"financial\">\n <Wallet className=\"mr-1.5 h-4 w-4\" />\n Financial Summary\n </TabsTrigger>\n <TabsTrigger value=\"maintenance\">\n <Wrench className=\"mr-1.5 h-4 w-4\" />\n Maintenance Log\n </TabsTrigger>\n <TabsTrigger value=\"utilization\">\n <Activity className=\"mr-1.5 h-4 w-4\" />\n Utilization\n </TabsTrigger>\n </TabsList>\n\n {/* ─── Asset Register ─── */}\n <TabsContent value=\"register\" className=\"mt-4 space-y-4\">\n {categoryValue.length > 0 ? (\n <ChartCard\n title=\"Asset value by category\"\n subtitle=\"Current book value aggregated from the register\"\n >\n <BarsChart\n data={categoryValue}\n xKey=\"category\"\n series={[{ key: 'value', label: 'Current value' }]}\n orientation=\"horizontal\"\n height={Math.max(200, categoryValue.length * 34)}\n valueFormat={compactUsd}\n categoryWidth={128}\n ariaLabel=\"Current asset value by category\"\n />\n </ChartCard>\n ) : null}\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n <div className=\"flex flex-col gap-3 border-b border-border-seam p-4 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3\">\n <h3 className=\"text-base font-semibold text-text-primary\">Asset Register</h3>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"h-8 w-40\">\n <SelectValue placeholder=\"Filter by status\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">All statuses</SelectItem>\n {ASSET_STATUSES.map((status) => (\n <SelectItem key={status} value={status} className=\"capitalize\">\n {status.toLowerCase()}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-wrap gap-2\">{registerActions}</div>\n </div>\n\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-left\">\n <th className=\"p-3 font-medium\">Asset</th>\n <th className=\"p-3 font-medium\">Category</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Department</th>\n <th className=\"p-3 text-right font-medium\">Purchase</th>\n <th className=\"p-3 text-right font-medium\">Current</th>\n <th className=\"p-3 text-right font-medium\">Depreciation</th>\n <th className=\"p-3 text-right font-medium\">TCO</th>\n </tr>\n </thead>\n <tbody>\n {registerLoading ? (\n <SkeletonRows cols={8} />\n ) : (\n registerPage.pageItems.map((a) => (\n <tr\n key={a.id}\n className=\"border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40\"\n >\n <td className=\"p-3\">\n <p className=\"font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetNumber}</p>\n </td>\n <td className=\"p-3 capitalize\">{a.category.replace(/_/g, ' ')}</td>\n <td className=\"p-3\">\n <StatusPill tone={assetStatusTone(a.status)}>\n {a.status.toLowerCase()}\n </StatusPill>\n </td>\n <td className=\"p-3\">{a.department || '—'}</td>\n <td className=\"p-3 text-right tabular-nums\">{money(a.purchaseValue)}</td>\n <td className=\"p-3 text-right tabular-nums\">{money(a.currentValue)}</td>\n <td className=\"p-3 text-right tabular-nums\">\n {money(a.accumulatedDepreciation)}\n </td>\n <td className=\"p-3 text-right tabular-nums\">\n {money(a.totalCostOfOwnership)}\n </td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* Mobile cards */}\n <div className=\"divide-y divide-border-seam/60 md:hidden\">\n {registerLoading ? (\n <div className=\"space-y-3 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 animate-pulse rounded bg-bg-sunken\" />\n ))}\n </div>\n ) : (\n registerPage.pageItems.map((a) => (\n <div key={a.id} className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{a.name}</p>\n <p className=\"text-xs text-text-secondary\">{a.assetNumber}</p>\n </div>\n <StatusPill tone={assetStatusTone(a.status)}>\n {a.status.toLowerCase()}\n </StatusPill>\n </div>\n <div className=\"mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <span>Category</span>\n <span className=\"text-right capitalize text-text-primary\">\n {a.category.replace(/_/g, ' ')}\n </span>\n <span>Current value</span>\n <span className=\"text-right tabular-nums text-text-primary\">\n {money(a.currentValue)}\n </span>\n <span>Depreciation</span>\n <span className=\"text-right tabular-nums text-text-primary\">\n {money(a.accumulatedDepreciation)}\n </span>\n </div>\n </div>\n ))\n )}\n </div>\n\n {register.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No assets in the register\"\n description=\"Register assets with financial details and they will appear here.\"\n />\n ) : (\n <div className=\"px-3\">\n <Pagination\n page={registerPage.page}\n pageCount={registerPage.pageCount}\n rangeStart={registerPage.rangeStart}\n rangeEnd={registerPage.rangeEnd}\n totalItems={registerPage.totalItems}\n canPrev={registerPage.canPrev}\n canNext={registerPage.canNext}\n onPrev={registerPage.prevPage}\n onNext={registerPage.nextPage}\n itemLabel=\"assets\"\n />\n </div>\n )}\n </GlassCard>\n </TabsContent>\n\n {/* ─── Financial Summary ─── */}\n <TabsContent value=\"financial\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportFinancial} disabled={!summary}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatTile label=\"Total asset value\" value={totalAssetValue} format={(v) => money(v)} />\n <StatTile\n label=\"Total depreciation\"\n value={totalDepreciation}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Maintenance spend\"\n value={summary?.totalMaintenanceSpend ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Transaction expense\"\n value={summary?.transactionExpense ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Budget allocated\"\n value={summary?.budgetAllocated ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Budget spent\"\n value={summary?.budgetSpent ?? 0}\n format={(v) => money(v)}\n />\n <StatTile\n label=\"Invoices outstanding\"\n value={summary?.invoicesOutstanding ?? 0}\n format={(v) => money(v)}\n />\n <StatTile label=\"Outstanding invoices\" value={summary?.invoicesOutstandingCount ?? 0} />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n {budgetBars.length > 0 && (summary?.budgetAllocated || summary?.budgetSpent) ? (\n <ChartCard title=\"Budget utilization\" subtitle=\"Allocated against spend\">\n <BarsChart\n data={budgetBars}\n xKey=\"metric\"\n series={[{ key: 'value', label: 'Amount' }]}\n orientation=\"horizontal\"\n height={200}\n valueFormat={compactUsd}\n categoryWidth={96}\n ariaLabel=\"Budget allocated versus spent\"\n />\n </ChartCard>\n ) : null}\n {valueSlices.length > 0 ? (\n <ChartCard\n title=\"Value vs depreciation\"\n subtitle=\"Current book value against accumulated depreciation\"\n >\n <DonutChart\n data={valueSlices}\n centerLabel=\"Original cost\"\n centerValue={totalAssetValue + totalDepreciation}\n valueFormat={(v) => money(v)}\n height={220}\n ariaLabel=\"Current value versus accumulated depreciation\"\n />\n </ChartCard>\n ) : null}\n </div>\n </TabsContent>\n\n {/* ─── Maintenance Log ─── */}\n <TabsContent value=\"maintenance\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportMaintenance} disabled={maintenance.length === 0}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n\n {maintenanceSpendByType.length > 0 ? (\n <ChartCard\n title=\"Maintenance spend by type\"\n subtitle=\"Actual cost, falling back to estimates\"\n >\n <BarsChart\n data={maintenanceSpendByType}\n xKey=\"type\"\n series={[{ key: 'cost', label: 'Spend' }]}\n orientation=\"horizontal\"\n height={Math.max(180, maintenanceSpendByType.length * 34)}\n valueFormat={compactUsd}\n categoryWidth={128}\n ariaLabel=\"Maintenance spend by type\"\n />\n </ChartCard>\n ) : null}\n\n <GlassCard treatment=\"glass\" className=\"overflow-hidden border-border-seam\">\n {/* Desktop table */}\n <div className=\"hidden overflow-x-auto md:block\">\n <table className=\"w-full min-w-[720px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam bg-bg-sunken/50 text-left\">\n <th className=\"p-3 font-medium\">Work</th>\n <th className=\"p-3 font-medium\">Asset</th>\n <th className=\"p-3 font-medium\">Type</th>\n <th className=\"p-3 font-medium\">Status</th>\n <th className=\"p-3 font-medium\">Completed</th>\n <th className=\"p-3 text-right font-medium\">Actual Cost</th>\n </tr>\n </thead>\n <tbody>\n {maintenanceLoading ? (\n <SkeletonRows cols={6} />\n ) : (\n maintenancePage.pageItems.map((m) => (\n <tr\n key={m.id}\n className=\"border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40\"\n >\n <td className=\"p-3 font-medium\">{m.title}</td>\n <td className=\"p-3\">{assetNameById.get(m.assetId) ?? m.assetId}</td>\n <td className=\"p-3 capitalize\">{m.type.replace(/_/g, ' ')}</td>\n <td className=\"p-3\">\n <StatusPill tone={maintenanceStatusTone(m.status)}>\n {m.status.replace(/_/g, ' ').toLowerCase()}\n </StatusPill>\n </td>\n <td className=\"p-3 text-xs text-text-secondary\">\n {m.completedAt ? new Date(m.completedAt).toLocaleDateString() : '—'}\n </td>\n <td className=\"p-3 text-right tabular-nums\">{money(m.actualCost)}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n\n {/* Mobile cards */}\n <div className=\"divide-y divide-border-seam/60 md:hidden\">\n {maintenanceLoading ? (\n <div className=\"space-y-3 p-4\">\n {Array.from({ length: 5 }).map((_, i) => (\n <div key={i} className=\"h-16 animate-pulse rounded bg-bg-sunken\" />\n ))}\n </div>\n ) : (\n maintenancePage.pageItems.map((m) => (\n <div key={m.id} className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"min-w-0 flex-1 truncate font-medium\">{m.title}</p>\n <StatusPill tone={maintenanceStatusTone(m.status)}>\n {m.status.replace(/_/g, ' ').toLowerCase()}\n </StatusPill>\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span className=\"capitalize\">{m.type.replace(/_/g, ' ')}</span>\n <span>· {assetNameById.get(m.assetId) ?? m.assetId}</span>\n {m.actualCost != null ? (\n <span className=\"ml-auto tabular-nums text-text-primary\">\n {money(m.actualCost)}\n </span>\n ) : null}\n </div>\n </div>\n ))\n )}\n </div>\n\n {maintenance.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No maintenance records\"\n description=\"Logged maintenance work will appear here once scheduled or completed.\"\n />\n ) : (\n <div className=\"px-3\">\n <Pagination\n page={maintenancePage.page}\n pageCount={maintenancePage.pageCount}\n rangeStart={maintenancePage.rangeStart}\n rangeEnd={maintenancePage.rangeEnd}\n totalItems={maintenancePage.totalItems}\n canPrev={maintenancePage.canPrev}\n canNext={maintenancePage.canNext}\n onPrev={maintenancePage.prevPage}\n onNext={maintenancePage.nextPage}\n itemLabel=\"records\"\n />\n </div>\n )}\n </GlassCard>\n </TabsContent>\n\n {/* ─── Utilization ─── */}\n <TabsContent value=\"utilization\" className=\"mt-4 space-y-4\">\n <div className=\"flex justify-end\">\n <Button size=\"sm\" onClick={exportUtilization} disabled={!utilization}>\n <Download className=\"mr-2 h-4 w-4\" />\n Export CSV\n </Button>\n </div>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-5\">\n <StatTile label=\"Total assets\" value={utilization?.totalAssets ?? 0} />\n <StatTile label=\"Assigned\" value={utilization?.assignedAssets ?? 0} />\n <StatTile label=\"Unassigned\" value={utilization?.unassignedAssets ?? 0} />\n <StatTile label=\"Active unassigned\" value={utilization?.idleAssets ?? 0} />\n <StatTile\n label=\"Overdue assignments\"\n value={utilization?.overdueAssignments ?? 0}\n delta={utilization && utilization.overdueAssignments > 0 ? 'Attention' : undefined}\n deltaTone=\"negative\"\n />\n </div>\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Assets by status\" subtitle=\"Distribution across lifecycle states\">\n <DonutChart\n data={statusSlices}\n centerLabel=\"Assets\"\n centerValue={utilization?.totalAssets ?? 0}\n height={240}\n emptyLabel=\"No status data available.\"\n ariaLabel=\"Assets by status\"\n />\n </ChartCard>\n <ChartCard\n title=\"Assignment coverage\"\n subtitle=\"Mutually exclusive assigned, active-unassigned and other-unassigned assets\"\n >\n <DonutChart\n data={coverageSlices}\n centerLabel=\"Assets\"\n centerValue={utilization?.totalAssets ?? 0}\n height={240}\n emptyLabel=\"No coverage data available.\"\n ariaLabel=\"Assignment coverage\"\n />\n </ChartCard>\n </div>\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface AssignmentCoverageSlice {
2
+ name: 'Assigned' | 'Active unassigned' | 'Other unassigned';
3
+ value: number;
4
+ }
5
+ /**
6
+ * Build mutually exclusive assignment-coverage slices.
7
+ *
8
+ * The backend's idle metric means an ACTIVE asset without a current holder,
9
+ * so it is a subset of unassigned assets rather than a third coverage state.
10
+ */
11
+ export declare function buildAssignmentCoverageSlices(assignedAssets: number, unassignedAssets: number, idleAssets: number): AssignmentCoverageSlice[];
12
+ //# sourceMappingURL=utilization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilization.d.ts","sourceRoot":"","sources":["../../../src/assethandler/utils/utilization.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,UAAU,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;IAC5D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,GACjB,uBAAuB,EAAE,CAa3B"}
@@ -0,0 +1,22 @@
1
+ //#region src/assethandler/utils/utilization.ts
2
+ function e(e, t, n) {
3
+ let r = Math.max(0, e), i = Math.max(0, t), a = Math.min(i, Math.max(0, n)), o = i - a;
4
+ return [
5
+ {
6
+ name: "Assigned",
7
+ value: r
8
+ },
9
+ {
10
+ name: "Active unassigned",
11
+ value: a
12
+ },
13
+ {
14
+ name: "Other unassigned",
15
+ value: o
16
+ }
17
+ ].filter((e) => e.value > 0);
18
+ }
19
+ //#endregion
20
+ export { e as buildAssignmentCoverageSlices };
21
+
22
+ //# sourceMappingURL=utilization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilization.js","names":[],"sources":["../../../src/assethandler/utils/utilization.ts"],"sourcesContent":["export interface AssignmentCoverageSlice {\n name: 'Assigned' | 'Active unassigned' | 'Other unassigned';\n value: number;\n}\n\n/**\n * Build mutually exclusive assignment-coverage slices.\n *\n * The backend's idle metric means an ACTIVE asset without a current holder,\n * so it is a subset of unassigned assets rather than a third coverage state.\n */\nexport function buildAssignmentCoverageSlices(\n assignedAssets: number,\n unassignedAssets: number,\n idleAssets: number\n): AssignmentCoverageSlice[] {\n const assigned = Math.max(0, assignedAssets);\n const unassigned = Math.max(0, unassignedAssets);\n const activeUnassigned = Math.min(unassigned, Math.max(0, idleAssets));\n const otherUnassigned = unassigned - activeUnassigned;\n\n const slices: AssignmentCoverageSlice[] = [\n { name: 'Assigned', value: assigned },\n { name: 'Active unassigned', value: activeUnassigned },\n { name: 'Other unassigned', value: otherUnassigned },\n ];\n\n return slices.filter((slice) => slice.value > 0);\n}\n"],"mappings":";AAWA,SAAgB,EACd,GACA,GACA,GAC2B;CAC3B,IAAM,IAAW,KAAK,IAAI,GAAG,CAAc,GACrC,IAAa,KAAK,IAAI,GAAG,CAAgB,GACzC,IAAmB,KAAK,IAAI,GAAY,KAAK,IAAI,GAAG,CAAU,CAAC,GAC/D,IAAkB,IAAa;CAQrC,OAAO;EALL;GAAE,MAAM;GAAY,OAAO;EAAS;EACpC;GAAE,MAAM;GAAqB,OAAO;EAAiB;EACrD;GAAE,MAAM;GAAoB,OAAO;EAAgB;CAG9C,EAAO,QAAQ,MAAU,EAAM,QAAQ,CAAC;AACjD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-assethandler",
3
- "version": "2026.826.8",
3
+ "version": "2026.826.9",
4
4
  "description": "Burdenoff AssetHandler Microfrontend",
5
5
  "type": "module",
6
6
  "files": [