@burdenoff/microfe-assethandler 2026.826.10 → 2026.826.11
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.
- package/dist/assethandler/pages/ReportsDashboardPage.d.ts.map +1 -1
- package/dist/assethandler/pages/ReportsDashboardPage.js +143 -150
- package/dist/assethandler/pages/ReportsDashboardPage.js.map +1 -1
- package/dist/assethandler/utils/utilization.d.ts +13 -0
- package/dist/assethandler/utils/utilization.d.ts.map +1 -1
- package/dist/assethandler/utils/utilization.js +12 -2
- package/dist/assethandler/utils/utilization.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,oBAAoB,gCAupBnC"}
|
|
@@ -8,13 +8,13 @@ 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 { buildAssignmentCoverageSlices as ee } from "../utils/utilization.js";
|
|
12
|
-
import { useMemo as u, useState as
|
|
13
|
-
import { Activity as
|
|
11
|
+
import { buildAssignmentCoverageSlices as ee, buildUtilizationCsvRows as te } from "../utils/utilization.js";
|
|
12
|
+
import { useMemo as u, useState as ne } from "react";
|
|
13
|
+
import { Activity as d, DollarSign as re, Download as f, FileBarChart2 as ie, Percent as p, Printer as m, TrendingDown as h, Wallet as g, Wrench as ae } from "lucide-react";
|
|
14
14
|
import { gql as _ } from "@apollo/client";
|
|
15
|
-
import { useQuery as
|
|
15
|
+
import { useQuery as oe } from "@apollo/client/react";
|
|
16
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
|
|
17
|
+
import { Button as x, GlassCard as S, GradientText as se, IllustratedEmptyState as C, PagePurpose as ce, Select as w, SelectContent as T, SelectItem as E, SelectTrigger as le, SelectValue as ue, Tabs as D, TabsContent as O, TabsList as de, TabsTrigger as k } from "@burdenoff/fe-libs/ui";
|
|
18
18
|
//#region src/assethandler/pages/ReportsDashboardPage.tsx
|
|
19
19
|
var fe = _`
|
|
20
20
|
query AssetHandlerReports($registerFilter: AssetRegisterFilterInput) {
|
|
@@ -71,27 +71,27 @@ var fe = _`
|
|
|
71
71
|
"MAINTENANCE",
|
|
72
72
|
"RETIRED",
|
|
73
73
|
"DISPOSED"
|
|
74
|
-
],
|
|
74
|
+
], A = {
|
|
75
75
|
success: "bg-status-success-subtle text-status-success-text",
|
|
76
76
|
warning: "bg-status-warning-subtle text-status-warning-text",
|
|
77
77
|
error: "bg-status-error-subtle text-status-error-text",
|
|
78
78
|
info: "bg-status-info-subtle text-status-info-text",
|
|
79
79
|
neutral: "bg-bg-sunken text-text-secondary"
|
|
80
80
|
};
|
|
81
|
-
function
|
|
81
|
+
function j({ tone: e, children: t }) {
|
|
82
82
|
return /* @__PURE__ */ y("span", {
|
|
83
|
-
className: n("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize",
|
|
83
|
+
className: n("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium capitalize", A[e]),
|
|
84
84
|
children: t
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
var
|
|
87
|
+
var M = (e) => {
|
|
88
88
|
let t = e.toLowerCase();
|
|
89
89
|
return t === "active" ? "success" : t === "maintenance" ? "warning" : t === "retired" || t === "disposed" ? "error" : "neutral";
|
|
90
|
-
},
|
|
90
|
+
}, N = (e) => {
|
|
91
91
|
let t = e.toLowerCase();
|
|
92
92
|
return t === "completed" ? "success" : t === "in_progress" || t === "scheduled" ? "info" : t === "overdue" || t === "cancelled" ? "error" : "neutral";
|
|
93
93
|
};
|
|
94
|
-
function
|
|
94
|
+
function P({ rows: e = 6, cols: t }) {
|
|
95
95
|
return /* @__PURE__ */ y(v, { children: Array.from({ length: e }).map((e, n) => /* @__PURE__ */ y("tr", {
|
|
96
96
|
className: "border-b border-border-seam/60",
|
|
97
97
|
children: Array.from({ length: t }).map((e, t) => /* @__PURE__ */ y("td", {
|
|
@@ -100,21 +100,21 @@ function N({ rows: e = 6, cols: t }) {
|
|
|
100
100
|
}, t))
|
|
101
101
|
}, n)) });
|
|
102
102
|
}
|
|
103
|
-
function
|
|
104
|
-
let { format: n, compact: _ } = t(), { assets:
|
|
105
|
-
variables: { registerFilter:
|
|
103
|
+
function F() {
|
|
104
|
+
let { format: n, compact: _ } = t(), { assets: A } = e(), [F, I] = ne("all"), { data: L, loading: R } = oe(fe, {
|
|
105
|
+
variables: { registerFilter: F === "all" ? null : { status: F } },
|
|
106
106
|
fetchPolicy: "cache-and-network",
|
|
107
107
|
errorPolicy: "all"
|
|
108
|
-
}),
|
|
108
|
+
}), z = u(() => L?.assetRegister ?? [], [L]), B = u(() => L?.maintenanceLog ?? [], [L]), V = L?.financialSummary, H = L?.utilizationReport, U = u(() => {
|
|
109
109
|
let e = /* @__PURE__ */ new Map();
|
|
110
|
-
for (let t of
|
|
110
|
+
for (let t of A) e.set(t.id, t.name);
|
|
111
111
|
return e;
|
|
112
|
-
}, [
|
|
112
|
+
}, [A]), W = o(z, {
|
|
113
113
|
pageSize: 12,
|
|
114
|
-
resetKey:
|
|
115
|
-
}),
|
|
114
|
+
resetKey: F
|
|
115
|
+
}), G = o(B, { pageSize: 12 }), K = V?.totalAssetValue ?? 0, q = V?.totalDepreciation ?? 0, me = K + q > 0 ? q / (K + q) * 100 : 0, J = u(() => {
|
|
116
116
|
let e = /* @__PURE__ */ new Map();
|
|
117
|
-
for (let t of
|
|
117
|
+
for (let t of z) {
|
|
118
118
|
let n = t.currentValue ?? t.purchaseValue ?? 0;
|
|
119
119
|
if (n > 0) {
|
|
120
120
|
let r = t.category.replace(/_/g, " ");
|
|
@@ -125,24 +125,24 @@ function P() {
|
|
|
125
125
|
category: e,
|
|
126
126
|
value: t
|
|
127
127
|
})).sort((e, t) => t.value - e.value).slice(0, 12);
|
|
128
|
-
}, [
|
|
128
|
+
}, [z]), he = u(() => (H?.byStatus ?? []).map((e) => ({
|
|
129
129
|
name: e.status.toLowerCase(),
|
|
130
130
|
value: e.count
|
|
131
|
-
})).filter((e) => e.value > 0), [
|
|
131
|
+
})).filter((e) => e.value > 0), [H]), ge = u(() => H ? ee(H.assignedAssets, H.unassignedAssets, H.idleAssets) : [], [H]), Y = u(() => [{
|
|
132
132
|
name: "Current value",
|
|
133
|
-
value:
|
|
133
|
+
value: K
|
|
134
134
|
}, {
|
|
135
135
|
name: "Accumulated depreciation",
|
|
136
|
-
value:
|
|
137
|
-
}].filter((e) => e.value > 0), [
|
|
136
|
+
value: q
|
|
137
|
+
}].filter((e) => e.value > 0), [K, q]), X = u(() => V ? [{
|
|
138
138
|
metric: "Allocated",
|
|
139
|
-
value:
|
|
139
|
+
value: V.budgetAllocated
|
|
140
140
|
}, {
|
|
141
141
|
metric: "Spent",
|
|
142
|
-
value:
|
|
143
|
-
}] : [], [
|
|
142
|
+
value: V.budgetSpent
|
|
143
|
+
}] : [], [V]), Z = u(() => {
|
|
144
144
|
let e = /* @__PURE__ */ new Map();
|
|
145
|
-
for (let t of
|
|
145
|
+
for (let t of B) {
|
|
146
146
|
let n = t.actualCost ?? t.estimatedCost ?? 0;
|
|
147
147
|
if (n > 0) {
|
|
148
148
|
let r = t.type.replace(/_/g, " ");
|
|
@@ -153,7 +153,7 @@ function P() {
|
|
|
153
153
|
type: e[0],
|
|
154
154
|
cost: e[1]
|
|
155
155
|
})).sort((e, t) => t.cost - e.cost);
|
|
156
|
-
}, [
|
|
156
|
+
}, [B]), _e = () => {
|
|
157
157
|
l(`asset-register-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, [
|
|
158
158
|
"Asset Number",
|
|
159
159
|
"Name",
|
|
@@ -165,7 +165,7 @@ function P() {
|
|
|
165
165
|
"Accumulated Depreciation",
|
|
166
166
|
"Total Cost of Ownership",
|
|
167
167
|
"Purchase Date"
|
|
168
|
-
],
|
|
168
|
+
], z.map((e) => [
|
|
169
169
|
e.assetNumber,
|
|
170
170
|
e.name,
|
|
171
171
|
e.category,
|
|
@@ -177,7 +177,7 @@ function P() {
|
|
|
177
177
|
e.totalCostOfOwnership ?? "",
|
|
178
178
|
e.purchaseDate ? new Date(e.purchaseDate).toISOString().slice(0, 10) : ""
|
|
179
179
|
]));
|
|
180
|
-
},
|
|
180
|
+
}, ve = () => {
|
|
181
181
|
l(`maintenance-log-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, [
|
|
182
182
|
"Title",
|
|
183
183
|
"Asset",
|
|
@@ -188,9 +188,9 @@ function P() {
|
|
|
188
188
|
"Completed",
|
|
189
189
|
"Estimated Cost",
|
|
190
190
|
"Actual Cost"
|
|
191
|
-
],
|
|
191
|
+
], B.map((e) => [
|
|
192
192
|
e.title,
|
|
193
|
-
|
|
193
|
+
U.get(e.assetId) ?? e.assetId,
|
|
194
194
|
e.type,
|
|
195
195
|
e.status,
|
|
196
196
|
e.priority,
|
|
@@ -199,36 +199,29 @@ function P() {
|
|
|
199
199
|
e.estimatedCost ?? "",
|
|
200
200
|
e.actualCost ?? ""
|
|
201
201
|
]));
|
|
202
|
-
}, ve = () => {
|
|
203
|
-
B && l(`financial-summary-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, ["Metric", "Value"], [
|
|
204
|
-
["Total asset value", B.totalAssetValue],
|
|
205
|
-
["Total depreciation", B.totalDepreciation],
|
|
206
|
-
["Total maintenance spend", B.totalMaintenanceSpend],
|
|
207
|
-
["Budget allocated", B.budgetAllocated],
|
|
208
|
-
["Budget spent", B.budgetSpent],
|
|
209
|
-
["Invoices outstanding", B.invoicesOutstanding],
|
|
210
|
-
["Invoices outstanding (count)", B.invoicesOutstandingCount],
|
|
211
|
-
["Transaction expense", B.transactionExpense]
|
|
212
|
-
]);
|
|
213
202
|
}, ye = () => {
|
|
214
|
-
V && l(`
|
|
215
|
-
["Total
|
|
216
|
-
["
|
|
217
|
-
["
|
|
218
|
-
["
|
|
219
|
-
["
|
|
220
|
-
|
|
203
|
+
V && l(`financial-summary-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, ["Metric", "Value"], [
|
|
204
|
+
["Total asset value", V.totalAssetValue],
|
|
205
|
+
["Total depreciation", V.totalDepreciation],
|
|
206
|
+
["Total maintenance spend", V.totalMaintenanceSpend],
|
|
207
|
+
["Budget allocated", V.budgetAllocated],
|
|
208
|
+
["Budget spent", V.budgetSpent],
|
|
209
|
+
["Invoices outstanding", V.invoicesOutstanding],
|
|
210
|
+
["Invoices outstanding (count)", V.invoicesOutstandingCount],
|
|
211
|
+
["Transaction expense", V.transactionExpense]
|
|
221
212
|
]);
|
|
222
|
-
},
|
|
213
|
+
}, be = () => {
|
|
214
|
+
H && l(`utilization-report-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`, ["Metric", "Value"], te(H));
|
|
215
|
+
}, Q = R && z.length === 0, $ = R && B.length === 0, xe = /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ b(x, {
|
|
223
216
|
size: "sm",
|
|
224
|
-
onClick:
|
|
225
|
-
disabled:
|
|
226
|
-
children: [/* @__PURE__ */ y(
|
|
217
|
+
onClick: _e,
|
|
218
|
+
disabled: z.length === 0,
|
|
219
|
+
children: [/* @__PURE__ */ y(f, { className: "mr-2 h-4 w-4" }), "Export CSV"]
|
|
227
220
|
}), /* @__PURE__ */ b(x, {
|
|
228
221
|
size: "sm",
|
|
229
222
|
variant: "outline",
|
|
230
223
|
onClick: () => window.print(),
|
|
231
|
-
children: [/* @__PURE__ */ y(
|
|
224
|
+
children: [/* @__PURE__ */ y(m, { className: "mr-2 h-4 w-4" }), "Print"]
|
|
232
225
|
})] });
|
|
233
226
|
return /* @__PURE__ */ b("div", {
|
|
234
227
|
className: "space-y-6 p-4 sm:p-6",
|
|
@@ -237,7 +230,7 @@ function P() {
|
|
|
237
230
|
className: "flex flex-col gap-5 xl:flex-row xl:items-end xl:justify-between",
|
|
238
231
|
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
|
|
239
232
|
className: "text-2xl font-bold sm:text-3xl",
|
|
240
|
-
children: /* @__PURE__ */ y(
|
|
233
|
+
children: /* @__PURE__ */ y(se, { children: "Reports" })
|
|
241
234
|
}), /* @__PURE__ */ y("p", {
|
|
242
235
|
className: "mt-1 max-w-xl text-sm text-text-secondary",
|
|
243
236
|
children: "Registers and summaries built from live asset, finance and maintenance data."
|
|
@@ -246,66 +239,66 @@ function P() {
|
|
|
246
239
|
children: [
|
|
247
240
|
/* @__PURE__ */ y(s, {
|
|
248
241
|
label: "Total asset value",
|
|
249
|
-
value:
|
|
242
|
+
value: K,
|
|
250
243
|
format: (e) => n(e),
|
|
251
244
|
icon: re,
|
|
252
245
|
hero: !0
|
|
253
246
|
}),
|
|
254
247
|
/* @__PURE__ */ y(s, {
|
|
255
248
|
label: "Total depreciation",
|
|
256
|
-
value:
|
|
249
|
+
value: q,
|
|
257
250
|
format: (e) => n(e),
|
|
258
|
-
icon:
|
|
251
|
+
icon: h
|
|
259
252
|
}),
|
|
260
253
|
/* @__PURE__ */ y(s, {
|
|
261
254
|
label: "Depreciated",
|
|
262
255
|
value: me,
|
|
263
256
|
format: (e) => `${e.toFixed(2)}%`,
|
|
264
|
-
icon:
|
|
257
|
+
icon: p
|
|
265
258
|
})
|
|
266
259
|
]
|
|
267
260
|
})]
|
|
268
261
|
}),
|
|
269
|
-
/* @__PURE__ */ y(
|
|
270
|
-
/* @__PURE__ */ b(
|
|
262
|
+
/* @__PURE__ */ y(ce, { 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." }),
|
|
263
|
+
/* @__PURE__ */ b(D, {
|
|
271
264
|
defaultValue: "register",
|
|
272
265
|
children: [
|
|
273
266
|
/* @__PURE__ */ b(de, {
|
|
274
267
|
className: "max-w-full justify-start overflow-x-auto",
|
|
275
268
|
children: [
|
|
276
|
-
/* @__PURE__ */ b(
|
|
269
|
+
/* @__PURE__ */ b(k, {
|
|
277
270
|
value: "register",
|
|
278
271
|
children: [/* @__PURE__ */ y(ie, { className: "mr-1.5 h-4 w-4" }), "Asset Register"]
|
|
279
272
|
}),
|
|
280
|
-
/* @__PURE__ */ b(
|
|
273
|
+
/* @__PURE__ */ b(k, {
|
|
281
274
|
value: "financial",
|
|
282
|
-
children: [/* @__PURE__ */ y(
|
|
275
|
+
children: [/* @__PURE__ */ y(g, { className: "mr-1.5 h-4 w-4" }), "Financial Summary"]
|
|
283
276
|
}),
|
|
284
|
-
/* @__PURE__ */ b(
|
|
277
|
+
/* @__PURE__ */ b(k, {
|
|
285
278
|
value: "maintenance",
|
|
286
|
-
children: [/* @__PURE__ */ y(
|
|
279
|
+
children: [/* @__PURE__ */ y(ae, { className: "mr-1.5 h-4 w-4" }), "Maintenance Log"]
|
|
287
280
|
}),
|
|
288
|
-
/* @__PURE__ */ b(
|
|
281
|
+
/* @__PURE__ */ b(k, {
|
|
289
282
|
value: "utilization",
|
|
290
|
-
children: [/* @__PURE__ */ y(
|
|
283
|
+
children: [/* @__PURE__ */ y(d, { className: "mr-1.5 h-4 w-4" }), "Utilization"]
|
|
291
284
|
})
|
|
292
285
|
]
|
|
293
286
|
}),
|
|
294
|
-
/* @__PURE__ */ b(
|
|
287
|
+
/* @__PURE__ */ b(O, {
|
|
295
288
|
value: "register",
|
|
296
289
|
className: "mt-4 space-y-4",
|
|
297
|
-
children: [
|
|
290
|
+
children: [J.length > 0 ? /* @__PURE__ */ y(c, {
|
|
298
291
|
title: "Asset value by category",
|
|
299
292
|
subtitle: "Current book value aggregated from the register",
|
|
300
293
|
children: /* @__PURE__ */ y(r, {
|
|
301
|
-
data:
|
|
294
|
+
data: J,
|
|
302
295
|
xKey: "category",
|
|
303
296
|
series: [{
|
|
304
297
|
key: "value",
|
|
305
298
|
label: "Current value"
|
|
306
299
|
}],
|
|
307
300
|
orientation: "horizontal",
|
|
308
|
-
height: Math.max(200,
|
|
301
|
+
height: Math.max(200, J.length * 34),
|
|
309
302
|
valueFormat: _,
|
|
310
303
|
categoryWidth: 128,
|
|
311
304
|
ariaLabel: "Current asset value by category"
|
|
@@ -321,16 +314,16 @@ function P() {
|
|
|
321
314
|
children: [/* @__PURE__ */ y("h3", {
|
|
322
315
|
className: "text-base font-semibold text-text-primary",
|
|
323
316
|
children: "Asset Register"
|
|
324
|
-
}), /* @__PURE__ */ b(
|
|
325
|
-
value:
|
|
326
|
-
onValueChange:
|
|
327
|
-
children: [/* @__PURE__ */ y(
|
|
317
|
+
}), /* @__PURE__ */ b(w, {
|
|
318
|
+
value: F,
|
|
319
|
+
onValueChange: I,
|
|
320
|
+
children: [/* @__PURE__ */ y(le, {
|
|
328
321
|
className: "h-8 w-40",
|
|
329
|
-
children: /* @__PURE__ */ y(
|
|
330
|
-
}), /* @__PURE__ */ b(
|
|
322
|
+
children: /* @__PURE__ */ y(ue, { placeholder: "Filter by status" })
|
|
323
|
+
}), /* @__PURE__ */ b(T, { children: [/* @__PURE__ */ y(E, {
|
|
331
324
|
value: "all",
|
|
332
325
|
children: "All statuses"
|
|
333
|
-
}), pe.map((e) => /* @__PURE__ */ y(
|
|
326
|
+
}), pe.map((e) => /* @__PURE__ */ y(E, {
|
|
334
327
|
value: e,
|
|
335
328
|
className: "capitalize",
|
|
336
329
|
children: e.toLowerCase()
|
|
@@ -338,7 +331,7 @@ function P() {
|
|
|
338
331
|
})]
|
|
339
332
|
}), /* @__PURE__ */ y("div", {
|
|
340
333
|
className: "flex flex-wrap gap-2",
|
|
341
|
-
children:
|
|
334
|
+
children: xe
|
|
342
335
|
})]
|
|
343
336
|
}),
|
|
344
337
|
/* @__PURE__ */ y("div", {
|
|
@@ -381,7 +374,7 @@ function P() {
|
|
|
381
374
|
children: "TCO"
|
|
382
375
|
})
|
|
383
376
|
]
|
|
384
|
-
}) }), /* @__PURE__ */ y("tbody", { children: Q ? /* @__PURE__ */ y(
|
|
377
|
+
}) }), /* @__PURE__ */ y("tbody", { children: Q ? /* @__PURE__ */ y(P, { cols: 8 }) : W.pageItems.map((e) => /* @__PURE__ */ b("tr", {
|
|
385
378
|
className: "border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40",
|
|
386
379
|
children: [
|
|
387
380
|
/* @__PURE__ */ b("td", {
|
|
@@ -400,8 +393,8 @@ function P() {
|
|
|
400
393
|
}),
|
|
401
394
|
/* @__PURE__ */ y("td", {
|
|
402
395
|
className: "p-3",
|
|
403
|
-
children: /* @__PURE__ */ y(
|
|
404
|
-
tone:
|
|
396
|
+
children: /* @__PURE__ */ y(j, {
|
|
397
|
+
tone: M(e.status),
|
|
405
398
|
children: e.status.toLowerCase()
|
|
406
399
|
})
|
|
407
400
|
}),
|
|
@@ -434,7 +427,7 @@ function P() {
|
|
|
434
427
|
children: Q ? /* @__PURE__ */ y("div", {
|
|
435
428
|
className: "space-y-3 p-4",
|
|
436
429
|
children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ y("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
|
|
437
|
-
}) :
|
|
430
|
+
}) : W.pageItems.map((e) => /* @__PURE__ */ b("div", {
|
|
438
431
|
className: "p-4",
|
|
439
432
|
children: [/* @__PURE__ */ b("div", {
|
|
440
433
|
className: "flex items-start justify-between gap-2",
|
|
@@ -447,8 +440,8 @@ function P() {
|
|
|
447
440
|
className: "text-xs text-text-secondary",
|
|
448
441
|
children: e.assetNumber
|
|
449
442
|
})]
|
|
450
|
-
}), /* @__PURE__ */ y(
|
|
451
|
-
tone:
|
|
443
|
+
}), /* @__PURE__ */ y(j, {
|
|
444
|
+
tone: M(e.status),
|
|
452
445
|
children: e.status.toLowerCase()
|
|
453
446
|
})]
|
|
454
447
|
}), /* @__PURE__ */ b("div", {
|
|
@@ -473,29 +466,29 @@ function P() {
|
|
|
473
466
|
})]
|
|
474
467
|
}, e.id))
|
|
475
468
|
}),
|
|
476
|
-
|
|
469
|
+
z.length === 0 && !R ? /* @__PURE__ */ y(C, {
|
|
477
470
|
illustration: "empty-data",
|
|
478
471
|
title: "No assets in the register",
|
|
479
472
|
description: "Register assets with financial details and they will appear here."
|
|
480
473
|
}) : /* @__PURE__ */ y("div", {
|
|
481
474
|
className: "px-3",
|
|
482
475
|
children: /* @__PURE__ */ y(a, {
|
|
483
|
-
page:
|
|
484
|
-
pageCount:
|
|
485
|
-
rangeStart:
|
|
486
|
-
rangeEnd:
|
|
487
|
-
totalItems:
|
|
488
|
-
canPrev:
|
|
489
|
-
canNext:
|
|
490
|
-
onPrev:
|
|
491
|
-
onNext:
|
|
476
|
+
page: W.page,
|
|
477
|
+
pageCount: W.pageCount,
|
|
478
|
+
rangeStart: W.rangeStart,
|
|
479
|
+
rangeEnd: W.rangeEnd,
|
|
480
|
+
totalItems: W.totalItems,
|
|
481
|
+
canPrev: W.canPrev,
|
|
482
|
+
canNext: W.canNext,
|
|
483
|
+
onPrev: W.prevPage,
|
|
484
|
+
onNext: W.nextPage,
|
|
492
485
|
itemLabel: "assets"
|
|
493
486
|
})
|
|
494
487
|
})
|
|
495
488
|
]
|
|
496
489
|
})]
|
|
497
490
|
}),
|
|
498
|
-
/* @__PURE__ */ b(
|
|
491
|
+
/* @__PURE__ */ b(O, {
|
|
499
492
|
value: "financial",
|
|
500
493
|
className: "mt-4 space-y-4",
|
|
501
494
|
children: [
|
|
@@ -503,9 +496,9 @@ function P() {
|
|
|
503
496
|
className: "flex justify-end",
|
|
504
497
|
children: /* @__PURE__ */ b(x, {
|
|
505
498
|
size: "sm",
|
|
506
|
-
onClick:
|
|
507
|
-
disabled: !
|
|
508
|
-
children: [/* @__PURE__ */ y(
|
|
499
|
+
onClick: ye,
|
|
500
|
+
disabled: !V,
|
|
501
|
+
children: [/* @__PURE__ */ y(f, { className: "mr-2 h-4 w-4" }), "Export CSV"]
|
|
509
502
|
})
|
|
510
503
|
}),
|
|
511
504
|
/* @__PURE__ */ b("div", {
|
|
@@ -513,48 +506,48 @@ function P() {
|
|
|
513
506
|
children: [
|
|
514
507
|
/* @__PURE__ */ y(s, {
|
|
515
508
|
label: "Total asset value",
|
|
516
|
-
value:
|
|
509
|
+
value: K,
|
|
517
510
|
format: (e) => n(e)
|
|
518
511
|
}),
|
|
519
512
|
/* @__PURE__ */ y(s, {
|
|
520
513
|
label: "Total depreciation",
|
|
521
|
-
value:
|
|
514
|
+
value: q,
|
|
522
515
|
format: (e) => n(e)
|
|
523
516
|
}),
|
|
524
517
|
/* @__PURE__ */ y(s, {
|
|
525
518
|
label: "Maintenance spend",
|
|
526
|
-
value:
|
|
519
|
+
value: V?.totalMaintenanceSpend ?? 0,
|
|
527
520
|
format: (e) => n(e)
|
|
528
521
|
}),
|
|
529
522
|
/* @__PURE__ */ y(s, {
|
|
530
523
|
label: "Transaction expense",
|
|
531
|
-
value:
|
|
524
|
+
value: V?.transactionExpense ?? 0,
|
|
532
525
|
format: (e) => n(e)
|
|
533
526
|
}),
|
|
534
527
|
/* @__PURE__ */ y(s, {
|
|
535
528
|
label: "Budget allocated",
|
|
536
|
-
value:
|
|
529
|
+
value: V?.budgetAllocated ?? 0,
|
|
537
530
|
format: (e) => n(e)
|
|
538
531
|
}),
|
|
539
532
|
/* @__PURE__ */ y(s, {
|
|
540
533
|
label: "Budget spent",
|
|
541
|
-
value:
|
|
534
|
+
value: V?.budgetSpent ?? 0,
|
|
542
535
|
format: (e) => n(e)
|
|
543
536
|
}),
|
|
544
537
|
/* @__PURE__ */ y(s, {
|
|
545
538
|
label: "Invoices outstanding",
|
|
546
|
-
value:
|
|
539
|
+
value: V?.invoicesOutstanding ?? 0,
|
|
547
540
|
format: (e) => n(e)
|
|
548
541
|
}),
|
|
549
542
|
/* @__PURE__ */ y(s, {
|
|
550
543
|
label: "Outstanding invoices",
|
|
551
|
-
value:
|
|
544
|
+
value: V?.invoicesOutstandingCount ?? 0
|
|
552
545
|
})
|
|
553
546
|
]
|
|
554
547
|
}),
|
|
555
548
|
/* @__PURE__ */ b("div", {
|
|
556
549
|
className: "grid gap-4 lg:grid-cols-2",
|
|
557
|
-
children: [X.length > 0 && (
|
|
550
|
+
children: [X.length > 0 && (V?.budgetAllocated || V?.budgetSpent) ? /* @__PURE__ */ y(c, {
|
|
558
551
|
title: "Budget utilization",
|
|
559
552
|
subtitle: "Allocated against spend",
|
|
560
553
|
children: /* @__PURE__ */ y(r, {
|
|
@@ -576,7 +569,7 @@ function P() {
|
|
|
576
569
|
children: /* @__PURE__ */ y(i, {
|
|
577
570
|
data: Y,
|
|
578
571
|
centerLabel: "Original cost",
|
|
579
|
-
centerValue:
|
|
572
|
+
centerValue: K + q,
|
|
580
573
|
valueFormat: (e) => n(e),
|
|
581
574
|
height: 220,
|
|
582
575
|
ariaLabel: "Current value versus accumulated depreciation"
|
|
@@ -585,7 +578,7 @@ function P() {
|
|
|
585
578
|
})
|
|
586
579
|
]
|
|
587
580
|
}),
|
|
588
|
-
/* @__PURE__ */ b(
|
|
581
|
+
/* @__PURE__ */ b(O, {
|
|
589
582
|
value: "maintenance",
|
|
590
583
|
className: "mt-4 space-y-4",
|
|
591
584
|
children: [
|
|
@@ -593,9 +586,9 @@ function P() {
|
|
|
593
586
|
className: "flex justify-end",
|
|
594
587
|
children: /* @__PURE__ */ b(x, {
|
|
595
588
|
size: "sm",
|
|
596
|
-
onClick:
|
|
597
|
-
disabled:
|
|
598
|
-
children: [/* @__PURE__ */ y(
|
|
589
|
+
onClick: ve,
|
|
590
|
+
disabled: B.length === 0,
|
|
591
|
+
children: [/* @__PURE__ */ y(f, { className: "mr-2 h-4 w-4" }), "Export CSV"]
|
|
599
592
|
})
|
|
600
593
|
}),
|
|
601
594
|
Z.length > 0 ? /* @__PURE__ */ y(c, {
|
|
@@ -651,7 +644,7 @@ function P() {
|
|
|
651
644
|
children: "Actual Cost"
|
|
652
645
|
})
|
|
653
646
|
]
|
|
654
|
-
}) }), /* @__PURE__ */ y("tbody", { children: $ ? /* @__PURE__ */ y(
|
|
647
|
+
}) }), /* @__PURE__ */ y("tbody", { children: $ ? /* @__PURE__ */ y(P, { cols: 6 }) : G.pageItems.map((e) => /* @__PURE__ */ b("tr", {
|
|
655
648
|
className: "border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/40",
|
|
656
649
|
children: [
|
|
657
650
|
/* @__PURE__ */ y("td", {
|
|
@@ -660,7 +653,7 @@ function P() {
|
|
|
660
653
|
}),
|
|
661
654
|
/* @__PURE__ */ y("td", {
|
|
662
655
|
className: "p-3",
|
|
663
|
-
children:
|
|
656
|
+
children: U.get(e.assetId) ?? e.assetId
|
|
664
657
|
}),
|
|
665
658
|
/* @__PURE__ */ y("td", {
|
|
666
659
|
className: "p-3 capitalize",
|
|
@@ -668,8 +661,8 @@ function P() {
|
|
|
668
661
|
}),
|
|
669
662
|
/* @__PURE__ */ y("td", {
|
|
670
663
|
className: "p-3",
|
|
671
|
-
children: /* @__PURE__ */ y(
|
|
672
|
-
tone:
|
|
664
|
+
children: /* @__PURE__ */ y(j, {
|
|
665
|
+
tone: N(e.status),
|
|
673
666
|
children: e.status.replace(/_/g, " ").toLowerCase()
|
|
674
667
|
})
|
|
675
668
|
}),
|
|
@@ -690,15 +683,15 @@ function P() {
|
|
|
690
683
|
children: $ ? /* @__PURE__ */ y("div", {
|
|
691
684
|
className: "space-y-3 p-4",
|
|
692
685
|
children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ y("div", { className: "h-16 animate-pulse rounded bg-bg-sunken" }, t))
|
|
693
|
-
}) :
|
|
686
|
+
}) : G.pageItems.map((e) => /* @__PURE__ */ b("div", {
|
|
694
687
|
className: "p-4",
|
|
695
688
|
children: [/* @__PURE__ */ b("div", {
|
|
696
689
|
className: "flex items-start justify-between gap-2",
|
|
697
690
|
children: [/* @__PURE__ */ y("p", {
|
|
698
691
|
className: "min-w-0 flex-1 truncate font-medium",
|
|
699
692
|
children: e.title
|
|
700
|
-
}), /* @__PURE__ */ y(
|
|
701
|
-
tone:
|
|
693
|
+
}), /* @__PURE__ */ y(j, {
|
|
694
|
+
tone: N(e.status),
|
|
702
695
|
children: e.status.replace(/_/g, " ").toLowerCase()
|
|
703
696
|
})]
|
|
704
697
|
}), /* @__PURE__ */ b("div", {
|
|
@@ -708,7 +701,7 @@ function P() {
|
|
|
708
701
|
className: "capitalize",
|
|
709
702
|
children: e.type.replace(/_/g, " ")
|
|
710
703
|
}),
|
|
711
|
-
/* @__PURE__ */ b("span", { children: ["· ",
|
|
704
|
+
/* @__PURE__ */ b("span", { children: ["· ", U.get(e.assetId) ?? e.assetId] }),
|
|
712
705
|
e.actualCost == null ? null : /* @__PURE__ */ y("span", {
|
|
713
706
|
className: "ml-auto tabular-nums text-text-primary",
|
|
714
707
|
children: n(e.actualCost)
|
|
@@ -717,22 +710,22 @@ function P() {
|
|
|
717
710
|
})]
|
|
718
711
|
}, e.id))
|
|
719
712
|
}),
|
|
720
|
-
|
|
713
|
+
B.length === 0 && !R ? /* @__PURE__ */ y(C, {
|
|
721
714
|
illustration: "empty-data",
|
|
722
715
|
title: "No maintenance records",
|
|
723
716
|
description: "Logged maintenance work will appear here once scheduled or completed."
|
|
724
717
|
}) : /* @__PURE__ */ y("div", {
|
|
725
718
|
className: "px-3",
|
|
726
719
|
children: /* @__PURE__ */ y(a, {
|
|
727
|
-
page:
|
|
728
|
-
pageCount:
|
|
729
|
-
rangeStart:
|
|
730
|
-
rangeEnd:
|
|
731
|
-
totalItems:
|
|
732
|
-
canPrev:
|
|
733
|
-
canNext:
|
|
734
|
-
onPrev:
|
|
735
|
-
onNext:
|
|
720
|
+
page: G.page,
|
|
721
|
+
pageCount: G.pageCount,
|
|
722
|
+
rangeStart: G.rangeStart,
|
|
723
|
+
rangeEnd: G.rangeEnd,
|
|
724
|
+
totalItems: G.totalItems,
|
|
725
|
+
canPrev: G.canPrev,
|
|
726
|
+
canNext: G.canNext,
|
|
727
|
+
onPrev: G.prevPage,
|
|
728
|
+
onNext: G.nextPage,
|
|
736
729
|
itemLabel: "records"
|
|
737
730
|
})
|
|
738
731
|
})
|
|
@@ -740,7 +733,7 @@ function P() {
|
|
|
740
733
|
})
|
|
741
734
|
]
|
|
742
735
|
}),
|
|
743
|
-
/* @__PURE__ */ b(
|
|
736
|
+
/* @__PURE__ */ b(O, {
|
|
744
737
|
value: "utilization",
|
|
745
738
|
className: "mt-4 space-y-4",
|
|
746
739
|
children: [
|
|
@@ -748,9 +741,9 @@ function P() {
|
|
|
748
741
|
className: "flex justify-end",
|
|
749
742
|
children: /* @__PURE__ */ b(x, {
|
|
750
743
|
size: "sm",
|
|
751
|
-
onClick:
|
|
752
|
-
disabled: !
|
|
753
|
-
children: [/* @__PURE__ */ y(
|
|
744
|
+
onClick: be,
|
|
745
|
+
disabled: !H,
|
|
746
|
+
children: [/* @__PURE__ */ y(f, { className: "mr-2 h-4 w-4" }), "Export CSV"]
|
|
754
747
|
})
|
|
755
748
|
}),
|
|
756
749
|
/* @__PURE__ */ b("div", {
|
|
@@ -758,24 +751,24 @@ function P() {
|
|
|
758
751
|
children: [
|
|
759
752
|
/* @__PURE__ */ y(s, {
|
|
760
753
|
label: "Total assets",
|
|
761
|
-
value:
|
|
754
|
+
value: H?.totalAssets ?? 0
|
|
762
755
|
}),
|
|
763
756
|
/* @__PURE__ */ y(s, {
|
|
764
757
|
label: "Assigned",
|
|
765
|
-
value:
|
|
758
|
+
value: H?.assignedAssets ?? 0
|
|
766
759
|
}),
|
|
767
760
|
/* @__PURE__ */ y(s, {
|
|
768
761
|
label: "Unassigned",
|
|
769
|
-
value:
|
|
762
|
+
value: H?.unassignedAssets ?? 0
|
|
770
763
|
}),
|
|
771
764
|
/* @__PURE__ */ y(s, {
|
|
772
765
|
label: "Active unassigned",
|
|
773
|
-
value:
|
|
766
|
+
value: H?.idleAssets ?? 0
|
|
774
767
|
}),
|
|
775
768
|
/* @__PURE__ */ y(s, {
|
|
776
769
|
label: "Overdue assignments",
|
|
777
|
-
value:
|
|
778
|
-
delta:
|
|
770
|
+
value: H?.overdueAssignments ?? 0,
|
|
771
|
+
delta: H && H.overdueAssignments > 0 ? "Attention" : void 0,
|
|
779
772
|
deltaTone: "negative"
|
|
780
773
|
})
|
|
781
774
|
]
|
|
@@ -786,9 +779,9 @@ function P() {
|
|
|
786
779
|
title: "Assets by status",
|
|
787
780
|
subtitle: "Distribution across lifecycle states",
|
|
788
781
|
children: /* @__PURE__ */ y(i, {
|
|
789
|
-
data:
|
|
782
|
+
data: he,
|
|
790
783
|
centerLabel: "Assets",
|
|
791
|
-
centerValue:
|
|
784
|
+
centerValue: H?.totalAssets ?? 0,
|
|
792
785
|
height: 240,
|
|
793
786
|
emptyLabel: "No status data available.",
|
|
794
787
|
ariaLabel: "Assets by status"
|
|
@@ -797,9 +790,9 @@ function P() {
|
|
|
797
790
|
title: "Assignment coverage",
|
|
798
791
|
subtitle: "Mutually exclusive assigned, active-unassigned and other-unassigned assets",
|
|
799
792
|
children: /* @__PURE__ */ y(i, {
|
|
800
|
-
data:
|
|
793
|
+
data: ge,
|
|
801
794
|
centerLabel: "Assets",
|
|
802
|
-
centerValue:
|
|
795
|
+
centerValue: H?.totalAssets ?? 0,
|
|
803
796
|
height: 240,
|
|
804
797
|
emptyLabel: "No coverage data available.",
|
|
805
798
|
ariaLabel: "Assignment coverage"
|
|
@@ -814,6 +807,6 @@ function P() {
|
|
|
814
807
|
});
|
|
815
808
|
}
|
|
816
809
|
//#endregion
|
|
817
|
-
export {
|
|
810
|
+
export { F as ReportsDashboardPage };
|
|
818
811
|
|
|
819
812
|
//# sourceMappingURL=ReportsDashboardPage.js.map
|
|
@@ -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';\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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"}
|
|
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, buildUtilizationCsvRows } 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 buildUtilizationCsvRows(utilization)\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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"}
|
|
@@ -2,6 +2,18 @@ export interface AssignmentCoverageSlice {
|
|
|
2
2
|
name: 'Assigned' | 'Active unassigned' | 'Other unassigned';
|
|
3
3
|
value: number;
|
|
4
4
|
}
|
|
5
|
+
interface UtilizationCsvReport {
|
|
6
|
+
totalAssets: number;
|
|
7
|
+
assignedAssets: number;
|
|
8
|
+
unassignedAssets: number;
|
|
9
|
+
idleAssets: number;
|
|
10
|
+
overdueAssignments: number;
|
|
11
|
+
byStatus: ReadonlyArray<{
|
|
12
|
+
status: string;
|
|
13
|
+
count: number;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildUtilizationCsvRows(report: UtilizationCsvReport): Array<[string, number]>;
|
|
5
17
|
/**
|
|
6
18
|
* Build mutually exclusive assignment-coverage slices.
|
|
7
19
|
*
|
|
@@ -9,4 +21,5 @@ export interface AssignmentCoverageSlice {
|
|
|
9
21
|
* so it is a subset of unassigned assets rather than a third coverage state.
|
|
10
22
|
*/
|
|
11
23
|
export declare function buildAssignmentCoverageSlices(assignedAssets: number, unassignedAssets: number, idleAssets: number): AssignmentCoverageSlice[];
|
|
24
|
+
export {};
|
|
12
25
|
//# sourceMappingURL=utilization.d.ts.map
|
|
@@ -1 +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"}
|
|
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,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,aAAa,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5D;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,oBAAoB,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAS7F;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,GACjB,uBAAuB,EAAE,CAa3B"}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
//#region src/assethandler/utils/utilization.ts
|
|
2
|
-
function e(e
|
|
2
|
+
function e(e) {
|
|
3
|
+
return [
|
|
4
|
+
["Total assets", e.totalAssets],
|
|
5
|
+
["Assigned assets", e.assignedAssets],
|
|
6
|
+
["Unassigned assets", e.unassignedAssets],
|
|
7
|
+
["Active unassigned assets", e.idleAssets],
|
|
8
|
+
["Overdue assignments", e.overdueAssignments],
|
|
9
|
+
...e.byStatus.map((e) => [`Status: ${e.status}`, e.count])
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
function t(e, t, n) {
|
|
3
13
|
let r = Math.max(0, e), i = Math.max(0, t), a = Math.min(i, Math.max(0, n)), o = i - a;
|
|
4
14
|
return [
|
|
5
15
|
{
|
|
@@ -17,6 +27,6 @@ function e(e, t, n) {
|
|
|
17
27
|
].filter((e) => e.value > 0);
|
|
18
28
|
}
|
|
19
29
|
//#endregion
|
|
20
|
-
export {
|
|
30
|
+
export { t as buildAssignmentCoverageSlices, e as buildUtilizationCsvRows };
|
|
21
31
|
|
|
22
32
|
//# sourceMappingURL=utilization.js.map
|
|
@@ -1 +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":";
|
|
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\ninterface UtilizationCsvReport {\n totalAssets: number;\n assignedAssets: number;\n unassignedAssets: number;\n idleAssets: number;\n overdueAssignments: number;\n byStatus: ReadonlyArray<{ status: string; count: number }>;\n}\n\nexport function buildUtilizationCsvRows(report: UtilizationCsvReport): Array<[string, number]> {\n return [\n ['Total assets', report.totalAssets],\n ['Assigned assets', report.assignedAssets],\n ['Unassigned assets', report.unassignedAssets],\n ['Active unassigned assets', report.idleAssets],\n ['Overdue assignments', report.overdueAssignments],\n ...report.byStatus.map((entry): [string, number] => [`Status: ${entry.status}`, entry.count]),\n ];\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":";AAcA,SAAgB,EAAwB,GAAuD;CAC7F,OAAO;EACL,CAAC,gBAAgB,EAAO,WAAW;EACnC,CAAC,mBAAmB,EAAO,cAAc;EACzC,CAAC,qBAAqB,EAAO,gBAAgB;EAC7C,CAAC,4BAA4B,EAAO,UAAU;EAC9C,CAAC,uBAAuB,EAAO,kBAAkB;EACjD,GAAG,EAAO,SAAS,KAAK,MAA4B,CAAC,WAAW,EAAM,UAAU,EAAM,KAAK,CAAC;CAC9F;AACF;AAQA,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"}
|