@burdenoff/microfe-subscriberbot 2026.706.2 → 2026.710.1

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.
Files changed (140) hide show
  1. package/dist/generated/global-operations.d.ts +2 -0
  2. package/dist/generated/global-operations.d.ts.map +1 -0
  3. package/dist/generated/global-types.d.ts +23527 -0
  4. package/dist/generated/global-types.d.ts.map +1 -0
  5. package/dist/generated/wspace-operations.d.ts +2 -0
  6. package/dist/generated/wspace-operations.d.ts.map +1 -0
  7. package/dist/generated/wspace-types.d.ts +57851 -0
  8. package/dist/generated/wspace-types.d.ts.map +1 -0
  9. package/dist/index.d.ts +6 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +2 -1
  12. package/dist/subscriberbot/SubscriberBotRoot.d.ts +5 -0
  13. package/dist/subscriberbot/SubscriberBotRoot.d.ts.map +1 -0
  14. package/dist/subscriberbot/SubscriberBotRoot.js +56 -40
  15. package/dist/subscriberbot/SubscriberBotRoot.js.map +1 -1
  16. package/dist/subscriberbot/SubscriberBotRoutes.d.ts +4 -0
  17. package/dist/subscriberbot/SubscriberBotRoutes.d.ts.map +1 -0
  18. package/dist/subscriberbot/SubscriberBotRoutes.js +14 -6
  19. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  20. package/dist/subscriberbot/components/EmptyState.d.ts +18 -0
  21. package/dist/subscriberbot/components/EmptyState.d.ts.map +1 -0
  22. package/dist/subscriberbot/components/MetricsCard.d.ts +16 -0
  23. package/dist/subscriberbot/components/MetricsCard.d.ts.map +1 -0
  24. package/dist/subscriberbot/components/Modal.d.ts +13 -0
  25. package/dist/subscriberbot/components/Modal.d.ts.map +1 -0
  26. package/dist/subscriberbot/components/PageLayout.d.ts +23 -0
  27. package/dist/subscriberbot/components/PageLayout.d.ts.map +1 -0
  28. package/dist/subscriberbot/components/StateViews.d.ts +24 -0
  29. package/dist/subscriberbot/components/StateViews.d.ts.map +1 -0
  30. package/dist/subscriberbot/components/StatusBadge.d.ts +9 -0
  31. package/dist/subscriberbot/components/StatusBadge.d.ts.map +1 -0
  32. package/dist/subscriberbot/components/index.d.ts +13 -0
  33. package/dist/subscriberbot/components/index.d.ts.map +1 -0
  34. package/dist/subscriberbot/components/index.js +7 -0
  35. package/dist/subscriberbot/components/viz.d.ts +58 -0
  36. package/dist/subscriberbot/components/viz.d.ts.map +1 -0
  37. package/dist/subscriberbot/components/viz.js +196 -0
  38. package/dist/subscriberbot/components/viz.js.map +1 -0
  39. package/dist/subscriberbot/config/assistantUsecases.d.ts +13 -0
  40. package/dist/subscriberbot/config/assistantUsecases.d.ts.map +1 -0
  41. package/dist/subscriberbot/context/SubscriberBotContext.d.ts +16 -0
  42. package/dist/subscriberbot/context/SubscriberBotContext.d.ts.map +1 -0
  43. package/dist/subscriberbot/context/index.d.ts +6 -0
  44. package/dist/subscriberbot/context/index.d.ts.map +1 -0
  45. package/dist/subscriberbot/hooks/index.d.ts +7 -0
  46. package/dist/subscriberbot/hooks/index.d.ts.map +1 -0
  47. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +105 -0
  48. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -0
  49. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +38 -30
  50. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  51. package/dist/subscriberbot/index.d.ts +12 -0
  52. package/dist/subscriberbot/index.d.ts.map +1 -0
  53. package/dist/subscriberbot/index.js +1 -0
  54. package/dist/subscriberbot/pages/AssetVaultPage.d.ts +4 -0
  55. package/dist/subscriberbot/pages/AssetVaultPage.d.ts.map +1 -0
  56. package/dist/subscriberbot/pages/AssetVaultPage.js +182 -0
  57. package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -0
  58. package/dist/subscriberbot/pages/DashboardPage.d.ts +12 -0
  59. package/dist/subscriberbot/pages/DashboardPage.d.ts.map +1 -0
  60. package/dist/subscriberbot/pages/DashboardPage.js +272 -199
  61. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
  62. package/dist/subscriberbot/pages/InboxPage.d.ts +12 -0
  63. package/dist/subscriberbot/pages/InboxPage.d.ts.map +1 -0
  64. package/dist/subscriberbot/pages/InboxPage.js +517 -234
  65. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  66. package/dist/subscriberbot/pages/InsightsPage.d.ts +4 -0
  67. package/dist/subscriberbot/pages/InsightsPage.d.ts.map +1 -0
  68. package/dist/subscriberbot/pages/InsightsPage.js +220 -0
  69. package/dist/subscriberbot/pages/InsightsPage.js.map +1 -0
  70. package/dist/subscriberbot/pages/InvoicesPage.d.ts +13 -0
  71. package/dist/subscriberbot/pages/InvoicesPage.d.ts.map +1 -0
  72. package/dist/subscriberbot/pages/InvoicesPage.js +325 -237
  73. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  74. package/dist/subscriberbot/pages/WorkflowsPage.d.ts +15 -0
  75. package/dist/subscriberbot/pages/WorkflowsPage.d.ts.map +1 -0
  76. package/dist/subscriberbot/pages/WorkflowsPage.js +301 -112
  77. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  78. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts +11 -0
  79. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -0
  80. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +311 -165
  81. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  82. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts +8 -0
  83. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts.map +1 -0
  84. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts +11 -0
  85. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts.map +1 -0
  86. package/dist/subscriberbot/pages/agents/AgentsListPage.js +183 -93
  87. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  88. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts +10 -0
  89. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts.map +1 -0
  90. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +426 -293
  91. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  92. package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts +10 -0
  93. package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts.map +1 -0
  94. package/dist/subscriberbot/pages/providers/ProviderNewPage.js +217 -153
  95. package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -1
  96. package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts +12 -0
  97. package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts.map +1 -0
  98. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +215 -112
  99. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
  100. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts +13 -0
  101. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -0
  102. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +542 -428
  103. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  104. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts +10 -0
  105. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -0
  106. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +242 -192
  107. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
  108. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts +10 -0
  109. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts.map +1 -0
  110. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +174 -133
  111. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
  112. package/dist/subscriberbot/services/assistantApi.d.ts +66 -0
  113. package/dist/subscriberbot/services/assistantApi.d.ts.map +1 -0
  114. package/dist/subscriberbot/services/assistantApi.js +260 -0
  115. package/dist/subscriberbot/services/assistantApi.js.map +1 -0
  116. package/dist/subscriberbot/services/createSandboxAssistantTransport.d.ts +13 -0
  117. package/dist/subscriberbot/services/createSandboxAssistantTransport.d.ts.map +1 -0
  118. package/dist/subscriberbot/services/createSandboxAssistantTransport.js +120 -0
  119. package/dist/subscriberbot/services/createSandboxAssistantTransport.js.map +1 -0
  120. package/dist/subscriberbot/store/index.d.ts +6 -0
  121. package/dist/subscriberbot/store/index.d.ts.map +1 -0
  122. package/dist/subscriberbot/store/subscriberbotStore.d.ts +60 -0
  123. package/dist/subscriberbot/store/subscriberbotStore.d.ts.map +1 -0
  124. package/dist/subscriberbot/types/assistant.d.ts +57 -0
  125. package/dist/subscriberbot/types/assistant.d.ts.map +1 -0
  126. package/dist/subscriberbot/types/index.d.ts +465 -0
  127. package/dist/subscriberbot/types/index.d.ts.map +1 -0
  128. package/dist/subscriberbot/utils/cn.d.ts +4 -0
  129. package/dist/subscriberbot/utils/cn.d.ts.map +1 -0
  130. package/dist/subscriberbot/utils/formatters.d.ts +53 -0
  131. package/dist/subscriberbot/utils/formatters.d.ts.map +1 -0
  132. package/dist/subscriberbot/utils/index.d.ts +8 -0
  133. package/dist/subscriberbot/utils/index.d.ts.map +1 -0
  134. package/dist/subscriberbot/utils/navigation.d.ts +20 -0
  135. package/dist/subscriberbot/utils/navigation.d.ts.map +1 -0
  136. package/dist/subscriberbot/utils/pageContext.d.ts +21 -0
  137. package/dist/subscriberbot/utils/pageContext.d.ts.map +1 -0
  138. package/dist/subscriberbot/utils/pageContext.js +47 -0
  139. package/dist/subscriberbot/utils/pageContext.js.map +1 -0
  140. package/package.json +5 -1
@@ -0,0 +1,182 @@
1
+ import { cn as e } from "../utils/cn.js";
2
+ import { PageLayout as t } from "../components/PageLayout.js";
3
+ import { MetricsCard as n } from "../components/MetricsCard.js";
4
+ import { formatDate as r, formatEnumLabel as i } from "../utils/formatters.js";
5
+ import { EmptyState as a } from "../components/EmptyState.js";
6
+ import { ErrorView as o, LoadingView as s, Section as c } from "../components/StateViews.js";
7
+ import "../components/index.js";
8
+ import { useAllAssets as l, useFileDownloadUrl as u, useRelationships as d } from "../hooks/useSubscriberBotApi.js";
9
+ import { useMemo as f, useState as p } from "react";
10
+ import { Award as m, Download as h, File as g, FileKey as _, FileText as v, Globe as y, Receipt as b, Search as x, ShieldCheck as S, Vault as C } from "lucide-react";
11
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
12
+ import { GlassCard as E, PagePurpose as D } from "@burdenoff/fe-libs/ui";
13
+ //#region src/subscriberbot/pages/AssetVaultPage.tsx
14
+ var O = {
15
+ CONTRACT: v,
16
+ LICENSE_KEY: _,
17
+ CREDENTIAL: _,
18
+ CERTIFICATE: m,
19
+ INVOICE: b,
20
+ RECEIPT: b,
21
+ WARRANTY: S,
22
+ DOMAIN: y
23
+ }, k = [
24
+ "CONTRACT",
25
+ "LICENSE_KEY",
26
+ "CREDENTIAL",
27
+ "CERTIFICATE",
28
+ "INVOICE",
29
+ "RECEIPT",
30
+ "WARRANTY",
31
+ "DOMAIN"
32
+ ], A = (e) => {
33
+ if (!e) return !1;
34
+ let t = new Date(e).getTime();
35
+ if (Number.isNaN(t)) return !1;
36
+ let n = (t - Date.now()) / 864e5;
37
+ return n >= 0 && n <= 30;
38
+ };
39
+ function j({ asset: t, subscription: n }) {
40
+ let a = u(), [o, s] = p(!1), c = O[t.type] ?? g, l = A(t.expiresAt);
41
+ return /* @__PURE__ */ T(E, {
42
+ treatment: "metric",
43
+ className: "flex items-start gap-3 p-4",
44
+ children: [
45
+ /* @__PURE__ */ w("span", {
46
+ className: "grid h-10 w-10 shrink-0 place-items-center rounded-lg bg-accent-wash text-text-link",
47
+ children: /* @__PURE__ */ w(c, { className: "h-5 w-5" })
48
+ }),
49
+ /* @__PURE__ */ T("div", {
50
+ className: "min-w-0 flex-1",
51
+ children: [
52
+ /* @__PURE__ */ w("p", {
53
+ className: "truncate font-medium text-text-primary",
54
+ children: t.name
55
+ }),
56
+ /* @__PURE__ */ w("p", {
57
+ className: "truncate text-xs text-text-secondary",
58
+ children: n
59
+ }),
60
+ /* @__PURE__ */ T("div", {
61
+ className: "mt-1 flex flex-wrap items-center gap-2 text-xs",
62
+ children: [/* @__PURE__ */ w("span", {
63
+ className: "rounded bg-bg-sunken px-1.5 py-0.5 text-text-secondary",
64
+ children: i(t.type)
65
+ }), t.expiresAt && /* @__PURE__ */ T("span", {
66
+ className: e(l ? "text-status-warning-text" : "text-text-secondary"),
67
+ children: ["Expires ", r(t.expiresAt)]
68
+ })]
69
+ })
70
+ ]
71
+ }),
72
+ t.file?.id && /* @__PURE__ */ w("button", {
73
+ type: "button",
74
+ onClick: async () => {
75
+ if (!(!t.file?.id || o)) {
76
+ s(!0);
77
+ try {
78
+ let e = await a(t.file.id);
79
+ window.open(e, "_blank", "noopener,noreferrer");
80
+ } finally {
81
+ s(!1);
82
+ }
83
+ }
84
+ },
85
+ disabled: o,
86
+ "aria-label": `Download ${t.name}`,
87
+ className: "shrink-0 rounded-lg border border-border-subtle p-2 text-text-secondary hover:text-text-primary disabled:opacity-50",
88
+ children: /* @__PURE__ */ w(h, { className: "h-4 w-4" })
89
+ })
90
+ ]
91
+ });
92
+ }
93
+ var M = () => {
94
+ let r = l(), u = d({ pagination: { limit: 100 } }), [m, h] = p(""), [_, y] = p("ALL"), b = f(() => {
95
+ let e = /* @__PURE__ */ new Map();
96
+ for (let t of u.data?.items ?? []) e.set(t.id, t.label);
97
+ return e;
98
+ }, [u.data]), O = f(() => r.data ?? [], [r.data]), M = f(() => O.filter((e) => (_ === "ALL" || e.type === _) && (!m || e.name.toLowerCase().includes(m.toLowerCase()))), [
99
+ O,
100
+ _,
101
+ m
102
+ ]), N = f(() => {
103
+ let e = /* @__PURE__ */ new Map();
104
+ for (let t of M) e.set(t.type, [...e.get(t.type) ?? [], t]);
105
+ return k.filter((t) => e.has(t)).map((t) => [t, e.get(t)]);
106
+ }, [M]), P = f(() => O.filter((e) => A(e.expiresAt)), [O]);
107
+ return r.isLoading ? /* @__PURE__ */ w(s, { label: "Loading your asset vault…" }) : r.isError ? /* @__PURE__ */ w(o, {
108
+ message: "Could not load the asset vault.",
109
+ onRetry: () => void r.refetch()
110
+ }) : /* @__PURE__ */ T(t, {
111
+ title: "Asset vault",
112
+ description: "Every contract, receipt, license key and document attached to your subscriptions — in one secure place.",
113
+ children: [
114
+ /* @__PURE__ */ w(D, {
115
+ className: "mb-2",
116
+ children: "Your subscription documents, together — contracts, receipts, license keys and more. Assets are stored in the shared files service and linked to the subscription they belong to. Attach new documents from any relationship’s detail page."
117
+ }),
118
+ /* @__PURE__ */ T("div", {
119
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
120
+ children: [
121
+ /* @__PURE__ */ w(n, {
122
+ icon: /* @__PURE__ */ w(g, { className: "h-5 w-5" }),
123
+ value: O.length,
124
+ label: "Documents stored"
125
+ }),
126
+ /* @__PURE__ */ w(n, {
127
+ icon: /* @__PURE__ */ w(v, { className: "h-5 w-5" }),
128
+ value: N.length,
129
+ label: "Document types"
130
+ }),
131
+ /* @__PURE__ */ w(n, {
132
+ icon: /* @__PURE__ */ w(S, { className: "h-5 w-5" }),
133
+ value: P.length,
134
+ label: "Expiring within 30 days",
135
+ trend: P.length > 0 ? "down" : void 0
136
+ })
137
+ ]
138
+ }),
139
+ /* @__PURE__ */ T(E, {
140
+ treatment: "plain",
141
+ className: "flex flex-col gap-3 p-4 sm:flex-row sm:items-center",
142
+ children: [/* @__PURE__ */ T("div", {
143
+ className: "relative flex-1",
144
+ children: [/* @__PURE__ */ w(x, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ w("input", {
145
+ value: m,
146
+ onChange: (e) => h(e.target.value),
147
+ placeholder: "Search documents…",
148
+ "aria-label": "Search documents",
149
+ className: "w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary"
150
+ })]
151
+ }), /* @__PURE__ */ w("div", {
152
+ className: "flex flex-wrap gap-1.5",
153
+ children: ["ALL", ...k].map((t) => /* @__PURE__ */ w("button", {
154
+ type: "button",
155
+ onClick: () => y(t),
156
+ "aria-pressed": _ === t,
157
+ className: e("rounded-full px-3 py-1 text-xs font-medium transition-colors", _ === t ? "bg-accent-primary text-accent-foreground" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
158
+ children: t === "ALL" ? "All" : i(t)
159
+ }, t))
160
+ })]
161
+ }),
162
+ M.length === 0 ? /* @__PURE__ */ w(a, {
163
+ icon: /* @__PURE__ */ w(C, { className: "h-8 w-8" }),
164
+ title: O.length === 0 ? "No documents yet" : "No matching documents",
165
+ description: O.length === 0 ? "Attach a contract, receipt or license key from any subscription’s detail page and it will appear here." : "Try a different search or type filter."
166
+ }) : N.map(([e, t]) => /* @__PURE__ */ w(c, {
167
+ title: `${i(e)} · ${t.length}`,
168
+ children: /* @__PURE__ */ w("div", {
169
+ className: "grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3",
170
+ children: t.map((e) => /* @__PURE__ */ w(j, {
171
+ asset: e,
172
+ subscription: b.get(e.relationshipId) ?? "Subscription"
173
+ }, e.id))
174
+ })
175
+ }, e))
176
+ ]
177
+ });
178
+ };
179
+ //#endregion
180
+ export { M as AssetVaultPage };
181
+
182
+ //# sourceMappingURL=AssetVaultPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssetVaultPage.js","names":[],"sources":["../../../src/subscriberbot/pages/AssetVaultPage.tsx"],"sourcesContent":["/**\n * Digital Asset Vault — every document attached to any subscription in the\n * workspace (contracts, receipts, license keys, warranties). Real data only:\n * `useAllAssets` (workspace-wide) joined to `useRelationships` for the owning\n * subscription label; downloads resolve a presigned URL via files-svc.\n * @module subscriberbot/pages\n */\nimport { useMemo, useState, type FC } from 'react';\nimport {\n FileText,\n FileKey,\n Receipt,\n ShieldCheck,\n File as FileIcon,\n Globe,\n Award,\n Search,\n Download,\n Vault,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n MetricsCard,\n EmptyState,\n LoadingView,\n ErrorView,\n Section,\n} from '../components';\nimport { useAllAssets, useRelationships, useFileDownloadUrl } from '../hooks/useSubscriberBotApi';\nimport { formatDate, formatEnumLabel } from '../utils/formatters';\nimport type { SubAsset, SubAssetType } from '../types';\nimport { cn } from '../utils/cn';\n\nconst TYPE_ICON: Record<SubAssetType, typeof FileText> = {\n CONTRACT: FileText,\n LICENSE_KEY: FileKey,\n CREDENTIAL: FileKey,\n CERTIFICATE: Award,\n INVOICE: Receipt,\n RECEIPT: Receipt,\n WARRANTY: ShieldCheck,\n DOMAIN: Globe,\n};\n\nconst TYPE_ORDER: SubAssetType[] = [\n 'CONTRACT',\n 'LICENSE_KEY',\n 'CREDENTIAL',\n 'CERTIFICATE',\n 'INVOICE',\n 'RECEIPT',\n 'WARRANTY',\n 'DOMAIN',\n];\n\nconst isExpiringSoon = (expiresAt: string | null): boolean => {\n if (!expiresAt) return false;\n const t = new Date(expiresAt).getTime();\n if (Number.isNaN(t)) return false;\n const days = (t - Date.now()) / 86_400_000;\n return days >= 0 && days <= 30;\n};\n\nfunction AssetCard({ asset, subscription }: { asset: SubAsset; subscription: string }) {\n const getDownloadUrl = useFileDownloadUrl();\n const [busy, setBusy] = useState(false);\n const Icon = TYPE_ICON[asset.type] ?? FileIcon;\n const soon = isExpiringSoon(asset.expiresAt);\n\n const download = async () => {\n if (!asset.file?.id || busy) return;\n setBusy(true);\n try {\n const url = await getDownloadUrl(asset.file.id);\n window.open(url, '_blank', 'noopener,noreferrer');\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <GlassCard treatment=\"metric\" className=\"flex items-start gap-3 p-4\">\n <span className=\"grid h-10 w-10 shrink-0 place-items-center rounded-lg bg-accent-wash text-text-link\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium text-text-primary\">{asset.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">{subscription}</p>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-secondary\">\n {formatEnumLabel(asset.type)}\n </span>\n {asset.expiresAt && (\n <span className={cn(soon ? 'text-status-warning-text' : 'text-text-secondary')}>\n Expires {formatDate(asset.expiresAt)}\n </span>\n )}\n </div>\n </div>\n {asset.file?.id && (\n <button\n type=\"button\"\n onClick={download}\n disabled={busy}\n aria-label={`Download ${asset.name}`}\n className=\"shrink-0 rounded-lg border border-border-subtle p-2 text-text-secondary hover:text-text-primary disabled:opacity-50\"\n >\n <Download className=\"h-4 w-4\" />\n </button>\n )}\n </GlassCard>\n );\n}\n\nexport const AssetVaultPage: FC = () => {\n const assetsQuery = useAllAssets();\n const relQuery = useRelationships({ pagination: { limit: 100 } });\n const [search, setSearch] = useState('');\n const [typeFilter, setTypeFilter] = useState<SubAssetType | 'ALL'>('ALL');\n\n const relLabels = useMemo(() => {\n const map = new Map<string, string>();\n for (const r of relQuery.data?.items ?? []) map.set(r.id, r.label);\n return map;\n }, [relQuery.data]);\n\n const assets = useMemo(() => assetsQuery.data ?? [], [assetsQuery.data]);\n const filtered = useMemo(\n () =>\n assets.filter(\n (a) =>\n (typeFilter === 'ALL' || a.type === typeFilter) &&\n (!search || a.name.toLowerCase().includes(search.toLowerCase()))\n ),\n [assets, typeFilter, search]\n );\n\n const grouped = useMemo(() => {\n const g = new Map<SubAssetType, SubAsset[]>();\n for (const a of filtered) g.set(a.type, [...(g.get(a.type) ?? []), a]);\n return TYPE_ORDER.filter((t) => g.has(t)).map((t) => [t, g.get(t)!] as const);\n }, [filtered]);\n\n const expiringSoon = useMemo(() => assets.filter((a) => isExpiringSoon(a.expiresAt)), [assets]);\n\n if (assetsQuery.isLoading) return <LoadingView label=\"Loading your asset vault…\" />;\n if (assetsQuery.isError)\n return (\n <ErrorView\n message=\"Could not load the asset vault.\"\n onRetry={() => void assetsQuery.refetch()}\n />\n );\n\n return (\n <PageLayout\n title=\"Asset vault\"\n description=\"Every contract, receipt, license key and document attached to your subscriptions — in one secure place.\"\n >\n <PagePurpose className=\"mb-2\">\n Your subscription documents, together — contracts, receipts, license keys and more. Assets\n are stored in the shared files service and linked to the subscription they belong to. Attach\n new documents from any relationship’s detail page.\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<FileIcon className=\"h-5 w-5\" />}\n value={assets.length}\n label=\"Documents stored\"\n />\n <MetricsCard\n icon={<FileText className=\"h-5 w-5\" />}\n value={grouped.length}\n label=\"Document types\"\n />\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={expiringSoon.length}\n label=\"Expiring within 30 days\"\n trend={expiringSoon.length > 0 ? 'down' : undefined}\n />\n </div>\n\n <GlassCard treatment=\"plain\" className=\"flex flex-col gap-3 p-4 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search documents…\"\n aria-label=\"Search documents\"\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary\"\n />\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {(['ALL', ...TYPE_ORDER] as const).map((t) => (\n <button\n key={t}\n type=\"button\"\n onClick={() => setTypeFilter(t)}\n aria-pressed={typeFilter === t}\n className={cn(\n 'rounded-full px-3 py-1 text-xs font-medium transition-colors',\n typeFilter === t\n ? 'bg-accent-primary text-accent-foreground'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {t === 'ALL' ? 'All' : formatEnumLabel(t)}\n </button>\n ))}\n </div>\n </GlassCard>\n\n {filtered.length === 0 ? (\n <EmptyState\n icon={<Vault className=\"h-8 w-8\" />}\n title={assets.length === 0 ? 'No documents yet' : 'No matching documents'}\n description={\n assets.length === 0\n ? 'Attach a contract, receipt or license key from any subscription’s detail page and it will appear here.'\n : 'Try a different search or type filter.'\n }\n />\n ) : (\n grouped.map(([type, items]) => (\n <Section key={type} title={`${formatEnumLabel(type)} · ${items.length}`}>\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((a) => (\n <AssetCard\n key={a.id}\n asset={a}\n subscription={relLabels.get(a.relationshipId) ?? 'Subscription'}\n />\n ))}\n </div>\n </Section>\n ))\n )}\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAkCA,IAAM,IAAmD;CACvD,UAAU;CACV,aAAa;CACb,YAAY;CACZ,aAAa;CACb,SAAS;CACT,SAAS;CACT,UAAU;CACV,QAAQ;CACT,EAEK,IAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAEK,KAAkB,MAAsC;AAC5D,KAAI,CAAC,EAAW,QAAO;CACvB,IAAM,IAAI,IAAI,KAAK,EAAU,CAAC,SAAS;AACvC,KAAI,OAAO,MAAM,EAAE,CAAE,QAAO;CAC5B,IAAM,KAAQ,IAAI,KAAK,KAAK,IAAI;AAChC,QAAO,KAAQ,KAAK,KAAQ;;AAG9B,SAAS,EAAU,EAAE,UAAO,mBAA2D;CACrF,IAAM,IAAiB,GAAoB,EACrC,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,IAAO,EAAU,EAAM,SAAS,GAChC,IAAO,EAAe,EAAM,UAAU;AAa5C,QACE,kBAAC,GAAD;EAAW,WAAU;EAAS,WAAU;YAAxC;GACE,kBAAC,QAAD;IAAM,WAAU;cACd,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;IACvB,CAAA;GACP,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,KAAD;MAAG,WAAU;gBAA0C,EAAM;MAAS,CAAA;KACtE,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAiB,CAAA;KACtE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAgB,EAAM,KAAK;OACvB,CAAA,EACN,EAAM,aACL,kBAAC,QAAD;OAAM,WAAW,EAAG,IAAO,6BAA6B,sBAAsB;iBAA9E,CAAgF,YACrE,EAAW,EAAM,UAAU,CAC/B;SAEL;;KACF;;GACL,EAAM,MAAM,MACX,kBAAC,UAAD;IACE,MAAK;IACL,SAjCS,YAAY;AACvB,YAAC,EAAM,MAAM,MAAM,IACvB;QAAQ,GAAK;AACb,UAAI;OACF,IAAM,IAAM,MAAM,EAAe,EAAM,KAAK,GAAG;AAC/C,cAAO,KAAK,GAAK,UAAU,sBAAsB;gBACzC;AACR,SAAQ,GAAM;;;;IA2BV,UAAU;IACV,cAAY,YAAY,EAAM;IAC9B,WAAU;cAEV,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;IACzB,CAAA;GAED;;;AAIhB,IAAa,UAA2B;CACtC,IAAM,IAAc,GAAc,EAC5B,IAAW,EAAiB,EAAE,YAAY,EAAE,OAAO,KAAK,EAAE,CAAC,EAC3D,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAY,KAAiB,EAA+B,MAAM,EAEnE,IAAY,QAAc;EAC9B,IAAM,oBAAM,IAAI,KAAqB;AACrC,OAAK,IAAM,KAAK,EAAS,MAAM,SAAS,EAAE,CAAE,GAAI,IAAI,EAAE,IAAI,EAAE,MAAM;AAClE,SAAO;IACN,CAAC,EAAS,KAAK,CAAC,EAEb,IAAS,QAAc,EAAY,QAAQ,EAAE,EAAE,CAAC,EAAY,KAAK,CAAC,EAClE,IAAW,QAEb,EAAO,QACJ,OACE,MAAe,SAAS,EAAE,SAAS,OACnC,CAAC,KAAU,EAAE,KAAK,aAAa,CAAC,SAAS,EAAO,aAAa,CAAC,EAClE,EACH;EAAC;EAAQ;EAAY;EAAO,CAC7B,EAEK,IAAU,QAAc;EAC5B,IAAM,oBAAI,IAAI,KAA+B;AAC7C,OAAK,IAAM,KAAK,EAAU,GAAE,IAAI,EAAE,MAAM,CAAC,GAAI,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,EAAG,EAAE,CAAC;AACtE,SAAO,EAAW,QAAQ,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,CAAE,CAAU;IAC5E,CAAC,EAAS,CAAC,EAER,IAAe,QAAc,EAAO,QAAQ,MAAM,EAAe,EAAE,UAAU,CAAC,EAAE,CAAC,EAAO,CAAC;AAW/F,QATI,EAAY,YAAkB,kBAAC,GAAD,EAAa,OAAM,6BAA8B,CAAA,GAC/E,EAAY,UAEZ,kBAAC,GAAD;EACE,SAAQ;EACR,eAAe,KAAK,EAAY,SAAS;EACzC,CAAA,GAIJ,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;YAFd;GAIE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA;GAEd,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,OAAO,EAAO;MACd,OAAM;MACN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;MACtC,OAAO,EAAQ;MACf,OAAM;MACN,CAAA;KACF,kBAAC,GAAD;MACE,MAAM,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA;MACzC,OAAO,EAAa;MACpB,OAAM;MACN,OAAO,EAAa,SAAS,IAAI,SAAS,KAAA;MAC1C,CAAA;KACE;;GAEN,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cAAvC,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,4FAA6F,CAAA,EAC/G,kBAAC,SAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;MAC1C,aAAY;MACZ,cAAW;MACX,WAAU;MACV,CAAA,CACE;QACN,kBAAC,OAAD;KAAK,WAAU;eACX,CAAC,OAAO,GAAG,EAAW,CAAW,KAAK,MACtC,kBAAC,UAAD;MAEE,MAAK;MACL,eAAe,EAAc,EAAE;MAC/B,gBAAc,MAAe;MAC7B,WAAW,EACT,gEACA,MAAe,IACX,6CACA,2DACL;gBAEA,MAAM,QAAQ,QAAQ,EAAgB,EAAE;MAClC,EAZF,EAYE,CACT;KACE,CAAA,CACI;;GAEX,EAAS,WAAW,IACnB,kBAAC,GAAD;IACE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;IACnC,OAAO,EAAO,WAAW,IAAI,qBAAqB;IAClD,aACE,EAAO,WAAW,IACd,2GACA;IAEN,CAAA,GAEF,EAAQ,KAAK,CAAC,GAAM,OAClB,kBAAC,GAAD;IAAoB,OAAO,GAAG,EAAgB,EAAK,CAAC,KAAK,EAAM;cAC7D,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,MACV,kBAAC,GAAD;MAEE,OAAO;MACP,cAAc,EAAU,IAAI,EAAE,eAAe,IAAI;MACjD,EAHK,EAAE,GAGP,CACF;KACE,CAAA;IACE,EAVI,EAUJ,CACV;GAEO"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Dashboard / Overview
3
+ * @module subscriberbot/pages
4
+ *
5
+ * The Subscriber Bot landing page: a premium fintech console over every
6
+ * recurring digital relationship — total recurring spend, portfolio-by-status,
7
+ * upcoming renewals, the action-required inbox, and outstanding invoices. Every
8
+ * number and chart is COMPUTED from real data returned by
9
+ * `wspace-subscriberbot-svc` — nothing is mocked.
10
+ */
11
+ export declare function DashboardPage(): import("react").JSX.Element;
12
+ //# sourceMappingURL=DashboardPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/subscriberbot/pages/DashboardPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAmEH,wBAAgB,aAAa,gCA4X5B"}