@burdenoff/microfe-assethandler 2026.703.2 → 2026.703.3
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/AssetHandlerRoot.js +18 -18
- package/dist/assethandler/hooks/useAssetHandlerNavigate.js +19 -0
- package/dist/assethandler/hooks/useAssetHandlerNavigate.js.map +1 -0
- package/dist/assethandler/pages/AiPredictionsPage.js +29 -29
- package/dist/assethandler/pages/AnalyticsPage.js +154 -154
- package/dist/assethandler/pages/AssetsAssetCategoriesPage.js +48 -48
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js +84 -84
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCreatePage.js +82 -82
- package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetDetailPage.js +104 -103
- package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetListPage.js +132 -132
- package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetTrackingPage.js +52 -52
- package/dist/assethandler/pages/CmdbBrowserPage.js +27 -27
- package/dist/assethandler/pages/DashboardPage.js +119 -119
- package/dist/assethandler/pages/DashboardPage.js.map +1 -1
- package/dist/assethandler/pages/DigitalTwinPage.js +22 -22
- package/dist/assethandler/pages/DiscoveryJobsPage.js +35 -35
- package/dist/assethandler/pages/EsgDashboardPage.js +32 -32
- package/dist/assethandler/pages/FinanceBudgetDetailPage.js +57 -56
- package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js +98 -98
- package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceInvoiceDetailPage.js +58 -57
- package/dist/assethandler/pages/FinanceInvoiceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/IotDevicesPage.js +29 -29
- package/dist/assethandler/pages/ItilChangeDetailPage.js +76 -75
- package/dist/assethandler/pages/ItilChangeDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeManagementPage.js +49 -49
- package/dist/assethandler/pages/ItilIncidentDetailPage.js +63 -62
- package/dist/assethandler/pages/ItilIncidentDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentManagementPage.js +72 -72
- package/dist/assethandler/pages/ItilItilhubPage.js +112 -112
- package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemDetailPage.js +61 -60
- package/dist/assethandler/pages/ItilProblemDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemManagementPage.js +46 -46
- package/dist/assethandler/pages/KnowledgeBasePage.js +28 -28
- package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js +52 -52
- package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js +29 -29
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js +58 -57
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsOperationsHubPage.js +80 -80
- package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js +49 -48
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
- package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js +52 -52
- package/dist/assethandler/pages/ProvenancePage.js +36 -36
- package/dist/assethandler/pages/SamLicensesPage.js +27 -27
- package/dist/assethandler/pages/SecurityComplianceDetailPage.js +39 -38
- package/dist/assethandler/pages/SecurityComplianceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecurityPolicyDetailPage.js +50 -49
- package/dist/assethandler/pages/SecurityPolicyDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityEventDetailPage.js +47 -46
- package/dist/assethandler/pages/SecuritySecurityEventDetailPage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityHubPage.js +104 -104
- package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js +74 -73
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionListPage.js +77 -77
- package/dist/assethandler/providers/AssetHandlerProvider.js +12 -12
- package/package.json +1 -1
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
import { useAssetHandlerStore as e } from "../store/assethandlerStore.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { useAssetHandlerNavigate as t } from "../hooks/useAssetHandlerNavigate.js";
|
|
3
|
+
import { tWithFallback as n } from "../utils/i18n.js";
|
|
4
|
+
import { Activity as r, AlertTriangle as i, Box as a, CheckCircle as o, ClipboardList as s, Clock as c, Receipt as l, Wrench as u } from "lucide-react";
|
|
5
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
6
|
+
import { AuroraBackground as p, Badge as m, CTAOverflowMenu as h, Card as g, CardContent as _, CardDescription as v, CardHeader as y, CardTitle as b, EmphasisPanel as x, GlassCard as S, GradientText as C, IllustratedEmptyState as w, NextSteps as T, PagePurpose as E } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
import { useI18n as D } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
8
|
//#region src/assethandler/pages/DashboardPage.tsx
|
|
9
9
|
function O() {
|
|
10
|
-
let { t: O } =
|
|
10
|
+
let { t: O } = D(), k = t(), { hydrated: A, overview: j, assets: M, incidents: N, maintenanceRecords: P, changeRequests: F, workOrders: I } = e(), L = N.filter((e) => e.status !== "resolved" && e.status !== "closed"), R = N.filter((e) => e.priority === "critical" && e.status !== "resolved" && e.status !== "closed"), z = P.filter((e) => e.status === "scheduled" || e.status === "in_progress"), B = I.filter((e) => e.status !== "completed" && e.status !== "cancelled"), V = F.filter((e) => e.status === "approved" || e.status === "submitted"), H = [
|
|
11
11
|
{
|
|
12
|
-
label:
|
|
12
|
+
label: n(O, "assethandler.dashboard.metrics.totalAssets", "Total Assets"),
|
|
13
13
|
value: j?.totalAssets ?? M.length,
|
|
14
|
-
icon:
|
|
14
|
+
icon: a
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
|
-
label:
|
|
17
|
+
label: n(O, "assethandler.dashboard.metrics.openIncidents", "Open Incidents"),
|
|
18
18
|
value: j?.openIncidents ?? L.length,
|
|
19
|
-
icon:
|
|
19
|
+
icon: i
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
|
-
label:
|
|
22
|
+
label: n(O, "assethandler.dashboard.metrics.openWorkOrders", "Open Work Orders"),
|
|
23
23
|
value: j?.openWorkOrders ?? B.length,
|
|
24
|
-
icon:
|
|
24
|
+
icon: s
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
label:
|
|
27
|
+
label: n(O, "assethandler.dashboard.metrics.transactions", "Transactions"),
|
|
28
28
|
value: j?.totalTransactions ?? 0,
|
|
29
|
-
icon:
|
|
29
|
+
icon: l
|
|
30
30
|
}
|
|
31
31
|
], U = M.reduce((e, t) => {
|
|
32
32
|
let n = t.category || "uncategorized";
|
|
33
33
|
return e[n] = (e[n] ?? 0) + 1, e;
|
|
34
34
|
}, {}), W = Object.entries(U).sort((e, t) => t[1] - e[1]), G = [...P].filter((e) => e.status !== "completed" && e.status !== "cancelled").sort((e, t) => (e.scheduledDate ?? "").localeCompare(t.scheduledDate ?? "")).slice(0, 8), K = [...B].sort((e, t) => t.createdAt.localeCompare(e.createdAt)).slice(0, 5);
|
|
35
|
-
return /* @__PURE__ */
|
|
35
|
+
return /* @__PURE__ */ f("div", {
|
|
36
36
|
className: "space-y-6 p-6",
|
|
37
37
|
children: [
|
|
38
|
-
/* @__PURE__ */
|
|
38
|
+
/* @__PURE__ */ f("div", {
|
|
39
39
|
className: "relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6",
|
|
40
|
-
children: [/* @__PURE__ */
|
|
40
|
+
children: [/* @__PURE__ */ d(p, { intensity: "subtle" }), /* @__PURE__ */ f("div", {
|
|
41
41
|
className: "relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
42
|
-
children: [/* @__PURE__ */
|
|
42
|
+
children: [/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("h1", {
|
|
43
43
|
className: "text-3xl font-bold",
|
|
44
|
-
children: /* @__PURE__ */
|
|
45
|
-
}), /* @__PURE__ */
|
|
44
|
+
children: /* @__PURE__ */ d(C, { children: n(O, "assethandler.dashboard.title", "Dashboard") })
|
|
45
|
+
}), /* @__PURE__ */ d("p", {
|
|
46
46
|
className: "text-sm text-text-secondary mt-1",
|
|
47
|
-
children:
|
|
48
|
-
})] }), /* @__PURE__ */
|
|
47
|
+
children: n(O, "assethandler.dashboard.description", "Overview of your IT asset portfolio and operations")
|
|
48
|
+
})] }), /* @__PURE__ */ d(h, {
|
|
49
49
|
primary: {
|
|
50
|
-
label:
|
|
50
|
+
label: n(O, "assethandler.dashboard.actions.addAsset", "Add Asset"),
|
|
51
51
|
onSelect: () => k("/assets/asset-create")
|
|
52
52
|
},
|
|
53
53
|
actions: [{
|
|
54
|
-
label:
|
|
54
|
+
label: n(O, "assethandler.dashboard.actions.viewAnalytics", "View Analytics"),
|
|
55
55
|
onSelect: () => k("/analytics")
|
|
56
56
|
}]
|
|
57
57
|
})]
|
|
58
58
|
})]
|
|
59
59
|
}),
|
|
60
|
-
/* @__PURE__ */ E
|
|
61
|
-
/* @__PURE__ */
|
|
60
|
+
/* @__PURE__ */ d(E, { children: n(O, "assethandler.dashboard.purpose", "Your command center for the whole asset estate — see what needs attention (open incidents, due maintenance, critical alerts) and recent activity at a glance, then jump straight to the area that needs you. Start here every day to know where to act.") }),
|
|
61
|
+
/* @__PURE__ */ d(T, {
|
|
62
62
|
storageKey: "assethandler-dashboard",
|
|
63
63
|
steps: [
|
|
64
64
|
{
|
|
@@ -87,52 +87,52 @@ function O() {
|
|
|
87
87
|
}
|
|
88
88
|
]
|
|
89
89
|
}),
|
|
90
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ d("div", {
|
|
91
91
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
92
92
|
children: H.map((e, t) => {
|
|
93
93
|
let n = e.icon, r = t === 0;
|
|
94
|
-
return /* @__PURE__ */
|
|
94
|
+
return /* @__PURE__ */ f(S, {
|
|
95
95
|
treatment: r ? "glass" : "metric",
|
|
96
96
|
glow: r,
|
|
97
97
|
className: "border-border-seam",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
98
|
+
children: [/* @__PURE__ */ f(y, {
|
|
99
99
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
100
|
+
children: [/* @__PURE__ */ d(b, {
|
|
101
101
|
className: "text-sm font-medium",
|
|
102
102
|
children: e.label
|
|
103
|
-
}), /* @__PURE__ */
|
|
104
|
-
}), /* @__PURE__ */
|
|
103
|
+
}), /* @__PURE__ */ d(n, { className: "h-4 w-4 text-text-secondary" })]
|
|
104
|
+
}), /* @__PURE__ */ d(_, { children: /* @__PURE__ */ d("div", {
|
|
105
105
|
className: "text-2xl font-bold tabular-nums",
|
|
106
106
|
children: A ? e.value.toLocaleString() : "—"
|
|
107
107
|
}) })]
|
|
108
108
|
}, e.label);
|
|
109
109
|
})
|
|
110
110
|
}),
|
|
111
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ f("div", {
|
|
112
112
|
className: "grid gap-6 lg:grid-cols-3",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ f(x, {
|
|
114
114
|
className: "lg:col-span-2",
|
|
115
|
-
children: [/* @__PURE__ */
|
|
115
|
+
children: [/* @__PURE__ */ f(y, {
|
|
116
116
|
className: "px-0 pt-0",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
118
|
-
}), /* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ d(b, { children: n(O, "assethandler.dashboard.portfolio.title", "Portfolio Breakdown") }), /* @__PURE__ */ d(v, { children: n(O, "assethandler.dashboard.portfolio.description", "Asset distribution by category") })]
|
|
118
|
+
}), /* @__PURE__ */ d(_, {
|
|
119
119
|
className: "px-0 pb-0",
|
|
120
|
-
children: W.length === 0 ? /* @__PURE__ */
|
|
120
|
+
children: W.length === 0 ? /* @__PURE__ */ d(w, {
|
|
121
121
|
illustration: "empty-data",
|
|
122
|
-
title:
|
|
123
|
-
description:
|
|
124
|
-
}) : /* @__PURE__ */
|
|
122
|
+
title: n(O, "assethandler.dashboard.portfolio.empty.title", "No assets yet"),
|
|
123
|
+
description: n(O, "assethandler.dashboard.portfolio.empty.description", "Register your first asset and category distribution will appear here.")
|
|
124
|
+
}) : /* @__PURE__ */ d("div", {
|
|
125
125
|
className: "space-y-4",
|
|
126
126
|
children: W.map(([e, t]) => {
|
|
127
127
|
let n = M.length > 0 ? Math.round(t / M.length * 100) : 0;
|
|
128
|
-
return /* @__PURE__ */
|
|
128
|
+
return /* @__PURE__ */ f("div", {
|
|
129
129
|
className: "space-y-1",
|
|
130
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ f("div", {
|
|
131
131
|
className: "flex items-center justify-between text-sm",
|
|
132
|
-
children: [/* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ d("span", {
|
|
133
133
|
className: "font-medium capitalize",
|
|
134
134
|
children: e.replace(/_/g, " ")
|
|
135
|
-
}), /* @__PURE__ */
|
|
135
|
+
}), /* @__PURE__ */ f("span", {
|
|
136
136
|
className: "text-text-secondary tabular-nums",
|
|
137
137
|
children: [
|
|
138
138
|
t,
|
|
@@ -140,9 +140,9 @@ function O() {
|
|
|
140
140
|
t === 1 ? "asset" : "assets"
|
|
141
141
|
]
|
|
142
142
|
})]
|
|
143
|
-
}), /* @__PURE__ */
|
|
143
|
+
}), /* @__PURE__ */ d("div", {
|
|
144
144
|
className: "h-2 rounded-full bg-bg-sunken overflow-hidden",
|
|
145
|
-
children: /* @__PURE__ */
|
|
145
|
+
children: /* @__PURE__ */ d("div", {
|
|
146
146
|
className: "h-full rounded-full bg-action-primary-bg motion-safe:animate-vc-glow-pulse",
|
|
147
147
|
style: { width: `${n}%` }
|
|
148
148
|
})
|
|
@@ -151,41 +151,41 @@ function O() {
|
|
|
151
151
|
})
|
|
152
152
|
})
|
|
153
153
|
})]
|
|
154
|
-
}), /* @__PURE__ */
|
|
154
|
+
}), /* @__PURE__ */ f(S, {
|
|
155
155
|
treatment: "insight",
|
|
156
156
|
className: "border-border-seam",
|
|
157
|
-
children: [/* @__PURE__ */
|
|
157
|
+
children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ f(b, {
|
|
158
158
|
className: "flex items-center gap-2",
|
|
159
|
-
children: [/* @__PURE__ */
|
|
160
|
-
}), /* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ d(i, { className: "h-4 w-4 text-status-error-text" }), n(O, "assethandler.dashboard.incidents.title", "Active Incidents")]
|
|
160
|
+
}), /* @__PURE__ */ f(v, { children: [
|
|
161
161
|
L.length,
|
|
162
162
|
" ",
|
|
163
|
-
|
|
164
|
-
] })] }), /* @__PURE__ */
|
|
163
|
+
n(O, "assethandler.dashboard.incidents.unresolvedCount", "unresolved incidents")
|
|
164
|
+
] })] }), /* @__PURE__ */ d(_, { children: L.length === 0 ? /* @__PURE__ */ d("p", {
|
|
165
165
|
className: "text-sm text-text-secondary py-4 text-center",
|
|
166
|
-
children:
|
|
167
|
-
}) : /* @__PURE__ */
|
|
166
|
+
children: n(O, "assethandler.dashboard.incidents.empty", "No unresolved incidents — all clear.")
|
|
167
|
+
}) : /* @__PURE__ */ d("div", {
|
|
168
168
|
className: "space-y-3",
|
|
169
|
-
children: L.slice(0, 4).map((e) => /* @__PURE__ */
|
|
169
|
+
children: L.slice(0, 4).map((e) => /* @__PURE__ */ d("div", {
|
|
170
170
|
className: "flex items-start gap-3 rounded-lg border p-3",
|
|
171
|
-
children: /* @__PURE__ */
|
|
171
|
+
children: /* @__PURE__ */ f("div", {
|
|
172
172
|
className: "flex-1 min-w-0",
|
|
173
173
|
children: [
|
|
174
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ d("div", {
|
|
175
175
|
className: "flex items-center gap-2",
|
|
176
|
-
children: /* @__PURE__ */
|
|
176
|
+
children: /* @__PURE__ */ d(m, {
|
|
177
177
|
variant: e.priority === "critical" || e.priority === "high" ? "destructive" : "secondary",
|
|
178
178
|
className: "text-[10px]",
|
|
179
179
|
children: e.priority
|
|
180
180
|
})
|
|
181
181
|
}),
|
|
182
|
-
/* @__PURE__ */
|
|
182
|
+
/* @__PURE__ */ d("p", {
|
|
183
183
|
className: "text-sm font-medium truncate mt-1",
|
|
184
184
|
children: e.title
|
|
185
185
|
}),
|
|
186
|
-
/* @__PURE__ */
|
|
186
|
+
/* @__PURE__ */ d("p", {
|
|
187
187
|
className: "text-xs text-text-secondary mt-0.5",
|
|
188
|
-
children: e.assignedTo ||
|
|
188
|
+
children: e.assignedTo || n(O, "assethandler.dashboard.incidents.unassigned", "Unassigned")
|
|
189
189
|
})
|
|
190
190
|
]
|
|
191
191
|
})
|
|
@@ -193,24 +193,24 @@ function O() {
|
|
|
193
193
|
}) })]
|
|
194
194
|
})]
|
|
195
195
|
}),
|
|
196
|
-
/* @__PURE__ */
|
|
196
|
+
/* @__PURE__ */ f("div", {
|
|
197
197
|
className: "grid gap-6 lg:grid-cols-2",
|
|
198
|
-
children: [/* @__PURE__ */
|
|
198
|
+
children: [/* @__PURE__ */ f(g, { children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: n(O, "assethandler.dashboard.workOrders.title", "Open Work Orders") }), /* @__PURE__ */ d(v, { children: n(O, "assethandler.dashboard.workOrders.description", "Latest work in progress") })] }), /* @__PURE__ */ d(_, { children: K.length === 0 ? /* @__PURE__ */ d("p", {
|
|
199
199
|
className: "text-sm text-text-secondary py-4 text-center",
|
|
200
|
-
children:
|
|
201
|
-
}) : /* @__PURE__ */
|
|
200
|
+
children: n(O, "assethandler.dashboard.workOrders.empty", "No open work orders. Create one from the Operations hub.")
|
|
201
|
+
}) : /* @__PURE__ */ d("div", {
|
|
202
202
|
className: "space-y-3",
|
|
203
|
-
children: K.map((e) => /* @__PURE__ */
|
|
203
|
+
children: K.map((e) => /* @__PURE__ */ f("div", {
|
|
204
204
|
className: "flex items-center gap-3",
|
|
205
|
-
children: [/* @__PURE__ */
|
|
205
|
+
children: [/* @__PURE__ */ d("span", {
|
|
206
206
|
className: "inline-flex items-center rounded-md px-2 py-1 text-[10px] font-medium bg-status-info-bg-subtle text-status-info-text capitalize",
|
|
207
207
|
children: e.status.replace(/_/g, " ")
|
|
208
|
-
}), /* @__PURE__ */
|
|
208
|
+
}), /* @__PURE__ */ f("div", {
|
|
209
209
|
className: "flex-1 min-w-0",
|
|
210
|
-
children: [/* @__PURE__ */
|
|
210
|
+
children: [/* @__PURE__ */ d("p", {
|
|
211
211
|
className: "text-sm truncate",
|
|
212
212
|
children: e.title
|
|
213
|
-
}), /* @__PURE__ */
|
|
213
|
+
}), /* @__PURE__ */ f("p", {
|
|
214
214
|
className: "text-xs text-text-secondary capitalize",
|
|
215
215
|
children: [
|
|
216
216
|
e.type,
|
|
@@ -220,128 +220,128 @@ function O() {
|
|
|
220
220
|
})]
|
|
221
221
|
})]
|
|
222
222
|
}, e.id))
|
|
223
|
-
}) })] }), /* @__PURE__ */
|
|
223
|
+
}) })] }), /* @__PURE__ */ f(g, { children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: n(O, "assethandler.dashboard.operations.title", "Operations Summary") }), /* @__PURE__ */ d(v, { children: n(O, "assethandler.dashboard.operations.description", "Quick view of current operations") })] }), /* @__PURE__ */ d(_, { children: /* @__PURE__ */ f("div", {
|
|
224
224
|
className: "grid grid-cols-2 gap-4",
|
|
225
225
|
children: [
|
|
226
|
-
/* @__PURE__ */
|
|
226
|
+
/* @__PURE__ */ f("div", {
|
|
227
227
|
className: "rounded-lg border border-border-seam bg-gloss-card p-4 text-center",
|
|
228
228
|
children: [
|
|
229
|
-
/* @__PURE__ */
|
|
230
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ d(u, { className: "h-5 w-5 mx-auto text-text-secondary mb-2" }),
|
|
230
|
+
/* @__PURE__ */ d("p", {
|
|
231
231
|
className: "text-2xl font-bold tabular-nums",
|
|
232
232
|
children: z.length
|
|
233
233
|
}),
|
|
234
|
-
/* @__PURE__ */
|
|
234
|
+
/* @__PURE__ */ d("p", {
|
|
235
235
|
className: "text-xs text-text-secondary",
|
|
236
|
-
children:
|
|
236
|
+
children: n(O, "assethandler.dashboard.operations.pendingMaintenance", "Pending Maintenance")
|
|
237
237
|
})
|
|
238
238
|
]
|
|
239
239
|
}),
|
|
240
|
-
/* @__PURE__ */
|
|
240
|
+
/* @__PURE__ */ f("div", {
|
|
241
241
|
className: "rounded-lg border border-border-seam bg-gloss-card p-4 text-center",
|
|
242
242
|
children: [
|
|
243
|
-
/* @__PURE__ */
|
|
244
|
-
/* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ d(r, { className: "h-5 w-5 mx-auto text-text-secondary mb-2" }),
|
|
244
|
+
/* @__PURE__ */ d("p", {
|
|
245
245
|
className: "text-2xl font-bold tabular-nums",
|
|
246
246
|
children: B.length
|
|
247
247
|
}),
|
|
248
|
-
/* @__PURE__ */
|
|
248
|
+
/* @__PURE__ */ d("p", {
|
|
249
249
|
className: "text-xs text-text-secondary",
|
|
250
|
-
children:
|
|
250
|
+
children: n(O, "assethandler.dashboard.operations.openWorkOrders", "Open Work Orders")
|
|
251
251
|
})
|
|
252
252
|
]
|
|
253
253
|
}),
|
|
254
|
-
/* @__PURE__ */
|
|
254
|
+
/* @__PURE__ */ f("div", {
|
|
255
255
|
className: "rounded-lg border border-border-seam bg-gloss-card p-4 text-center",
|
|
256
256
|
children: [
|
|
257
|
-
/* @__PURE__ */
|
|
258
|
-
/* @__PURE__ */
|
|
257
|
+
/* @__PURE__ */ d(c, { className: "h-5 w-5 mx-auto text-text-secondary mb-2" }),
|
|
258
|
+
/* @__PURE__ */ d("p", {
|
|
259
259
|
className: "text-2xl font-bold tabular-nums",
|
|
260
260
|
children: V.length
|
|
261
261
|
}),
|
|
262
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ d("p", {
|
|
263
263
|
className: "text-xs text-text-secondary",
|
|
264
|
-
children:
|
|
264
|
+
children: n(O, "assethandler.dashboard.operations.pendingChanges", "Pending Changes")
|
|
265
265
|
})
|
|
266
266
|
]
|
|
267
267
|
}),
|
|
268
|
-
/* @__PURE__ */
|
|
268
|
+
/* @__PURE__ */ f("div", {
|
|
269
269
|
className: "rounded-lg border border-border-seam bg-gloss-card p-4 text-center",
|
|
270
270
|
children: [
|
|
271
|
-
/* @__PURE__ */
|
|
272
|
-
/* @__PURE__ */
|
|
271
|
+
/* @__PURE__ */ d(o, { className: "h-5 w-5 mx-auto text-text-secondary mb-2" }),
|
|
272
|
+
/* @__PURE__ */ d("p", {
|
|
273
273
|
className: "text-2xl font-bold tabular-nums",
|
|
274
274
|
children: R.length
|
|
275
275
|
}),
|
|
276
|
-
/* @__PURE__ */
|
|
276
|
+
/* @__PURE__ */ d("p", {
|
|
277
277
|
className: "text-xs text-text-secondary",
|
|
278
|
-
children:
|
|
278
|
+
children: n(O, "assethandler.dashboard.operations.criticalAlerts", "Critical Alerts")
|
|
279
279
|
})
|
|
280
280
|
]
|
|
281
281
|
})
|
|
282
282
|
]
|
|
283
283
|
}) })] })]
|
|
284
284
|
}),
|
|
285
|
-
/* @__PURE__ */
|
|
285
|
+
/* @__PURE__ */ f(g, { children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ f(b, {
|
|
286
286
|
className: "flex items-center gap-2",
|
|
287
|
-
children: [/* @__PURE__ */
|
|
288
|
-
}), /* @__PURE__ */
|
|
287
|
+
children: [/* @__PURE__ */ d(u, { className: "h-4 w-4" }), n(O, "assethandler.dashboard.maintenance.title", "Upcoming Maintenance")]
|
|
288
|
+
}), /* @__PURE__ */ d(v, { children: n(O, "assethandler.dashboard.maintenance.description", "Scheduled maintenance activities") })] }), /* @__PURE__ */ d(_, { children: G.length === 0 ? /* @__PURE__ */ d(w, {
|
|
289
289
|
illustration: "empty-tasks",
|
|
290
|
-
title:
|
|
291
|
-
description:
|
|
292
|
-
}) : /* @__PURE__ */
|
|
290
|
+
title: n(O, "assethandler.dashboard.maintenance.empty.title", "No maintenance scheduled"),
|
|
291
|
+
description: n(O, "assethandler.dashboard.maintenance.empty.description", "Plan preventive maintenance from the scheduler and it will show up here.")
|
|
292
|
+
}) : /* @__PURE__ */ d("div", {
|
|
293
293
|
className: "overflow-x-auto",
|
|
294
|
-
children: /* @__PURE__ */
|
|
294
|
+
children: /* @__PURE__ */ f("table", {
|
|
295
295
|
className: "w-full text-sm",
|
|
296
|
-
children: [/* @__PURE__ */
|
|
296
|
+
children: [/* @__PURE__ */ d("thead", { children: /* @__PURE__ */ f("tr", {
|
|
297
297
|
className: "border-b",
|
|
298
298
|
children: [
|
|
299
|
-
/* @__PURE__ */
|
|
299
|
+
/* @__PURE__ */ d("th", {
|
|
300
300
|
className: "text-left py-2 font-medium",
|
|
301
|
-
children:
|
|
301
|
+
children: n(O, "assethandler.dashboard.maintenance.table.title", "Title")
|
|
302
302
|
}),
|
|
303
|
-
/* @__PURE__ */
|
|
303
|
+
/* @__PURE__ */ d("th", {
|
|
304
304
|
className: "text-left py-2 font-medium",
|
|
305
|
-
children:
|
|
305
|
+
children: n(O, "assethandler.dashboard.maintenance.table.type", "Type")
|
|
306
306
|
}),
|
|
307
|
-
/* @__PURE__ */
|
|
307
|
+
/* @__PURE__ */ d("th", {
|
|
308
308
|
className: "text-left py-2 font-medium",
|
|
309
|
-
children:
|
|
309
|
+
children: n(O, "assethandler.dashboard.maintenance.table.priority", "Priority")
|
|
310
310
|
}),
|
|
311
|
-
/* @__PURE__ */
|
|
311
|
+
/* @__PURE__ */ d("th", {
|
|
312
312
|
className: "text-left py-2 font-medium",
|
|
313
|
-
children:
|
|
313
|
+
children: n(O, "assethandler.dashboard.maintenance.table.scheduled", "Scheduled")
|
|
314
314
|
}),
|
|
315
|
-
/* @__PURE__ */
|
|
315
|
+
/* @__PURE__ */ d("th", {
|
|
316
316
|
className: "text-left py-2 font-medium",
|
|
317
|
-
children:
|
|
317
|
+
children: n(O, "assethandler.dashboard.maintenance.table.status", "Status")
|
|
318
318
|
})
|
|
319
319
|
]
|
|
320
|
-
}) }), /* @__PURE__ */
|
|
320
|
+
}) }), /* @__PURE__ */ d("tbody", { children: G.map((e) => /* @__PURE__ */ f("tr", {
|
|
321
321
|
className: "border-b hover:bg-bg-sunken/50",
|
|
322
322
|
children: [
|
|
323
|
-
/* @__PURE__ */
|
|
323
|
+
/* @__PURE__ */ d("td", {
|
|
324
324
|
className: "py-2",
|
|
325
325
|
children: e.title
|
|
326
326
|
}),
|
|
327
|
-
/* @__PURE__ */
|
|
327
|
+
/* @__PURE__ */ d("td", {
|
|
328
328
|
className: "py-2 capitalize",
|
|
329
329
|
children: e.type
|
|
330
330
|
}),
|
|
331
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ d("td", {
|
|
332
332
|
className: "py-2",
|
|
333
|
-
children: /* @__PURE__ */
|
|
333
|
+
children: /* @__PURE__ */ d(m, {
|
|
334
334
|
variant: e.priority === "critical" || e.priority === "high" ? "destructive" : "secondary",
|
|
335
335
|
children: e.priority
|
|
336
336
|
})
|
|
337
337
|
}),
|
|
338
|
-
/* @__PURE__ */
|
|
338
|
+
/* @__PURE__ */ d("td", {
|
|
339
339
|
className: "py-2",
|
|
340
340
|
children: e.scheduledDate ? new Date(e.scheduledDate).toLocaleDateString() : "—"
|
|
341
341
|
}),
|
|
342
|
-
/* @__PURE__ */
|
|
342
|
+
/* @__PURE__ */ d("td", {
|
|
343
343
|
className: "py-2",
|
|
344
|
-
children: /* @__PURE__ */
|
|
344
|
+
children: /* @__PURE__ */ d(m, {
|
|
345
345
|
variant: e.status === "completed" ? "default" : e.status === "in_progress" ? "secondary" : "outline",
|
|
346
346
|
className: "capitalize",
|
|
347
347
|
children: e.status.replace(/_/g, " ")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/DashboardPage.tsx"],"sourcesContent":["import {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Activity,\n AlertTriangle,\n Box,\n Clock,\n ClipboardList,\n Receipt,\n Wrench,\n CheckCircle,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { tWithFallback } from '../utils/i18n';\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { hydrated, overview, assets, incidents, maintenanceRecords, changeRequests, workOrders } =\n useAssetHandlerStore();\n\n const activeIncidents = incidents.filter((i) => i.status !== 'resolved' && i.status !== 'closed');\n const criticalIncidents = incidents.filter(\n (i) => i.priority === 'critical' && i.status !== 'resolved' && i.status !== 'closed'\n );\n const pendingMaintenance = maintenanceRecords.filter(\n (m) => m.status === 'scheduled' || m.status === 'in_progress'\n );\n const openWorkOrders = workOrders.filter(\n (w) => w.status !== 'completed' && w.status !== 'cancelled'\n );\n const pendingChanges = changeRequests.filter(\n (c) => c.status === 'approved' || c.status === 'submitted'\n );\n\n const metrics = [\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.totalAssets', 'Total Assets'),\n value: overview?.totalAssets ?? assets.length,\n icon: Box,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.openIncidents', 'Open Incidents'),\n value: overview?.openIncidents ?? activeIncidents.length,\n icon: AlertTriangle,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.openWorkOrders', 'Open Work Orders'),\n value: overview?.openWorkOrders ?? openWorkOrders.length,\n icon: ClipboardList,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.transactions', 'Transactions'),\n value: overview?.totalTransactions ?? 0,\n icon: Receipt,\n },\n ];\n\n const categoryCounts = assets.reduce<Record<string, number>>((acc, asset) => {\n const key = asset.category || 'uncategorized';\n acc[key] = (acc[key] ?? 0) + 1;\n return acc;\n }, {});\n const categoryBreakdown = Object.entries(categoryCounts).sort((a, b) => b[1] - a[1]);\n\n const upcomingMaintenance = [...maintenanceRecords]\n .filter((m) => m.status !== 'completed' && m.status !== 'cancelled')\n .sort((a, b) => (a.scheduledDate ?? '').localeCompare(b.scheduledDate ?? ''))\n .slice(0, 8);\n\n const recentWorkOrders = [...openWorkOrders]\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, 5);\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-3xl font-bold\">\n <GradientText>\n {tWithFallback(t, 'assethandler.dashboard.title', 'Dashboard')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.description',\n 'Overview of your IT asset portfolio and operations'\n )}\n </p>\n </div>\n <CTAOverflowMenu\n primary={{\n label: tWithFallback(t, 'assethandler.dashboard.actions.addAsset', 'Add Asset'),\n onSelect: () => navigate('/assets/asset-create'),\n }}\n actions={[\n {\n label: tWithFallback(\n t,\n 'assethandler.dashboard.actions.viewAnalytics',\n 'View Analytics'\n ),\n onSelect: () => navigate('/analytics'),\n },\n ]}\n />\n </div>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'assethandler.dashboard.purpose',\n 'Your command center for the whole asset estate — see what needs attention (open incidents, due maintenance, critical alerts) and recent activity at a glance, then jump straight to the area that needs you. Start here every day to know where to act.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-dashboard\"\n steps={[\n {\n id: 'view-assets',\n label: 'Browse your asset inventory',\n description: 'See every tracked asset, its status and owner.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'add-asset',\n label: 'Register a new asset',\n description: 'Add equipment, hardware or software to start tracking it.',\n onClick: () => navigate('/assets/asset-create'),\n },\n {\n id: 'incidents',\n label: 'Resolve open incidents',\n description: 'Triage service-affecting issues before they breach SLA.',\n onClick: () => navigate('/itil/incident-management'),\n },\n {\n id: 'maintenance',\n label: 'Check the maintenance calendar',\n description: 'Stay ahead of scheduled and overdue maintenance.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n {/* KPI Metrics */}\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n {metrics.map((metric, i) => {\n const Icon = metric.icon;\n const hero = i === 0;\n return (\n <GlassCard\n key={metric.label}\n treatment={hero ? 'glass' : 'metric'}\n glow={hero}\n className=\"border-border-seam\"\n >\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">{metric.label}</CardTitle>\n <Icon className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {hydrated ? metric.value.toLocaleString() : '—'}\n </div>\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {/* Portfolio Breakdown & Active Incidents */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Portfolio by Category */}\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.portfolio.title', 'Portfolio Breakdown')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.description',\n 'Asset distribution by category'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n {categoryBreakdown.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.empty.title',\n 'No assets yet'\n )}\n description={tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.empty.description',\n 'Register your first asset and category distribution will appear here.'\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {categoryBreakdown.map(([category, count]) => {\n const pct = assets.length > 0 ? Math.round((count / assets.length) * 100) : 0;\n return (\n <div key={category} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium capitalize\">\n {category.replace(/_/g, ' ')}\n </span>\n <span className=\"text-text-secondary tabular-nums\">\n {count} {count === 1 ? 'asset' : 'assets'}\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg motion-safe:animate-vc-glow-pulse\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n </CardContent>\n </EmphasisPanel>\n\n {/* Active Incidents */}\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <AlertTriangle className=\"h-4 w-4 text-status-error-text\" />\n {tWithFallback(t, 'assethandler.dashboard.incidents.title', 'Active Incidents')}\n </CardTitle>\n <CardDescription>\n {activeIncidents.length}{' '}\n {tWithFallback(\n t,\n 'assethandler.dashboard.incidents.unresolvedCount',\n 'unresolved incidents'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {activeIncidents.length === 0 ? (\n <p className=\"text-sm text-text-secondary py-4 text-center\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.incidents.empty',\n 'No unresolved incidents — all clear.'\n )}\n </p>\n ) : (\n <div className=\"space-y-3\">\n {activeIncidents.slice(0, 4).map((inc) => (\n <div key={inc.id} className=\"flex items-start gap-3 rounded-lg border p-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={\n inc.priority === 'critical' || inc.priority === 'high'\n ? 'destructive'\n : 'secondary'\n }\n className=\"text-[10px]\"\n >\n {inc.priority}\n </Badge>\n </div>\n <p className=\"text-sm font-medium truncate mt-1\">{inc.title}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {inc.assignedTo ||\n tWithFallback(\n t,\n 'assethandler.dashboard.incidents.unassigned',\n 'Unassigned'\n )}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </GlassCard>\n </div>\n\n {/* Work Orders & Operations Summary */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {/* Recent Work Orders */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.workOrders.title', 'Open Work Orders')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.workOrders.description',\n 'Latest work in progress'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {recentWorkOrders.length === 0 ? (\n <p className=\"text-sm text-text-secondary py-4 text-center\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.workOrders.empty',\n 'No open work orders. Create one from the Operations hub.'\n )}\n </p>\n ) : (\n <div className=\"space-y-3\">\n {recentWorkOrders.map((item) => (\n <div key={item.id} className=\"flex items-center gap-3\">\n <span className=\"inline-flex items-center rounded-md px-2 py-1 text-[10px] font-medium bg-status-info-bg-subtle text-status-info-text capitalize\">\n {item.status.replace(/_/g, ' ')}\n </span>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm truncate\">{item.title}</p>\n <p className=\"text-xs text-text-secondary capitalize\">\n {item.type} · {item.priority}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Operations Quick View */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.operations.title', 'Operations Summary')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.description',\n 'Quick view of current operations'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Wrench className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{pendingMaintenance.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.pendingMaintenance',\n 'Pending Maintenance'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Activity className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{openWorkOrders.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.openWorkOrders',\n 'Open Work Orders'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Clock className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{pendingChanges.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.pendingChanges',\n 'Pending Changes'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{criticalIncidents.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.criticalAlerts',\n 'Critical Alerts'\n )}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Upcoming Maintenance */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n {tWithFallback(t, 'assethandler.dashboard.maintenance.title', 'Upcoming Maintenance')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.description',\n 'Scheduled maintenance activities'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {upcomingMaintenance.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-tasks\"\n title={tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.empty.title',\n 'No maintenance scheduled'\n )}\n description={tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.empty.description',\n 'Plan preventive maintenance from the scheduler and it will show up here.'\n )}\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b\">\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(t, 'assethandler.dashboard.maintenance.table.title', 'Title')}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(t, 'assethandler.dashboard.maintenance.table.type', 'Type')}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.priority',\n 'Priority'\n )}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.scheduled',\n 'Scheduled'\n )}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.status',\n 'Status'\n )}\n </th>\n </tr>\n </thead>\n <tbody>\n {upcomingMaintenance.map((rec) => (\n <tr key={rec.id} className=\"border-b hover:bg-bg-sunken/50\">\n <td className=\"py-2\">{rec.title}</td>\n <td className=\"py-2 capitalize\">{rec.type}</td>\n <td className=\"py-2\">\n <Badge\n variant={\n rec.priority === 'critical' || rec.priority === 'high'\n ? 'destructive'\n : 'secondary'\n }\n >\n {rec.priority}\n </Badge>\n </td>\n <td className=\"py-2\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"py-2\">\n <Badge\n variant={\n rec.status === 'completed'\n ? 'default'\n : rec.status === 'in_progress'\n ? 'secondary'\n : 'outline'\n }\n className=\"capitalize\"\n >\n {rec.status.replace(/_/g, ' ')}\n </Badge>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/assethandler/pages/DashboardPage.tsx"],"sourcesContent":["import { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n GlassCard,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n CTAOverflowMenu,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Activity,\n AlertTriangle,\n Box,\n Clock,\n ClipboardList,\n Receipt,\n Wrench,\n CheckCircle,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { tWithFallback } from '../utils/i18n';\n\nexport function DashboardPage() {\n const { t } = useI18n();\n const navigate = useAssetHandlerNavigate();\n const { hydrated, overview, assets, incidents, maintenanceRecords, changeRequests, workOrders } =\n useAssetHandlerStore();\n\n const activeIncidents = incidents.filter((i) => i.status !== 'resolved' && i.status !== 'closed');\n const criticalIncidents = incidents.filter(\n (i) => i.priority === 'critical' && i.status !== 'resolved' && i.status !== 'closed'\n );\n const pendingMaintenance = maintenanceRecords.filter(\n (m) => m.status === 'scheduled' || m.status === 'in_progress'\n );\n const openWorkOrders = workOrders.filter(\n (w) => w.status !== 'completed' && w.status !== 'cancelled'\n );\n const pendingChanges = changeRequests.filter(\n (c) => c.status === 'approved' || c.status === 'submitted'\n );\n\n const metrics = [\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.totalAssets', 'Total Assets'),\n value: overview?.totalAssets ?? assets.length,\n icon: Box,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.openIncidents', 'Open Incidents'),\n value: overview?.openIncidents ?? activeIncidents.length,\n icon: AlertTriangle,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.openWorkOrders', 'Open Work Orders'),\n value: overview?.openWorkOrders ?? openWorkOrders.length,\n icon: ClipboardList,\n },\n {\n label: tWithFallback(t, 'assethandler.dashboard.metrics.transactions', 'Transactions'),\n value: overview?.totalTransactions ?? 0,\n icon: Receipt,\n },\n ];\n\n const categoryCounts = assets.reduce<Record<string, number>>((acc, asset) => {\n const key = asset.category || 'uncategorized';\n acc[key] = (acc[key] ?? 0) + 1;\n return acc;\n }, {});\n const categoryBreakdown = Object.entries(categoryCounts).sort((a, b) => b[1] - a[1]);\n\n const upcomingMaintenance = [...maintenanceRecords]\n .filter((m) => m.status !== 'completed' && m.status !== 'cancelled')\n .sort((a, b) => (a.scheduledDate ?? '').localeCompare(b.scheduledDate ?? ''))\n .slice(0, 8);\n\n const recentWorkOrders = [...openWorkOrders]\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n .slice(0, 5);\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl border border-border-seam bg-gloss-card p-6\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-3xl font-bold\">\n <GradientText>\n {tWithFallback(t, 'assethandler.dashboard.title', 'Dashboard')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.description',\n 'Overview of your IT asset portfolio and operations'\n )}\n </p>\n </div>\n <CTAOverflowMenu\n primary={{\n label: tWithFallback(t, 'assethandler.dashboard.actions.addAsset', 'Add Asset'),\n onSelect: () => navigate('/assets/asset-create'),\n }}\n actions={[\n {\n label: tWithFallback(\n t,\n 'assethandler.dashboard.actions.viewAnalytics',\n 'View Analytics'\n ),\n onSelect: () => navigate('/analytics'),\n },\n ]}\n />\n </div>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'assethandler.dashboard.purpose',\n 'Your command center for the whole asset estate — see what needs attention (open incidents, due maintenance, critical alerts) and recent activity at a glance, then jump straight to the area that needs you. Start here every day to know where to act.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-dashboard\"\n steps={[\n {\n id: 'view-assets',\n label: 'Browse your asset inventory',\n description: 'See every tracked asset, its status and owner.',\n onClick: () => navigate('/assets/asset-list'),\n },\n {\n id: 'add-asset',\n label: 'Register a new asset',\n description: 'Add equipment, hardware or software to start tracking it.',\n onClick: () => navigate('/assets/asset-create'),\n },\n {\n id: 'incidents',\n label: 'Resolve open incidents',\n description: 'Triage service-affecting issues before they breach SLA.',\n onClick: () => navigate('/itil/incident-management'),\n },\n {\n id: 'maintenance',\n label: 'Check the maintenance calendar',\n description: 'Stay ahead of scheduled and overdue maintenance.',\n onClick: () => navigate('/maintenance/maintenance-calendar'),\n },\n ]}\n />\n\n {/* KPI Metrics */}\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-4\">\n {metrics.map((metric, i) => {\n const Icon = metric.icon;\n const hero = i === 0;\n return (\n <GlassCard\n key={metric.label}\n treatment={hero ? 'glass' : 'metric'}\n glow={hero}\n className=\"border-border-seam\"\n >\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-2\">\n <CardTitle className=\"text-sm font-medium\">{metric.label}</CardTitle>\n <Icon className=\"h-4 w-4 text-text-secondary\" />\n </CardHeader>\n <CardContent>\n <div className=\"text-2xl font-bold tabular-nums\">\n {hydrated ? metric.value.toLocaleString() : '—'}\n </div>\n </CardContent>\n </GlassCard>\n );\n })}\n </div>\n\n {/* Portfolio Breakdown & Active Incidents */}\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Portfolio by Category */}\n <EmphasisPanel className=\"lg:col-span-2\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.portfolio.title', 'Portfolio Breakdown')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.description',\n 'Asset distribution by category'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n {categoryBreakdown.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.empty.title',\n 'No assets yet'\n )}\n description={tWithFallback(\n t,\n 'assethandler.dashboard.portfolio.empty.description',\n 'Register your first asset and category distribution will appear here.'\n )}\n />\n ) : (\n <div className=\"space-y-4\">\n {categoryBreakdown.map(([category, count]) => {\n const pct = assets.length > 0 ? Math.round((count / assets.length) * 100) : 0;\n return (\n <div key={category} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-medium capitalize\">\n {category.replace(/_/g, ' ')}\n </span>\n <span className=\"text-text-secondary tabular-nums\">\n {count} {count === 1 ? 'asset' : 'assets'}\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg motion-safe:animate-vc-glow-pulse\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n </CardContent>\n </EmphasisPanel>\n\n {/* Active Incidents */}\n <GlassCard treatment=\"insight\" className=\"border-border-seam\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <AlertTriangle className=\"h-4 w-4 text-status-error-text\" />\n {tWithFallback(t, 'assethandler.dashboard.incidents.title', 'Active Incidents')}\n </CardTitle>\n <CardDescription>\n {activeIncidents.length}{' '}\n {tWithFallback(\n t,\n 'assethandler.dashboard.incidents.unresolvedCount',\n 'unresolved incidents'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {activeIncidents.length === 0 ? (\n <p className=\"text-sm text-text-secondary py-4 text-center\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.incidents.empty',\n 'No unresolved incidents — all clear.'\n )}\n </p>\n ) : (\n <div className=\"space-y-3\">\n {activeIncidents.slice(0, 4).map((inc) => (\n <div key={inc.id} className=\"flex items-start gap-3 rounded-lg border p-3\">\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={\n inc.priority === 'critical' || inc.priority === 'high'\n ? 'destructive'\n : 'secondary'\n }\n className=\"text-[10px]\"\n >\n {inc.priority}\n </Badge>\n </div>\n <p className=\"text-sm font-medium truncate mt-1\">{inc.title}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">\n {inc.assignedTo ||\n tWithFallback(\n t,\n 'assethandler.dashboard.incidents.unassigned',\n 'Unassigned'\n )}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </GlassCard>\n </div>\n\n {/* Work Orders & Operations Summary */}\n <div className=\"grid gap-6 lg:grid-cols-2\">\n {/* Recent Work Orders */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.workOrders.title', 'Open Work Orders')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.workOrders.description',\n 'Latest work in progress'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {recentWorkOrders.length === 0 ? (\n <p className=\"text-sm text-text-secondary py-4 text-center\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.workOrders.empty',\n 'No open work orders. Create one from the Operations hub.'\n )}\n </p>\n ) : (\n <div className=\"space-y-3\">\n {recentWorkOrders.map((item) => (\n <div key={item.id} className=\"flex items-center gap-3\">\n <span className=\"inline-flex items-center rounded-md px-2 py-1 text-[10px] font-medium bg-status-info-bg-subtle text-status-info-text capitalize\">\n {item.status.replace(/_/g, ' ')}\n </span>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm truncate\">{item.title}</p>\n <p className=\"text-xs text-text-secondary capitalize\">\n {item.type} · {item.priority}\n </p>\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Operations Quick View */}\n <Card>\n <CardHeader>\n <CardTitle>\n {tWithFallback(t, 'assethandler.dashboard.operations.title', 'Operations Summary')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.description',\n 'Quick view of current operations'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Wrench className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{pendingMaintenance.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.pendingMaintenance',\n 'Pending Maintenance'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Activity className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{openWorkOrders.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.openWorkOrders',\n 'Open Work Orders'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <Clock className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{pendingChanges.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.pendingChanges',\n 'Pending Changes'\n )}\n </p>\n </div>\n <div className=\"rounded-lg border border-border-seam bg-gloss-card p-4 text-center\">\n <CheckCircle className=\"h-5 w-5 mx-auto text-text-secondary mb-2\" />\n <p className=\"text-2xl font-bold tabular-nums\">{criticalIncidents.length}</p>\n <p className=\"text-xs text-text-secondary\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.operations.criticalAlerts',\n 'Critical Alerts'\n )}\n </p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Upcoming Maintenance */}\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench className=\"h-4 w-4\" />\n {tWithFallback(t, 'assethandler.dashboard.maintenance.title', 'Upcoming Maintenance')}\n </CardTitle>\n <CardDescription>\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.description',\n 'Scheduled maintenance activities'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent>\n {upcomingMaintenance.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-tasks\"\n title={tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.empty.title',\n 'No maintenance scheduled'\n )}\n description={tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.empty.description',\n 'Plan preventive maintenance from the scheduler and it will show up here.'\n )}\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b\">\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(t, 'assethandler.dashboard.maintenance.table.title', 'Title')}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(t, 'assethandler.dashboard.maintenance.table.type', 'Type')}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.priority',\n 'Priority'\n )}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.scheduled',\n 'Scheduled'\n )}\n </th>\n <th className=\"text-left py-2 font-medium\">\n {tWithFallback(\n t,\n 'assethandler.dashboard.maintenance.table.status',\n 'Status'\n )}\n </th>\n </tr>\n </thead>\n <tbody>\n {upcomingMaintenance.map((rec) => (\n <tr key={rec.id} className=\"border-b hover:bg-bg-sunken/50\">\n <td className=\"py-2\">{rec.title}</td>\n <td className=\"py-2 capitalize\">{rec.type}</td>\n <td className=\"py-2\">\n <Badge\n variant={\n rec.priority === 'critical' || rec.priority === 'high'\n ? 'destructive'\n : 'secondary'\n }\n >\n {rec.priority}\n </Badge>\n </td>\n <td className=\"py-2\">\n {rec.scheduledDate ? new Date(rec.scheduledDate).toLocaleDateString() : '—'}\n </td>\n <td className=\"py-2\">\n <Badge\n variant={\n rec.status === 'completed'\n ? 'default'\n : rec.status === 'in_progress'\n ? 'secondary'\n : 'outline'\n }\n className=\"capitalize\"\n >\n {rec.status.replace(/_/g, ' ')}\n </Badge>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|