@burdenoff/microfe-billing 2026.624.3 → 2026.625.2

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 (95) hide show
  1. package/dist/billing/BillingAdminRoutes.js +1 -1
  2. package/dist/billing/BillingAdminRoutes.js.map +1 -1
  3. package/dist/billing/modules/addons/pages/AddonCreatePage.js +2 -2
  4. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  5. package/dist/billing/modules/addons/pages/AddonDetailPage.js +4 -4
  6. package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
  7. package/dist/billing/modules/addons/pages/AddonEditPage.js +2 -2
  8. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  9. package/dist/billing/modules/addons/pages/AddonsListPage.js +1 -1
  10. package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
  11. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +98 -99
  12. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  13. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +88 -85
  14. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  15. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +6 -6
  16. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  17. package/dist/billing/modules/billing/pages/InvoicesListPage.js +2 -2
  18. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  19. package/dist/billing/modules/billing/pages/RefundsPage.js +360 -370
  20. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  21. package/dist/billing/modules/billing/pages/UserRefundsPage.js +2 -2
  22. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  23. package/dist/billing/modules/checkout/components/BillingAccountSelector.js +1 -1
  24. package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
  25. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +1 -1
  26. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
  27. package/dist/billing/modules/checkout/components/SubscriptionSelector.js +1 -1
  28. package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
  29. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +2 -2
  30. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
  31. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +102 -104
  32. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  33. package/dist/billing/modules/coupons/pages/CouponsListPage.js +5 -5
  34. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  35. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
  36. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  37. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +1 -1
  38. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
  39. package/dist/billing/modules/credits/pages/CreditsPage.js +29 -28
  40. package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
  41. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +2 -2
  42. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
  43. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +1 -1
  44. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
  45. package/dist/billing/modules/dashboard/components/BillingAccountCard.js +3 -3
  46. package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
  47. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +2 -2
  48. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
  49. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +1 -1
  50. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
  51. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +1 -1
  52. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
  53. package/dist/billing/modules/dashboard/pages/OverviewPage.js +139 -142
  54. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  55. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +6 -6
  56. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  57. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +4 -4
  58. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  59. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +1 -1
  60. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  61. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +142 -133
  62. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  63. package/dist/billing/modules/plans/pages/PlanCreatePage.js +2 -2
  64. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  65. package/dist/billing/modules/plans/pages/PlanDetailPage.js +4 -4
  66. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  67. package/dist/billing/modules/plans/pages/PlanEditPage.js +2 -2
  68. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  69. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +4 -4
  70. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  71. package/dist/billing/modules/plans/pages/PlansListPage.js +2 -2
  72. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  73. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +4 -4
  74. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  75. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +2 -2
  76. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
  77. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +2 -2
  78. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  79. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +5 -5
  80. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
  81. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +2 -2
  82. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  83. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +1 -1
  84. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
  85. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +259 -265
  86. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  87. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +7 -7
  88. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  89. package/dist/billing/modules/usage/pages/UsagePage.js +13 -13
  90. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  91. package/dist/billing/shared/ui/Card.js +1 -1
  92. package/dist/billing/shared/ui/Card.js.map +1 -1
  93. package/dist/billing/shared/ui/MetricCard.js +28 -21
  94. package/dist/billing/shared/ui/MetricCard.js.map +1 -1
  95. package/package.json +2 -2
@@ -14,9 +14,9 @@ import { addAffiliateCodeNote as d, createAffiliateCode as f, deactivateAffiliat
14
14
  import { useEffect as v, useMemo as y, useState as b } from "react";
15
15
  import { Link2 as x, Plus as S, RefreshCw as C, StickyNote as w, Ticket as T, TrendingUp as E, Users as D } from "lucide-react";
16
16
  import { jsx as O, jsxs as k } from "react/jsx-runtime";
17
- import { ResponsiveTable as A } from "@burdenoff/fe-libs/ui";
17
+ import { CTAOverflowMenu as A, ResponsiveTable as j } from "@burdenoff/fe-libs/ui";
18
18
  //#region src/billing/modules/affiliate/pages/AffiliateDashboardPage.tsx
19
- var j = [
19
+ var M = [
20
20
  {
21
21
  key: "code",
22
22
  header: "Code",
@@ -48,86 +48,86 @@ var j = [
48
48
  header: "Visited",
49
49
  cell: (e) => c(e.lastVisitedAt)
50
50
  }
51
- ], M = () => {
52
- let c = u(), { emit: M } = o(), { apiGatewayUrl: N, authToken: P, orgId: F } = e(), [I, L] = b([]), [R, z] = b([]), [B, V] = b(null), [H, U] = b(!0), [W, G] = b(null), [K, q] = b(null), [J, Y] = b({
51
+ ], N = () => {
52
+ let c = u(), { emit: N } = o(), { apiGatewayUrl: P, authToken: F, orgId: I } = e(), [L, R] = b([]), [z, B] = b([]), [V, H] = b(null), [U, W] = b(!0), [G, K] = b(null), [q, J] = b(null), [Y, X] = b({
53
53
  label: "",
54
54
  description: "",
55
55
  notes: "",
56
56
  productSlug: "",
57
57
  destinationPath: "",
58
58
  destinationUrl: ""
59
- }), X = y(() => ({
60
- apiGatewayUrl: N,
61
- authToken: P,
62
- orgId: F
59
+ }), Z = y(() => ({
60
+ apiGatewayUrl: P,
61
+ authToken: F,
62
+ orgId: I
63
63
  }), [
64
- N,
65
64
  P,
66
- F
67
- ]), Z = async () => {
68
- U(!0), G(null);
65
+ F,
66
+ I
67
+ ]), Q = async () => {
68
+ W(!0), K(null);
69
69
  try {
70
70
  let [e, t, n] = await Promise.all([
71
- h(X),
72
- m(X),
73
- g(X)
71
+ h(Z),
72
+ m(Z),
73
+ g(Z)
74
74
  ]);
75
- L(e), V(t), z(n);
75
+ R(e), H(t), B(n);
76
76
  } catch (e) {
77
- G(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load affiliate dashboard"));
77
+ K(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load affiliate dashboard"));
78
78
  } finally {
79
- U(!1);
79
+ W(!1);
80
80
  }
81
81
  };
82
82
  if (v(() => {
83
- Z();
84
- }, [X]), !c.canViewBillingAccount) return /* @__PURE__ */ O(t, { message: "You don't have permission to view affiliate analytics." });
85
- if (W && l(W)) return /* @__PURE__ */ O(a, {
83
+ Q();
84
+ }, [Z]), !c.canViewBillingAccount) return /* @__PURE__ */ O(t, { message: "You don't have permission to view affiliate analytics." });
85
+ if (G && l(G)) return /* @__PURE__ */ O(a, {
86
86
  title: "Affiliate service unavailable",
87
- message: W.message,
88
- onRetry: () => void Z(),
87
+ message: G.message,
88
+ onRetry: () => void Q(),
89
89
  showRetry: !0
90
90
  });
91
- let Q = I.find((e) => e.id === K) ?? null, $ = async () => {
92
- if (!J.productSlug.trim()) {
93
- G(/* @__PURE__ */ Error("Product slug is required"));
91
+ let $ = L.find((e) => e.id === q) ?? null, ee = async () => {
92
+ if (!Y.productSlug.trim()) {
93
+ K(/* @__PURE__ */ Error("Product slug is required"));
94
94
  return;
95
95
  }
96
96
  try {
97
- Q ? (await _(Q.id, {
98
- label: J.label,
99
- description: J.description,
100
- notes: J.notes,
101
- destinationPath: J.destinationPath,
102
- destinationUrl: J.destinationUrl
103
- }, X), M("billing.affiliate_code.updated", {
97
+ $ ? (await _($.id, {
98
+ label: Y.label,
99
+ description: Y.description,
100
+ notes: Y.notes,
101
+ destinationPath: Y.destinationPath,
102
+ destinationUrl: Y.destinationUrl
103
+ }, Z), N("billing.affiliate_code.updated", {
104
104
  route: "/billing/affiliate",
105
- entityId: Q.id,
105
+ entityId: $.id,
106
106
  source: "affiliate-dashboard"
107
- })) : M("billing.affiliate_code.created", {
107
+ })) : N("billing.affiliate_code.created", {
108
108
  route: "/billing/affiliate",
109
109
  entityId: (await f({
110
- label: J.label,
111
- description: J.description,
112
- notes: J.notes,
113
- productSlug: J.productSlug,
114
- destinationPath: J.destinationPath,
115
- destinationUrl: J.destinationUrl
116
- }, X)).id,
110
+ label: Y.label,
111
+ description: Y.description,
112
+ notes: Y.notes,
113
+ productSlug: Y.productSlug,
114
+ destinationPath: Y.destinationPath,
115
+ destinationUrl: Y.destinationUrl
116
+ }, Z)).id,
117
117
  source: "affiliate-dashboard"
118
- }), q(null), Y({
118
+ }), J(null), X({
119
119
  label: "",
120
120
  description: "",
121
121
  notes: "",
122
122
  productSlug: "",
123
123
  destinationPath: "",
124
124
  destinationUrl: ""
125
- }), await Z();
125
+ }), await Q();
126
126
  } catch (e) {
127
- G(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to save affiliate code"));
127
+ K(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to save affiliate code"));
128
128
  }
129
- }, ee = (e) => {
130
- q(e.id), Y({
129
+ }, te = (e) => {
130
+ J(e.id), X({
131
131
  label: e.label ?? "",
132
132
  description: e.description ?? "",
133
133
  notes: e.notes ?? "",
@@ -135,38 +135,38 @@ var j = [
135
135
  destinationPath: e.destinationPath ?? "",
136
136
  destinationUrl: e.destinationUrl ?? ""
137
137
  });
138
- }, te = async (e) => {
139
- await p(e, X), M("billing.affiliate_code.deactivated", {
138
+ }, ne = async (e) => {
139
+ await p(e, Z), N("billing.affiliate_code.deactivated", {
140
140
  route: "/billing/affiliate",
141
141
  entityId: e,
142
142
  source: "affiliate-dashboard"
143
- }), await Z();
144
- }, ne = async (e) => {
143
+ }), await Q();
144
+ }, re = async (e) => {
145
145
  let t = window.prompt("Add an internal note for this affiliate code");
146
- t && (await d(e, t, X), M("billing.affiliate_code.note_added", {
146
+ t && (await d(e, t, Z), N("billing.affiliate_code.note_added", {
147
147
  route: "/billing/affiliate",
148
148
  entityId: e,
149
149
  source: "affiliate-dashboard"
150
- }), await Z());
151
- }, re = B ? [
150
+ }), await Q());
151
+ }, ie = V ? [
152
152
  {
153
153
  title: "Codes",
154
- value: B.totalCodes,
154
+ value: V.totalCodes,
155
155
  icon: /* @__PURE__ */ O(T, { className: "size-5" })
156
156
  },
157
157
  {
158
158
  title: "Visits",
159
- value: B.totalVisits,
159
+ value: V.totalVisits,
160
160
  icon: /* @__PURE__ */ O(D, { className: "size-5" })
161
161
  },
162
162
  {
163
163
  title: "Journeys",
164
- value: B.totalJourneys,
164
+ value: V.totalJourneys,
165
165
  icon: /* @__PURE__ */ O(x, { className: "size-5" })
166
166
  },
167
167
  {
168
168
  title: "Revenue influenced",
169
- value: s(B.totalRevenueAmount, "USD"),
169
+ value: s(V.totalRevenueAmount, "USD"),
170
170
  icon: /* @__PURE__ */ O(E, { className: "size-5" })
171
171
  }
172
172
  ] : [];
@@ -176,14 +176,13 @@ var j = [
176
176
  /* @__PURE__ */ O(n, {
177
177
  title: "Affiliate codes",
178
178
  description: "Create referral codes, add internal notes, and monitor attributed journeys.",
179
- actions: /* @__PURE__ */ k("button", {
180
- type: "button",
181
- onClick: () => void Z(),
182
- className: "inline-flex items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary",
183
- children: [/* @__PURE__ */ O(C, { className: "size-4" }), "Refresh"]
184
- })
179
+ actions: /* @__PURE__ */ O(A, { actions: [{
180
+ label: "Refresh",
181
+ onSelect: () => void Q(),
182
+ icon: /* @__PURE__ */ O(C, { className: "size-4" })
183
+ }] })
185
184
  }),
186
- H ? /* @__PURE__ */ O("div", {
185
+ U ? /* @__PURE__ */ O("div", {
187
186
  className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4",
188
187
  children: [
189
188
  1,
@@ -191,36 +190,36 @@ var j = [
191
190
  3,
192
191
  4
193
192
  ].map((e) => /* @__PURE__ */ O("div", { className: "h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface" }, e))
194
- }) : B ? /* @__PURE__ */ O("div", {
193
+ }) : V ? /* @__PURE__ */ O("div", {
195
194
  className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4",
196
- children: re.map((e) => /* @__PURE__ */ O(r, {
195
+ children: ie.map((e) => /* @__PURE__ */ O(r, {
197
196
  label: e.title,
198
197
  value: e.value,
199
198
  icon: e.icon
200
199
  }, e.title))
201
200
  }) : null,
202
- W && !l(W) ? /* @__PURE__ */ O("div", {
201
+ G && !l(G) ? /* @__PURE__ */ O("div", {
203
202
  className: "rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text",
204
- children: W.message
203
+ children: G.message
205
204
  }) : null,
206
205
  /* @__PURE__ */ k("div", {
207
206
  className: "grid gap-6 xl:grid-cols-[1.1fr,1.9fr]",
208
207
  children: [/* @__PURE__ */ k("section", {
209
- className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
208
+ className: "rounded-lg border border-border-seam bg-bg-surface p-4 xl:sticky xl:top-6 xl:self-start",
210
209
  children: [
211
210
  /* @__PURE__ */ k("div", {
212
211
  className: "mb-4 flex items-center justify-between",
213
212
  children: [/* @__PURE__ */ O("h2", {
214
213
  className: "text-lg font-semibold text-text-primary",
215
- children: Q ? "Update affiliate code" : "Create affiliate code"
216
- }), Q ? null : /* @__PURE__ */ O(S, { className: "size-4 text-text-secondary" })]
214
+ children: $ ? "Update affiliate code" : "Create affiliate code"
215
+ }), $ ? null : /* @__PURE__ */ O(S, { className: "size-4 text-text-secondary" })]
217
216
  }),
218
217
  /* @__PURE__ */ k("div", {
219
218
  className: "space-y-3",
220
219
  children: [
221
220
  /* @__PURE__ */ O("input", {
222
- value: J.label,
223
- onChange: (e) => Y((t) => ({
221
+ value: Y.label,
222
+ onChange: (e) => X((t) => ({
224
223
  ...t,
225
224
  label: e.target.value
226
225
  })),
@@ -228,18 +227,18 @@ var j = [
228
227
  className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
229
228
  }),
230
229
  /* @__PURE__ */ O("input", {
231
- value: J.productSlug,
232
- onChange: (e) => Y((t) => ({
230
+ value: Y.productSlug,
231
+ onChange: (e) => X((t) => ({
233
232
  ...t,
234
233
  productSlug: e.target.value
235
234
  })),
236
235
  placeholder: "Product slug (eg. bigconsole)",
237
236
  className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
238
- disabled: !!Q
237
+ disabled: !!$
239
238
  }),
240
239
  /* @__PURE__ */ O("input", {
241
- value: J.destinationPath,
242
- onChange: (e) => Y((t) => ({
240
+ value: Y.destinationPath,
241
+ onChange: (e) => X((t) => ({
243
242
  ...t,
244
243
  destinationPath: e.target.value
245
244
  })),
@@ -247,8 +246,8 @@ var j = [
247
246
  className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
248
247
  }),
249
248
  /* @__PURE__ */ O("input", {
250
- value: J.destinationUrl,
251
- onChange: (e) => Y((t) => ({
249
+ value: Y.destinationUrl,
250
+ onChange: (e) => X((t) => ({
252
251
  ...t,
253
252
  destinationUrl: e.target.value
254
253
  })),
@@ -256,8 +255,8 @@ var j = [
256
255
  className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
257
256
  }),
258
257
  /* @__PURE__ */ O("textarea", {
259
- value: J.description,
260
- onChange: (e) => Y((t) => ({
258
+ value: Y.description,
259
+ onChange: (e) => X((t) => ({
261
260
  ...t,
262
261
  description: e.target.value
263
262
  })),
@@ -265,8 +264,8 @@ var j = [
265
264
  className: "min-h-24 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary"
266
265
  }),
267
266
  /* @__PURE__ */ O("textarea", {
268
- value: J.notes,
269
- onChange: (e) => Y((t) => ({
267
+ value: Y.notes,
268
+ onChange: (e) => X((t) => ({
270
269
  ...t,
271
270
  notes: e.target.value
272
271
  })),
@@ -279,13 +278,13 @@ var j = [
279
278
  className: "mt-4 flex flex-wrap gap-3",
280
279
  children: [/* @__PURE__ */ O("button", {
281
280
  type: "button",
282
- onClick: () => void $(),
281
+ onClick: () => void ee(),
283
282
  className: "rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text",
284
- children: Q ? "Save changes" : "Create code"
285
- }), Q ? /* @__PURE__ */ O("button", {
283
+ children: $ ? "Save changes" : "Create code"
284
+ }), $ ? /* @__PURE__ */ O("button", {
286
285
  type: "button",
287
286
  onClick: () => {
288
- q(null), Y({
287
+ J(null), X({
289
288
  label: "",
290
289
  description: "",
291
290
  notes: "",
@@ -306,13 +305,13 @@ var j = [
306
305
  children: [/* @__PURE__ */ O("h2", {
307
306
  className: "mb-4 text-lg font-semibold text-text-primary",
308
307
  children: "My codes"
309
- }), I.length === 0 && !H ? /* @__PURE__ */ O(i, {
308
+ }), L.length === 0 && !U ? /* @__PURE__ */ O(i, {
310
309
  icon: /* @__PURE__ */ O(T, { className: "size-8" }),
311
310
  title: "No affiliate codes yet",
312
311
  description: "Create your first code to start tracking attributable journeys."
313
312
  }) : /* @__PURE__ */ O("div", {
314
313
  className: "space-y-4",
315
- children: I.map((e) => {
314
+ children: L.map((e) => {
316
315
  let t = e.destinationUrl || `https://${e.productSlug}.com${e.destinationPath || ""}?ref=${e.code}`;
317
316
  return /* @__PURE__ */ k("div", {
318
317
  className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
@@ -341,19 +340,19 @@ var j = [
341
340
  children: [
342
341
  /* @__PURE__ */ O("button", {
343
342
  type: "button",
344
- onClick: () => ee(e),
343
+ onClick: () => te(e),
345
344
  className: "rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary",
346
345
  children: "Edit"
347
346
  }),
348
347
  /* @__PURE__ */ k("button", {
349
348
  type: "button",
350
- onClick: () => void ne(e.id),
349
+ onClick: () => void re(e.id),
351
350
  className: "inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary",
352
351
  children: [/* @__PURE__ */ O(w, { className: "size-3.5" }), "Note"]
353
352
  }),
354
353
  e.status === "ACTIVE" ? /* @__PURE__ */ O("button", {
355
354
  type: "button",
356
- onClick: () => void te(e.id),
355
+ onClick: () => void ne(e.id),
357
356
  className: "rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text",
358
357
  children: "Deactivate"
359
358
  }) : null
@@ -418,14 +417,14 @@ var j = [
418
417
  children: [/* @__PURE__ */ O("h2", {
419
418
  className: "mb-4 text-lg font-semibold text-text-primary",
420
419
  children: "Recent attributed journeys"
421
- }), R.length === 0 ? /* @__PURE__ */ O(i, {
420
+ }), z.length === 0 ? /* @__PURE__ */ O(i, {
422
421
  icon: /* @__PURE__ */ O(D, { className: "size-8" }),
423
422
  title: "No journeys yet",
424
423
  description: "Journeys will appear as visitors land on your affiliate links."
425
- }) : /* @__PURE__ */ O(A, {
426
- data: R,
424
+ }) : /* @__PURE__ */ O(j, {
425
+ data: z,
427
426
  rowKey: (e) => e.id,
428
- columns: j
427
+ columns: M
429
428
  })]
430
429
  })]
431
430
  })]
@@ -434,6 +433,6 @@ var j = [
434
433
  });
435
434
  };
436
435
  //#endregion
437
- export { M as AffiliateDashboardPage };
436
+ export { N as AffiliateDashboardPage };
438
437
 
439
438
  //# sourceMappingURL=AffiliateDashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AffiliateDashboardPage.js","names":[],"sources":["../../../../../src/billing/modules/affiliate/pages/AffiliateDashboardPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type FC } from 'react';\nimport { Link2, Plus, RefreshCw, StickyNote, Ticket, TrendingUp, Users } from 'lucide-react';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n AccessDenied,\n EmptyState,\n PageHeader,\n ServerError,\n StatCard,\n} from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\n\nconst journeyColumns: ResponsiveTableColumn<AffiliateJourney>[] = [\n { key: 'code', header: 'Code', priority: 'primary', cell: (journey) => journey.codeValue },\n { key: 'product', header: 'Product', cell: (journey) => journey.productSlug },\n {\n key: 'path',\n header: 'Path',\n cell: (journey) => journey.currentPath || journey.landingPath || '-',\n },\n { key: 'country', header: 'Country', cell: (journey) => journey.geographyCountry || '-' },\n { key: 'status', header: 'Status', cell: (journey) => journey.status },\n {\n key: 'visited',\n header: 'Visited',\n cell: (journey) => formatDateTime(journey.lastVisitedAt),\n },\n];\nimport {\n addAffiliateCodeNote,\n createAffiliateCode,\n deactivateAffiliateCode,\n fetchMyAffiliateAnalytics,\n fetchMyAffiliateCodes,\n fetchMyAffiliateJourneys,\n updateAffiliateCode,\n type AffiliateCode,\n type AffiliateJourney,\n type AffiliateAnalyticsSummary,\n} from '../api';\n\nexport const AffiliateDashboardPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n\n const [codes, setCodes] = useState<AffiliateCode[]>([]);\n const [journeys, setJourneys] = useState<AffiliateJourney[]>([]);\n const [analytics, setAnalytics] = useState<AffiliateAnalyticsSummary | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [selectedCodeId, setSelectedCodeId] = useState<string | null>(null);\n const [form, setForm] = useState({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [loadedCodes, loadedAnalytics, loadedJourneys] = await Promise.all([\n fetchMyAffiliateCodes(requestContext),\n fetchMyAffiliateAnalytics(requestContext),\n fetchMyAffiliateJourneys(requestContext),\n ]);\n setCodes(loadedCodes);\n setAnalytics(loadedAnalytics);\n setJourneys(loadedJourneys);\n } catch (loadError) {\n setError(\n loadError instanceof Error ? loadError : new Error('Failed to load affiliate dashboard')\n );\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, [requestContext]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view affiliate analytics.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Affiliate service unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const selectedCode = codes.find((item) => item.id === selectedCodeId) ?? null;\n\n const handleSubmit = async () => {\n if (!form.productSlug.trim()) {\n setError(new Error('Product slug is required'));\n return;\n }\n\n try {\n if (selectedCode) {\n await updateAffiliateCode(\n selectedCode.id,\n {\n label: form.label,\n description: form.description,\n notes: form.notes,\n destinationPath: form.destinationPath,\n destinationUrl: form.destinationUrl,\n },\n requestContext\n );\n emit('billing.affiliate_code.updated', {\n route: '/billing/affiliate',\n entityId: selectedCode.id,\n source: 'affiliate-dashboard',\n });\n } else {\n const createdCode = await createAffiliateCode(\n {\n label: form.label,\n description: form.description,\n notes: form.notes,\n productSlug: form.productSlug,\n destinationPath: form.destinationPath,\n destinationUrl: form.destinationUrl,\n },\n requestContext\n );\n emit('billing.affiliate_code.created', {\n route: '/billing/affiliate',\n entityId: createdCode.id,\n source: 'affiliate-dashboard',\n });\n }\n\n setSelectedCodeId(null);\n setForm({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n await loadData();\n } catch (submitError) {\n setError(\n submitError instanceof Error ? submitError : new Error('Failed to save affiliate code')\n );\n }\n };\n\n const handleEdit = (code: AffiliateCode) => {\n setSelectedCodeId(code.id);\n setForm({\n label: code.label ?? '',\n description: code.description ?? '',\n notes: code.notes ?? '',\n productSlug: code.productSlug,\n destinationPath: code.destinationPath ?? '',\n destinationUrl: code.destinationUrl ?? '',\n });\n };\n\n const handleDeactivate = async (codeId: string) => {\n await deactivateAffiliateCode(codeId, requestContext);\n emit('billing.affiliate_code.deactivated', {\n route: '/billing/affiliate',\n entityId: codeId,\n source: 'affiliate-dashboard',\n });\n await loadData();\n };\n\n const handleQuickNote = async (codeId: string) => {\n const note = window.prompt('Add an internal note for this affiliate code');\n if (!note) return;\n await addAffiliateCodeNote(codeId, note, requestContext);\n emit('billing.affiliate_code.note_added', {\n route: '/billing/affiliate',\n entityId: codeId,\n source: 'affiliate-dashboard',\n });\n await loadData();\n };\n\n const metricCards = analytics\n ? [\n { title: 'Codes', value: analytics.totalCodes, icon: <Ticket className=\"size-5\" /> },\n { title: 'Visits', value: analytics.totalVisits, icon: <Users className=\"size-5\" /> },\n { title: 'Journeys', value: analytics.totalJourneys, icon: <Link2 className=\"size-5\" /> },\n {\n title: 'Revenue influenced',\n value: formatCurrency(analytics.totalRevenueAmount, 'USD'),\n icon: <TrendingUp className=\"size-5\" />,\n },\n ]\n : [];\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Affiliate codes\"\n description=\"Create referral codes, add internal notes, and monitor attributed journeys.\"\n actions={\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n }\n />\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : analytics ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {metricCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <div className=\"grid gap-6 xl:grid-cols-[1.1fr,1.9fr]\">\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {selectedCode ? 'Update affiliate code' : 'Create affiliate code'}\n </h2>\n {!selectedCode ? <Plus className=\"size-4 text-text-secondary\" /> : null}\n </div>\n\n <div className=\"space-y-3\">\n <input\n value={form.label}\n onChange={(event) =>\n setForm((current) => ({ ...current, label: event.target.value }))\n }\n placeholder=\"Label\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={form.productSlug}\n onChange={(event) =>\n setForm((current) => ({ ...current, productSlug: event.target.value }))\n }\n placeholder=\"Product slug (eg. bigconsole)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n disabled={Boolean(selectedCode)}\n />\n <input\n value={form.destinationPath}\n onChange={(event) =>\n setForm((current) => ({ ...current, destinationPath: event.target.value }))\n }\n placeholder=\"Destination path (eg. /pricing)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={form.destinationUrl}\n onChange={(event) =>\n setForm((current) => ({ ...current, destinationUrl: event.target.value }))\n }\n placeholder=\"Absolute destination URL (optional)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <textarea\n value={form.description}\n onChange={(event) =>\n setForm((current) => ({ ...current, description: event.target.value }))\n }\n placeholder=\"Description\"\n className=\"min-h-24 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <textarea\n value={form.notes}\n onChange={(event) =>\n setForm((current) => ({ ...current, notes: event.target.value }))\n }\n placeholder=\"Internal notes\"\n className=\"min-h-24 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-3\">\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {selectedCode ? 'Save changes' : 'Create code'}\n </button>\n {selectedCode ? (\n <button\n type=\"button\"\n onClick={() => {\n setSelectedCodeId(null);\n setForm({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n }}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-4 py-2 text-sm font-medium text-text-primary\"\n >\n Cancel\n </button>\n ) : null}\n </div>\n </section>\n\n <section className=\"space-y-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">My codes</h2>\n {codes.length === 0 && !loading ? (\n <EmptyState\n icon={<Ticket className=\"size-8\" />}\n title=\"No affiliate codes yet\"\n description=\"Create your first code to start tracking attributable journeys.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {codes.map((code) => {\n const shareUrl =\n code.destinationUrl ||\n `https://${code.productSlug}.com${code.destinationPath || ''}?ref=${code.code}`;\n return (\n <div\n key={code.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {code.label || code.code}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {code.code} · {code.productSlug}\n </p>\n <p className=\"mt-1 break-all text-xs text-text-secondary\">{shareUrl}</p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleEdit(code)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => void handleQuickNote(code.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n <StickyNote className=\"size-3.5\" />\n Note\n </button>\n {code.status === 'ACTIVE' ? (\n <button\n type=\"button\"\n onClick={() => void handleDeactivate(code.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n Deactivate\n </button>\n ) : null}\n </div>\n </div>\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2 xl:grid-cols-4\">\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Visits</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalVisits}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Signups</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalSignups}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Paid conversions</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalPaidConversions + code.totalStorePurchases}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Rewards earned</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {formatCurrency(code.totalRewardAmount, 'USD')}\n </p>\n </div>\n </div>\n {code.notes ? (\n <p className=\"mt-3 text-sm text-text-secondary\">{code.notes}</p>\n ) : null}\n </div>\n );\n })}\n </div>\n )}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n Recent attributed journeys\n </h2>\n {journeys.length === 0 ? (\n <EmptyState\n icon={<Users className=\"size-8\" />}\n title=\"No journeys yet\"\n description=\"Journeys will appear as visitors land on your affiliate links.\"\n />\n ) : (\n <ResponsiveTable\n data={journeys}\n rowKey={(journey) => journey.id}\n columns={journeyColumns}\n />\n )}\n </div>\n </section>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AffiliateDashboardPage.js","names":[],"sources":["../../../../../src/billing/modules/affiliate/pages/AffiliateDashboardPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type FC } from 'react';\nimport { Link2, Plus, RefreshCw, StickyNote, Ticket, TrendingUp, Users } from 'lucide-react';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n AccessDenied,\n EmptyState,\n PageHeader,\n ServerError,\n StatCard,\n} from '../../../shared/components';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\n\nconst journeyColumns: ResponsiveTableColumn<AffiliateJourney>[] = [\n { key: 'code', header: 'Code', priority: 'primary', cell: (journey) => journey.codeValue },\n { key: 'product', header: 'Product', cell: (journey) => journey.productSlug },\n {\n key: 'path',\n header: 'Path',\n cell: (journey) => journey.currentPath || journey.landingPath || '-',\n },\n { key: 'country', header: 'Country', cell: (journey) => journey.geographyCountry || '-' },\n { key: 'status', header: 'Status', cell: (journey) => journey.status },\n {\n key: 'visited',\n header: 'Visited',\n cell: (journey) => formatDateTime(journey.lastVisitedAt),\n },\n];\nimport {\n addAffiliateCodeNote,\n createAffiliateCode,\n deactivateAffiliateCode,\n fetchMyAffiliateAnalytics,\n fetchMyAffiliateCodes,\n fetchMyAffiliateJourneys,\n updateAffiliateCode,\n type AffiliateCode,\n type AffiliateJourney,\n type AffiliateAnalyticsSummary,\n} from '../api';\n\nexport const AffiliateDashboardPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n\n const [codes, setCodes] = useState<AffiliateCode[]>([]);\n const [journeys, setJourneys] = useState<AffiliateJourney[]>([]);\n const [analytics, setAnalytics] = useState<AffiliateAnalyticsSummary | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [selectedCodeId, setSelectedCodeId] = useState<string | null>(null);\n const [form, setForm] = useState({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [loadedCodes, loadedAnalytics, loadedJourneys] = await Promise.all([\n fetchMyAffiliateCodes(requestContext),\n fetchMyAffiliateAnalytics(requestContext),\n fetchMyAffiliateJourneys(requestContext),\n ]);\n setCodes(loadedCodes);\n setAnalytics(loadedAnalytics);\n setJourneys(loadedJourneys);\n } catch (loadError) {\n setError(\n loadError instanceof Error ? loadError : new Error('Failed to load affiliate dashboard')\n );\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, [requestContext]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view affiliate analytics.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Affiliate service unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const selectedCode = codes.find((item) => item.id === selectedCodeId) ?? null;\n\n const handleSubmit = async () => {\n if (!form.productSlug.trim()) {\n setError(new Error('Product slug is required'));\n return;\n }\n\n try {\n if (selectedCode) {\n await updateAffiliateCode(\n selectedCode.id,\n {\n label: form.label,\n description: form.description,\n notes: form.notes,\n destinationPath: form.destinationPath,\n destinationUrl: form.destinationUrl,\n },\n requestContext\n );\n emit('billing.affiliate_code.updated', {\n route: '/billing/affiliate',\n entityId: selectedCode.id,\n source: 'affiliate-dashboard',\n });\n } else {\n const createdCode = await createAffiliateCode(\n {\n label: form.label,\n description: form.description,\n notes: form.notes,\n productSlug: form.productSlug,\n destinationPath: form.destinationPath,\n destinationUrl: form.destinationUrl,\n },\n requestContext\n );\n emit('billing.affiliate_code.created', {\n route: '/billing/affiliate',\n entityId: createdCode.id,\n source: 'affiliate-dashboard',\n });\n }\n\n setSelectedCodeId(null);\n setForm({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n await loadData();\n } catch (submitError) {\n setError(\n submitError instanceof Error ? submitError : new Error('Failed to save affiliate code')\n );\n }\n };\n\n const handleEdit = (code: AffiliateCode) => {\n setSelectedCodeId(code.id);\n setForm({\n label: code.label ?? '',\n description: code.description ?? '',\n notes: code.notes ?? '',\n productSlug: code.productSlug,\n destinationPath: code.destinationPath ?? '',\n destinationUrl: code.destinationUrl ?? '',\n });\n };\n\n const handleDeactivate = async (codeId: string) => {\n await deactivateAffiliateCode(codeId, requestContext);\n emit('billing.affiliate_code.deactivated', {\n route: '/billing/affiliate',\n entityId: codeId,\n source: 'affiliate-dashboard',\n });\n await loadData();\n };\n\n const handleQuickNote = async (codeId: string) => {\n const note = window.prompt('Add an internal note for this affiliate code');\n if (!note) return;\n await addAffiliateCodeNote(codeId, note, requestContext);\n emit('billing.affiliate_code.note_added', {\n route: '/billing/affiliate',\n entityId: codeId,\n source: 'affiliate-dashboard',\n });\n await loadData();\n };\n\n const metricCards = analytics\n ? [\n { title: 'Codes', value: analytics.totalCodes, icon: <Ticket className=\"size-5\" /> },\n { title: 'Visits', value: analytics.totalVisits, icon: <Users className=\"size-5\" /> },\n { title: 'Journeys', value: analytics.totalJourneys, icon: <Link2 className=\"size-5\" /> },\n {\n title: 'Revenue influenced',\n value: formatCurrency(analytics.totalRevenueAmount, 'USD'),\n icon: <TrendingUp className=\"size-5\" />,\n },\n ]\n : [];\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Affiliate codes\"\n description=\"Create referral codes, add internal notes, and monitor attributed journeys.\"\n actions={\n <CTAOverflowMenu\n actions={[\n {\n label: 'Refresh',\n onSelect: () => void loadData(),\n icon: <RefreshCw className=\"size-4\" />,\n },\n ]}\n />\n }\n />\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : analytics ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {metricCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <div className=\"grid gap-6 xl:grid-cols-[1.1fr,1.9fr]\">\n <section className=\"rounded-lg border border-border-seam bg-bg-surface p-4 xl:sticky xl:top-6 xl:self-start\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {selectedCode ? 'Update affiliate code' : 'Create affiliate code'}\n </h2>\n {!selectedCode ? <Plus className=\"size-4 text-text-secondary\" /> : null}\n </div>\n\n <div className=\"space-y-3\">\n <input\n value={form.label}\n onChange={(event) =>\n setForm((current) => ({ ...current, label: event.target.value }))\n }\n placeholder=\"Label\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={form.productSlug}\n onChange={(event) =>\n setForm((current) => ({ ...current, productSlug: event.target.value }))\n }\n placeholder=\"Product slug (eg. bigconsole)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n disabled={Boolean(selectedCode)}\n />\n <input\n value={form.destinationPath}\n onChange={(event) =>\n setForm((current) => ({ ...current, destinationPath: event.target.value }))\n }\n placeholder=\"Destination path (eg. /pricing)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={form.destinationUrl}\n onChange={(event) =>\n setForm((current) => ({ ...current, destinationUrl: event.target.value }))\n }\n placeholder=\"Absolute destination URL (optional)\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <textarea\n value={form.description}\n onChange={(event) =>\n setForm((current) => ({ ...current, description: event.target.value }))\n }\n placeholder=\"Description\"\n className=\"min-h-24 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <textarea\n value={form.notes}\n onChange={(event) =>\n setForm((current) => ({ ...current, notes: event.target.value }))\n }\n placeholder=\"Internal notes\"\n className=\"min-h-24 w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n\n <div className=\"mt-4 flex flex-wrap gap-3\">\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n {selectedCode ? 'Save changes' : 'Create code'}\n </button>\n {selectedCode ? (\n <button\n type=\"button\"\n onClick={() => {\n setSelectedCodeId(null);\n setForm({\n label: '',\n description: '',\n notes: '',\n productSlug: '',\n destinationPath: '',\n destinationUrl: '',\n });\n }}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-4 py-2 text-sm font-medium text-text-primary\"\n >\n Cancel\n </button>\n ) : null}\n </div>\n </section>\n\n <section className=\"space-y-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">My codes</h2>\n {codes.length === 0 && !loading ? (\n <EmptyState\n icon={<Ticket className=\"size-8\" />}\n title=\"No affiliate codes yet\"\n description=\"Create your first code to start tracking attributable journeys.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {codes.map((code) => {\n const shareUrl =\n code.destinationUrl ||\n `https://${code.productSlug}.com${code.destinationPath || ''}?ref=${code.code}`;\n return (\n <div\n key={code.id}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-4\">\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">\n {code.label || code.code}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {code.code} · {code.productSlug}\n </p>\n <p className=\"mt-1 break-all text-xs text-text-secondary\">{shareUrl}</p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleEdit(code)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Edit\n </button>\n <button\n type=\"button\"\n onClick={() => void handleQuickNote(code.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n <StickyNote className=\"size-3.5\" />\n Note\n </button>\n {code.status === 'ACTIVE' ? (\n <button\n type=\"button\"\n onClick={() => void handleDeactivate(code.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n Deactivate\n </button>\n ) : null}\n </div>\n </div>\n <div className=\"mt-4 grid gap-3 sm:grid-cols-2 xl:grid-cols-4\">\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Visits</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalVisits}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Signups</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalSignups}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Paid conversions</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {code.totalPaidConversions + code.totalStorePurchases}\n </p>\n </div>\n <div className=\"rounded-md border border-border-subtle bg-bg-surface p-3\">\n <p className=\"text-xs text-text-secondary\">Rewards earned</p>\n <p className=\"text-lg font-semibold text-text-primary\">\n {formatCurrency(code.totalRewardAmount, 'USD')}\n </p>\n </div>\n </div>\n {code.notes ? (\n <p className=\"mt-3 text-sm text-text-secondary\">{code.notes}</p>\n ) : null}\n </div>\n );\n })}\n </div>\n )}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n Recent attributed journeys\n </h2>\n {journeys.length === 0 ? (\n <EmptyState\n icon={<Users className=\"size-8\" />}\n title=\"No journeys yet\"\n description=\"Journeys will appear as visitors land on your affiliate links.\"\n />\n ) : (\n <ResponsiveTable\n data={journeys}\n rowKey={(journey) => journey.id}\n columns={journeyColumns}\n />\n )}\n </div>\n </section>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}