@burdenoff/microfe-subscriberbot 2026.706.1 → 2026.706.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.
Files changed (38) hide show
  1. package/dist/subscriberbot/SubscriberBotRoutes.js +14 -6
  2. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  3. package/dist/subscriberbot/components/Modal.js +51 -0
  4. package/dist/subscriberbot/components/Modal.js.map +1 -0
  5. package/dist/subscriberbot/components/index.js +7 -0
  6. package/dist/subscriberbot/components/viz.js +196 -0
  7. package/dist/subscriberbot/components/viz.js.map +1 -0
  8. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +364 -161
  9. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  10. package/dist/subscriberbot/pages/AssetVaultPage.js +182 -0
  11. package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -0
  12. package/dist/subscriberbot/pages/DashboardPage.js +272 -199
  13. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
  14. package/dist/subscriberbot/pages/InboxPage.js +682 -126
  15. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  16. package/dist/subscriberbot/pages/InsightsPage.js +220 -0
  17. package/dist/subscriberbot/pages/InsightsPage.js.map +1 -0
  18. package/dist/subscriberbot/pages/InvoicesPage.js +592 -81
  19. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  20. package/dist/subscriberbot/pages/WorkflowsPage.js +344 -169
  21. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  22. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +401 -116
  23. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  24. package/dist/subscriberbot/pages/agents/AgentsListPage.js +185 -93
  25. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  26. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +735 -135
  27. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  28. package/dist/subscriberbot/pages/providers/ProviderNewPage.js +217 -153
  29. package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -1
  30. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +216 -111
  31. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
  32. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +902 -250
  33. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  34. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +242 -192
  35. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
  36. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +174 -131
  37. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
  38. package/package.json +1 -1
@@ -3,304 +3,956 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { formatCurrency as n, formatDate as r, formatEnumLabel as i, formatIntervalSuffix as a } from "../../utils/formatters.js";
4
4
  import { StatusBadge as o } from "../../components/StatusBadge.js";
5
5
  import { EmptyState as s } from "../../components/EmptyState.js";
6
- import { ErrorView as c, LoadingView as l, Section as u } from "../../components/StateViews.js";
7
- import { useCancelRelationship as d, useRelationship as f, useTransitionRelationship as p } from "../../hooks/useSubscriberBotApi.js";
8
- import { useState as m } from "react";
9
- import { Activity as h, ArrowLeft as g, Building2 as _, CalendarClock as v, CreditCard as y, Paperclip as b, ShieldCheck as x, Tag as S } from "lucide-react";
10
- import { useParams as C } from "react-router-dom";
11
- import { jsx as w, jsxs as T } from "react/jsx-runtime";
12
- import { GlassCard as E } from "@burdenoff/fe-libs/ui";
6
+ import { Modal as c } from "../../components/Modal.js";
7
+ import { ErrorView as l, LoadingView as u, Section as d } from "../../components/StateViews.js";
8
+ import { Gauge as f, MiniProgress as p, Timeline as m } from "../../components/viz.js";
9
+ import "../../components/index.js";
10
+ import { useCancelRelationship as h, useCreateAsset as g, useCreateEntitlement as _, useFileDownloadUrl as v, usePlans as y, useProviders as b, useRelationship as x, useTransitionRelationship as S, useUpdateRelationship as C, useUploadFile as w } from "../../hooks/useSubscriberBotApi.js";
11
+ import { useState as T } from "react";
12
+ import { Activity as E, ArrowLeft as D, Ban as O, CalendarClock as k, CreditCard as A, Download as j, Paperclip as M, Pause as N, Pencil as P, Play as F, Plus as I, ShieldCheck as L, Tag as ee, Wallet as te } from "lucide-react";
13
+ import { useParams as ne } from "react-router-dom";
14
+ import { Fragment as R, jsx as z, jsxs as B } from "react/jsx-runtime";
15
+ import { GlassCard as V } from "@burdenoff/fe-libs/ui";
13
16
  //#region src/subscriberbot/pages/relationships/RelationshipDetailPage.tsx
14
- var D = [
17
+ var H = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", U = "mb-1 block text-xs font-medium text-text-secondary", W = [
18
+ "MONTHLY",
19
+ "YEARLY",
20
+ "QUARTERLY",
21
+ "WEEKLY",
22
+ "DAILY",
23
+ "USAGE_BASED",
24
+ "LIFETIME",
25
+ "FREE"
26
+ ], G = [
27
+ "FEATURE_ACCESS",
28
+ "SEAT",
29
+ "USAGE_QUOTA",
30
+ "CONTENT",
31
+ "DISCOUNT",
32
+ "SUPPORT_TIER"
33
+ ], K = [
34
+ "RECEIPT",
35
+ "INVOICE",
36
+ "CONTRACT",
37
+ "LICENSE_KEY",
38
+ "CREDENTIAL",
39
+ "CERTIFICATE",
40
+ "WARRANTY",
41
+ "DOMAIN"
42
+ ], q = [
15
43
  {
16
44
  status: "ACTIVE",
17
- label: "Activate"
45
+ label: "Activate",
46
+ icon: F
18
47
  },
19
48
  {
20
49
  status: "PAUSED",
21
- label: "Pause"
50
+ label: "Pause",
51
+ icon: N
22
52
  },
23
53
  {
24
54
  status: "EXPIRED",
25
- label: "Mark expired"
55
+ label: "Mark expired",
56
+ icon: O
26
57
  }
27
58
  ];
28
- function O() {
29
- let { id: O } = C(), { navigateTo: k } = e(), { data: A, isLoading: j, isError: M, refetch: N } = f(O), P = p(), F = d(), [I, L] = m(null);
30
- if (j) return /* @__PURE__ */ w(t, {
59
+ function J({ label: e, value: t }) {
60
+ return /* @__PURE__ */ B("div", {
61
+ className: "flex items-center justify-between gap-3 border-b border-border-subtle/60 py-2.5 last:border-0 last:pb-0",
62
+ children: [/* @__PURE__ */ z("span", {
63
+ className: "shrink-0 text-sm text-text-secondary",
64
+ children: e
65
+ }), /* @__PURE__ */ z("span", {
66
+ className: "min-w-0 truncate text-right text-sm font-medium text-text-primary",
67
+ children: t
68
+ })]
69
+ });
70
+ }
71
+ function re(e) {
72
+ return e == null ? "accent" : e >= 66 ? "positive" : e >= 33 ? "warning" : "negative";
73
+ }
74
+ function Y(e) {
75
+ if (!e) return "";
76
+ let t = new Date(e);
77
+ return Number.isNaN(t.getTime()) ? "" : t.toISOString().slice(0, 10);
78
+ }
79
+ function ie({ relationship: e, onClose: t }) {
80
+ let n = C(), r = b({ pagination: {
81
+ limit: 100,
82
+ offset: 0
83
+ } }), [i, a] = T(e.label), [o, s] = T(e.providerId ?? ""), [l, u] = T(e.planId ?? ""), [d, f] = T(String(e.amount ?? "")), [p, m] = T(e.currency), [h, g] = T(e.interval), [_, v] = T(Y(e.renewsAt)), [x, S] = T(e.autoRenew), [w, E] = T(e.healthScore == null ? "" : String(e.healthScore)), [D, O] = T(e.notes ?? ""), [k, A] = T(null), j = y(o || void 0), M = (() => {
84
+ let t = r.data?.items ?? [];
85
+ return e.provider && !t.some((t) => t.id === e.provider?.id) ? [e.provider, ...t] : t;
86
+ })(), N = j.data ?? [];
87
+ return /* @__PURE__ */ z(c, {
88
+ title: "Edit relationship",
89
+ onClose: t,
90
+ maxWidthClassName: "max-w-2xl",
91
+ children: /* @__PURE__ */ B("form", {
92
+ onSubmit: (r) => {
93
+ if (r.preventDefault(), A(null), !i.trim()) {
94
+ A("A label is required.");
95
+ return;
96
+ }
97
+ let a = {
98
+ label: i.trim(),
99
+ interval: h,
100
+ autoRenew: x,
101
+ currency: p.trim() || "USD",
102
+ notes: D.trim(),
103
+ ...o ? { providerId: o } : {},
104
+ ...l ? { planId: l } : {},
105
+ ...d.trim() ? { amount: Number(d) } : {},
106
+ ...w.trim() ? { healthScore: Number(w) } : {},
107
+ ..._ ? { renewsAt: new Date(_).toISOString() } : {}
108
+ };
109
+ n.mutate({
110
+ id: e.id,
111
+ input: a
112
+ }, {
113
+ onSuccess: () => t(),
114
+ onError: (e) => A(e instanceof Error ? e.message : "Could not update relationship.")
115
+ });
116
+ },
117
+ className: "space-y-4",
118
+ children: [
119
+ k && /* @__PURE__ */ z("div", {
120
+ className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
121
+ children: k
122
+ }),
123
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ B("label", {
124
+ htmlFor: "edit-label",
125
+ className: U,
126
+ children: ["Label ", /* @__PURE__ */ z("span", {
127
+ className: "text-status-error-text",
128
+ children: "*"
129
+ })]
130
+ }), /* @__PURE__ */ z("input", {
131
+ id: "edit-label",
132
+ type: "text",
133
+ value: i,
134
+ onChange: (e) => a(e.target.value),
135
+ className: H,
136
+ required: !0
137
+ })] }),
138
+ /* @__PURE__ */ B("div", {
139
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
140
+ children: [/* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
141
+ htmlFor: "edit-provider",
142
+ className: U,
143
+ children: "Provider"
144
+ }), /* @__PURE__ */ B("select", {
145
+ id: "edit-provider",
146
+ value: o,
147
+ onChange: (e) => {
148
+ s(e.target.value), u("");
149
+ },
150
+ className: H,
151
+ children: [/* @__PURE__ */ z("option", {
152
+ value: "",
153
+ children: "— None —"
154
+ }), M.map((e) => /* @__PURE__ */ z("option", {
155
+ value: e.id,
156
+ children: e.name
157
+ }, e.id))]
158
+ })] }), /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
159
+ htmlFor: "edit-plan",
160
+ className: U,
161
+ children: "Plan"
162
+ }), /* @__PURE__ */ B("select", {
163
+ id: "edit-plan",
164
+ value: l,
165
+ onChange: (e) => u(e.target.value),
166
+ className: H,
167
+ disabled: !o || N.length === 0,
168
+ children: [/* @__PURE__ */ z("option", {
169
+ value: "",
170
+ children: "— None —"
171
+ }), N.map((e) => /* @__PURE__ */ z("option", {
172
+ value: e.id,
173
+ children: e.name
174
+ }, e.id))]
175
+ })] })]
176
+ }),
177
+ /* @__PURE__ */ B("div", {
178
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
179
+ children: [
180
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
181
+ htmlFor: "edit-amount",
182
+ className: U,
183
+ children: "Amount"
184
+ }), /* @__PURE__ */ z("input", {
185
+ id: "edit-amount",
186
+ type: "number",
187
+ min: "0",
188
+ step: "0.01",
189
+ value: d,
190
+ onChange: (e) => f(e.target.value),
191
+ className: H
192
+ })] }),
193
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
194
+ htmlFor: "edit-currency",
195
+ className: U,
196
+ children: "Currency"
197
+ }), /* @__PURE__ */ z("input", {
198
+ id: "edit-currency",
199
+ type: "text",
200
+ value: p,
201
+ onChange: (e) => m(e.target.value.toUpperCase()),
202
+ maxLength: 3,
203
+ className: H
204
+ })] }),
205
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
206
+ htmlFor: "edit-interval",
207
+ className: U,
208
+ children: "Billing interval"
209
+ }), /* @__PURE__ */ z("select", {
210
+ id: "edit-interval",
211
+ value: h,
212
+ onChange: (e) => g(e.target.value),
213
+ className: H,
214
+ children: W.map((e) => /* @__PURE__ */ z("option", {
215
+ value: e,
216
+ children: e.replace(/_/g, " ")
217
+ }, e))
218
+ })] })
219
+ ]
220
+ }),
221
+ /* @__PURE__ */ B("div", {
222
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
223
+ children: [
224
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
225
+ htmlFor: "edit-renews",
226
+ className: U,
227
+ children: "Renews on"
228
+ }), /* @__PURE__ */ z("input", {
229
+ id: "edit-renews",
230
+ type: "date",
231
+ value: _,
232
+ onChange: (e) => v(e.target.value),
233
+ className: H
234
+ })] }),
235
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
236
+ htmlFor: "edit-health",
237
+ className: U,
238
+ children: "Health score (0–100)"
239
+ }), /* @__PURE__ */ z("input", {
240
+ id: "edit-health",
241
+ type: "number",
242
+ min: "0",
243
+ max: "100",
244
+ value: w,
245
+ onChange: (e) => E(e.target.value),
246
+ className: H
247
+ })] }),
248
+ /* @__PURE__ */ z("div", {
249
+ className: "flex items-end",
250
+ children: /* @__PURE__ */ B("label", {
251
+ className: "flex items-center gap-2 text-sm text-text-primary",
252
+ children: [/* @__PURE__ */ z("input", {
253
+ type: "checkbox",
254
+ checked: x,
255
+ onChange: (e) => S(e.target.checked),
256
+ className: "size-4 rounded border-border-subtle"
257
+ }), "Auto-renews"]
258
+ })
259
+ })
260
+ ]
261
+ }),
262
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
263
+ htmlFor: "edit-notes",
264
+ className: U,
265
+ children: "Notes"
266
+ }), /* @__PURE__ */ z("textarea", {
267
+ id: "edit-notes",
268
+ value: D,
269
+ onChange: (e) => O(e.target.value),
270
+ rows: 3,
271
+ className: H
272
+ })] }),
273
+ /* @__PURE__ */ B("div", {
274
+ className: "flex justify-end gap-3",
275
+ children: [/* @__PURE__ */ z("button", {
276
+ type: "button",
277
+ onClick: t,
278
+ className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
279
+ children: "Cancel"
280
+ }), /* @__PURE__ */ z("button", {
281
+ type: "submit",
282
+ disabled: n.isPending,
283
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
284
+ children: n.isPending ? "Saving…" : "Save changes"
285
+ })]
286
+ })
287
+ ]
288
+ })
289
+ });
290
+ }
291
+ function ae({ relationshipId: e, onClose: t }) {
292
+ let n = _(), [r, i] = T(""), [a, o] = T("FEATURE_ACCESS"), [s, l] = T(""), [u, d] = T(""), [f, p] = T(""), [m, h] = T(null);
293
+ return /* @__PURE__ */ z(c, {
294
+ title: "Add entitlement",
295
+ onClose: t,
296
+ children: /* @__PURE__ */ B("form", {
297
+ onSubmit: (i) => {
298
+ if (i.preventDefault(), h(null), !r.trim()) {
299
+ h("An entitlement name is required.");
300
+ return;
301
+ }
302
+ n.mutate({
303
+ relationshipId: e,
304
+ name: r.trim(),
305
+ type: a,
306
+ ...s.trim() ? { quota: Number(s) } : {},
307
+ ...u.trim() ? { unit: u.trim() } : {},
308
+ ...f.trim() ? { description: f.trim() } : {}
309
+ }, {
310
+ onSuccess: () => t(),
311
+ onError: (e) => h(e instanceof Error ? e.message : "Could not add entitlement.")
312
+ });
313
+ },
314
+ className: "space-y-4",
315
+ children: [
316
+ m && /* @__PURE__ */ z("div", {
317
+ className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
318
+ children: m
319
+ }),
320
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ B("label", {
321
+ htmlFor: "ent-name",
322
+ className: U,
323
+ children: ["Name ", /* @__PURE__ */ z("span", {
324
+ className: "text-status-error-text",
325
+ children: "*"
326
+ })]
327
+ }), /* @__PURE__ */ z("input", {
328
+ id: "ent-name",
329
+ type: "text",
330
+ value: r,
331
+ onChange: (e) => i(e.target.value),
332
+ placeholder: "e.g. Seats, API calls, Priority support",
333
+ className: H,
334
+ required: !0
335
+ })] }),
336
+ /* @__PURE__ */ B("div", {
337
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
338
+ children: [
339
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
340
+ htmlFor: "ent-type",
341
+ className: U,
342
+ children: "Type"
343
+ }), /* @__PURE__ */ z("select", {
344
+ id: "ent-type",
345
+ value: a,
346
+ onChange: (e) => o(e.target.value),
347
+ className: H,
348
+ children: G.map((e) => /* @__PURE__ */ z("option", {
349
+ value: e,
350
+ children: e.replace(/_/g, " ")
351
+ }, e))
352
+ })] }),
353
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
354
+ htmlFor: "ent-quota",
355
+ className: U,
356
+ children: "Quota"
357
+ }), /* @__PURE__ */ z("input", {
358
+ id: "ent-quota",
359
+ type: "number",
360
+ min: "0",
361
+ value: s,
362
+ onChange: (e) => l(e.target.value),
363
+ placeholder: "e.g. 5",
364
+ className: H
365
+ })] }),
366
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
367
+ htmlFor: "ent-unit",
368
+ className: U,
369
+ children: "Unit"
370
+ }), /* @__PURE__ */ z("input", {
371
+ id: "ent-unit",
372
+ type: "text",
373
+ value: u,
374
+ onChange: (e) => d(e.target.value),
375
+ placeholder: "e.g. seats, GB",
376
+ className: H
377
+ })] })
378
+ ]
379
+ }),
380
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
381
+ htmlFor: "ent-desc",
382
+ className: U,
383
+ children: "Description"
384
+ }), /* @__PURE__ */ z("textarea", {
385
+ id: "ent-desc",
386
+ value: f,
387
+ onChange: (e) => p(e.target.value),
388
+ rows: 2,
389
+ className: H
390
+ })] }),
391
+ /* @__PURE__ */ B("div", {
392
+ className: "flex justify-end gap-3",
393
+ children: [/* @__PURE__ */ z("button", {
394
+ type: "button",
395
+ onClick: t,
396
+ className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
397
+ children: "Cancel"
398
+ }), /* @__PURE__ */ z("button", {
399
+ type: "submit",
400
+ disabled: n.isPending,
401
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
402
+ children: n.isPending ? "Adding…" : "Add entitlement"
403
+ })]
404
+ })
405
+ ]
406
+ })
407
+ });
408
+ }
409
+ function oe({ relationshipId: e, onClose: t }) {
410
+ let n = g(), { uploadFile: r, progress: i, isUploading: a } = w(), [o, s] = T(""), [l, u] = T("RECEIPT"), [d, f] = T(null), [p, m] = T(""), [h, _] = T(null), v = a || n.isPending;
411
+ return /* @__PURE__ */ z(c, {
412
+ title: "Attach asset",
413
+ onClose: t,
414
+ children: /* @__PURE__ */ B("form", {
415
+ onSubmit: async (i) => {
416
+ if (i.preventDefault(), _(null), !d) {
417
+ _("Choose a file to attach.");
418
+ return;
419
+ }
420
+ try {
421
+ let { fileId: i, fileName: a } = await r(d);
422
+ await n.mutateAsync({
423
+ relationshipId: e,
424
+ name: o.trim() || a,
425
+ type: l,
426
+ fileId: i,
427
+ ...p ? { expiresAt: new Date(p).toISOString() } : {}
428
+ }), t();
429
+ } catch (e) {
430
+ _(e instanceof Error ? e.message : "Could not attach the asset.");
431
+ }
432
+ },
433
+ className: "space-y-4",
434
+ children: [
435
+ h && /* @__PURE__ */ z("div", {
436
+ className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
437
+ children: h
438
+ }),
439
+ /* @__PURE__ */ B("div", { children: [
440
+ /* @__PURE__ */ B("label", {
441
+ htmlFor: "asset-file",
442
+ className: U,
443
+ children: ["File ", /* @__PURE__ */ z("span", {
444
+ className: "text-status-error-text",
445
+ children: "*"
446
+ })]
447
+ }),
448
+ /* @__PURE__ */ z("input", {
449
+ id: "asset-file",
450
+ type: "file",
451
+ onChange: (e) => {
452
+ let t = e.target.files?.[0] ?? null;
453
+ f(t), t && !o.trim() && s(t.name);
454
+ },
455
+ className: "w-full text-sm text-text-secondary file:mr-3 file:rounded-lg file:border file:border-border-subtle file:bg-bg-surface file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-text-primary hover:file:bg-bg-sunken"
456
+ }),
457
+ /* @__PURE__ */ z("p", {
458
+ className: "mt-1 text-xs text-text-secondary",
459
+ children: "Stored securely in files — only a reference is kept here."
460
+ })
461
+ ] }),
462
+ /* @__PURE__ */ B("div", {
463
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
464
+ children: [/* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
465
+ htmlFor: "asset-name",
466
+ className: U,
467
+ children: "Name"
468
+ }), /* @__PURE__ */ z("input", {
469
+ id: "asset-name",
470
+ type: "text",
471
+ value: o,
472
+ onChange: (e) => s(e.target.value),
473
+ placeholder: "Defaults to the file name",
474
+ className: H
475
+ })] }), /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
476
+ htmlFor: "asset-type",
477
+ className: U,
478
+ children: "Type"
479
+ }), /* @__PURE__ */ z("select", {
480
+ id: "asset-type",
481
+ value: l,
482
+ onChange: (e) => u(e.target.value),
483
+ className: H,
484
+ children: K.map((e) => /* @__PURE__ */ z("option", {
485
+ value: e,
486
+ children: e.replace(/_/g, " ")
487
+ }, e))
488
+ })] })]
489
+ }),
490
+ /* @__PURE__ */ B("div", { children: [/* @__PURE__ */ z("label", {
491
+ htmlFor: "asset-expires",
492
+ className: U,
493
+ children: "Expires on"
494
+ }), /* @__PURE__ */ z("input", {
495
+ id: "asset-expires",
496
+ type: "date",
497
+ value: p,
498
+ onChange: (e) => m(e.target.value),
499
+ className: H
500
+ })] }),
501
+ a && /* @__PURE__ */ B("p", {
502
+ className: "text-xs text-text-secondary",
503
+ children: [
504
+ "Uploading… ",
505
+ i,
506
+ "%"
507
+ ]
508
+ }),
509
+ /* @__PURE__ */ B("div", {
510
+ className: "flex justify-end gap-3",
511
+ children: [/* @__PURE__ */ z("button", {
512
+ type: "button",
513
+ onClick: t,
514
+ className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
515
+ children: "Cancel"
516
+ }), /* @__PURE__ */ z("button", {
517
+ type: "submit",
518
+ disabled: v,
519
+ className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
520
+ children: v ? "Attaching…" : "Attach asset"
521
+ })]
522
+ })
523
+ ]
524
+ })
525
+ });
526
+ }
527
+ function se({ asset: e }) {
528
+ let t = v(), [n, a] = T(!1);
529
+ return /* @__PURE__ */ B("div", {
530
+ className: "flex items-center justify-between gap-3 p-3",
531
+ children: [/* @__PURE__ */ B("div", {
532
+ className: "flex min-w-0 items-center gap-2",
533
+ children: [/* @__PURE__ */ z(M, { className: "h-4 w-4 shrink-0 text-text-secondary" }), /* @__PURE__ */ B("div", {
534
+ className: "min-w-0",
535
+ children: [/* @__PURE__ */ z("p", {
536
+ className: "truncate text-sm font-medium text-text-primary",
537
+ children: e.name
538
+ }), /* @__PURE__ */ z("p", {
539
+ className: "text-xs text-text-secondary",
540
+ children: i(e.type)
541
+ })]
542
+ })]
543
+ }), /* @__PURE__ */ B("div", {
544
+ className: "flex shrink-0 items-center gap-3",
545
+ children: [e.expiresAt && /* @__PURE__ */ B("span", {
546
+ className: "text-xs text-text-secondary",
547
+ children: ["Expires ", r(e.expiresAt)]
548
+ }), e.file?.id && /* @__PURE__ */ B("button", {
549
+ type: "button",
550
+ onClick: async () => {
551
+ if (e.file?.id) {
552
+ a(!0);
553
+ try {
554
+ let n = await t(e.file.id);
555
+ window.open(n, "_blank", "noopener,noreferrer");
556
+ } catch {} finally {
557
+ a(!1);
558
+ }
559
+ }
560
+ },
561
+ disabled: n,
562
+ className: "inline-flex items-center gap-1 rounded-lg border border-border-subtle px-2.5 py-1 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
563
+ children: [
564
+ /* @__PURE__ */ z(j, { className: "h-3.5 w-3.5" }),
565
+ " ",
566
+ n ? "Opening…" : "Download"
567
+ ]
568
+ })]
569
+ })]
570
+ });
571
+ }
572
+ function X() {
573
+ let { id: c } = ne(), { navigateTo: g } = e(), { data: _, isLoading: v, isError: y, refetch: b } = x(c), C = S(), w = h(), [j, M] = T(null), [N, F] = T(!1), [H, U] = T(!1), [W, G] = T(!1);
574
+ if (v) return /* @__PURE__ */ z(t, {
31
575
  title: "Relationship",
32
- children: /* @__PURE__ */ w(l, { label: "Loading relationship…" })
576
+ children: /* @__PURE__ */ z(u, { label: "Loading relationship…" })
33
577
  });
34
- if (M) return /* @__PURE__ */ w(t, {
578
+ if (y) return /* @__PURE__ */ z(t, {
35
579
  title: "Relationship",
36
- children: /* @__PURE__ */ w(c, {
580
+ children: /* @__PURE__ */ z(l, {
37
581
  message: "Could not load this relationship.",
38
- onRetry: () => void N()
582
+ onRetry: () => void b()
39
583
  })
40
584
  });
41
- if (!A) return /* @__PURE__ */ w(t, {
585
+ if (!_) return /* @__PURE__ */ z(t, {
42
586
  title: "Relationship",
43
- children: /* @__PURE__ */ w(s, {
587
+ children: /* @__PURE__ */ z(s, {
44
588
  illustration: "empty-data",
45
589
  title: "Relationship not found",
46
590
  description: "It may have been removed, or you may not have access to it.",
47
- action: /* @__PURE__ */ w("button", {
591
+ action: /* @__PURE__ */ z("button", {
48
592
  type: "button",
49
- onClick: () => k("/relationships"),
593
+ onClick: () => g("/relationships"),
50
594
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
51
595
  children: "Back to relationships"
52
596
  })
53
597
  })
54
598
  });
55
- let R = A, z = P.isPending || F.isPending, B = (e) => {
56
- L(null), P.mutate({
57
- id: R.id,
599
+ let K = _, Y = C.isPending || w.isPending, X = (e) => {
600
+ M(null), C.mutate({
601
+ id: K.id,
58
602
  status: e
59
- }, { onError: (e) => L(e instanceof Error ? e.message : "Transition failed") });
60
- };
61
- return /* @__PURE__ */ T(t, {
62
- title: R.label,
63
- description: R.provider?.name ?? i(R.kind),
64
- actions: /* @__PURE__ */ T("button", {
65
- type: "button",
66
- onClick: () => k("/relationships"),
67
- className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
68
- children: [/* @__PURE__ */ w(g, { className: "h-4 w-4" }), " Back"]
603
+ }, { onError: (e) => M(e instanceof Error ? e.message : "Transition failed") });
604
+ }, ce = () => {
605
+ M(null), w.mutate(K.id, { onError: (e) => M(e instanceof Error ? e.message : "Cancel failed") });
606
+ }, Z = [...K.renewalEvents ?? []].sort((e, t) => new Date(e.occursAt).getTime() - new Date(t.occursAt).getTime()).map((e) => {
607
+ let t = new Date(e.occursAt).getTime(), a = !Number.isNaN(t) && t > Date.now();
608
+ return {
609
+ title: i(e.eventType),
610
+ sub: `${r(e.occursAt)}${e.detail ? ` · ${e.detail}` : ""}`,
611
+ meta: e.amount == null ? void 0 : n(e.amount, e.currency ?? K.currency),
612
+ tone: a ? "warning" : "muted"
613
+ };
614
+ }), Q = K.autoRenew ? /* @__PURE__ */ z("span", {
615
+ className: "inline-flex items-center rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text",
616
+ children: "On"
617
+ }) : /* @__PURE__ */ z("span", {
618
+ className: "inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
619
+ children: "Off"
620
+ }), le = q.filter((e) => e.status !== K.status), $ = K.plan?.features ?? [];
621
+ return /* @__PURE__ */ B(t, {
622
+ title: K.label,
623
+ description: K.provider?.name ?? i(K.kind),
624
+ actions: /* @__PURE__ */ B("div", {
625
+ className: "flex items-center gap-2",
626
+ children: [/* @__PURE__ */ B("button", {
627
+ type: "button",
628
+ onClick: () => F(!0),
629
+ className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
630
+ children: [/* @__PURE__ */ z(P, { className: "h-4 w-4" }), " Edit"]
631
+ }), /* @__PURE__ */ B("button", {
632
+ type: "button",
633
+ onClick: () => g("/relationships"),
634
+ className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken",
635
+ children: [/* @__PURE__ */ z(D, { className: "h-4 w-4" }), " Back"]
636
+ })]
69
637
  }),
70
638
  children: [
71
- /* @__PURE__ */ T("div", {
72
- className: "flex flex-wrap items-center gap-3",
73
- children: [
74
- /* @__PURE__ */ w(o, { status: R.status }),
75
- /* @__PURE__ */ w("span", {
76
- className: "text-sm text-text-secondary",
77
- children: i(R.kind)
78
- }),
79
- /* @__PURE__ */ w("span", {
80
- className: "text-sm text-text-secondary",
81
- children: "·"
82
- }),
83
- /* @__PURE__ */ T("span", {
84
- className: "text-sm font-semibold text-text-primary",
85
- children: [n(R.amount, R.currency), /* @__PURE__ */ w("span", {
86
- className: "text-xs font-normal text-text-secondary",
87
- children: a(R.interval)
639
+ /* @__PURE__ */ z(V, {
640
+ treatment: "glass",
641
+ glow: !0,
642
+ className: "p-5 sm:p-6",
643
+ children: /* @__PURE__ */ B("div", {
644
+ className: "flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between",
645
+ children: [/* @__PURE__ */ B("div", {
646
+ className: "min-w-0",
647
+ children: [
648
+ /* @__PURE__ */ z("p", {
649
+ className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
650
+ children: i(K.kind)
651
+ }),
652
+ /* @__PURE__ */ B("div", {
653
+ className: "mt-2 flex flex-wrap items-center gap-3",
654
+ children: [/* @__PURE__ */ B("span", {
655
+ className: "text-3xl font-bold tabular-nums text-text-primary",
656
+ children: [n(K.amount, K.currency), /* @__PURE__ */ z("span", {
657
+ className: "text-base font-normal text-text-secondary",
658
+ children: a(K.interval)
659
+ })]
660
+ }), /* @__PURE__ */ z(o, { status: K.status })]
661
+ }),
662
+ /* @__PURE__ */ B("div", {
663
+ className: "mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary",
664
+ children: [
665
+ /* @__PURE__ */ B("span", {
666
+ className: "inline-flex items-center gap-1.5",
667
+ children: [/* @__PURE__ */ z(k, { className: "h-3.5 w-3.5" }), K.renewsAt ? `Renews ${r(K.renewsAt)}` : "No renewal scheduled"]
668
+ }),
669
+ /* @__PURE__ */ B("span", {
670
+ className: "inline-flex items-center gap-1.5",
671
+ children: [/* @__PURE__ */ z(L, { className: "h-3.5 w-3.5" }), i(K.discoverySource)]
672
+ }),
673
+ /* @__PURE__ */ B("span", {
674
+ className: "inline-flex items-center gap-1.5",
675
+ children: ["Auto-renew ", Q]
676
+ })
677
+ ]
678
+ }),
679
+ K.tags.length > 0 && /* @__PURE__ */ B("div", {
680
+ className: "mt-3 flex flex-wrap items-center gap-2",
681
+ children: [/* @__PURE__ */ z(ee, { className: "h-3.5 w-3.5 text-text-secondary" }), K.tags.map((e) => /* @__PURE__ */ z("span", {
682
+ className: "rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary",
683
+ children: e
684
+ }, e))]
685
+ })
686
+ ]
687
+ }), /* @__PURE__ */ B("div", {
688
+ className: "flex shrink-0 flex-wrap gap-2 lg:flex-col lg:items-stretch",
689
+ children: [le.map((e) => {
690
+ let t = e.icon;
691
+ return /* @__PURE__ */ B("button", {
692
+ type: "button",
693
+ disabled: Y,
694
+ onClick: () => X(e.status),
695
+ className: "inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-subtle bg-bg-surface px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
696
+ children: [
697
+ /* @__PURE__ */ z(t, { className: "h-3.5 w-3.5" }),
698
+ " ",
699
+ e.label
700
+ ]
701
+ }, e.status);
702
+ }), K.status !== "CANCELLED" && /* @__PURE__ */ B("button", {
703
+ type: "button",
704
+ disabled: Y,
705
+ onClick: ce,
706
+ className: "inline-flex items-center justify-center gap-1.5 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:opacity-90 disabled:opacity-50",
707
+ children: [/* @__PURE__ */ z(O, { className: "h-3.5 w-3.5" }), " Cancel"]
88
708
  })]
89
- }),
90
- R.autoRenew && /* @__PURE__ */ w("span", {
91
- className: "text-xs text-text-secondary",
92
- children: "Auto-renews"
93
- })
94
- ]
709
+ })]
710
+ })
95
711
  }),
96
- I && /* @__PURE__ */ w("div", {
712
+ j && /* @__PURE__ */ z("div", {
97
713
  className: "mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
98
- children: I
714
+ children: j
99
715
  }),
100
- /* @__PURE__ */ T("div", {
101
- className: "mt-5 flex flex-wrap gap-2",
102
- children: [D.filter((e) => e.status !== R.status).map((e) => /* @__PURE__ */ w("button", {
103
- type: "button",
104
- disabled: z,
105
- onClick: () => B(e.status),
106
- className: "rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50",
107
- children: e.label
108
- }, e.status)), R.status !== "CANCELLED" && /* @__PURE__ */ w("button", {
109
- type: "button",
110
- disabled: z,
111
- onClick: () => {
112
- L(null), F.mutate(R.id, { onError: (e) => L(e instanceof Error ? e.message : "Cancel failed") });
113
- },
114
- className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-3 py-1.5 text-xs font-medium text-status-error-text hover:opacity-90 disabled:opacity-50",
115
- children: "Cancel relationship"
116
- })]
117
- }),
118
- /* @__PURE__ */ T("div", {
119
- className: "mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
120
- children: [
121
- /* @__PURE__ */ T(E, {
122
- treatment: "metric",
123
- className: "p-4",
124
- children: [/* @__PURE__ */ T("div", {
125
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
126
- children: [/* @__PURE__ */ w(_, { className: "h-3.5 w-3.5" }), " Provider"]
127
- }), /* @__PURE__ */ w("p", {
128
- className: "mt-1.5 text-sm text-text-primary",
129
- children: R.provider?.name ?? "—"
130
- })]
131
- }),
132
- /* @__PURE__ */ T(E, {
133
- treatment: "metric",
134
- className: "p-4",
135
- children: [/* @__PURE__ */ T("div", {
136
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
137
- children: [/* @__PURE__ */ w(y, { className: "h-3.5 w-3.5" }), " Plan"]
138
- }), /* @__PURE__ */ w("p", {
139
- className: "mt-1.5 text-sm text-text-primary",
140
- children: R.plan?.name ?? "—"
141
- })]
142
- }),
143
- /* @__PURE__ */ T(E, {
144
- treatment: "metric",
145
- className: "p-4",
146
- children: [/* @__PURE__ */ T("div", {
147
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
148
- children: [/* @__PURE__ */ w(v, { className: "h-3.5 w-3.5" }), " Next renewal"]
149
- }), /* @__PURE__ */ w("p", {
150
- className: "mt-1.5 text-sm text-text-primary",
151
- children: R.renewsAt ? r(R.renewsAt) : "—"
152
- })]
153
- }),
154
- /* @__PURE__ */ T(E, {
155
- treatment: "metric",
156
- className: "p-4",
157
- children: [/* @__PURE__ */ T("div", {
158
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
159
- children: [/* @__PURE__ */ w(h, { className: "h-3.5 w-3.5" }), " Health score"]
160
- }), /* @__PURE__ */ w("p", {
161
- className: "mt-1.5 text-sm text-text-primary",
162
- children: R.healthScore == null ? "—" : `${R.healthScore}/100`
163
- })]
164
- }),
165
- /* @__PURE__ */ T(E, {
716
+ /* @__PURE__ */ B("div", {
717
+ className: "mt-6 grid grid-cols-1 gap-4 lg:grid-cols-3",
718
+ children: [/* @__PURE__ */ B("div", {
719
+ className: "space-y-4 lg:col-span-2",
720
+ children: [
721
+ /* @__PURE__ */ B("div", {
722
+ className: "grid grid-cols-1 gap-4 md:grid-cols-2",
723
+ children: [/* @__PURE__ */ B(V, {
724
+ treatment: "metric",
725
+ className: "p-5",
726
+ children: [
727
+ /* @__PURE__ */ B("div", {
728
+ className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
729
+ children: [/* @__PURE__ */ z(A, { className: "h-4 w-4 text-text-secondary" }), " Plan & pricing"]
730
+ }),
731
+ /* @__PURE__ */ B("div", {
732
+ className: "mt-3",
733
+ children: [
734
+ /* @__PURE__ */ z(J, {
735
+ label: "Plan",
736
+ value: K.plan?.name ?? "—"
737
+ }),
738
+ /* @__PURE__ */ z(J, {
739
+ label: "Price",
740
+ value: /* @__PURE__ */ B(R, { children: [n(K.amount, K.currency), /* @__PURE__ */ z("span", {
741
+ className: "font-normal text-text-secondary",
742
+ children: a(K.interval)
743
+ })] })
744
+ }),
745
+ /* @__PURE__ */ z(J, {
746
+ label: "Billing interval",
747
+ value: i(K.interval)
748
+ }),
749
+ /* @__PURE__ */ z(J, {
750
+ label: "Provider",
751
+ value: K.provider?.name ?? "—"
752
+ })
753
+ ]
754
+ }),
755
+ $.length > 0 && /* @__PURE__ */ z("div", {
756
+ className: "mt-3 flex flex-wrap gap-1.5",
757
+ children: $.map((e) => /* @__PURE__ */ z("span", {
758
+ className: "rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary",
759
+ children: e
760
+ }, e))
761
+ })
762
+ ]
763
+ }), /* @__PURE__ */ B(V, {
764
+ treatment: "metric",
765
+ className: "p-5",
766
+ children: [/* @__PURE__ */ B("div", {
767
+ className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
768
+ children: [/* @__PURE__ */ z(te, { className: "h-4 w-4 text-text-secondary" }), " Payment & billing"]
769
+ }), /* @__PURE__ */ B("div", {
770
+ className: "mt-3",
771
+ children: [
772
+ /* @__PURE__ */ z(J, {
773
+ label: "Currency",
774
+ value: K.currency
775
+ }),
776
+ /* @__PURE__ */ z(J, {
777
+ label: "Auto-renew",
778
+ value: Q
779
+ }),
780
+ /* @__PURE__ */ z(J, {
781
+ label: "Next renewal",
782
+ value: K.renewsAt ? r(K.renewsAt) : "—"
783
+ }),
784
+ /* @__PURE__ */ z(J, {
785
+ label: "Started",
786
+ value: K.startedAt ? r(K.startedAt) : "—"
787
+ }),
788
+ K.trialEndsAt && /* @__PURE__ */ z(J, {
789
+ label: "Trial ends",
790
+ value: r(K.trialEndsAt)
791
+ })
792
+ ]
793
+ })]
794
+ })]
795
+ }),
796
+ /* @__PURE__ */ z(d, {
797
+ className: "mt-0",
798
+ title: "Entitlements",
799
+ description: "What this relationship grants you",
800
+ action: /* @__PURE__ */ B("button", {
801
+ type: "button",
802
+ onClick: () => U(!0),
803
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken",
804
+ children: [/* @__PURE__ */ z(I, { className: "h-3.5 w-3.5" }), " Add entitlement"]
805
+ }),
806
+ children: !K.entitlements || K.entitlements.length === 0 ? /* @__PURE__ */ z(s, {
807
+ illustration: "empty-data",
808
+ title: "No entitlements",
809
+ description: "Entitlements (seats, quotas, feature access) will appear here."
810
+ }) : /* @__PURE__ */ z("div", {
811
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
812
+ children: K.entitlements.map((e) => {
813
+ let t = e.quota != null && e.quota > 0;
814
+ return /* @__PURE__ */ B(V, {
815
+ treatment: "plain",
816
+ className: "p-4",
817
+ children: [
818
+ /* @__PURE__ */ B("div", {
819
+ className: "flex items-start justify-between gap-2",
820
+ children: [/* @__PURE__ */ z("p", {
821
+ className: "min-w-0 truncate text-sm font-medium text-text-primary",
822
+ children: e.name
823
+ }), /* @__PURE__ */ z(o, { status: e.isActive ? "ACTIVE" : "DISABLED" })]
824
+ }),
825
+ /* @__PURE__ */ z("p", {
826
+ className: "mt-1 text-xs text-text-secondary",
827
+ children: i(e.type)
828
+ }),
829
+ t && /* @__PURE__ */ B("div", {
830
+ className: "mt-3",
831
+ children: [/* @__PURE__ */ B("div", {
832
+ className: "flex items-center justify-between text-xs text-text-secondary",
833
+ children: [/* @__PURE__ */ B("span", { children: [
834
+ e.used,
835
+ " / ",
836
+ e.quota,
837
+ e.unit ? ` ${e.unit}` : ""
838
+ ] }), /* @__PURE__ */ B("span", {
839
+ className: "tabular-nums",
840
+ children: [Math.round(e.used / e.quota * 100), "%"]
841
+ })]
842
+ }), /* @__PURE__ */ z(p, {
843
+ value: e.used,
844
+ max: e.quota,
845
+ tone: e.used / e.quota >= .9 ? "negative" : e.used / e.quota >= .7 ? "warning" : "accent",
846
+ className: "mt-1.5"
847
+ })]
848
+ })
849
+ ]
850
+ }, e.id);
851
+ })
852
+ })
853
+ }),
854
+ /* @__PURE__ */ z(d, {
855
+ className: "mt-0",
856
+ title: "Assets",
857
+ description: "Invoices, contracts, licenses and credentials",
858
+ action: /* @__PURE__ */ B("button", {
859
+ type: "button",
860
+ onClick: () => G(!0),
861
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken",
862
+ children: [/* @__PURE__ */ z(I, { className: "h-3.5 w-3.5" }), " Attach asset"]
863
+ }),
864
+ children: !K.assets || K.assets.length === 0 ? /* @__PURE__ */ z(s, {
865
+ illustration: "empty-data",
866
+ title: "No assets attached",
867
+ description: "Attach invoices, contracts, licenses or receipts to this relationship."
868
+ }) : /* @__PURE__ */ z(V, {
869
+ treatment: "plain",
870
+ className: "divide-y divide-border-subtle p-0",
871
+ children: K.assets.map((e) => /* @__PURE__ */ z(se, { asset: e }, e.id))
872
+ })
873
+ }),
874
+ K.notes && /* @__PURE__ */ B(V, {
875
+ treatment: "plain",
876
+ className: "p-4",
877
+ children: [/* @__PURE__ */ z("p", {
878
+ className: "text-xs font-medium text-text-secondary",
879
+ children: "Notes"
880
+ }), /* @__PURE__ */ z("p", {
881
+ className: "mt-1 whitespace-pre-wrap text-sm text-text-primary",
882
+ children: K.notes
883
+ })]
884
+ })
885
+ ]
886
+ }), /* @__PURE__ */ B("div", {
887
+ className: "space-y-4",
888
+ children: [/* @__PURE__ */ B(V, {
166
889
  treatment: "metric",
167
- className: "p-4",
168
- children: [/* @__PURE__ */ T("div", {
169
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
170
- children: [/* @__PURE__ */ w(x, { className: "h-3.5 w-3.5" }), " Discovery"]
171
- }), /* @__PURE__ */ w("p", {
172
- className: "mt-1.5 text-sm text-text-primary",
173
- children: i(R.discoverySource)
890
+ className: "p-5",
891
+ children: [/* @__PURE__ */ B("div", {
892
+ className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
893
+ children: [/* @__PURE__ */ z(E, { className: "h-4 w-4 text-text-secondary" }), " Health score"]
894
+ }), K.healthScore == null ? /* @__PURE__ */ z("p", {
895
+ className: "mt-4 text-sm text-text-secondary",
896
+ children: "Not scored yet. A health score appears once Subscriber Bot has enough signal."
897
+ }) : /* @__PURE__ */ B("div", {
898
+ className: "mt-4 flex flex-col items-center",
899
+ children: [/* @__PURE__ */ z(f, {
900
+ value: K.healthScore,
901
+ max: 100,
902
+ size: 160,
903
+ label: "of 100"
904
+ }), /* @__PURE__ */ z("div", {
905
+ className: "mt-2 w-full",
906
+ children: /* @__PURE__ */ z(p, {
907
+ value: K.healthScore,
908
+ max: 100,
909
+ tone: re(K.healthScore)
910
+ })
911
+ })]
174
912
  })]
175
- }),
176
- /* @__PURE__ */ T(E, {
913
+ }), /* @__PURE__ */ B(V, {
177
914
  treatment: "metric",
178
- className: "p-4",
179
- children: [/* @__PURE__ */ T("div", {
180
- className: "flex items-center gap-2 text-xs font-medium text-text-secondary",
181
- children: [/* @__PURE__ */ w(v, { className: "h-3.5 w-3.5" }), " Started"]
182
- }), /* @__PURE__ */ w("p", {
183
- className: "mt-1.5 text-sm text-text-primary",
184
- children: R.startedAt ? r(R.startedAt) : "—"
185
- })]
186
- })
187
- ]
188
- }),
189
- R.tags.length > 0 && /* @__PURE__ */ T("div", {
190
- className: "mt-5 flex flex-wrap items-center gap-2",
191
- children: [/* @__PURE__ */ w(S, { className: "h-3.5 w-3.5 text-text-secondary" }), R.tags.map((e) => /* @__PURE__ */ w("span", {
192
- className: "rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs text-text-secondary",
193
- children: e
194
- }, e))]
195
- }),
196
- R.notes && /* @__PURE__ */ T("div", {
197
- className: "mt-5 rounded-lg border border-border-subtle bg-bg-surface p-4",
198
- children: [/* @__PURE__ */ w("p", {
199
- className: "text-xs font-medium text-text-secondary",
200
- children: "Notes"
201
- }), /* @__PURE__ */ w("p", {
202
- className: "mt-1 whitespace-pre-wrap text-sm text-text-primary",
203
- children: R.notes
204
- })]
205
- }),
206
- /* @__PURE__ */ w(u, {
207
- title: "Entitlements",
208
- description: "What this relationship grants you",
209
- children: !R.entitlements || R.entitlements.length === 0 ? /* @__PURE__ */ w(s, {
210
- illustration: "empty-data",
211
- title: "No entitlements",
212
- description: "Entitlements (seats, quotas, feature access) will appear here."
213
- }) : /* @__PURE__ */ w("div", {
214
- className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",
215
- children: R.entitlements.map((e) => /* @__PURE__ */ T("div", {
216
- className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
915
+ className: "p-5",
217
916
  children: [
218
- /* @__PURE__ */ T("div", {
219
- className: "flex items-start justify-between gap-2",
220
- children: [/* @__PURE__ */ w("p", {
221
- className: "text-sm font-medium text-text-primary",
222
- children: e.name
223
- }), /* @__PURE__ */ w(o, { status: e.isActive ? "ACTIVE" : "DISABLED" })]
917
+ /* @__PURE__ */ B("div", {
918
+ className: "flex items-center gap-2 text-sm font-semibold text-text-primary",
919
+ children: [/* @__PURE__ */ z(k, { className: "h-4 w-4 text-text-secondary" }), " Renewal timeline"]
224
920
  }),
225
- /* @__PURE__ */ w("p", {
226
- className: "mt-1 text-xs text-text-secondary",
227
- children: i(e.type)
921
+ /* @__PURE__ */ z("p", {
922
+ className: "mt-0.5 text-xs text-text-secondary",
923
+ children: "Detected renewals and price changes"
228
924
  }),
229
- e.quota != null && /* @__PURE__ */ T("p", {
230
- className: "mt-2 text-xs text-text-secondary",
231
- children: [
232
- "Used ",
233
- e.used,
234
- " of ",
235
- e.quota,
236
- e.unit ? ` ${e.unit}` : ""
237
- ]
925
+ Z.length === 0 ? /* @__PURE__ */ z("div", {
926
+ className: "mt-4",
927
+ children: /* @__PURE__ */ z(s, {
928
+ illustration: "empty-calendar",
929
+ title: "No renewal events",
930
+ description: "Renewals and price changes will appear here as they're detected."
931
+ })
932
+ }) : /* @__PURE__ */ z(m, {
933
+ items: Z,
934
+ className: "mt-4"
238
935
  })
239
936
  ]
240
- }, e.id))
241
- })
937
+ })]
938
+ })]
242
939
  }),
243
- /* @__PURE__ */ w(u, {
244
- title: "Assets",
245
- description: "Invoices, contracts, licenses and credentials",
246
- children: !R.assets || R.assets.length === 0 ? /* @__PURE__ */ w(s, {
247
- illustration: "empty-data",
248
- title: "No assets attached",
249
- description: "Attach invoices, contracts, licenses or receipts to this relationship."
250
- }) : /* @__PURE__ */ w("div", {
251
- className: "divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface",
252
- children: R.assets.map((e) => /* @__PURE__ */ T("div", {
253
- className: "flex items-center justify-between gap-3 p-3",
254
- children: [/* @__PURE__ */ T("div", {
255
- className: "flex min-w-0 items-center gap-2",
256
- children: [/* @__PURE__ */ w(b, { className: "h-4 w-4 shrink-0 text-text-secondary" }), /* @__PURE__ */ T("div", {
257
- className: "min-w-0",
258
- children: [/* @__PURE__ */ w("p", {
259
- className: "truncate text-sm font-medium text-text-primary",
260
- children: e.name
261
- }), /* @__PURE__ */ w("p", {
262
- className: "text-xs text-text-secondary",
263
- children: i(e.type)
264
- })]
265
- })]
266
- }), e.expiresAt && /* @__PURE__ */ T("span", {
267
- className: "shrink-0 text-xs text-text-secondary",
268
- children: ["Expires ", r(e.expiresAt)]
269
- })]
270
- }, e.id))
271
- })
940
+ N && /* @__PURE__ */ z(ie, {
941
+ relationship: K,
942
+ onClose: () => F(!1)
272
943
  }),
273
- /* @__PURE__ */ w(u, {
274
- title: "Renewal timeline",
275
- description: "Detected renewals and price changes",
276
- children: !R.renewalEvents || R.renewalEvents.length === 0 ? /* @__PURE__ */ w(s, {
277
- illustration: "empty-calendar",
278
- title: "No renewal events",
279
- description: "Renewals and price changes detected for this relationship will appear here."
280
- }) : /* @__PURE__ */ w("div", {
281
- className: "divide-y divide-border-subtle rounded-lg border border-border-subtle bg-bg-surface",
282
- children: R.renewalEvents.map((e) => /* @__PURE__ */ T("div", {
283
- className: "flex items-center justify-between gap-3 p-3",
284
- children: [/* @__PURE__ */ T("div", {
285
- className: "min-w-0",
286
- children: [/* @__PURE__ */ w("p", {
287
- className: "truncate text-sm font-medium text-text-primary",
288
- children: i(e.eventType)
289
- }), /* @__PURE__ */ T("p", {
290
- className: "text-xs text-text-secondary",
291
- children: [r(e.occursAt), e.detail ? ` · ${e.detail}` : ""]
292
- })]
293
- }), e.amount != null && /* @__PURE__ */ w("span", {
294
- className: "shrink-0 text-sm font-semibold tabular-nums text-text-primary",
295
- children: n(e.amount, e.currency ?? R.currency)
296
- })]
297
- }, e.id))
298
- })
944
+ H && /* @__PURE__ */ z(ae, {
945
+ relationshipId: K.id,
946
+ onClose: () => U(!1)
947
+ }),
948
+ W && /* @__PURE__ */ z(oe, {
949
+ relationshipId: K.id,
950
+ onClose: () => G(!1)
299
951
  })
300
952
  ]
301
953
  });
302
954
  }
303
955
  //#endregion
304
- export { O as RelationshipDetailPage };
956
+ export { X as RelationshipDetailPage };
305
957
 
306
958
  //# sourceMappingURL=RelationshipDetailPage.js.map