@burdenoff/microfe-assethandler 2026.826.7 → 2026.826.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ import { useAssetHandlerNavigate as e } from "../hooks/useAssetHandlerNavigate.js";
2
+ import { SectionHeader as t } from "../components/SectionHeader.js";
3
+ import "../components/index.js";
4
+ import { useMemo as n, useState as r } from "react";
5
+ import { AlertTriangle as i, RefreshCw as a } from "lucide-react";
6
+ import { gql as o } from "@apollo/client";
7
+ import { useQuery as s } from "@apollo/client/react";
8
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
9
+ import { Badge as u, Button as d, GlassCard as f, IllustratedEmptyState as p, PagePurpose as m, Select as h, SelectContent as g, SelectItem as _, SelectTrigger as v, SelectValue as y } from "@burdenoff/fe-libs/ui";
10
+ //#region src/assethandler/pages/ForecastingAlertsPage.tsx
11
+ var b = o`
12
+ query AssetHandlerDeadlineAlerts($withinDays: Int!) {
13
+ assetDeadlineAlerts(withinDays: $withinDays) {
14
+ id
15
+ kind
16
+ subjectId
17
+ subjectName
18
+ assetId
19
+ dueAt
20
+ daysRemaining
21
+ status
22
+ headline
23
+ recommendedAction
24
+ }
25
+ }
26
+ `, x = {
27
+ WARRANTY_EXPIRY: "Warranty expiry",
28
+ LICENSE_RENEWAL: "Licence renewal",
29
+ END_OF_LIFE: "Replacement planning",
30
+ MAINTENANCE_DUE: "Maintenance due"
31
+ }, S = {
32
+ OVERDUE: "bg-status-error-bg text-status-error-text",
33
+ DUE_SOON: "bg-status-warning-bg text-status-warning-text",
34
+ UPCOMING: "bg-status-info-bg text-status-info-text"
35
+ };
36
+ function C(e) {
37
+ if (e.daysRemaining < 0) {
38
+ let t = Math.abs(e.daysRemaining);
39
+ return `${t} ${t === 1 ? "day" : "days"} overdue`;
40
+ }
41
+ return e.daysRemaining === 0 ? "Due today" : `Due in ${e.daysRemaining} days`;
42
+ }
43
+ function w() {
44
+ let o = e(), [w, T] = r(90), { data: E, loading: D, error: O, refetch: k } = s(b, {
45
+ variables: { withinDays: w },
46
+ fetchPolicy: "network-only"
47
+ }), A = n(() => E?.assetDeadlineAlerts ?? [], [E?.assetDeadlineAlerts]);
48
+ return /* @__PURE__ */ l("div", {
49
+ className: "space-y-5 p-4 sm:p-6",
50
+ children: [
51
+ /* @__PURE__ */ c(t, {
52
+ title: "Deadline Alerts",
53
+ description: "Warranty, licence, replacement, and maintenance deadlines derived from your saved registry facts.",
54
+ actions: /* @__PURE__ */ l("div", {
55
+ className: "flex items-center gap-2",
56
+ children: [/* @__PURE__ */ l(h, {
57
+ value: String(w),
58
+ onValueChange: (e) => T(Number(e)),
59
+ children: [/* @__PURE__ */ c(v, {
60
+ className: "w-36",
61
+ "aria-label": "Planning window",
62
+ children: /* @__PURE__ */ c(y, {})
63
+ }), /* @__PURE__ */ l(g, { children: [
64
+ /* @__PURE__ */ c(_, {
65
+ value: "30",
66
+ children: "Next 30 days"
67
+ }),
68
+ /* @__PURE__ */ c(_, {
69
+ value: "90",
70
+ children: "Next 90 days"
71
+ }),
72
+ /* @__PURE__ */ c(_, {
73
+ value: "180",
74
+ children: "Next 180 days"
75
+ }),
76
+ /* @__PURE__ */ c(_, {
77
+ value: "365",
78
+ children: "Next 365 days"
79
+ })
80
+ ] })]
81
+ }), /* @__PURE__ */ l(d, {
82
+ variant: "outline",
83
+ onClick: () => void k(),
84
+ disabled: D,
85
+ children: [/* @__PURE__ */ c(a, { className: "mr-2 h-4 w-4" }), "Refresh"]
86
+ })]
87
+ })
88
+ }),
89
+ /* @__PURE__ */ c(m, { children: "Alerts remain stable across reloads because each one is calculated from the persisted source record and carries a deterministic source-backed ID." }),
90
+ O ? /* @__PURE__ */ l(f, {
91
+ treatment: "glass",
92
+ className: "border-status-error-border p-4",
93
+ children: [/* @__PURE__ */ c("p", {
94
+ className: "font-medium text-status-error-text",
95
+ children: "Could not load deadline alerts"
96
+ }), /* @__PURE__ */ c("p", {
97
+ className: "mt-1 text-sm text-text-muted",
98
+ children: O.message
99
+ })]
100
+ }) : null,
101
+ !D && !O && A.length === 0 ? /* @__PURE__ */ c(p, {
102
+ illustration: "empty-notifications",
103
+ title: "No deadlines in this window",
104
+ description: "Add warranty, useful-life, licence-expiry, or scheduled-maintenance dates to raise planning alerts."
105
+ }) : null,
106
+ /* @__PURE__ */ c("div", {
107
+ className: "grid gap-3 lg:grid-cols-2",
108
+ "aria-busy": D,
109
+ children: A.map((e) => /* @__PURE__ */ l(f, {
110
+ treatment: "glass",
111
+ className: "border-border-seam p-4",
112
+ children: [/* @__PURE__ */ l("div", {
113
+ className: "flex items-start justify-between gap-3",
114
+ children: [/* @__PURE__ */ l("div", {
115
+ className: "min-w-0",
116
+ children: [
117
+ /* @__PURE__ */ l("div", {
118
+ className: "flex flex-wrap items-center gap-2",
119
+ children: [/* @__PURE__ */ c(u, {
120
+ variant: "outline",
121
+ children: x[e.kind]
122
+ }), /* @__PURE__ */ c("span", {
123
+ className: `rounded-full px-2 py-0.5 text-xs ${S[e.status]}`,
124
+ children: C(e)
125
+ })]
126
+ }),
127
+ /* @__PURE__ */ c("h2", {
128
+ className: "mt-3 font-semibold text-text-primary",
129
+ children: e.headline
130
+ }),
131
+ /* @__PURE__ */ c("p", {
132
+ className: "mt-1 break-words text-sm text-text-secondary",
133
+ children: e.subjectName
134
+ }),
135
+ /* @__PURE__ */ c("p", {
136
+ className: "mt-2 text-sm text-text-muted",
137
+ children: e.recommendedAction
138
+ }),
139
+ /* @__PURE__ */ l("p", {
140
+ className: "mt-3 text-xs text-text-muted",
141
+ children: ["Deadline ", new Date(e.dueAt).toLocaleDateString()]
142
+ })
143
+ ]
144
+ }), /* @__PURE__ */ c(i, { className: "h-5 w-5 shrink-0 text-status-warning-text" })]
145
+ }), e.assetId ? /* @__PURE__ */ c(d, {
146
+ className: "mt-4",
147
+ variant: "outline",
148
+ size: "sm",
149
+ onClick: () => o(`/assethandler/assets/${e.assetId}`),
150
+ children: "View asset"
151
+ }) : null]
152
+ }, e.id))
153
+ })
154
+ ]
155
+ });
156
+ }
157
+ //#endregion
158
+ export { w as ForecastingAlertsPage };
159
+
160
+ //# sourceMappingURL=ForecastingAlertsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ForecastingAlertsPage.js","names":[],"sources":["../../../src/assethandler/pages/ForecastingAlertsPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { AlertTriangle, RefreshCw } from 'lucide-react';\nimport { useMemo, useState } from 'react';\n\nimport {\n Badge,\n Button,\n GlassCard,\n IllustratedEmptyState,\n PagePurpose,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@burdenoff/fe-libs/ui';\nimport { SectionHeader } from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\n\nconst DEADLINE_ALERTS_QUERY = gql`\n query AssetHandlerDeadlineAlerts($withinDays: Int!) {\n assetDeadlineAlerts(withinDays: $withinDays) {\n id\n kind\n subjectId\n subjectName\n assetId\n dueAt\n daysRemaining\n status\n headline\n recommendedAction\n }\n }\n`;\n\ntype AlertKind = 'WARRANTY_EXPIRY' | 'LICENSE_RENEWAL' | 'END_OF_LIFE' | 'MAINTENANCE_DUE';\n\ninterface DeadlineAlert {\n id: string;\n kind: AlertKind;\n subjectId: string;\n subjectName: string;\n assetId: string | null;\n dueAt: string;\n daysRemaining: number;\n status: 'OVERDUE' | 'DUE_SOON' | 'UPCOMING';\n headline: string;\n recommendedAction: string;\n}\n\ninterface DeadlineAlertsResult {\n assetDeadlineAlerts: DeadlineAlert[];\n}\n\nconst KIND_LABELS: Record<AlertKind, string> = {\n WARRANTY_EXPIRY: 'Warranty expiry',\n LICENSE_RENEWAL: 'Licence renewal',\n END_OF_LIFE: 'Replacement planning',\n MAINTENANCE_DUE: 'Maintenance due',\n};\n\nconst STATUS_CLASS: Record<DeadlineAlert['status'], string> = {\n OVERDUE: 'bg-status-error-bg text-status-error-text',\n DUE_SOON: 'bg-status-warning-bg text-status-warning-text',\n UPCOMING: 'bg-status-info-bg text-status-info-text',\n};\n\nfunction dueLabel(alert: DeadlineAlert): string {\n if (alert.daysRemaining < 0) {\n const overdueDays = Math.abs(alert.daysRemaining);\n return `${overdueDays} ${overdueDays === 1 ? 'day' : 'days'} overdue`;\n }\n if (alert.daysRemaining === 0) return 'Due today';\n return `Due in ${alert.daysRemaining} days`;\n}\n\nexport function ForecastingAlertsPage() {\n const navigate = useAssetHandlerNavigate();\n const [withinDays, setWithinDays] = useState(90);\n const { data, loading, error, refetch } = useQuery<DeadlineAlertsResult>(DEADLINE_ALERTS_QUERY, {\n variables: { withinDays },\n fetchPolicy: 'network-only',\n });\n const alerts = useMemo(() => data?.assetDeadlineAlerts ?? [], [data?.assetDeadlineAlerts]);\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n title=\"Deadline Alerts\"\n description=\"Warranty, licence, replacement, and maintenance deadlines derived from your saved registry facts.\"\n actions={\n <div className=\"flex items-center gap-2\">\n <Select\n value={String(withinDays)}\n onValueChange={(value) => setWithinDays(Number(value))}\n >\n <SelectTrigger className=\"w-36\" aria-label=\"Planning window\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"30\">Next 30 days</SelectItem>\n <SelectItem value=\"90\">Next 90 days</SelectItem>\n <SelectItem value=\"180\">Next 180 days</SelectItem>\n <SelectItem value=\"365\">Next 365 days</SelectItem>\n </SelectContent>\n </Select>\n <Button variant=\"outline\" onClick={() => void refetch()} disabled={loading}>\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n Refresh\n </Button>\n </div>\n }\n />\n <PagePurpose>\n Alerts remain stable across reloads because each one is calculated from the persisted source\n record and carries a deterministic source-backed ID.\n </PagePurpose>\n\n {error ? (\n <GlassCard treatment=\"glass\" className=\"border-status-error-border p-4\">\n <p className=\"font-medium text-status-error-text\">Could not load deadline alerts</p>\n <p className=\"mt-1 text-sm text-text-muted\">{error.message}</p>\n </GlassCard>\n ) : null}\n\n {!loading && !error && alerts.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-notifications\"\n title=\"No deadlines in this window\"\n description=\"Add warranty, useful-life, licence-expiry, or scheduled-maintenance dates to raise planning alerts.\"\n />\n ) : null}\n\n <div className=\"grid gap-3 lg:grid-cols-2\" aria-busy={loading}>\n {alerts.map((alert) => (\n <GlassCard key={alert.id} treatment=\"glass\" className=\"border-border-seam p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"outline\">{KIND_LABELS[alert.kind]}</Badge>\n <span\n className={`rounded-full px-2 py-0.5 text-xs ${STATUS_CLASS[alert.status]}`}\n >\n {dueLabel(alert)}\n </span>\n </div>\n <h2 className=\"mt-3 font-semibold text-text-primary\">{alert.headline}</h2>\n <p className=\"mt-1 break-words text-sm text-text-secondary\">{alert.subjectName}</p>\n <p className=\"mt-2 text-sm text-text-muted\">{alert.recommendedAction}</p>\n <p className=\"mt-3 text-xs text-text-muted\">\n Deadline {new Date(alert.dueAt).toLocaleDateString()}\n </p>\n </div>\n <AlertTriangle className=\"h-5 w-5 shrink-0 text-status-warning-text\" />\n </div>\n {alert.assetId ? (\n <Button\n className=\"mt-4\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate(`/assethandler/assets/${alert.assetId}`)}\n >\n View asset\n </Button>\n ) : null}\n </GlassCard>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAgNA,wBAAgB,oBAAoB,gCA2pBnC"}
1
+ {"version":3,"file":"ReportsDashboardPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/ReportsDashboardPage.tsx"],"names":[],"mappings":"AAiNA,wBAAgB,oBAAoB,gCA8pBnC"}