@burdenoff/microfe-billing 2026.625.3 → 2026.625.5
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.
- package/dist/billing/lib/native-purchases.js +2 -44
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +192 -187
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +322 -317
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +190 -185
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +297 -292
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +60 -75
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +86 -101
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +124 -121
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +103 -111
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +196 -160
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +58 -73
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +65 -75
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +399 -399
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js +49 -48
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/UserRefundsPage.js +144 -151
- package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +430 -425
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +121 -93
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +154 -152
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +467 -462
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +294 -286
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +123 -117
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +43 -42
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +192 -207
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +40 -56
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +128 -121
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +165 -180
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +103 -100
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +175 -175
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +96 -96
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +42 -40
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +45 -38
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +339 -334
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +80 -74
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +342 -337
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +38 -53
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +60 -75
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +242 -237
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js +29 -39
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaPage.js +1 -0
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +299 -294
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +191 -186
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +308 -303
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +57 -78
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js +79 -78
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +15 -13
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +338 -299
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +82 -103
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +59 -54
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +172 -215
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/package.json +2 -2
- package/dist/billing/lib/native-purchases.js.map +0 -1
|
@@ -9,9 +9,9 @@ import { useEffect as s, useState as c } from "react";
|
|
|
9
9
|
import { ArrowLeft as l, BarChart2 as u, Calendar as d, ChevronLeft as f, ChevronRight as p, Edit as m, History as h, Package as g, Tag as _, Users as v } from "lucide-react";
|
|
10
10
|
import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
11
11
|
import { useI18n as S } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
12
|
-
import { CTAOverflowMenu as C,
|
|
12
|
+
import { CTAOverflowMenu as C, NextSteps as w, PagePurpose as T, ResponsiveTable as E } from "@burdenoff/fe-libs/ui";
|
|
13
13
|
//#region src/billing/modules/coupons/pages/CouponDetailPage.tsx
|
|
14
|
-
var
|
|
14
|
+
var D = [
|
|
15
15
|
{
|
|
16
16
|
key: "userId",
|
|
17
17
|
header: "User ID",
|
|
@@ -82,7 +82,7 @@ var T = [
|
|
|
82
82
|
cell: (e) => new Date(e.usedAt).toLocaleString()
|
|
83
83
|
}
|
|
84
84
|
];
|
|
85
|
-
function
|
|
85
|
+
function O({ status: e }) {
|
|
86
86
|
let { label: t, className: n } = {
|
|
87
87
|
[o.Active]: {
|
|
88
88
|
label: "Active",
|
|
@@ -109,7 +109,7 @@ function E({ status: e }) {
|
|
|
109
109
|
children: t
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
|
-
function
|
|
112
|
+
function k({ label: e, value: t }) {
|
|
113
113
|
return /* @__PURE__ */ x("div", {
|
|
114
114
|
className: "flex items-start gap-2 py-3 border-b border-border-subtle last:border-0",
|
|
115
115
|
children: [/* @__PURE__ */ b("span", {
|
|
@@ -121,29 +121,29 @@ function D({ label: e, value: t }) {
|
|
|
121
121
|
})]
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
|
-
var
|
|
125
|
-
let { t: o } = S(),
|
|
124
|
+
var A = () => {
|
|
125
|
+
let { t: o } = S(), A = (e, t) => {
|
|
126
126
|
let n = o(e);
|
|
127
127
|
return n === e ? t : n;
|
|
128
|
-
},
|
|
128
|
+
}, j = a(), M = n(), N = window.location.pathname.split("/").filter(Boolean).slice(-1)[0], [P, F] = c("details"), [I, L] = c(0), [R, { data: z, loading: B, error: V }] = r(), { data: H, loading: U } = i({
|
|
129
129
|
variables: {
|
|
130
|
-
couponId:
|
|
130
|
+
couponId: N,
|
|
131
131
|
limit: 20,
|
|
132
|
-
offset:
|
|
132
|
+
offset: I * 20
|
|
133
133
|
},
|
|
134
|
-
skip: !
|
|
134
|
+
skip: !N || P !== "usage"
|
|
135
135
|
});
|
|
136
136
|
if (s(() => {
|
|
137
|
-
|
|
138
|
-
}, [
|
|
139
|
-
if (
|
|
137
|
+
N && R({ variables: { id: N } });
|
|
138
|
+
}, [N, R]), !M.canManageDiscounts) return /* @__PURE__ */ b(e, { message: "You don't have permission to view coupon details." });
|
|
139
|
+
if (B) return /* @__PURE__ */ x("div", {
|
|
140
140
|
className: "p-8",
|
|
141
141
|
children: [/* @__PURE__ */ b(t, {
|
|
142
|
-
title:
|
|
142
|
+
title: A("billing.coupons.detailTitle", "Coupon Details"),
|
|
143
143
|
description: "Loading...",
|
|
144
144
|
actions: /* @__PURE__ */ x("button", {
|
|
145
145
|
type: "button",
|
|
146
|
-
onClick: () =>
|
|
146
|
+
onClick: () => j("/coupons"),
|
|
147
147
|
className: "px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2",
|
|
148
148
|
children: [/* @__PURE__ */ b(l, { className: "size-4" }), "Back"]
|
|
149
149
|
})
|
|
@@ -152,88 +152,116 @@ var O = () => {
|
|
|
152
152
|
children: /* @__PURE__ */ b("div", { className: "size-8 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent" })
|
|
153
153
|
})]
|
|
154
154
|
});
|
|
155
|
-
if (
|
|
155
|
+
if (V || !z?.getCoupon) return /* @__PURE__ */ x("div", {
|
|
156
156
|
className: "p-8",
|
|
157
157
|
children: [/* @__PURE__ */ b(t, {
|
|
158
158
|
title: "Coupon Details",
|
|
159
159
|
description: "Coupon not found",
|
|
160
160
|
actions: /* @__PURE__ */ x("button", {
|
|
161
161
|
type: "button",
|
|
162
|
-
onClick: () =>
|
|
162
|
+
onClick: () => j("/coupons"),
|
|
163
163
|
className: "px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2",
|
|
164
164
|
children: [/* @__PURE__ */ b(l, { className: "size-4" }), "Back"]
|
|
165
165
|
})
|
|
166
166
|
}), /* @__PURE__ */ b("div", {
|
|
167
167
|
className: "flex items-center justify-center h-64 text-status-error-text text-sm",
|
|
168
|
-
children:
|
|
168
|
+
children: V ? `Error: ${V.message}` : "Coupon not found"
|
|
169
169
|
})]
|
|
170
170
|
});
|
|
171
|
-
let
|
|
171
|
+
let W = z.getCoupon, G = W.maxTotalUses && W.maxTotalUses > 0 ? Math.round(W.currentUses / W.maxTotalUses * 100) : null, K = [
|
|
172
|
+
{
|
|
173
|
+
id: "edit",
|
|
174
|
+
label: "Edit this coupon",
|
|
175
|
+
description: "Adjust the discount, limits, expiry or applicable products.",
|
|
176
|
+
onClick: () => j(`/coupons/${W.id}/edit`)
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: "usage",
|
|
180
|
+
label: "Review who has redeemed it",
|
|
181
|
+
description: "Open the Usage History tab to see every redemption.",
|
|
182
|
+
onClick: () => F("usage")
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "back",
|
|
186
|
+
label: "Manage all coupons",
|
|
187
|
+
description: "Return to the full list of discount codes.",
|
|
188
|
+
onClick: () => j("/coupons")
|
|
189
|
+
}
|
|
190
|
+
], q = (e) => e ? new Date(e).toLocaleDateString(void 0, {
|
|
172
191
|
year: "numeric",
|
|
173
192
|
month: "short",
|
|
174
193
|
day: "numeric"
|
|
175
|
-
}) : null,
|
|
194
|
+
}) : null, J = () => W.type === "PERCENTAGE" ? `${W.value}%` : `${W.value}${W.currency ? ` ${W.currency}` : ""}`;
|
|
176
195
|
return /* @__PURE__ */ x("div", {
|
|
177
196
|
className: "p-8",
|
|
178
197
|
children: [
|
|
179
198
|
/* @__PURE__ */ b(t, {
|
|
180
|
-
title:
|
|
181
|
-
description:
|
|
199
|
+
title: W.name || W.code,
|
|
200
|
+
description: W.description || `Coupon code: ${W.code}`,
|
|
182
201
|
actions: /* @__PURE__ */ b(C, {
|
|
183
202
|
primary: {
|
|
184
203
|
label: "Edit",
|
|
185
|
-
onSelect: () =>
|
|
204
|
+
onSelect: () => j(`/coupons/${W.id}/edit`),
|
|
186
205
|
icon: /* @__PURE__ */ b(m, { className: "size-4" })
|
|
187
206
|
},
|
|
188
207
|
actions: [{
|
|
189
208
|
label: "Back to coupons",
|
|
190
|
-
onSelect: () =>
|
|
209
|
+
onSelect: () => j("/coupons"),
|
|
191
210
|
icon: /* @__PURE__ */ b(l, { className: "size-4" })
|
|
192
211
|
}]
|
|
193
212
|
})
|
|
194
213
|
}),
|
|
214
|
+
/* @__PURE__ */ b(T, {
|
|
215
|
+
className: "mt-2",
|
|
216
|
+
children: "Everything about this coupon — its discount, validity window, usage limits and the full redemption history. Use it to check how it is performing, edit its terms, or stop it being redeemed."
|
|
217
|
+
}),
|
|
218
|
+
/* @__PURE__ */ b(w, {
|
|
219
|
+
storageKey: "billing-coupon-detail",
|
|
220
|
+
steps: K,
|
|
221
|
+
className: "mt-4"
|
|
222
|
+
}),
|
|
195
223
|
/* @__PURE__ */ b("div", {
|
|
196
224
|
className: "mt-6 border-b border-border-subtle flex gap-1",
|
|
197
225
|
children: ["details", "usage"].map((e) => /* @__PURE__ */ x("button", {
|
|
198
226
|
type: "button",
|
|
199
|
-
onClick: () =>
|
|
200
|
-
className: `flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${
|
|
201
|
-
children: [b(e === "details" ? _ : h, { className: "size-4" }), e === "details" ? "Details" : `Usage History${
|
|
227
|
+
onClick: () => F(e),
|
|
228
|
+
className: `flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${P === e ? "border-action-primary-bg text-text-primary" : "border-transparent text-text-muted hover:text-text-primary"}`,
|
|
229
|
+
children: [b(e === "details" ? _ : h, { className: "size-4" }), e === "details" ? "Details" : `Usage History${H ? ` (${H.getCouponUsageHistory.total})` : ""}`]
|
|
202
230
|
}, e))
|
|
203
231
|
}),
|
|
204
|
-
|
|
232
|
+
P === "usage" && /* @__PURE__ */ b("div", {
|
|
205
233
|
className: "mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden",
|
|
206
|
-
children:
|
|
234
|
+
children: U ? /* @__PURE__ */ b("div", {
|
|
207
235
|
className: "flex items-center justify-center h-40",
|
|
208
236
|
children: /* @__PURE__ */ b("div", { className: "size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent" })
|
|
209
|
-
}) :
|
|
210
|
-
data:
|
|
237
|
+
}) : H?.getCouponUsageHistory.usages.length ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(E, {
|
|
238
|
+
data: H.getCouponUsageHistory.usages,
|
|
211
239
|
rowKey: (e) => e.id,
|
|
212
|
-
columns:
|
|
213
|
-
}), (
|
|
240
|
+
columns: D
|
|
241
|
+
}), (H.getCouponUsageHistory.total ?? 0) > 20 && /* @__PURE__ */ x("div", {
|
|
214
242
|
className: "flex items-center justify-between p-4 border-t border-border-subtle",
|
|
215
243
|
children: [/* @__PURE__ */ x("p", {
|
|
216
244
|
className: "text-sm text-text-muted",
|
|
217
245
|
children: [
|
|
218
|
-
|
|
246
|
+
I * 20 + 1,
|
|
219
247
|
"–",
|
|
220
|
-
Math.min((
|
|
248
|
+
Math.min((I + 1) * 20, H.getCouponUsageHistory.total),
|
|
221
249
|
" ",
|
|
222
250
|
"of ",
|
|
223
|
-
|
|
251
|
+
H.getCouponUsageHistory.total
|
|
224
252
|
]
|
|
225
253
|
}), /* @__PURE__ */ x("div", {
|
|
226
254
|
className: "flex items-center gap-2",
|
|
227
255
|
children: [/* @__PURE__ */ b("button", {
|
|
228
256
|
type: "button",
|
|
229
|
-
onClick: () =>
|
|
230
|
-
disabled:
|
|
257
|
+
onClick: () => L((e) => Math.max(0, e - 1)),
|
|
258
|
+
disabled: I === 0,
|
|
231
259
|
className: "p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40",
|
|
232
260
|
children: /* @__PURE__ */ b(f, { className: "size-4" })
|
|
233
261
|
}), /* @__PURE__ */ b("button", {
|
|
234
262
|
type: "button",
|
|
235
|
-
onClick: () =>
|
|
236
|
-
disabled: !
|
|
263
|
+
onClick: () => L((e) => e + 1),
|
|
264
|
+
disabled: !H.getCouponUsageHistory.hasMore,
|
|
237
265
|
className: "p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40",
|
|
238
266
|
children: /* @__PURE__ */ b(p, { className: "size-4" })
|
|
239
267
|
})]
|
|
@@ -243,7 +271,7 @@ var O = () => {
|
|
|
243
271
|
children: "No usage recorded for this coupon yet."
|
|
244
272
|
})
|
|
245
273
|
}),
|
|
246
|
-
|
|
274
|
+
P === "details" && /* @__PURE__ */ x("div", {
|
|
247
275
|
className: "mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
248
276
|
children: [
|
|
249
277
|
/* @__PURE__ */ x("div", {
|
|
@@ -259,7 +287,7 @@ var O = () => {
|
|
|
259
287
|
})]
|
|
260
288
|
}), /* @__PURE__ */ b("p", {
|
|
261
289
|
className: "text-lg font-mono font-bold text-text-primary",
|
|
262
|
-
children:
|
|
290
|
+
children: W.code
|
|
263
291
|
})]
|
|
264
292
|
}),
|
|
265
293
|
/* @__PURE__ */ x("div", {
|
|
@@ -274,11 +302,11 @@ var O = () => {
|
|
|
274
302
|
}),
|
|
275
303
|
/* @__PURE__ */ b("p", {
|
|
276
304
|
className: "text-lg font-bold text-text-primary",
|
|
277
|
-
children:
|
|
305
|
+
children: J()
|
|
278
306
|
}),
|
|
279
307
|
/* @__PURE__ */ b("p", {
|
|
280
308
|
className: "text-xs text-text-muted capitalize",
|
|
281
|
-
children:
|
|
309
|
+
children: W.type.replace("_", " ").toLowerCase()
|
|
282
310
|
})
|
|
283
311
|
]
|
|
284
312
|
}),
|
|
@@ -294,13 +322,13 @@ var O = () => {
|
|
|
294
322
|
}),
|
|
295
323
|
/* @__PURE__ */ x("p", {
|
|
296
324
|
className: "text-lg font-bold text-text-primary",
|
|
297
|
-
children: [
|
|
325
|
+
children: [W.currentUses, W.maxTotalUses ? ` / ${W.maxTotalUses}` : ""]
|
|
298
326
|
}),
|
|
299
|
-
|
|
327
|
+
G !== null && /* @__PURE__ */ b("div", {
|
|
300
328
|
className: "mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden",
|
|
301
329
|
children: /* @__PURE__ */ b("div", {
|
|
302
330
|
className: "h-full bg-action-primary-bg rounded-full",
|
|
303
|
-
style: { width: `${Math.min(
|
|
331
|
+
style: { width: `${Math.min(G, 100)}%` }
|
|
304
332
|
})
|
|
305
333
|
})
|
|
306
334
|
]
|
|
@@ -317,11 +345,11 @@ var O = () => {
|
|
|
317
345
|
}),
|
|
318
346
|
/* @__PURE__ */ b("div", {
|
|
319
347
|
className: "mt-1",
|
|
320
|
-
children: /* @__PURE__ */ b(
|
|
348
|
+
children: /* @__PURE__ */ b(O, { status: W.status })
|
|
321
349
|
}),
|
|
322
|
-
|
|
350
|
+
W.validUntil && /* @__PURE__ */ x("p", {
|
|
323
351
|
className: "text-xs text-text-muted mt-1",
|
|
324
|
-
children: ["Expires ", W
|
|
352
|
+
children: ["Expires ", q(W.validUntil)]
|
|
325
353
|
})
|
|
326
354
|
]
|
|
327
355
|
})
|
|
@@ -336,36 +364,36 @@ var O = () => {
|
|
|
336
364
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
337
365
|
children: "Coupon Details"
|
|
338
366
|
}),
|
|
339
|
-
/* @__PURE__ */ b(
|
|
367
|
+
/* @__PURE__ */ b(k, {
|
|
340
368
|
label: "Code",
|
|
341
369
|
value: /* @__PURE__ */ b("span", {
|
|
342
370
|
className: "font-mono",
|
|
343
|
-
children:
|
|
371
|
+
children: W.code
|
|
344
372
|
})
|
|
345
373
|
}),
|
|
346
|
-
/* @__PURE__ */ b(
|
|
374
|
+
/* @__PURE__ */ b(k, {
|
|
347
375
|
label: "Name",
|
|
348
|
-
value:
|
|
376
|
+
value: W.name
|
|
349
377
|
}),
|
|
350
|
-
/* @__PURE__ */ b(
|
|
378
|
+
/* @__PURE__ */ b(k, {
|
|
351
379
|
label: "Description",
|
|
352
|
-
value:
|
|
380
|
+
value: W.description
|
|
353
381
|
}),
|
|
354
|
-
/* @__PURE__ */ b(
|
|
382
|
+
/* @__PURE__ */ b(k, {
|
|
355
383
|
label: "Type",
|
|
356
|
-
value:
|
|
384
|
+
value: W.type.replace("_", " ").toLowerCase()
|
|
357
385
|
}),
|
|
358
|
-
/* @__PURE__ */ b(
|
|
386
|
+
/* @__PURE__ */ b(k, {
|
|
359
387
|
label: "Value",
|
|
360
|
-
value:
|
|
388
|
+
value: J()
|
|
361
389
|
}),
|
|
362
|
-
/* @__PURE__ */ b(
|
|
390
|
+
/* @__PURE__ */ b(k, {
|
|
363
391
|
label: "Scope",
|
|
364
|
-
value:
|
|
392
|
+
value: W.scope
|
|
365
393
|
}),
|
|
366
|
-
/* @__PURE__ */ b(
|
|
394
|
+
/* @__PURE__ */ b(k, {
|
|
367
395
|
label: "Status",
|
|
368
|
-
value: /* @__PURE__ */ b(
|
|
396
|
+
value: /* @__PURE__ */ b(O, { status: W.status })
|
|
369
397
|
})
|
|
370
398
|
]
|
|
371
399
|
}), /* @__PURE__ */ x("div", {
|
|
@@ -375,32 +403,32 @@ var O = () => {
|
|
|
375
403
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
376
404
|
children: "Restrictions"
|
|
377
405
|
}),
|
|
378
|
-
/* @__PURE__ */ b(
|
|
406
|
+
/* @__PURE__ */ b(k, {
|
|
379
407
|
label: "Min Purchase Amount",
|
|
380
|
-
value:
|
|
408
|
+
value: W.minPurchaseAmount == null ? null : `${W.minPurchaseAmount}${W.currency ? ` ${W.currency}` : ""}`
|
|
381
409
|
}),
|
|
382
|
-
/* @__PURE__ */ b(
|
|
410
|
+
/* @__PURE__ */ b(k, {
|
|
383
411
|
label: "Max Discount Amount",
|
|
384
|
-
value:
|
|
412
|
+
value: W.maxDiscountAmount == null ? null : `${W.maxDiscountAmount}${W.currency ? ` ${W.currency}` : ""}`
|
|
385
413
|
}),
|
|
386
|
-
/* @__PURE__ */ b(
|
|
414
|
+
/* @__PURE__ */ b(k, {
|
|
387
415
|
label: "Max Uses Per User",
|
|
388
|
-
value:
|
|
416
|
+
value: W.maxUsesPerUser
|
|
389
417
|
}),
|
|
390
|
-
/* @__PURE__ */ b(
|
|
418
|
+
/* @__PURE__ */ b(k, {
|
|
391
419
|
label: "Restricted Users",
|
|
392
|
-
value:
|
|
420
|
+
value: W.restrictedToUserIds?.length ? /* @__PURE__ */ b("span", {
|
|
393
421
|
className: "font-mono text-xs break-all",
|
|
394
|
-
children:
|
|
422
|
+
children: W.restrictedToUserIds.join(", ")
|
|
395
423
|
}) : "No restrictions"
|
|
396
424
|
}),
|
|
397
|
-
/* @__PURE__ */ b(
|
|
425
|
+
/* @__PURE__ */ b(k, {
|
|
398
426
|
label: "Applicable Products",
|
|
399
|
-
value:
|
|
427
|
+
value: W.applicableProducts?.length ? W.applicableProducts.join(", ") : "All products"
|
|
400
428
|
}),
|
|
401
|
-
/* @__PURE__ */ b(
|
|
429
|
+
/* @__PURE__ */ b(k, {
|
|
402
430
|
label: "Excluded Products",
|
|
403
|
-
value:
|
|
431
|
+
value: W.excludedProducts?.length ? W.excludedProducts.join(", ") : "None"
|
|
404
432
|
})
|
|
405
433
|
]
|
|
406
434
|
})]
|
|
@@ -415,33 +443,33 @@ var O = () => {
|
|
|
415
443
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
416
444
|
children: "Validity"
|
|
417
445
|
}),
|
|
418
|
-
/* @__PURE__ */ b(
|
|
446
|
+
/* @__PURE__ */ b(k, {
|
|
419
447
|
label: "Valid From",
|
|
420
|
-
value: W
|
|
448
|
+
value: q(W.validFrom)
|
|
421
449
|
}),
|
|
422
|
-
/* @__PURE__ */ b(
|
|
450
|
+
/* @__PURE__ */ b(k, {
|
|
423
451
|
label: "Valid Until",
|
|
424
|
-
value: W
|
|
452
|
+
value: q(W.validUntil) ?? "No expiry"
|
|
425
453
|
})
|
|
426
454
|
]
|
|
427
455
|
}),
|
|
428
|
-
|
|
456
|
+
W.campaignId && /* @__PURE__ */ x("div", {
|
|
429
457
|
className: "bg-bg-surface border border-border-subtle rounded-lg p-6",
|
|
430
458
|
children: [
|
|
431
459
|
/* @__PURE__ */ b("h3", {
|
|
432
460
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
433
461
|
children: "Campaign"
|
|
434
462
|
}),
|
|
435
|
-
/* @__PURE__ */ b(
|
|
463
|
+
/* @__PURE__ */ b(k, {
|
|
436
464
|
label: "Campaign ID",
|
|
437
465
|
value: /* @__PURE__ */ b("span", {
|
|
438
466
|
className: "font-mono text-xs",
|
|
439
|
-
children:
|
|
467
|
+
children: W.campaignId
|
|
440
468
|
})
|
|
441
469
|
}),
|
|
442
|
-
/* @__PURE__ */ b(
|
|
470
|
+
/* @__PURE__ */ b(k, {
|
|
443
471
|
label: "Campaign Name",
|
|
444
|
-
value:
|
|
472
|
+
value: W.campaignName
|
|
445
473
|
})
|
|
446
474
|
]
|
|
447
475
|
}),
|
|
@@ -452,17 +480,17 @@ var O = () => {
|
|
|
452
480
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
453
481
|
children: [/* @__PURE__ */ b(g, { className: "size-4 inline mr-1" }), "Audit"]
|
|
454
482
|
}),
|
|
455
|
-
/* @__PURE__ */ b(
|
|
483
|
+
/* @__PURE__ */ b(k, {
|
|
456
484
|
label: "Created",
|
|
457
|
-
value: W
|
|
485
|
+
value: q(W.createdAt)
|
|
458
486
|
}),
|
|
459
|
-
/* @__PURE__ */ b(
|
|
487
|
+
/* @__PURE__ */ b(k, {
|
|
460
488
|
label: "Last Updated",
|
|
461
|
-
value: W
|
|
489
|
+
value: q(W.updatedAt)
|
|
462
490
|
}),
|
|
463
|
-
/* @__PURE__ */ b(
|
|
491
|
+
/* @__PURE__ */ b(k, {
|
|
464
492
|
label: "Created By",
|
|
465
|
-
value:
|
|
493
|
+
value: W.createdBy ?? null
|
|
466
494
|
})
|
|
467
495
|
]
|
|
468
496
|
})
|
|
@@ -474,6 +502,6 @@ var O = () => {
|
|
|
474
502
|
});
|
|
475
503
|
};
|
|
476
504
|
//#endregion
|
|
477
|
-
export {
|
|
505
|
+
export { A as CouponDetailPage };
|
|
478
506
|
|
|
479
507
|
//# sourceMappingURL=CouponDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CouponDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/coupons/pages/CouponDetailPage.tsx"],"sourcesContent":["import { type FC, useEffect, useState } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport {\n ArrowLeft,\n Edit,\n Tag,\n Calendar,\n Users,\n Package,\n BarChart2,\n History,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport {\n useGetCouponLazyQuery,\n useGetCouponUsageHistoryQuery,\n} from '../../../../generated/global-operations';\nimport { Coupon, CouponStatus, CouponUsage } from '../../../../generated/global-types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\n\nconst couponUsageColumns: ResponsiveTableColumn<CouponUsage>[] = [\n {\n key: 'userId',\n header: 'User ID',\n priority: 'primary',\n cell: (u) => <span className=\"font-mono\">{u.userId.slice(0, 12)}…</span>,\n },\n {\n key: 'transaction',\n header: 'Transaction',\n cell: (u) =>\n u.transactionId ? (\n <span className=\"font-mono text-xs text-text-link\">{u.transactionId.slice(0, 12)}…</span>\n ) : u.orderId ? (\n <span className=\"text-xs text-text-muted\">Order: {u.orderId.slice(0, 12)}…</span>\n ) : (\n <span className=\"text-text-muted\">, </span>\n ),\n },\n {\n key: 'original',\n header: 'Original',\n cell: (u) => (\n <span className=\"tabular-nums\">\n {u.originalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'discount',\n header: 'Discount',\n cell: (u) => (\n <span className=\"tabular-nums text-status-success-text font-medium\">\n -{u.discountValue.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'final',\n header: 'Final',\n cell: (u) => (\n <span className=\"tabular-nums font-medium\">\n {u.finalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'usedAt',\n header: 'Used At',\n cell: (u) => new Date(u.usedAt).toLocaleString(),\n },\n];\n\nfunction StatusBadge({ status }: { status: CouponStatus }) {\n const map: Record<CouponStatus, { label: string; className: string }> = {\n [CouponStatus.Active]: {\n label: 'Active',\n className:\n 'bg-status-success-bg-subtle text-status-success-text border-status-success-bg-subtle',\n },\n [CouponStatus.Inactive]: {\n label: 'Inactive',\n className: 'bg-bg-sunken text-text-muted border-border-subtle',\n },\n [CouponStatus.Expired]: {\n label: 'Expired',\n className:\n 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-bg-subtle',\n },\n [CouponStatus.Depleted]: {\n label: 'Depleted',\n className: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n },\n };\n const { label, className } = map[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-muted',\n };\n return (\n <span\n className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ${className}`}\n >\n {label}\n </span>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-start gap-2 py-3 border-b border-border-subtle last:border-0\">\n <span className=\"text-sm text-text-muted w-44 shrink-0\">{label}</span>\n <span className=\"text-sm text-text-primary font-medium flex-1\">{value ?? '—'}</span>\n </div>\n );\n}\n\nexport const CouponDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n\n const couponId = window.location.pathname.split('/').filter(Boolean).slice(-1)[0];\n const [activeTab, setActiveTab] = useState<'details' | 'usage'>('details');\n const [usagePage, setUsagePage] = useState(0);\n const USAGE_PAGE_SIZE = 20;\n\n const [getCoupon, { data, loading, error }] = useGetCouponLazyQuery();\n\n const { data: usageData, loading: usageLoading } = useGetCouponUsageHistoryQuery({\n variables: { couponId, limit: USAGE_PAGE_SIZE, offset: usagePage * USAGE_PAGE_SIZE },\n skip: !couponId || activeTab !== 'usage',\n });\n\n useEffect(() => {\n if (couponId) {\n getCoupon({ variables: { id: couponId } });\n }\n }, [couponId, getCoupon]);\n\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to view coupon details.\" />;\n }\n\n if (loading) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title={tr('billing.coupons.detailTitle', 'Coupon Details')}\n description=\"Loading...\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n </div>\n );\n }\n\n if (error || !data?.getCoupon) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title=\"Coupon Details\"\n description=\"Coupon not found\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64 text-status-error-text text-sm\">\n {error ? `Error: ${error.message}` : 'Coupon not found'}\n </div>\n </div>\n );\n }\n\n const coupon = data.getCoupon as Coupon;\n const usagePercent =\n coupon.maxTotalUses && coupon.maxTotalUses > 0\n ? Math.round((coupon.currentUses / coupon.maxTotalUses) * 100)\n : null;\n\n const formatDate = (d: string | null | undefined) =>\n d\n ? new Date(d).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n : null;\n\n const formatValue = () =>\n coupon.type === 'PERCENTAGE'\n ? `${coupon.value}%`\n : `${coupon.value}${coupon.currency ? ` ${coupon.currency}` : ''}`;\n\n return (\n <div className=\"p-8\">\n <PageHeader\n title={coupon.name || coupon.code}\n description={coupon.description || `Coupon code: ${coupon.code}`}\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Edit',\n onSelect: () => navigateTo(`/coupons/${coupon.id}/edit`),\n icon: <Edit className=\"size-4\" />,\n }}\n actions={[\n {\n label: 'Back to coupons',\n onSelect: () => navigateTo('/coupons'),\n icon: <ArrowLeft className=\"size-4\" />,\n },\n ]}\n />\n }\n />\n\n {/* Tabs */}\n <div className=\"mt-6 border-b border-border-subtle flex gap-1\">\n {(['details', 'usage'] as const).map((tab) => (\n <button\n type=\"button\"\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${\n activeTab === tab\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab === 'details' ? <Tag className=\"size-4\" /> : <History className=\"size-4\" />}\n {tab === 'details'\n ? 'Details'\n : `Usage History${usageData ? ` (${usageData.getCouponUsageHistory.total})` : ''}`}\n </button>\n ))}\n </div>\n\n {activeTab === 'usage' && (\n <div className=\"mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden\">\n {usageLoading ? (\n <div className=\"flex items-center justify-center h-40\">\n <div className=\"size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n ) : !usageData?.getCouponUsageHistory.usages.length ? (\n <div className=\"p-8 text-center text-sm text-text-muted\">\n No usage recorded for this coupon yet.\n </div>\n ) : (\n <>\n <ResponsiveTable\n data={usageData.getCouponUsageHistory.usages}\n rowKey={(u) => u.id}\n columns={couponUsageColumns}\n />\n {(usageData.getCouponUsageHistory.total ?? 0) > USAGE_PAGE_SIZE && (\n <div className=\"flex items-center justify-between p-4 border-t border-border-subtle\">\n <p className=\"text-sm text-text-muted\">\n {usagePage * USAGE_PAGE_SIZE + 1}–\n {Math.min(\n (usagePage + 1) * USAGE_PAGE_SIZE,\n usageData.getCouponUsageHistory.total\n )}{' '}\n of {usageData.getCouponUsageHistory.total}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => Math.max(0, p - 1))}\n disabled={usagePage === 0}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => p + 1)}\n disabled={!usageData.getCouponUsageHistory.hasMore}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n\n {activeTab === 'details' && (\n <div className=\"mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Summary cards */}\n <div className=\"lg:col-span-3 grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Tag className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Code</span>\n </div>\n <p className=\"text-lg font-mono font-bold text-text-primary\">{coupon.code}</p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <BarChart2 className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Discount</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">{formatValue()}</p>\n <p className=\"text-xs text-text-muted capitalize\">\n {coupon.type.replace('_', ' ').toLowerCase()}\n </p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Users className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Usage</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">\n {coupon.currentUses}\n {coupon.maxTotalUses ? ` / ${coupon.maxTotalUses}` : ''}\n </p>\n {usagePercent !== null && (\n <div className=\"mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-action-primary-bg rounded-full\"\n style={{ width: `${Math.min(usagePercent, 100)}%` }}\n />\n </div>\n )}\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Calendar className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Status</span>\n </div>\n <div className=\"mt-1\">\n <StatusBadge status={coupon.status} />\n </div>\n {coupon.validUntil && (\n <p className=\"text-xs text-text-muted mt-1\">\n Expires {formatDate(coupon.validUntil)}\n </p>\n )}\n </div>\n </div>\n\n {/* Main details */}\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Coupon Details\n </h3>\n <DetailRow label=\"Code\" value={<span className=\"font-mono\">{coupon.code}</span>} />\n <DetailRow label=\"Name\" value={coupon.name} />\n <DetailRow label=\"Description\" value={coupon.description} />\n <DetailRow label=\"Type\" value={coupon.type.replace('_', ' ').toLowerCase()} />\n <DetailRow label=\"Value\" value={formatValue()} />\n <DetailRow label=\"Scope\" value={coupon.scope} />\n <DetailRow label=\"Status\" value={<StatusBadge status={coupon.status} />} />\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Restrictions\n </h3>\n <DetailRow\n label=\"Min Purchase Amount\"\n value={\n coupon.minPurchaseAmount != null\n ? `${coupon.minPurchaseAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow\n label=\"Max Discount Amount\"\n value={\n coupon.maxDiscountAmount != null\n ? `${coupon.maxDiscountAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow label=\"Max Uses Per User\" value={coupon.maxUsesPerUser} />\n <DetailRow\n label=\"Restricted Users\"\n value={\n coupon.restrictedToUserIds?.length ? (\n <span className=\"font-mono text-xs break-all\">\n {(coupon.restrictedToUserIds as string[]).join(', ')}\n </span>\n ) : (\n 'No restrictions'\n )\n }\n />\n <DetailRow\n label=\"Applicable Products\"\n value={\n coupon.applicableProducts?.length\n ? (coupon.applicableProducts as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Excluded Products\"\n value={\n coupon.excludedProducts?.length\n ? (coupon.excludedProducts as string[]).join(', ')\n : 'None'\n }\n />\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Validity\n </h3>\n <DetailRow label=\"Valid From\" value={formatDate(coupon.validFrom)} />\n <DetailRow label=\"Valid Until\" value={formatDate(coupon.validUntil) ?? 'No expiry'} />\n </div>\n\n {coupon.campaignId && (\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Campaign\n </h3>\n <DetailRow\n label=\"Campaign ID\"\n value={<span className=\"font-mono text-xs\">{coupon.campaignId}</span>}\n />\n <DetailRow label=\"Campaign Name\" value={coupon.campaignName} />\n </div>\n )}\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n <Package className=\"size-4 inline mr-1\" />\n Audit\n </h3>\n <DetailRow label=\"Created\" value={formatDate(coupon.createdAt)} />\n <DetailRow label=\"Last Updated\" value={formatDate(coupon.updatedAt)} />\n <DetailRow label=\"Created By\" value={coupon.createdBy ?? null} />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CouponDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/coupons/pages/CouponDetailPage.tsx"],"sourcesContent":["import { type FC, useEffect, useState } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport {\n ArrowLeft,\n Edit,\n Tag,\n Calendar,\n Users,\n Package,\n BarChart2,\n History,\n ChevronLeft,\n ChevronRight,\n} from 'lucide-react';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport {\n useGetCouponLazyQuery,\n useGetCouponUsageHistoryQuery,\n} from '../../../../generated/global-operations';\nimport { Coupon, CouponStatus, CouponUsage } from '../../../../generated/global-types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n NextSteps,\n type NextStep,\n} from '@burdenoff/fe-libs/ui';\n\nconst couponUsageColumns: ResponsiveTableColumn<CouponUsage>[] = [\n {\n key: 'userId',\n header: 'User ID',\n priority: 'primary',\n cell: (u) => <span className=\"font-mono\">{u.userId.slice(0, 12)}…</span>,\n },\n {\n key: 'transaction',\n header: 'Transaction',\n cell: (u) =>\n u.transactionId ? (\n <span className=\"font-mono text-xs text-text-link\">{u.transactionId.slice(0, 12)}…</span>\n ) : u.orderId ? (\n <span className=\"text-xs text-text-muted\">Order: {u.orderId.slice(0, 12)}…</span>\n ) : (\n <span className=\"text-text-muted\">, </span>\n ),\n },\n {\n key: 'original',\n header: 'Original',\n cell: (u) => (\n <span className=\"tabular-nums\">\n {u.originalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'discount',\n header: 'Discount',\n cell: (u) => (\n <span className=\"tabular-nums text-status-success-text font-medium\">\n -{u.discountValue.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'final',\n header: 'Final',\n cell: (u) => (\n <span className=\"tabular-nums font-medium\">\n {u.finalAmount.toFixed(2)} {u.currency}\n </span>\n ),\n },\n {\n key: 'usedAt',\n header: 'Used At',\n cell: (u) => new Date(u.usedAt).toLocaleString(),\n },\n];\n\nfunction StatusBadge({ status }: { status: CouponStatus }) {\n const map: Record<CouponStatus, { label: string; className: string }> = {\n [CouponStatus.Active]: {\n label: 'Active',\n className:\n 'bg-status-success-bg-subtle text-status-success-text border-status-success-bg-subtle',\n },\n [CouponStatus.Inactive]: {\n label: 'Inactive',\n className: 'bg-bg-sunken text-text-muted border-border-subtle',\n },\n [CouponStatus.Expired]: {\n label: 'Expired',\n className:\n 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-bg-subtle',\n },\n [CouponStatus.Depleted]: {\n label: 'Depleted',\n className: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border',\n },\n };\n const { label, className } = map[status] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-muted',\n };\n return (\n <span\n className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border ${className}`}\n >\n {label}\n </span>\n );\n}\n\nfunction DetailRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-start gap-2 py-3 border-b border-border-subtle last:border-0\">\n <span className=\"text-sm text-text-muted w-44 shrink-0\">{label}</span>\n <span className=\"text-sm text-text-primary font-medium flex-1\">{value ?? '—'}</span>\n </div>\n );\n}\n\nexport const CouponDetailPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n\n const couponId = window.location.pathname.split('/').filter(Boolean).slice(-1)[0];\n const [activeTab, setActiveTab] = useState<'details' | 'usage'>('details');\n const [usagePage, setUsagePage] = useState(0);\n const USAGE_PAGE_SIZE = 20;\n\n const [getCoupon, { data, loading, error }] = useGetCouponLazyQuery();\n\n const { data: usageData, loading: usageLoading } = useGetCouponUsageHistoryQuery({\n variables: { couponId, limit: USAGE_PAGE_SIZE, offset: usagePage * USAGE_PAGE_SIZE },\n skip: !couponId || activeTab !== 'usage',\n });\n\n useEffect(() => {\n if (couponId) {\n getCoupon({ variables: { id: couponId } });\n }\n }, [couponId, getCoupon]);\n\n if (!permissions.canManageDiscounts) {\n return <AccessDenied message=\"You don't have permission to view coupon details.\" />;\n }\n\n if (loading) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title={tr('billing.coupons.detailTitle', 'Coupon Details')}\n description=\"Loading...\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64\">\n <div className=\"size-8 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n </div>\n );\n }\n\n if (error || !data?.getCoupon) {\n return (\n <div className=\"p-8\">\n <PageHeader\n title=\"Coupon Details\"\n description=\"Coupon not found\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/coupons')}\n className=\"px-4 py-2 rounded-lg border border-border-subtle text-text-primary hover:bg-bg-sunken flex items-center gap-2\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n }\n />\n <div className=\"flex items-center justify-center h-64 text-status-error-text text-sm\">\n {error ? `Error: ${error.message}` : 'Coupon not found'}\n </div>\n </div>\n );\n }\n\n const coupon = data.getCoupon as Coupon;\n const usagePercent =\n coupon.maxTotalUses && coupon.maxTotalUses > 0\n ? Math.round((coupon.currentUses / coupon.maxTotalUses) * 100)\n : null;\n\n const nextSteps: NextStep[] = [\n {\n id: 'edit',\n label: 'Edit this coupon',\n description: 'Adjust the discount, limits, expiry or applicable products.',\n onClick: () => navigateTo(`/coupons/${coupon.id}/edit`),\n },\n {\n id: 'usage',\n label: 'Review who has redeemed it',\n description: 'Open the Usage History tab to see every redemption.',\n onClick: () => setActiveTab('usage'),\n },\n {\n id: 'back',\n label: 'Manage all coupons',\n description: 'Return to the full list of discount codes.',\n onClick: () => navigateTo('/coupons'),\n },\n ];\n\n const formatDate = (d: string | null | undefined) =>\n d\n ? new Date(d).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n : null;\n\n const formatValue = () =>\n coupon.type === 'PERCENTAGE'\n ? `${coupon.value}%`\n : `${coupon.value}${coupon.currency ? ` ${coupon.currency}` : ''}`;\n\n return (\n <div className=\"p-8\">\n <PageHeader\n title={coupon.name || coupon.code}\n description={coupon.description || `Coupon code: ${coupon.code}`}\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Edit',\n onSelect: () => navigateTo(`/coupons/${coupon.id}/edit`),\n icon: <Edit className=\"size-4\" />,\n }}\n actions={[\n {\n label: 'Back to coupons',\n onSelect: () => navigateTo('/coupons'),\n icon: <ArrowLeft className=\"size-4\" />,\n },\n ]}\n />\n }\n />\n\n <PagePurpose className=\"mt-2\">\n Everything about this coupon — its discount, validity window, usage limits and the full\n redemption history. Use it to check how it is performing, edit its terms, or stop it being\n redeemed.\n </PagePurpose>\n\n <NextSteps storageKey=\"billing-coupon-detail\" steps={nextSteps} className=\"mt-4\" />\n\n {/* Tabs */}\n <div className=\"mt-6 border-b border-border-subtle flex gap-1\">\n {(['details', 'usage'] as const).map((tab) => (\n <button\n type=\"button\"\n key={tab}\n onClick={() => setActiveTab(tab)}\n className={`flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${\n activeTab === tab\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab === 'details' ? <Tag className=\"size-4\" /> : <History className=\"size-4\" />}\n {tab === 'details'\n ? 'Details'\n : `Usage History${usageData ? ` (${usageData.getCouponUsageHistory.total})` : ''}`}\n </button>\n ))}\n </div>\n\n {activeTab === 'usage' && (\n <div className=\"mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden\">\n {usageLoading ? (\n <div className=\"flex items-center justify-center h-40\">\n <div className=\"size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent\" />\n </div>\n ) : !usageData?.getCouponUsageHistory.usages.length ? (\n <div className=\"p-8 text-center text-sm text-text-muted\">\n No usage recorded for this coupon yet.\n </div>\n ) : (\n <>\n <ResponsiveTable\n data={usageData.getCouponUsageHistory.usages}\n rowKey={(u) => u.id}\n columns={couponUsageColumns}\n />\n {(usageData.getCouponUsageHistory.total ?? 0) > USAGE_PAGE_SIZE && (\n <div className=\"flex items-center justify-between p-4 border-t border-border-subtle\">\n <p className=\"text-sm text-text-muted\">\n {usagePage * USAGE_PAGE_SIZE + 1}–\n {Math.min(\n (usagePage + 1) * USAGE_PAGE_SIZE,\n usageData.getCouponUsageHistory.total\n )}{' '}\n of {usageData.getCouponUsageHistory.total}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => Math.max(0, p - 1))}\n disabled={usagePage === 0}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronLeft className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setUsagePage((p) => p + 1)}\n disabled={!usageData.getCouponUsageHistory.hasMore}\n className=\"p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40\"\n >\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n )}\n\n {activeTab === 'details' && (\n <div className=\"mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Summary cards */}\n <div className=\"lg:col-span-3 grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Tag className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Code</span>\n </div>\n <p className=\"text-lg font-mono font-bold text-text-primary\">{coupon.code}</p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <BarChart2 className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Discount</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">{formatValue()}</p>\n <p className=\"text-xs text-text-muted capitalize\">\n {coupon.type.replace('_', ' ').toLowerCase()}\n </p>\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Users className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Usage</span>\n </div>\n <p className=\"text-lg font-bold text-text-primary\">\n {coupon.currentUses}\n {coupon.maxTotalUses ? ` / ${coupon.maxTotalUses}` : ''}\n </p>\n {usagePercent !== null && (\n <div className=\"mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden\">\n <div\n className=\"h-full bg-action-primary-bg rounded-full\"\n style={{ width: `${Math.min(usagePercent, 100)}%` }}\n />\n </div>\n )}\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-2 text-text-muted mb-1\">\n <Calendar className=\"size-4\" />\n <span className=\"text-xs font-medium uppercase tracking-wide\">Status</span>\n </div>\n <div className=\"mt-1\">\n <StatusBadge status={coupon.status} />\n </div>\n {coupon.validUntil && (\n <p className=\"text-xs text-text-muted mt-1\">\n Expires {formatDate(coupon.validUntil)}\n </p>\n )}\n </div>\n </div>\n\n {/* Main details */}\n <div className=\"lg:col-span-2 space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Coupon Details\n </h3>\n <DetailRow label=\"Code\" value={<span className=\"font-mono\">{coupon.code}</span>} />\n <DetailRow label=\"Name\" value={coupon.name} />\n <DetailRow label=\"Description\" value={coupon.description} />\n <DetailRow label=\"Type\" value={coupon.type.replace('_', ' ').toLowerCase()} />\n <DetailRow label=\"Value\" value={formatValue()} />\n <DetailRow label=\"Scope\" value={coupon.scope} />\n <DetailRow label=\"Status\" value={<StatusBadge status={coupon.status} />} />\n </div>\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Restrictions\n </h3>\n <DetailRow\n label=\"Min Purchase Amount\"\n value={\n coupon.minPurchaseAmount != null\n ? `${coupon.minPurchaseAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow\n label=\"Max Discount Amount\"\n value={\n coupon.maxDiscountAmount != null\n ? `${coupon.maxDiscountAmount}${coupon.currency ? ` ${coupon.currency}` : ''}`\n : null\n }\n />\n <DetailRow label=\"Max Uses Per User\" value={coupon.maxUsesPerUser} />\n <DetailRow\n label=\"Restricted Users\"\n value={\n coupon.restrictedToUserIds?.length ? (\n <span className=\"font-mono text-xs break-all\">\n {(coupon.restrictedToUserIds as string[]).join(', ')}\n </span>\n ) : (\n 'No restrictions'\n )\n }\n />\n <DetailRow\n label=\"Applicable Products\"\n value={\n coupon.applicableProducts?.length\n ? (coupon.applicableProducts as string[]).join(', ')\n : 'All products'\n }\n />\n <DetailRow\n label=\"Excluded Products\"\n value={\n coupon.excludedProducts?.length\n ? (coupon.excludedProducts as string[]).join(', ')\n : 'None'\n }\n />\n </div>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Validity\n </h3>\n <DetailRow label=\"Valid From\" value={formatDate(coupon.validFrom)} />\n <DetailRow label=\"Valid Until\" value={formatDate(coupon.validUntil) ?? 'No expiry'} />\n </div>\n\n {coupon.campaignId && (\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n Campaign\n </h3>\n <DetailRow\n label=\"Campaign ID\"\n value={<span className=\"font-mono text-xs\">{coupon.campaignId}</span>}\n />\n <DetailRow label=\"Campaign Name\" value={coupon.campaignName} />\n </div>\n )}\n\n <div className=\"bg-bg-surface border border-border-subtle rounded-lg p-6\">\n <h3 className=\"text-sm font-semibold text-text-primary uppercase tracking-wide mb-2\">\n <Package className=\"size-4 inline mr-1\" />\n Audit\n </h3>\n <DetailRow label=\"Created\" value={formatDate(coupon.createdAt)} />\n <DetailRow label=\"Last Updated\" value={formatDate(coupon.updatedAt)} />\n <DetailRow label=\"Created By\" value={coupon.createdBy ?? null} />\n </div>\n </div>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|