@burdenoff/microfe-subscriberbot 2026.827.1 → 2026.829.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 (56) hide show
  1. package/dist/subscriberbot/admin/AdminDashboardPage.d.ts.map +1 -1
  2. package/dist/subscriberbot/admin/AdminDashboardPage.js +80 -83
  3. package/dist/subscriberbot/admin/AdminDashboardPage.js.map +1 -1
  4. package/dist/subscriberbot/hooks/index.d.ts +1 -0
  5. package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
  6. package/dist/subscriberbot/hooks/index.js +1 -0
  7. package/dist/subscriberbot/hooks/useTr.d.ts +17 -0
  8. package/dist/subscriberbot/hooks/useTr.d.ts.map +1 -0
  9. package/dist/subscriberbot/hooks/useTr.js +14 -0
  10. package/dist/subscriberbot/hooks/useTr.js.map +1 -0
  11. package/dist/subscriberbot/pages/AssetVaultPage.d.ts.map +1 -1
  12. package/dist/subscriberbot/pages/AssetVaultPage.js +111 -109
  13. package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -1
  14. package/dist/subscriberbot/pages/DashboardPage.d.ts.map +1 -1
  15. package/dist/subscriberbot/pages/DashboardPage.js +113 -105
  16. package/dist/subscriberbot/pages/DashboardPage.js.map +1 -1
  17. package/dist/subscriberbot/pages/InboxPage.d.ts.map +1 -1
  18. package/dist/subscriberbot/pages/InboxPage.js +404 -369
  19. package/dist/subscriberbot/pages/InboxPage.js.map +1 -1
  20. package/dist/subscriberbot/pages/InsightsPage.d.ts.map +1 -1
  21. package/dist/subscriberbot/pages/InsightsPage.js +94 -93
  22. package/dist/subscriberbot/pages/InsightsPage.js.map +1 -1
  23. package/dist/subscriberbot/pages/InvoicesPage.d.ts.map +1 -1
  24. package/dist/subscriberbot/pages/InvoicesPage.js +360 -366
  25. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  26. package/dist/subscriberbot/pages/WorkflowsPage.d.ts.map +1 -1
  27. package/dist/subscriberbot/pages/WorkflowsPage.js +209 -193
  28. package/dist/subscriberbot/pages/WorkflowsPage.js.map +1 -1
  29. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -1
  30. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +268 -236
  31. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  32. package/dist/subscriberbot/pages/agents/AgentNewPage.d.ts.map +1 -1
  33. package/dist/subscriberbot/pages/agents/AgentNewPage.js +96 -76
  34. package/dist/subscriberbot/pages/agents/AgentNewPage.js.map +1 -1
  35. package/dist/subscriberbot/pages/agents/AgentsListPage.d.ts.map +1 -1
  36. package/dist/subscriberbot/pages/agents/AgentsListPage.js +145 -161
  37. package/dist/subscriberbot/pages/agents/AgentsListPage.js.map +1 -1
  38. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts.map +1 -1
  39. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +514 -441
  40. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  41. package/dist/subscriberbot/pages/providers/ProviderNewPage.d.ts.map +1 -1
  42. package/dist/subscriberbot/pages/providers/ProviderNewPage.js +167 -129
  43. package/dist/subscriberbot/pages/providers/ProviderNewPage.js.map +1 -1
  44. package/dist/subscriberbot/pages/providers/ProvidersListPage.d.ts.map +1 -1
  45. package/dist/subscriberbot/pages/providers/ProvidersListPage.js +171 -218
  46. package/dist/subscriberbot/pages/providers/ProvidersListPage.js.map +1 -1
  47. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.d.ts.map +1 -1
  48. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +340 -279
  49. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  50. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.d.ts.map +1 -1
  51. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js +185 -166
  52. package/dist/subscriberbot/pages/relationships/RelationshipNewPage.js.map +1 -1
  53. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.d.ts.map +1 -1
  54. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js +153 -182
  55. package/dist/subscriberbot/pages/relationships/RelationshipsListPage.js.map +1 -1
  56. package/package.json +1 -1
@@ -8,247 +8,222 @@ import { ErrorView as l, LoadingView as u } from "../../components/StateViews.js
8
8
  import { MiniProgress as d } from "../../components/viz.js";
9
9
  import "../../components/index.js";
10
10
  import { useRelationships as f } from "../../hooks/useSubscriberBotApi.js";
11
- import { useMemo as p, useState as m } from "react";
12
- import { ChevronRight as h, Plus as g, Repeat2 as _, Search as v } from "lucide-react";
13
- import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
14
- import { GlassCard as S, PagePurpose as C } from "@burdenoff/fe-libs/ui";
11
+ import { useTr as p } from "../../hooks/useTr.js";
12
+ import { useMemo as m, useState as h } from "react";
13
+ import { ChevronRight as g, Plus as _, Repeat2 as v, Search as y } from "lucide-react";
14
+ import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
15
+ import { GlassCard as C, PagePurpose as w } from "@burdenoff/fe-libs/ui";
15
16
  //#region src/subscriberbot/pages/relationships/RelationshipsListPage.tsx
16
- var w = 20, T = [
17
- {
18
- value: "",
19
- label: "All statuses"
20
- },
21
- {
22
- value: "ACTIVE",
23
- label: "Active"
24
- },
25
- {
26
- value: "TRIAL",
27
- label: "Trial"
28
- },
29
- {
30
- value: "PAUSED",
31
- label: "Paused"
32
- },
33
- {
34
- value: "PAST_DUE",
35
- label: "Past due"
36
- },
37
- {
38
- value: "LAPSED",
39
- label: "Lapsed"
40
- },
41
- {
42
- value: "EXPIRED",
43
- label: "Expired"
44
- },
45
- {
46
- value: "CANCELLED",
47
- label: "Cancelled"
48
- }
49
- ], E = [
50
- {
51
- value: "",
52
- label: "All kinds"
53
- },
54
- {
55
- value: "SUBSCRIPTION",
56
- label: "Subscription"
57
- },
58
- {
59
- value: "MEMBERSHIP",
60
- label: "Membership"
61
- },
62
- {
63
- value: "LICENSE",
64
- label: "License"
65
- },
66
- {
67
- value: "CONTRACT",
68
- label: "Contract"
69
- },
70
- {
71
- value: "NEWSLETTER",
72
- label: "Newsletter"
73
- },
74
- {
75
- value: "RECURRING_PAYMENT",
76
- label: "Recurring payment"
77
- },
78
- {
79
- value: "ENROLLMENT",
80
- label: "Enrollment"
81
- },
82
- {
83
- value: "TRIAL",
84
- label: "Trial"
85
- }
86
- ], D = "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
87
- function O(e) {
17
+ var T = 20, E = [
18
+ "ACTIVE",
19
+ "TRIAL",
20
+ "PAUSED",
21
+ "PAST_DUE",
22
+ "LAPSED",
23
+ "EXPIRED",
24
+ "CANCELLED"
25
+ ], D = [
26
+ "SUBSCRIPTION",
27
+ "MEMBERSHIP",
28
+ "LICENSE",
29
+ "CONTRACT",
30
+ "NEWSLETTER",
31
+ "RECURRING_PAYMENT",
32
+ "ENROLLMENT",
33
+ "TRIAL"
34
+ ], O = {
35
+ ACTIVE: "relationships.statuses.active",
36
+ TRIAL: "relationships.statuses.trial",
37
+ PAUSED: "relationships.statuses.paused",
38
+ PAST_DUE: "relationships.statuses.pastDue",
39
+ LAPSED: "relationships.statuses.lapsed",
40
+ EXPIRED: "relationships.statuses.expired",
41
+ CANCELLED: "relationships.statuses.cancelled"
42
+ }, k = {
43
+ SUBSCRIPTION: "relationships.kinds.subscription",
44
+ MEMBERSHIP: "relationships.kinds.membership",
45
+ LICENSE: "relationships.kinds.license",
46
+ CONTRACT: "relationships.kinds.contract",
47
+ NEWSLETTER: "relationships.kinds.newsletter",
48
+ RECURRING_PAYMENT: "relationships.kinds.recurringPayment",
49
+ ENROLLMENT: "relationships.kinds.enrollment",
50
+ TRIAL: "relationships.kinds.trial"
51
+ }, A = "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
52
+ function j(e) {
88
53
  return e == null ? "accent" : e >= 66 ? "positive" : e >= 33 ? "warning" : "negative";
89
54
  }
90
- function k() {
91
- let { navigateTo: k } = e(), [A, j] = m(0), [M, N] = m(""), [P, F] = m(""), [I, L] = m(""), [R, z] = m(""), { data: B, isLoading: V, isError: H, refetch: U, isFetching: W } = f({
92
- status: M || void 0,
93
- kind: P || void 0,
94
- search: I || void 0,
55
+ function M() {
56
+ let M = p(), { navigateTo: N } = e(), [P, F] = h(0), [I, L] = h(""), [R, z] = h(""), [B, V] = h(""), [H, U] = h(""), { data: W, isLoading: G, isError: K, refetch: q, isFetching: J } = f({
57
+ status: I || void 0,
58
+ kind: R || void 0,
59
+ search: B || void 0,
95
60
  pagination: {
96
- limit: w,
97
- offset: A * w
61
+ limit: T,
62
+ offset: P * T
98
63
  }
99
- }), G = p(() => B?.items ?? [], [B]), K = B?.pageInfo.hasMore ?? !1;
100
- return /* @__PURE__ */ x(n, {
101
- title: "Relationships",
102
- description: "Every subscription, membership, license and contract you track",
103
- actions: /* @__PURE__ */ x("button", {
64
+ }), Y = m(() => W?.items ?? [], [W]), X = W?.pageInfo.hasMore ?? !1;
65
+ return /* @__PURE__ */ S(n, {
66
+ title: M("relationships.title", "Relationships"),
67
+ description: M("relationships.description", "Every subscription, membership, license and contract you track"),
68
+ actions: /* @__PURE__ */ S("button", {
104
69
  type: "button",
105
- onClick: () => k("/relationships/new"),
70
+ onClick: () => N("/relationships/new"),
106
71
  className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
107
- children: [/* @__PURE__ */ b(g, { className: "h-4 w-4" }), " Add relationship"]
72
+ children: [
73
+ /* @__PURE__ */ x(_, { className: "h-4 w-4" }),
74
+ " ",
75
+ M("relationships.addRelationship", "Add relationship")
76
+ ]
108
77
  }),
109
78
  children: [
110
- /* @__PURE__ */ b(C, {
79
+ /* @__PURE__ */ x(w, {
111
80
  className: "mb-4",
112
- children: "This is the fundamental object of Subscriber Bot. Filter by lifecycle and kind, open any row to manage its plan, payment, entitlements, assets and renewals, or advance its lifecycle."
81
+ children: M("relationships.purpose", "This is the fundamental object of Subscriber Bot. Filter by lifecycle and kind, open any row to manage its plan, payment, entitlements, assets and renewals, or advance its lifecycle.")
113
82
  }),
114
- /* @__PURE__ */ b(S, {
83
+ /* @__PURE__ */ x(C, {
115
84
  treatment: "plain",
116
85
  className: "p-3 sm:p-4",
117
- children: /* @__PURE__ */ x("div", {
86
+ children: /* @__PURE__ */ S("div", {
118
87
  className: "flex flex-col gap-3 md:flex-row md:items-center",
119
- children: [/* @__PURE__ */ x("form", {
88
+ children: [/* @__PURE__ */ S("form", {
120
89
  onSubmit: (e) => {
121
- e.preventDefault(), L(R.trim()), j(0);
90
+ e.preventDefault(), V(H.trim()), F(0);
122
91
  },
123
92
  className: "relative flex-1 min-w-0",
124
- children: [/* @__PURE__ */ b(v, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ b("input", {
93
+ children: [/* @__PURE__ */ x(y, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ x("input", {
125
94
  type: "text",
126
- "aria-label": "Search relationships by label",
127
- placeholder: "Search relationships by label…",
128
- value: R,
129
- onChange: (e) => z(e.target.value),
95
+ "aria-label": M("relationships.searchPlaceholder", "Search relationships by label…"),
96
+ placeholder: M("relationships.searchPlaceholder", "Search relationships by label…"),
97
+ value: H,
98
+ onChange: (e) => U(e.target.value),
130
99
  className: "w-full rounded-lg border border-border-subtle bg-bg-surface py-2.5 pl-10 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
131
100
  })]
132
- }), /* @__PURE__ */ x("div", {
101
+ }), /* @__PURE__ */ S("div", {
133
102
  className: "flex flex-wrap gap-2 sm:flex-nowrap",
134
- children: [/* @__PURE__ */ b("select", {
135
- "aria-label": "Filter by kind",
136
- value: P,
103
+ children: [/* @__PURE__ */ S("select", {
104
+ "aria-label": M("relationships.filters.kindLabel", "Filter by kind"),
105
+ value: R,
137
106
  onChange: (e) => {
138
- F(e.target.value), j(0);
107
+ z(e.target.value), F(0);
139
108
  },
140
- className: t(D, "flex-1 sm:flex-none"),
141
- children: E.map((e) => /* @__PURE__ */ b("option", {
142
- value: e.value,
143
- children: e.label
144
- }, e.value))
145
- }), /* @__PURE__ */ b("select", {
146
- "aria-label": "Filter by status",
147
- value: M,
109
+ className: t(A, "flex-1 sm:flex-none"),
110
+ children: [/* @__PURE__ */ x("option", {
111
+ value: "",
112
+ children: M("relationships.filters.allKinds", "All kinds")
113
+ }), D.map((e) => /* @__PURE__ */ x("option", {
114
+ value: e,
115
+ children: M(k[e], a(e))
116
+ }, e))]
117
+ }), /* @__PURE__ */ S("select", {
118
+ "aria-label": M("relationships.filters.statusLabel", "Filter by status"),
119
+ value: I,
148
120
  onChange: (e) => {
149
- N(e.target.value), j(0);
121
+ L(e.target.value), F(0);
150
122
  },
151
- className: t(D, "flex-1 sm:flex-none"),
152
- children: T.map((e) => /* @__PURE__ */ b("option", {
153
- value: e.value,
154
- children: e.label
155
- }, e.value))
123
+ className: t(A, "flex-1 sm:flex-none"),
124
+ children: [/* @__PURE__ */ x("option", {
125
+ value: "",
126
+ children: M("relationships.filters.allStatuses", "All statuses")
127
+ }), E.map((e) => /* @__PURE__ */ x("option", {
128
+ value: e,
129
+ children: M(O[e], a(e))
130
+ }, e))]
156
131
  })]
157
132
  })]
158
133
  })
159
134
  }),
160
- V ? /* @__PURE__ */ b(u, { label: "Loading relationships…" }) : H ? /* @__PURE__ */ b(l, {
161
- message: "Could not load relationships.",
162
- onRetry: () => void U()
163
- }) : G.length === 0 ? /* @__PURE__ */ b("div", {
135
+ G ? /* @__PURE__ */ x(u, { label: M("relationships.loading", "Loading relationships…") }) : K ? /* @__PURE__ */ x(l, {
136
+ message: M("relationships.error", "Could not load relationships."),
137
+ onRetry: () => void q()
138
+ }) : Y.length === 0 ? /* @__PURE__ */ x("div", {
164
139
  className: "mt-6",
165
- children: /* @__PURE__ */ b(c, {
140
+ children: /* @__PURE__ */ x(c, {
166
141
  illustration: "empty-data",
167
- icon: /* @__PURE__ */ b(_, { className: "h-12 w-12" }),
168
- title: "No relationships found",
169
- description: I ? `No relationships match "${I}".` : "Add your first recurring relationship to start tracking it.",
170
- action: /* @__PURE__ */ b("button", {
142
+ icon: /* @__PURE__ */ x(v, { className: "h-12 w-12" }),
143
+ title: M("relationships.emptyTitle", "No relationships found"),
144
+ description: B ? M("relationships.emptyDescriptionSearch", "No relationships match \"{{search}}\".", { search: B }) : M("relationships.emptyDescription", "Add your first recurring relationship to start tracking it."),
145
+ action: /* @__PURE__ */ x("button", {
171
146
  type: "button",
172
- onClick: () => k("/relationships/new"),
147
+ onClick: () => N("/relationships/new"),
173
148
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90",
174
- children: "Add relationship"
149
+ children: M("relationships.addRelationship", "Add relationship")
175
150
  })
176
151
  })
177
- }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(S, {
152
+ }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(C, {
178
153
  treatment: "plain",
179
154
  className: "mt-4 overflow-hidden p-0",
180
- children: /* @__PURE__ */ b("div", {
155
+ children: /* @__PURE__ */ x("div", {
181
156
  className: "overflow-x-auto",
182
- children: /* @__PURE__ */ x("div", {
157
+ children: /* @__PURE__ */ S("div", {
183
158
  className: "min-w-[720px]",
184
- children: [/* @__PURE__ */ x("div", {
159
+ children: [/* @__PURE__ */ S("div", {
185
160
  className: "grid grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] gap-4 border-b border-border-seam bg-bg-sunken/60 px-4 py-2.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
186
161
  children: [
187
- /* @__PURE__ */ b("span", { children: "Subscription" }),
188
- /* @__PURE__ */ b("span", { children: "Kind" }),
189
- /* @__PURE__ */ b("span", { children: "Status" }),
190
- /* @__PURE__ */ b("span", {
162
+ /* @__PURE__ */ x("span", { children: M("relationships.table.subscription", "Subscription") }),
163
+ /* @__PURE__ */ x("span", { children: M("relationships.table.kind", "Kind") }),
164
+ /* @__PURE__ */ x("span", { children: M("relationships.table.status", "Status") }),
165
+ /* @__PURE__ */ x("span", {
191
166
  className: "text-right",
192
- children: "Amount"
167
+ children: M("relationships.table.amount", "Amount")
193
168
  }),
194
- /* @__PURE__ */ b("span", {
169
+ /* @__PURE__ */ x("span", {
195
170
  className: "text-right",
196
- children: "Renews on"
171
+ children: M("relationships.table.renewsOn", "Renews on")
197
172
  }),
198
- /* @__PURE__ */ b("span", { children: "Health" })
173
+ /* @__PURE__ */ x("span", { children: M("relationships.table.health", "Health") })
199
174
  ]
200
- }), /* @__PURE__ */ b("div", {
175
+ }), /* @__PURE__ */ x("div", {
201
176
  className: "divide-y divide-border-subtle",
202
- children: G.map((e) => {
177
+ children: Y.map((e) => {
203
178
  let t = e.healthScore;
204
- return /* @__PURE__ */ x("button", {
179
+ return /* @__PURE__ */ S("button", {
205
180
  type: "button",
206
- onClick: () => k(`/relationships/${e.id}`),
181
+ onClick: () => N(`/relationships/${e.id}`),
207
182
  className: "group grid w-full grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] items-center gap-4 px-4 py-3.5 text-left transition-colors hover:bg-bg-sunken",
208
183
  children: [
209
- /* @__PURE__ */ b("div", {
184
+ /* @__PURE__ */ x("div", {
210
185
  className: "flex min-w-0 items-center gap-2",
211
- children: /* @__PURE__ */ x("div", {
186
+ children: /* @__PURE__ */ S("div", {
212
187
  className: "min-w-0",
213
- children: [/* @__PURE__ */ b("p", {
188
+ children: [/* @__PURE__ */ x("p", {
214
189
  className: "truncate text-sm font-semibold text-text-primary",
215
190
  children: e.label
216
- }), e.provider?.name && /* @__PURE__ */ b("p", {
191
+ }), e.provider?.name && /* @__PURE__ */ x("p", {
217
192
  className: "truncate text-xs text-text-secondary",
218
193
  children: e.provider.name
219
194
  })]
220
195
  })
221
196
  }),
222
- /* @__PURE__ */ b("span", { children: /* @__PURE__ */ b("span", {
197
+ /* @__PURE__ */ x("span", { children: /* @__PURE__ */ x("span", {
223
198
  className: "inline-flex items-center rounded-md bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary",
224
- children: a(e.kind)
199
+ children: M(k[e.kind], a(e.kind))
225
200
  }) }),
226
- /* @__PURE__ */ b("span", { children: /* @__PURE__ */ b(s, { status: e.status }) }),
227
- /* @__PURE__ */ x("span", {
201
+ /* @__PURE__ */ x("span", { children: /* @__PURE__ */ x(s, { status: e.status }) }),
202
+ /* @__PURE__ */ S("span", {
228
203
  className: "text-right text-sm font-semibold tabular-nums text-text-primary",
229
- children: [r(e.amount, e.currency), /* @__PURE__ */ b("span", {
204
+ children: [r(e.amount, e.currency), /* @__PURE__ */ x("span", {
230
205
  className: "text-xs font-normal text-text-secondary",
231
206
  children: o(e.interval)
232
207
  })]
233
208
  }),
234
- /* @__PURE__ */ b("span", {
209
+ /* @__PURE__ */ x("span", {
235
210
  className: "text-right text-xs text-text-secondary",
236
211
  children: e.renewsAt ? i(e.renewsAt) : "—"
237
212
  }),
238
- /* @__PURE__ */ x("span", {
213
+ /* @__PURE__ */ S("span", {
239
214
  className: "flex items-center gap-2",
240
- children: [t == null ? /* @__PURE__ */ b("span", {
215
+ children: [t == null ? /* @__PURE__ */ x("span", {
241
216
  className: "text-xs text-text-secondary",
242
217
  children: "—"
243
- }) : /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(d, {
218
+ }) : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(d, {
244
219
  value: t,
245
220
  max: 100,
246
- tone: O(t),
221
+ tone: j(t),
247
222
  className: "w-16 shrink-0 sm:w-20"
248
- }), /* @__PURE__ */ b("span", {
223
+ }), /* @__PURE__ */ x("span", {
249
224
  className: "text-xs tabular-nums text-text-secondary",
250
225
  children: t
251
- })] }), /* @__PURE__ */ b(h, { className: "ml-auto h-4 w-4 shrink-0 text-text-secondary opacity-0 transition-opacity group-hover:opacity-100" })]
226
+ })] }), /* @__PURE__ */ x(g, { className: "ml-auto h-4 w-4 shrink-0 text-text-secondary opacity-0 transition-opacity group-hover:opacity-100" })]
252
227
  })
253
228
  ]
254
229
  }, e.id);
@@ -256,29 +231,25 @@ function k() {
256
231
  })]
257
232
  })
258
233
  })
259
- }), /* @__PURE__ */ x("div", {
234
+ }), /* @__PURE__ */ S("div", {
260
235
  className: "mt-4 flex items-center justify-between",
261
- children: [/* @__PURE__ */ x("p", {
236
+ children: [/* @__PURE__ */ S("p", {
262
237
  className: "text-xs text-text-secondary",
263
- children: [
264
- "Page ",
265
- A + 1,
266
- W ? " · refreshing…" : ""
267
- ]
268
- }), /* @__PURE__ */ x("div", {
238
+ children: [M("relationships.pagination.page", "Page {{page}}", { page: P + 1 }), J ? ` · ${M("relationships.pagination.refreshing", "refreshing…")}` : ""]
239
+ }), /* @__PURE__ */ S("div", {
269
240
  className: "flex gap-2",
270
- children: [/* @__PURE__ */ b("button", {
241
+ children: [/* @__PURE__ */ x("button", {
271
242
  type: "button",
272
- disabled: A === 0,
273
- onClick: () => j((e) => Math.max(0, e - 1)),
274
- className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", A === 0 ? "cursor-not-allowed text-text-secondary opacity-50" : "text-text-primary hover:bg-bg-sunken"),
275
- children: "Previous"
276
- }), /* @__PURE__ */ b("button", {
243
+ disabled: P === 0,
244
+ onClick: () => F((e) => Math.max(0, e - 1)),
245
+ className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", P === 0 ? "cursor-not-allowed text-text-secondary opacity-50" : "text-text-primary hover:bg-bg-sunken"),
246
+ children: M("relationships.pagination.previous", "Previous")
247
+ }), /* @__PURE__ */ x("button", {
277
248
  type: "button",
278
- disabled: !K,
279
- onClick: () => j((e) => e + 1),
280
- className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", K ? "text-text-primary hover:bg-bg-sunken" : "cursor-not-allowed text-text-secondary opacity-50"),
281
- children: "Next"
249
+ disabled: !X,
250
+ onClick: () => F((e) => e + 1),
251
+ className: t("rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium", X ? "text-text-primary hover:bg-bg-sunken" : "cursor-not-allowed text-text-secondary opacity-50"),
252
+ children: M("relationships.pagination.next", "Next")
282
253
  })]
283
254
  })]
284
255
  })] })
@@ -286,6 +257,6 @@ function k() {
286
257
  });
287
258
  }
288
259
  //#endregion
289
- export { k as RelationshipsListPage };
260
+ export { M as RelationshipsListPage };
290
261
 
291
262
  //# sourceMappingURL=RelationshipsListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RelationshipsListPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/relationships/RelationshipsListPage.tsx"],"sourcesContent":["/**\n * Relationships list\n * @module subscriberbot/pages/relationships\n *\n * The core CRUDL list — every recurring relationship (subscription /\n * membership / license / contract) in one paginated, filterable view.\n * Data comes from `subListRelationships` (a SubRelationshipConnection).\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Search, Repeat2, ChevronRight } from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { MiniProgress } from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useRelationships } from '../../hooks/useSubscriberBotApi';\nimport { cn } from '../../utils/cn';\nimport {\n formatCurrency,\n formatDate,\n formatEnumLabel,\n formatIntervalSuffix,\n} from '../../utils/formatters';\nimport type { SubRelationshipKind, SubRelationshipStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nconst STATUS_OPTIONS: Array<{ value: '' | SubRelationshipStatus; label: string }> = [\n { value: '', label: 'All statuses' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'TRIAL', label: 'Trial' },\n { value: 'PAUSED', label: 'Paused' },\n { value: 'PAST_DUE', label: 'Past due' },\n { value: 'LAPSED', label: 'Lapsed' },\n { value: 'EXPIRED', label: 'Expired' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nconst KIND_OPTIONS: Array<{ value: '' | SubRelationshipKind; label: string }> = [\n { value: '', label: 'All kinds' },\n { value: 'SUBSCRIPTION', label: 'Subscription' },\n { value: 'MEMBERSHIP', label: 'Membership' },\n { value: 'LICENSE', label: 'License' },\n { value: 'CONTRACT', label: 'Contract' },\n { value: 'NEWSLETTER', label: 'Newsletter' },\n { value: 'RECURRING_PAYMENT', label: 'Recurring payment' },\n { value: 'ENROLLMENT', label: 'Enrollment' },\n { value: 'TRIAL', label: 'Trial' },\n];\n\nconst selectCls =\n 'rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n/** Map a 0–100 health score onto a MiniProgress tone. */\nfunction healthTone(\n score: number | null | undefined\n): 'positive' | 'accent' | 'warning' | 'negative' {\n if (score == null) return 'accent';\n if (score >= 66) return 'positive';\n if (score >= 33) return 'warning';\n return 'negative';\n}\n\nexport function RelationshipsListPage() {\n const { navigateTo } = useSubscriberBot();\n const [page, setPage] = useState(0);\n const [statusFilter, setStatusFilter] = useState<'' | SubRelationshipStatus>('');\n const [kindFilter, setKindFilter] = useState<'' | SubRelationshipKind>('');\n const [search, setSearch] = useState('');\n const [searchInput, setSearchInput] = useState('');\n\n const { data, isLoading, isError, refetch, isFetching } = useRelationships({\n status: statusFilter || undefined,\n kind: kindFilter || undefined,\n search: search || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = useMemo(() => data?.items ?? [], [data]);\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n const submitSearch = (e: React.FormEvent) => {\n e.preventDefault();\n setSearch(searchInput.trim());\n setPage(0);\n };\n\n return (\n <PageLayout\n title=\"Relationships\"\n description=\"Every subscription, membership, license and contract you track\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> Add relationship\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n This is the fundamental object of Subscriber Bot. Filter by lifecycle and kind, open any row\n to manage its plan, payment, entitlements, assets and renewals, or advance its lifecycle.\n </PagePurpose>\n\n {/* Toolbar — search + filters, responsive */}\n <GlassCard treatment=\"plain\" className=\"p-3 sm:p-4\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-center\">\n <form onSubmit={submitSearch} className=\"relative flex-1 min-w-0\">\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 type=\"text\"\n aria-label=\"Search relationships by label\"\n placeholder=\"Search relationships by label…\"\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2.5 pl-10 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </form>\n <div className=\"flex flex-wrap gap-2 sm:flex-nowrap\">\n <select\n aria-label=\"Filter by kind\"\n value={kindFilter}\n onChange={(e) => {\n setKindFilter(e.target.value as '' | SubRelationshipKind);\n setPage(0);\n }}\n className={cn(selectCls, 'flex-1 sm:flex-none')}\n >\n {KIND_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Filter by status\"\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as '' | SubRelationshipStatus);\n setPage(0);\n }}\n className={cn(selectCls, 'flex-1 sm:flex-none')}\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n </GlassCard>\n\n {isLoading ? (\n <LoadingView label=\"Loading relationships…\" />\n ) : isError ? (\n <ErrorView message=\"Could not load relationships.\" onRetry={() => void refetch()} />\n ) : items.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Repeat2 className=\"h-12 w-12\" />}\n title=\"No relationships found\"\n description={\n search\n ? `No relationships match \"${search}\".`\n : 'Add your first recurring relationship to start tracking it.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add relationship\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* Portfolio table — scrolls horizontally on small screens, never the page */}\n <GlassCard treatment=\"plain\" className=\"mt-4 overflow-hidden p-0\">\n <div className=\"overflow-x-auto\">\n <div className=\"min-w-[720px]\">\n <div className=\"grid grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] gap-4 border-b border-border-seam bg-bg-sunken/60 px-4 py-2.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n <span>Subscription</span>\n <span>Kind</span>\n <span>Status</span>\n <span className=\"text-right\">Amount</span>\n <span className=\"text-right\">Renews on</span>\n <span>Health</span>\n </div>\n <div className=\"divide-y divide-border-subtle\">\n {items.map((r) => {\n const score = r.healthScore;\n return (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/relationships/${r.id}`)}\n className=\"group grid w-full grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] items-center gap-4 px-4 py-3.5 text-left transition-colors hover:bg-bg-sunken\"\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {r.label}\n </p>\n {r.provider?.name && (\n <p className=\"truncate text-xs text-text-secondary\">\n {r.provider.name}\n </p>\n )}\n </div>\n </div>\n <span>\n <span className=\"inline-flex items-center rounded-md bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {formatEnumLabel(r.kind)}\n </span>\n </span>\n <span>\n <StatusBadge status={r.status} />\n </span>\n <span className=\"text-right text-sm font-semibold tabular-nums text-text-primary\">\n {formatCurrency(r.amount, r.currency)}\n <span className=\"text-xs font-normal text-text-secondary\">\n {formatIntervalSuffix(r.interval)}\n </span>\n </span>\n <span className=\"text-right text-xs text-text-secondary\">\n {r.renewsAt ? formatDate(r.renewsAt) : '—'}\n </span>\n <span className=\"flex items-center gap-2\">\n {score != null ? (\n <>\n <MiniProgress\n value={score}\n max={100}\n tone={healthTone(score)}\n className=\"w-16 shrink-0 sm:w-20\"\n />\n <span className=\"text-xs tabular-nums text-text-secondary\">\n {score}\n </span>\n </>\n ) : (\n <span className=\"text-xs text-text-secondary\">—</span>\n )}\n <ChevronRight className=\"ml-auto h-4 w-4 shrink-0 text-text-secondary opacity-0 transition-opacity group-hover:opacity-100\" />\n </span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n </GlassCard>\n\n <div className=\"mt-4 flex items-center justify-between\">\n <p className=\"text-xs text-text-secondary\">\n Page {page + 1}\n {isFetching ? ' · refreshing…' : ''}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n disabled={page === 0}\n onClick={() => setPage((p) => Math.max(0, p - 1))}\n className={cn(\n 'rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium',\n page === 0\n ? 'cursor-not-allowed text-text-secondary opacity-50'\n : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n Previous\n </button>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setPage((p) => p + 1)}\n className={cn(\n 'rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium',\n !hasMore\n ? 'cursor-not-allowed text-text-secondary opacity-50'\n : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n Next\n </button>\n </div>\n </div>\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RelationshipsListPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/relationships/RelationshipsListPage.tsx"],"sourcesContent":["/**\n * Relationships list\n * @module subscriberbot/pages/relationships\n *\n * The core CRUDL list — every recurring relationship (subscription /\n * membership / license / contract) in one paginated, filterable view.\n * Data comes from `subListRelationships` (a SubRelationshipConnection).\n */\n\nimport { useMemo, useState } from 'react';\nimport { Plus, Search, Repeat2, ChevronRight } from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { MiniProgress } from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useRelationships } from '../../hooks/useSubscriberBotApi';\nimport { cn } from '../../utils/cn';\nimport {\n formatCurrency,\n formatDate,\n formatEnumLabel,\n formatIntervalSuffix,\n} from '../../utils/formatters';\nimport { useTr } from '../../hooks/useTr';\nimport type { SubRelationshipKind, SubRelationshipStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nconst STATUSES: SubRelationshipStatus[] = [\n 'ACTIVE',\n 'TRIAL',\n 'PAUSED',\n 'PAST_DUE',\n 'LAPSED',\n 'EXPIRED',\n 'CANCELLED',\n];\n\nconst KINDS: SubRelationshipKind[] = [\n 'SUBSCRIPTION',\n 'MEMBERSHIP',\n 'LICENSE',\n 'CONTRACT',\n 'NEWSLETTER',\n 'RECURRING_PAYMENT',\n 'ENROLLMENT',\n 'TRIAL',\n];\n\nconst STATUS_KEY: Record<SubRelationshipStatus, string> = {\n ACTIVE: 'relationships.statuses.active',\n TRIAL: 'relationships.statuses.trial',\n PAUSED: 'relationships.statuses.paused',\n PAST_DUE: 'relationships.statuses.pastDue',\n LAPSED: 'relationships.statuses.lapsed',\n EXPIRED: 'relationships.statuses.expired',\n CANCELLED: 'relationships.statuses.cancelled',\n};\n\nconst KIND_KEY: Record<SubRelationshipKind, string> = {\n SUBSCRIPTION: 'relationships.kinds.subscription',\n MEMBERSHIP: 'relationships.kinds.membership',\n LICENSE: 'relationships.kinds.license',\n CONTRACT: 'relationships.kinds.contract',\n NEWSLETTER: 'relationships.kinds.newsletter',\n RECURRING_PAYMENT: 'relationships.kinds.recurringPayment',\n ENROLLMENT: 'relationships.kinds.enrollment',\n TRIAL: 'relationships.kinds.trial',\n};\n\nconst selectCls =\n 'rounded-lg border border-border-subtle bg-bg-surface px-3 py-2.5 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n/** Map a 0–100 health score onto a MiniProgress tone. */\nfunction healthTone(\n score: number | null | undefined\n): 'positive' | 'accent' | 'warning' | 'negative' {\n if (score == null) return 'accent';\n if (score >= 66) return 'positive';\n if (score >= 33) return 'warning';\n return 'negative';\n}\n\nexport function RelationshipsListPage() {\n const tr = useTr();\n const { navigateTo } = useSubscriberBot();\n const [page, setPage] = useState(0);\n const [statusFilter, setStatusFilter] = useState<'' | SubRelationshipStatus>('');\n const [kindFilter, setKindFilter] = useState<'' | SubRelationshipKind>('');\n const [search, setSearch] = useState('');\n const [searchInput, setSearchInput] = useState('');\n\n const { data, isLoading, isError, refetch, isFetching } = useRelationships({\n status: statusFilter || undefined,\n kind: kindFilter || undefined,\n search: search || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = useMemo(() => data?.items ?? [], [data]);\n const hasMore = data?.pageInfo.hasMore ?? false;\n\n const submitSearch = (e: React.FormEvent) => {\n e.preventDefault();\n setSearch(searchInput.trim());\n setPage(0);\n };\n\n return (\n <PageLayout\n title={tr('relationships.title', 'Relationships')}\n description={tr(\n 'relationships.description',\n 'Every subscription, membership, license and contract you track'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n <Plus className=\"h-4 w-4\" /> {tr('relationships.addRelationship', 'Add relationship')}\n </button>\n }\n >\n <PagePurpose className=\"mb-4\">\n {tr(\n 'relationships.purpose',\n 'This is the fundamental object of Subscriber Bot. Filter by lifecycle and kind, open any row to manage its plan, payment, entitlements, assets and renewals, or advance its lifecycle.'\n )}\n </PagePurpose>\n\n {/* Toolbar — search + filters, responsive */}\n <GlassCard treatment=\"plain\" className=\"p-3 sm:p-4\">\n <div className=\"flex flex-col gap-3 md:flex-row md:items-center\">\n <form onSubmit={submitSearch} className=\"relative flex-1 min-w-0\">\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 type=\"text\"\n aria-label={tr('relationships.searchPlaceholder', 'Search relationships by label…')}\n placeholder={tr('relationships.searchPlaceholder', 'Search relationships by label…')}\n value={searchInput}\n onChange={(e) => setSearchInput(e.target.value)}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2.5 pl-10 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </form>\n <div className=\"flex flex-wrap gap-2 sm:flex-nowrap\">\n <select\n aria-label={tr('relationships.filters.kindLabel', 'Filter by kind')}\n value={kindFilter}\n onChange={(e) => {\n setKindFilter(e.target.value as '' | SubRelationshipKind);\n setPage(0);\n }}\n className={cn(selectCls, 'flex-1 sm:flex-none')}\n >\n <option value=\"\">{tr('relationships.filters.allKinds', 'All kinds')}</option>\n {KINDS.map((k) => (\n <option key={k} value={k}>\n {tr(KIND_KEY[k], formatEnumLabel(k))}\n </option>\n ))}\n </select>\n <select\n aria-label={tr('relationships.filters.statusLabel', 'Filter by status')}\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as '' | SubRelationshipStatus);\n setPage(0);\n }}\n className={cn(selectCls, 'flex-1 sm:flex-none')}\n >\n <option value=\"\">{tr('relationships.filters.allStatuses', 'All statuses')}</option>\n {STATUSES.map((s) => (\n <option key={s} value={s}>\n {tr(STATUS_KEY[s], formatEnumLabel(s))}\n </option>\n ))}\n </select>\n </div>\n </div>\n </GlassCard>\n\n {isLoading ? (\n <LoadingView label={tr('relationships.loading', 'Loading relationships…')} />\n ) : isError ? (\n <ErrorView\n message={tr('relationships.error', 'Could not load relationships.')}\n onRetry={() => void refetch()}\n />\n ) : items.length === 0 ? (\n <div className=\"mt-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Repeat2 className=\"h-12 w-12\" />}\n title={tr('relationships.emptyTitle', 'No relationships found')}\n description={\n search\n ? tr(\n 'relationships.emptyDescriptionSearch',\n 'No relationships match \"{{search}}\".',\n { search }\n )\n : tr(\n 'relationships.emptyDescription',\n 'Add your first recurring relationship to start tracking it.'\n )\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/relationships/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n {tr('relationships.addRelationship', 'Add relationship')}\n </button>\n }\n />\n </div>\n ) : (\n <>\n {/* Portfolio table — scrolls horizontally on small screens, never the page */}\n <GlassCard treatment=\"plain\" className=\"mt-4 overflow-hidden p-0\">\n <div className=\"overflow-x-auto\">\n <div className=\"min-w-[720px]\">\n <div className=\"grid grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] gap-4 border-b border-border-seam bg-bg-sunken/60 px-4 py-2.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n <span>{tr('relationships.table.subscription', 'Subscription')}</span>\n <span>{tr('relationships.table.kind', 'Kind')}</span>\n <span>{tr('relationships.table.status', 'Status')}</span>\n <span className=\"text-right\">{tr('relationships.table.amount', 'Amount')}</span>\n <span className=\"text-right\">\n {tr('relationships.table.renewsOn', 'Renews on')}\n </span>\n <span>{tr('relationships.table.health', 'Health')}</span>\n </div>\n <div className=\"divide-y divide-border-subtle\">\n {items.map((r) => {\n const score = r.healthScore;\n return (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/relationships/${r.id}`)}\n className=\"group grid w-full grid-cols-[minmax(0,2.4fr)_1fr_1fr_1fr_1fr_1.3fr] items-center gap-4 px-4 py-3.5 text-left transition-colors hover:bg-bg-sunken\"\n >\n <div className=\"flex min-w-0 items-center gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-text-primary\">\n {r.label}\n </p>\n {r.provider?.name && (\n <p className=\"truncate text-xs text-text-secondary\">\n {r.provider.name}\n </p>\n )}\n </div>\n </div>\n <span>\n <span className=\"inline-flex items-center rounded-md bg-bg-sunken px-2 py-0.5 text-xs font-medium text-text-secondary\">\n {tr(KIND_KEY[r.kind], formatEnumLabel(r.kind))}\n </span>\n </span>\n <span>\n <StatusBadge status={r.status} />\n </span>\n <span className=\"text-right text-sm font-semibold tabular-nums text-text-primary\">\n {formatCurrency(r.amount, r.currency)}\n <span className=\"text-xs font-normal text-text-secondary\">\n {formatIntervalSuffix(r.interval)}\n </span>\n </span>\n <span className=\"text-right text-xs text-text-secondary\">\n {r.renewsAt ? formatDate(r.renewsAt) : '—'}\n </span>\n <span className=\"flex items-center gap-2\">\n {score != null ? (\n <>\n <MiniProgress\n value={score}\n max={100}\n tone={healthTone(score)}\n className=\"w-16 shrink-0 sm:w-20\"\n />\n <span className=\"text-xs tabular-nums text-text-secondary\">\n {score}\n </span>\n </>\n ) : (\n <span className=\"text-xs text-text-secondary\">—</span>\n )}\n <ChevronRight className=\"ml-auto h-4 w-4 shrink-0 text-text-secondary opacity-0 transition-opacity group-hover:opacity-100\" />\n </span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n </GlassCard>\n\n <div className=\"mt-4 flex items-center justify-between\">\n <p className=\"text-xs text-text-secondary\">\n {tr('relationships.pagination.page', 'Page {{page}}', { page: page + 1 })}\n {isFetching ? ` · ${tr('relationships.pagination.refreshing', 'refreshing…')}` : ''}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n disabled={page === 0}\n onClick={() => setPage((p) => Math.max(0, p - 1))}\n className={cn(\n 'rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium',\n page === 0\n ? 'cursor-not-allowed text-text-secondary opacity-50'\n : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n {tr('relationships.pagination.previous', 'Previous')}\n </button>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setPage((p) => p + 1)}\n className={cn(\n 'rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium',\n !hasMore\n ? 'cursor-not-allowed text-text-secondary opacity-50'\n : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n {tr('relationships.pagination.next', 'Next')}\n </button>\n </div>\n </div>\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-subscriberbot",
3
- "version": "2026.827.1",
3
+ "version": "2026.829.1",
4
4
  "description": "Burdenoff SubscriberBot Microfrontend",
5
5
  "type": "module",
6
6
  "files": [