@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,11 +3,11 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { ErrorView as n } from "../../components/StateViews.js";
4
4
  import { useCreateRelationship as r, usePlans as i, useProviders as a } from "../../hooks/useSubscriberBotApi.js";
5
5
  import { useState as o } from "react";
6
- import { ArrowLeft as s } from "lucide-react";
7
- import { jsx as c, jsxs as l } from "react/jsx-runtime";
8
- import { PagePurpose as u } from "@burdenoff/fe-libs/ui";
6
+ import { ArrowLeft as s, Building2 as c, StickyNote as l, Tag as u, Wallet as d } from "lucide-react";
7
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
8
+ import { GlassCard as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
9
9
  //#region src/subscriberbot/pages/relationships/RelationshipNewPage.tsx
10
- var d = [
10
+ var g = [
11
11
  "SUBSCRIPTION",
12
12
  "MEMBERSHIP",
13
13
  "LICENSE",
@@ -16,7 +16,7 @@ var d = [
16
16
  "RECURRING_PAYMENT",
17
17
  "ENROLLMENT",
18
18
  "TRIAL"
19
- ], f = [
19
+ ], _ = [
20
20
  "MONTHLY",
21
21
  "YEARLY",
22
22
  "QUARTERLY",
@@ -25,220 +25,270 @@ var d = [
25
25
  "USAGE_BASED",
26
26
  "LIFETIME",
27
27
  "FREE"
28
- ], p = "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)]", m = "mb-1 block text-xs font-medium text-text-secondary";
29
- function h() {
30
- let { navigateTo: h } = e(), g = r(), _ = a({ pagination: {
28
+ ], v = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", y = "mb-1.5 block text-xs font-medium text-text-secondary";
29
+ function b({ icon: e, title: t, description: n, children: r }) {
30
+ return /* @__PURE__ */ p(m, {
31
+ treatment: "metric",
32
+ className: "p-5 sm:p-6",
33
+ children: [/* @__PURE__ */ p("div", {
34
+ className: "flex items-start gap-3",
35
+ children: [/* @__PURE__ */ f("span", {
36
+ className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary",
37
+ children: e
38
+ }), /* @__PURE__ */ p("div", {
39
+ className: "min-w-0",
40
+ children: [/* @__PURE__ */ f("h2", {
41
+ className: "text-sm font-semibold text-text-primary",
42
+ children: t
43
+ }), /* @__PURE__ */ f("p", {
44
+ className: "mt-0.5 text-xs text-text-secondary",
45
+ children: n
46
+ })]
47
+ })]
48
+ }), /* @__PURE__ */ f("div", {
49
+ className: "mt-4",
50
+ children: r
51
+ })]
52
+ });
53
+ }
54
+ function x() {
55
+ let { navigateTo: m } = e(), x = r(), S = a({ pagination: {
31
56
  limit: 100,
32
57
  offset: 0
33
- } }), [v, y] = o(""), [b, x] = o("SUBSCRIPTION"), [S, C] = o(""), [w, T] = o(""), [E, D] = o(""), [O, k] = o("USD"), [A, j] = o("MONTHLY"), [M, N] = o(""), [P, F] = o(!0), [I, L] = o(""), [R, z] = o(null), B = i(S || void 0), V = _.data?.items ?? [], H = B.data ?? [];
34
- return _.isError ? /* @__PURE__ */ c(t, {
58
+ } }), [C, w] = o(""), [T, E] = o("SUBSCRIPTION"), [D, O] = o(""), [k, A] = o(""), [j, M] = o(""), [N, P] = o("USD"), [F, I] = o("MONTHLY"), [L, R] = o(""), [z, B] = o(!0), [V, H] = o(""), [U, W] = o(null), G = i(D || void 0), K = S.data?.items ?? [], q = G.data ?? [];
59
+ return S.isError ? /* @__PURE__ */ f(t, {
35
60
  title: "Add relationship",
36
- children: /* @__PURE__ */ c(n, {
61
+ children: /* @__PURE__ */ f(n, {
37
62
  message: "Could not load the provider registry.",
38
- onRetry: () => void _.refetch()
63
+ onRetry: () => void S.refetch()
39
64
  })
40
- }) : /* @__PURE__ */ l(t, {
65
+ }) : /* @__PURE__ */ p(t, {
41
66
  title: "Add relationship",
42
67
  description: "Track a new recurring digital relationship",
43
- actions: /* @__PURE__ */ l("button", {
68
+ actions: /* @__PURE__ */ p("button", {
44
69
  type: "button",
45
- onClick: () => h("/relationships"),
70
+ onClick: () => m("/relationships"),
46
71
  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",
47
- children: [/* @__PURE__ */ c(s, { className: "h-4 w-4" }), " Back"]
72
+ children: [/* @__PURE__ */ f(s, { className: "h-4 w-4" }), " Back"]
48
73
  }),
49
- children: [/* @__PURE__ */ c(u, {
74
+ children: [/* @__PURE__ */ f(h, {
50
75
  className: "mb-6",
51
76
  children: "Manually add a subscription, membership, license or contract. Link it to a provider and plan from the registry, set the price and renewal date, and Subscriber Bot will track its lifecycle from here."
52
- }), /* @__PURE__ */ l("form", {
77
+ }), /* @__PURE__ */ p("form", {
53
78
  onSubmit: (e) => {
54
- if (e.preventDefault(), z(null), !v.trim()) {
55
- z("A label is required.");
79
+ if (e.preventDefault(), W(null), !C.trim()) {
80
+ W("A label is required.");
56
81
  return;
57
82
  }
58
83
  let t = {
59
- label: v.trim(),
60
- kind: b,
61
- interval: A,
62
- autoRenew: P,
63
- currency: O.trim() || "USD",
64
- ...S ? { providerId: S } : {},
65
- ...w ? { planId: w } : {},
66
- ...E ? { amount: Number(E) } : {},
67
- ...M ? { renewsAt: new Date(M).toISOString() } : {},
68
- ...I.trim() ? { notes: I.trim() } : {}
84
+ label: C.trim(),
85
+ kind: T,
86
+ interval: F,
87
+ autoRenew: z,
88
+ currency: N.trim() || "USD",
89
+ ...D ? { providerId: D } : {},
90
+ ...k ? { planId: k } : {},
91
+ ...j ? { amount: Number(j) } : {},
92
+ ...L ? { renewsAt: new Date(L).toISOString() } : {},
93
+ ...V.trim() ? { notes: V.trim() } : {}
69
94
  };
70
- g.mutate(t, {
71
- onSuccess: (e) => h(`/relationships/${e.id}`),
72
- onError: (e) => z(e instanceof Error ? e.message : "Could not create relationship.")
95
+ x.mutate(t, {
96
+ onSuccess: (e) => m(`/relationships/${e.id}`),
97
+ onError: (e) => W(e instanceof Error ? e.message : "Could not create relationship.")
73
98
  });
74
99
  },
75
- className: "max-w-2xl space-y-5",
100
+ className: "max-w-3xl space-y-5",
76
101
  children: [
77
- R && /* @__PURE__ */ c("div", {
102
+ U && /* @__PURE__ */ f("div", {
78
103
  className: "rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
79
- children: R
80
- }),
81
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ l("label", {
82
- htmlFor: "rel-label",
83
- className: m,
84
- children: ["Label ", /* @__PURE__ */ c("span", {
85
- className: "text-status-error-text",
86
- children: "*"
87
- })]
88
- }), /* @__PURE__ */ c("input", {
89
- id: "rel-label",
90
- type: "text",
91
- value: v,
92
- onChange: (e) => y(e.target.value),
93
- placeholder: "e.g. Netflix Premium, AWS Production",
94
- className: p,
95
- required: !0
96
- })] }),
97
- /* @__PURE__ */ l("div", {
98
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
99
- children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
100
- htmlFor: "rel-kind",
101
- className: m,
102
- children: "Kind"
103
- }), /* @__PURE__ */ c("select", {
104
- id: "rel-kind",
105
- value: b,
106
- onChange: (e) => x(e.target.value),
107
- className: p,
108
- children: d.map((e) => /* @__PURE__ */ c("option", {
109
- value: e,
110
- children: e.replace(/_/g, " ")
111
- }, e))
112
- })] }), /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
113
- htmlFor: "rel-provider",
114
- className: m,
115
- children: "Provider"
116
- }), /* @__PURE__ */ l("select", {
117
- id: "rel-provider",
118
- value: S,
119
- onChange: (e) => {
120
- C(e.target.value), T("");
121
- },
122
- className: p,
123
- children: [/* @__PURE__ */ c("option", {
124
- value: "",
125
- children: "— None —"
126
- }), V.map((e) => /* @__PURE__ */ c("option", {
127
- value: e.id,
128
- children: e.name
129
- }, e.id))]
130
- })] })]
104
+ children: U
131
105
  }),
132
- S && H.length > 0 && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
133
- htmlFor: "rel-plan",
134
- className: m,
135
- children: "Plan"
136
- }), /* @__PURE__ */ l("select", {
137
- id: "rel-plan",
138
- value: w,
139
- onChange: (e) => T(e.target.value),
140
- className: p,
141
- children: [/* @__PURE__ */ c("option", {
142
- value: "",
143
- children: "— None —"
144
- }), H.map((e) => /* @__PURE__ */ c("option", {
145
- value: e.id,
146
- children: e.name
147
- }, e.id))]
148
- })] }),
149
- /* @__PURE__ */ l("div", {
150
- className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
151
- children: [
152
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
153
- htmlFor: "rel-amount",
154
- className: m,
155
- children: "Amount"
156
- }), /* @__PURE__ */ c("input", {
157
- id: "rel-amount",
158
- type: "number",
159
- min: "0",
160
- step: "0.01",
161
- value: E,
162
- onChange: (e) => D(e.target.value),
163
- placeholder: "0.00",
164
- className: p
165
- })] }),
166
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
167
- htmlFor: "rel-currency",
168
- className: m,
169
- children: "Currency"
170
- }), /* @__PURE__ */ c("input", {
171
- id: "rel-currency",
106
+ /* @__PURE__ */ f(b, {
107
+ icon: /* @__PURE__ */ f(u, { className: "h-4 w-4" }),
108
+ title: "Basics",
109
+ description: "Name this relationship and choose what kind it is.",
110
+ children: /* @__PURE__ */ p("div", {
111
+ className: "space-y-4",
112
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p("label", {
113
+ htmlFor: "rel-label",
114
+ className: y,
115
+ children: ["Label ", /* @__PURE__ */ f("span", {
116
+ className: "text-status-error-text",
117
+ children: "*"
118
+ })]
119
+ }), /* @__PURE__ */ f("input", {
120
+ id: "rel-label",
172
121
  type: "text",
173
- value: O,
174
- onChange: (e) => k(e.target.value.toUpperCase()),
175
- placeholder: "USD",
176
- maxLength: 3,
177
- className: p
178
- })] }),
179
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
180
- htmlFor: "rel-interval",
181
- className: m,
182
- children: "Billing interval"
183
- }), /* @__PURE__ */ c("select", {
184
- id: "rel-interval",
185
- value: A,
186
- onChange: (e) => j(e.target.value),
187
- className: p,
188
- children: f.map((e) => /* @__PURE__ */ c("option", {
189
- value: e,
190
- children: e.replace(/_/g, " ")
191
- }, e))
192
- })] })
193
- ]
122
+ value: C,
123
+ onChange: (e) => w(e.target.value),
124
+ placeholder: "e.g. Netflix Premium, AWS Production",
125
+ className: v,
126
+ required: !0
127
+ })] }), /* @__PURE__ */ p("div", {
128
+ className: "max-w-xs",
129
+ children: [/* @__PURE__ */ f("label", {
130
+ htmlFor: "rel-kind",
131
+ className: y,
132
+ children: "Kind"
133
+ }), /* @__PURE__ */ f("select", {
134
+ id: "rel-kind",
135
+ value: T,
136
+ onChange: (e) => E(e.target.value),
137
+ className: v,
138
+ children: g.map((e) => /* @__PURE__ */ f("option", {
139
+ value: e,
140
+ children: e.replace(/_/g, " ")
141
+ }, e))
142
+ })]
143
+ })]
144
+ })
194
145
  }),
195
- /* @__PURE__ */ l("div", {
196
- className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
197
- children: [/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
198
- htmlFor: "rel-renews",
199
- className: m,
200
- children: "Renews on"
201
- }), /* @__PURE__ */ c("input", {
202
- id: "rel-renews",
203
- type: "date",
204
- value: M,
205
- onChange: (e) => N(e.target.value),
206
- className: p
207
- })] }), /* @__PURE__ */ c("div", {
208
- className: "flex items-end",
209
- children: /* @__PURE__ */ l("label", {
210
- className: "flex items-center gap-2 text-sm text-text-primary",
211
- children: [/* @__PURE__ */ c("input", {
212
- type: "checkbox",
213
- checked: P,
214
- onChange: (e) => F(e.target.checked),
215
- className: "size-4 rounded border-border-subtle"
216
- }), "Auto-renews"]
217
- })
218
- })]
146
+ /* @__PURE__ */ f(b, {
147
+ icon: /* @__PURE__ */ f(c, { className: "h-4 w-4" }),
148
+ title: "Provider & plan",
149
+ description: "Link this relationship to a provider and plan from the registry (optional).",
150
+ children: /* @__PURE__ */ p("div", {
151
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
152
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
153
+ htmlFor: "rel-provider",
154
+ className: y,
155
+ children: "Provider"
156
+ }), /* @__PURE__ */ p("select", {
157
+ id: "rel-provider",
158
+ value: D,
159
+ onChange: (e) => {
160
+ O(e.target.value), A("");
161
+ },
162
+ className: v,
163
+ children: [/* @__PURE__ */ f("option", {
164
+ value: "",
165
+ children: "— None —"
166
+ }), K.map((e) => /* @__PURE__ */ f("option", {
167
+ value: e.id,
168
+ children: e.name
169
+ }, e.id))]
170
+ })] }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
171
+ htmlFor: "rel-plan",
172
+ className: y,
173
+ children: "Plan"
174
+ }), /* @__PURE__ */ p("select", {
175
+ id: "rel-plan",
176
+ value: k,
177
+ onChange: (e) => A(e.target.value),
178
+ className: v,
179
+ disabled: !D || q.length === 0,
180
+ children: [/* @__PURE__ */ f("option", {
181
+ value: "",
182
+ children: D ? q.length === 0 ? "No plans available" : "— None —" : "Select a provider first"
183
+ }), q.map((e) => /* @__PURE__ */ f("option", {
184
+ value: e.id,
185
+ children: e.name
186
+ }, e.id))]
187
+ })] })]
188
+ })
189
+ }),
190
+ /* @__PURE__ */ f(b, {
191
+ icon: /* @__PURE__ */ f(d, { className: "h-4 w-4" }),
192
+ title: "Pricing & billing",
193
+ description: "Set the price, cadence and next renewal so Subscriber Bot can track it.",
194
+ children: /* @__PURE__ */ p("div", {
195
+ className: "space-y-4",
196
+ children: [/* @__PURE__ */ p("div", {
197
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
198
+ children: [
199
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
200
+ htmlFor: "rel-amount",
201
+ className: y,
202
+ children: "Amount"
203
+ }), /* @__PURE__ */ f("input", {
204
+ id: "rel-amount",
205
+ type: "number",
206
+ min: "0",
207
+ step: "0.01",
208
+ value: j,
209
+ onChange: (e) => M(e.target.value),
210
+ placeholder: "0.00",
211
+ className: v
212
+ })] }),
213
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
214
+ htmlFor: "rel-currency",
215
+ className: y,
216
+ children: "Currency"
217
+ }), /* @__PURE__ */ f("input", {
218
+ id: "rel-currency",
219
+ type: "text",
220
+ value: N,
221
+ onChange: (e) => P(e.target.value.toUpperCase()),
222
+ placeholder: "USD",
223
+ maxLength: 3,
224
+ className: v
225
+ })] }),
226
+ /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
227
+ htmlFor: "rel-interval",
228
+ className: y,
229
+ children: "Billing interval"
230
+ }), /* @__PURE__ */ f("select", {
231
+ id: "rel-interval",
232
+ value: F,
233
+ onChange: (e) => I(e.target.value),
234
+ className: v,
235
+ children: _.map((e) => /* @__PURE__ */ f("option", {
236
+ value: e,
237
+ children: e.replace(/_/g, " ")
238
+ }, e))
239
+ })] })
240
+ ]
241
+ }), /* @__PURE__ */ p("div", {
242
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
243
+ children: [/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
244
+ htmlFor: "rel-renews",
245
+ className: y,
246
+ children: "Renews on"
247
+ }), /* @__PURE__ */ f("input", {
248
+ id: "rel-renews",
249
+ type: "date",
250
+ value: L,
251
+ onChange: (e) => R(e.target.value),
252
+ className: v
253
+ })] }), /* @__PURE__ */ p("label", {
254
+ className: "flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 sm:mt-6",
255
+ children: [/* @__PURE__ */ f("input", {
256
+ type: "checkbox",
257
+ checked: z,
258
+ onChange: (e) => B(e.target.checked),
259
+ className: "size-4 rounded border-border-subtle"
260
+ }), /* @__PURE__ */ f("span", {
261
+ className: "text-sm text-text-primary",
262
+ children: "Auto-renews"
263
+ })]
264
+ })]
265
+ })]
266
+ })
267
+ }),
268
+ /* @__PURE__ */ f(b, {
269
+ icon: /* @__PURE__ */ f(l, { className: "h-4 w-4" }),
270
+ title: "Notes",
271
+ description: "Anything worth remembering about this relationship.",
272
+ children: /* @__PURE__ */ f("textarea", {
273
+ id: "rel-notes",
274
+ "aria-label": "Notes",
275
+ value: V,
276
+ onChange: (e) => H(e.target.value),
277
+ rows: 3,
278
+ placeholder: "Anything worth remembering about this relationship…",
279
+ className: v
280
+ })
219
281
  }),
220
- /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
221
- htmlFor: "rel-notes",
222
- className: m,
223
- children: "Notes"
224
- }), /* @__PURE__ */ c("textarea", {
225
- id: "rel-notes",
226
- value: I,
227
- onChange: (e) => L(e.target.value),
228
- rows: 3,
229
- placeholder: "Anything worth remembering about this relationship…",
230
- className: p
231
- })] }),
232
- /* @__PURE__ */ l("div", {
233
- className: "flex gap-3",
234
- children: [/* @__PURE__ */ c("button", {
282
+ /* @__PURE__ */ p("div", {
283
+ className: "flex flex-col gap-3 sm:flex-row",
284
+ children: [/* @__PURE__ */ f("button", {
235
285
  type: "submit",
236
- disabled: g.isPending,
286
+ disabled: x.isPending,
237
287
  className: "rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50",
238
- children: g.isPending ? "Creating…" : "Create relationship"
239
- }), /* @__PURE__ */ c("button", {
288
+ children: x.isPending ? "Creating…" : "Create relationship"
289
+ }), /* @__PURE__ */ f("button", {
240
290
  type: "button",
241
- onClick: () => h("/relationships"),
291
+ onClick: () => m("/relationships"),
242
292
  className: "rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken",
243
293
  children: "Cancel"
244
294
  })]
@@ -248,6 +298,6 @@ function h() {
248
298
  });
249
299
  }
250
300
  //#endregion
251
- export { h as RelationshipNewPage };
301
+ export { x as RelationshipNewPage };
252
302
 
253
303
  //# sourceMappingURL=RelationshipNewPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RelationshipNewPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/relationships/RelationshipNewPage.tsx"],"sourcesContent":["/**\n * Create relationship\n * @module subscriberbot/pages/relationships\n *\n * Manual-add form for a recurring relationship AI can't auto-detect.\n * Writes `subCreateRelationship`. Provider + plan are optional pickers\n * sourced from the real registry (`subListProviders` / `subListPlans`).\n */\n\nimport { useState } from 'react';\nimport { ArrowLeft } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { ErrorView } from '../../components/StateViews';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useCreateRelationship, useProviders, usePlans } from '../../hooks/useSubscriberBotApi';\nimport type {\n SubBillingInterval,\n SubCreateRelationshipInput,\n SubRelationshipKind,\n} from '../../types';\n\nconst KINDS: SubRelationshipKind[] = [\n 'SUBSCRIPTION',\n 'MEMBERSHIP',\n 'LICENSE',\n 'CONTRACT',\n 'NEWSLETTER',\n 'RECURRING_PAYMENT',\n 'ENROLLMENT',\n 'TRIAL',\n];\n\nconst INTERVALS: SubBillingInterval[] = [\n 'MONTHLY',\n 'YEARLY',\n 'QUARTERLY',\n 'WEEKLY',\n 'DAILY',\n 'USAGE_BASED',\n 'LIFETIME',\n 'FREE',\n];\n\nconst inputCls =\n '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)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\nexport function RelationshipNewPage() {\n const { navigateTo } = useSubscriberBot();\n const create = useCreateRelationship();\n const providersQ = useProviders({ pagination: { limit: 100, offset: 0 } });\n\n const [label, setLabel] = useState('');\n const [kind, setKind] = useState<SubRelationshipKind>('SUBSCRIPTION');\n const [providerId, setProviderId] = useState('');\n const [planId, setPlanId] = useState('');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [interval, setInterval] = useState<SubBillingInterval>('MONTHLY');\n const [renewsAt, setRenewsAt] = useState('');\n const [autoRenew, setAutoRenew] = useState(true);\n const [notes, setNotes] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const plansQ = usePlans(providerId || undefined);\n const providers = providersQ.data?.items ?? [];\n const plans = plansQ.data ?? [];\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!label.trim()) {\n setFormError('A label is required.');\n return;\n }\n const input: SubCreateRelationshipInput = {\n label: label.trim(),\n kind,\n interval,\n autoRenew,\n currency: currency.trim() || 'USD',\n ...(providerId ? { providerId } : {}),\n ...(planId ? { planId } : {}),\n ...(amount ? { amount: Number(amount) } : {}),\n ...(renewsAt ? { renewsAt: new Date(renewsAt).toISOString() } : {}),\n ...(notes.trim() ? { notes: notes.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: (rel) => navigateTo(`/relationships/${rel.id}`),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not create relationship.'),\n });\n };\n\n if (providersQ.isError) {\n return (\n <PageLayout title=\"Add relationship\">\n <ErrorView\n message=\"Could not load the provider registry.\"\n onRetry={() => void providersQ.refetch()}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Add relationship\"\n description=\"Track a new recurring digital relationship\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Manually add a subscription, membership, license or contract. Link it to a provider and plan\n from the registry, set the price and renewal date, and Subscriber Bot will track its\n lifecycle from here.\n </PagePurpose>\n\n <form onSubmit={handleSubmit} className=\"max-w-2xl space-y-5\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n\n <div>\n <label htmlFor=\"rel-label\" className={labelCls}>\n Label <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"rel-label\"\n type=\"text\"\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n placeholder=\"e.g. Netflix Premium, AWS Production\"\n className={inputCls}\n required\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"rel-kind\" className={labelCls}>\n Kind\n </label>\n <select\n id=\"rel-kind\"\n value={kind}\n onChange={(e) => setKind(e.target.value as SubRelationshipKind)}\n className={inputCls}\n >\n {KINDS.map((k) => (\n <option key={k} value={k}>\n {k.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"rel-provider\" className={labelCls}>\n Provider\n </label>\n <select\n id=\"rel-provider\"\n value={providerId}\n onChange={(e) => {\n setProviderId(e.target.value);\n setPlanId('');\n }}\n className={inputCls}\n >\n <option value=\"\">— None —</option>\n {providers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n {providerId && plans.length > 0 && (\n <div>\n <label htmlFor=\"rel-plan\" className={labelCls}>\n Plan\n </label>\n <select\n id=\"rel-plan\"\n value={planId}\n onChange={(e) => setPlanId(e.target.value)}\n className={inputCls}\n >\n <option value=\"\">— None —</option>\n {plans.map((pl) => (\n <option key={pl.id} value={pl.id}>\n {pl.name}\n </option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <div>\n <label htmlFor=\"rel-amount\" className={labelCls}>\n Amount\n </label>\n <input\n id=\"rel-amount\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n placeholder=\"0.00\"\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"rel-currency\" className={labelCls}>\n Currency\n </label>\n <input\n id=\"rel-currency\"\n type=\"text\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n placeholder=\"USD\"\n maxLength={3}\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"rel-interval\" className={labelCls}>\n Billing interval\n </label>\n <select\n id=\"rel-interval\"\n value={interval}\n onChange={(e) => setInterval(e.target.value as SubBillingInterval)}\n className={inputCls}\n >\n {INTERVALS.map((i) => (\n <option key={i} value={i}>\n {i.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"rel-renews\" className={labelCls}>\n Renews on\n </label>\n <input\n id=\"rel-renews\"\n type=\"date\"\n value={renewsAt}\n onChange={(e) => setRenewsAt(e.target.value)}\n className={inputCls}\n />\n </div>\n <div className=\"flex items-end\">\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={autoRenew}\n onChange={(e) => setAutoRenew(e.target.checked)}\n className=\"size-4 rounded border-border-subtle\"\n />\n Auto-renews\n </label>\n </div>\n </div>\n\n <div>\n <label htmlFor=\"rel-notes\" className={labelCls}>\n Notes\n </label>\n <textarea\n id=\"rel-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder=\"Anything worth remembering about this relationship…\"\n className={inputCls}\n />\n </div>\n\n <div className=\"flex gap-3\">\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create relationship'}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n className=\"rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n </div>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RelationshipNewPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/relationships/RelationshipNewPage.tsx"],"sourcesContent":["/**\n * Create relationship\n * @module subscriberbot/pages/relationships\n *\n * Manual-add form for a recurring relationship AI can't auto-detect.\n * Writes `subCreateRelationship`. Provider + plan are optional pickers\n * sourced from the real registry (`subListProviders` / `subListPlans`).\n */\n\nimport { useState, type ReactNode } from 'react';\nimport { ArrowLeft, Tag, Building2, Wallet, StickyNote } from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { ErrorView } from '../../components/StateViews';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useCreateRelationship, useProviders, usePlans } from '../../hooks/useSubscriberBotApi';\nimport type {\n SubBillingInterval,\n SubCreateRelationshipInput,\n SubRelationshipKind,\n} from '../../types';\n\nconst KINDS: SubRelationshipKind[] = [\n 'SUBSCRIPTION',\n 'MEMBERSHIP',\n 'LICENSE',\n 'CONTRACT',\n 'NEWSLETTER',\n 'RECURRING_PAYMENT',\n 'ENROLLMENT',\n 'TRIAL',\n];\n\nconst INTERVALS: SubBillingInterval[] = [\n 'MONTHLY',\n 'YEARLY',\n 'QUARTERLY',\n 'WEEKLY',\n 'DAILY',\n 'USAGE_BASED',\n 'LIFETIME',\n 'FREE',\n];\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\n/** Grouped form section on a glass surface. */\nfunction FormSection({\n icon,\n title,\n description,\n children,\n}: {\n icon: ReactNode;\n title: string;\n description: string;\n children: ReactNode;\n}) {\n return (\n <GlassCard treatment=\"metric\" className=\"p-5 sm:p-6\">\n <div className=\"flex items-start gap-3\">\n <span className=\"mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n {icon}\n </span>\n <div className=\"min-w-0\">\n <h2 className=\"text-sm font-semibold text-text-primary\">{title}</h2>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{description}</p>\n </div>\n </div>\n <div className=\"mt-4\">{children}</div>\n </GlassCard>\n );\n}\n\nexport function RelationshipNewPage() {\n const { navigateTo } = useSubscriberBot();\n const create = useCreateRelationship();\n const providersQ = useProviders({ pagination: { limit: 100, offset: 0 } });\n\n const [label, setLabel] = useState('');\n const [kind, setKind] = useState<SubRelationshipKind>('SUBSCRIPTION');\n const [providerId, setProviderId] = useState('');\n const [planId, setPlanId] = useState('');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [interval, setInterval] = useState<SubBillingInterval>('MONTHLY');\n const [renewsAt, setRenewsAt] = useState('');\n const [autoRenew, setAutoRenew] = useState(true);\n const [notes, setNotes] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n\n const plansQ = usePlans(providerId || undefined);\n const providers = providersQ.data?.items ?? [];\n const plans = plansQ.data ?? [];\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!label.trim()) {\n setFormError('A label is required.');\n return;\n }\n const input: SubCreateRelationshipInput = {\n label: label.trim(),\n kind,\n interval,\n autoRenew,\n currency: currency.trim() || 'USD',\n ...(providerId ? { providerId } : {}),\n ...(planId ? { planId } : {}),\n ...(amount ? { amount: Number(amount) } : {}),\n ...(renewsAt ? { renewsAt: new Date(renewsAt).toISOString() } : {}),\n ...(notes.trim() ? { notes: notes.trim() } : {}),\n };\n create.mutate(input, {\n onSuccess: (rel) => navigateTo(`/relationships/${rel.id}`),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not create relationship.'),\n });\n };\n\n if (providersQ.isError) {\n return (\n <PageLayout title=\"Add relationship\">\n <ErrorView\n message=\"Could not load the provider registry.\"\n onRetry={() => void providersQ.refetch()}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Add relationship\"\n description=\"Track a new recurring digital relationship\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Manually add a subscription, membership, license or contract. Link it to a provider and plan\n from the registry, set the price and renewal date, and Subscriber Bot will track its\n lifecycle from here.\n </PagePurpose>\n\n <form onSubmit={handleSubmit} className=\"max-w-3xl space-y-5\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n\n {/* Basics */}\n <FormSection\n icon={<Tag className=\"h-4 w-4\" />}\n title=\"Basics\"\n description=\"Name this relationship and choose what kind it is.\"\n >\n <div className=\"space-y-4\">\n <div>\n <label htmlFor=\"rel-label\" className={labelCls}>\n Label <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"rel-label\"\n type=\"text\"\n value={label}\n onChange={(e) => setLabel(e.target.value)}\n placeholder=\"e.g. Netflix Premium, AWS Production\"\n className={inputCls}\n required\n />\n </div>\n <div className=\"max-w-xs\">\n <label htmlFor=\"rel-kind\" className={labelCls}>\n Kind\n </label>\n <select\n id=\"rel-kind\"\n value={kind}\n onChange={(e) => setKind(e.target.value as SubRelationshipKind)}\n className={inputCls}\n >\n {KINDS.map((k) => (\n <option key={k} value={k}>\n {k.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n </FormSection>\n\n {/* Provider & plan */}\n <FormSection\n icon={<Building2 className=\"h-4 w-4\" />}\n title=\"Provider & plan\"\n description=\"Link this relationship to a provider and plan from the registry (optional).\"\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"rel-provider\" className={labelCls}>\n Provider\n </label>\n <select\n id=\"rel-provider\"\n value={providerId}\n onChange={(e) => {\n setProviderId(e.target.value);\n setPlanId('');\n }}\n className={inputCls}\n >\n <option value=\"\">— None —</option>\n {providers.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"rel-plan\" className={labelCls}>\n Plan\n </label>\n <select\n id=\"rel-plan\"\n value={planId}\n onChange={(e) => setPlanId(e.target.value)}\n className={inputCls}\n disabled={!providerId || plans.length === 0}\n >\n <option value=\"\">\n {providerId ? (plans.length === 0 ? 'No plans available' : '— None —') : 'Select a provider first'}\n </option>\n {plans.map((pl) => (\n <option key={pl.id} value={pl.id}>\n {pl.name}\n </option>\n ))}\n </select>\n </div>\n </div>\n </FormSection>\n\n {/* Pricing & billing */}\n <FormSection\n icon={<Wallet className=\"h-4 w-4\" />}\n title=\"Pricing & billing\"\n description=\"Set the price, cadence and next renewal so Subscriber Bot can track it.\"\n >\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <div>\n <label htmlFor=\"rel-amount\" className={labelCls}>\n Amount\n </label>\n <input\n id=\"rel-amount\"\n type=\"number\"\n min=\"0\"\n step=\"0.01\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n placeholder=\"0.00\"\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"rel-currency\" className={labelCls}>\n Currency\n </label>\n <input\n id=\"rel-currency\"\n type=\"text\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n placeholder=\"USD\"\n maxLength={3}\n className={inputCls}\n />\n </div>\n <div>\n <label htmlFor=\"rel-interval\" className={labelCls}>\n Billing interval\n </label>\n <select\n id=\"rel-interval\"\n value={interval}\n onChange={(e) => setInterval(e.target.value as SubBillingInterval)}\n className={inputCls}\n >\n {INTERVALS.map((i) => (\n <option key={i} value={i}>\n {i.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"rel-renews\" className={labelCls}>\n Renews on\n </label>\n <input\n id=\"rel-renews\"\n type=\"date\"\n value={renewsAt}\n onChange={(e) => setRenewsAt(e.target.value)}\n className={inputCls}\n />\n </div>\n <label className=\"flex items-center gap-3 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 sm:mt-6\">\n <input\n type=\"checkbox\"\n checked={autoRenew}\n onChange={(e) => setAutoRenew(e.target.checked)}\n className=\"size-4 rounded border-border-subtle\"\n />\n <span className=\"text-sm text-text-primary\">Auto-renews</span>\n </label>\n </div>\n </div>\n </FormSection>\n\n {/* Notes */}\n <FormSection\n icon={<StickyNote className=\"h-4 w-4\" />}\n title=\"Notes\"\n description=\"Anything worth remembering about this relationship.\"\n >\n <textarea\n id=\"rel-notes\"\n aria-label=\"Notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder=\"Anything worth remembering about this relationship…\"\n className={inputCls}\n />\n </FormSection>\n\n <div className=\"flex flex-col gap-3 sm:flex-row\">\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Creating…' : 'Create relationship'}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships')}\n className=\"rounded-lg border border-border-subtle px-5 py-2.5 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n </div>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}