@burdenoff/microfe-assethandler 2026.826.11 → 2026.826.12

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.
@@ -146,7 +146,7 @@ function w() {
146
146
  className: "mt-4",
147
147
  variant: "outline",
148
148
  size: "sm",
149
- onClick: () => o(`/assethandler/assets/${e.assetId}`),
149
+ onClick: () => o(`/assets/${e.assetId}`),
150
150
  children: "View asset"
151
151
  }) : null]
152
152
  }, e.id))
@@ -1 +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
+ {"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(`/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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-assethandler",
3
- "version": "2026.826.11",
3
+ "version": "2026.826.12",
4
4
  "description": "Burdenoff AssetHandler Microfrontend",
5
5
  "type": "module",
6
6
  "files": [