@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.
- package/dist/billing/BillingAdminRoutes.js +1 -1
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +2 -2
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +4 -4
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +2 -2
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +98 -99
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +88 -85
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +6 -6
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +2 -2
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +360 -370
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/UserRefundsPage.js +2 -2
- package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +1 -1
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +2 -2
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +102 -104
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +5 -5
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +29 -28
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +2 -2
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +3 -3
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +2 -2
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +139 -142
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +6 -6
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +4 -4
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +142 -133
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +2 -2
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +4 -4
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +2 -2
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +4 -4
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +2 -2
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +4 -4
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js +2 -2
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +2 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +5 -5
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +2 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +259 -265
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +7 -7
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +13 -13
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/ui/Card.js +1 -1
- package/dist/billing/shared/ui/Card.js.map +1 -1
- package/dist/billing/shared/ui/MetricCard.js +28 -21
- package/dist/billing/shared/ui/MetricCard.js.map +1 -1
- package/package.json +2 -2
|
@@ -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 {
|
|
12
|
+
import { CTAOverflowMenu as C, ResponsiveTable as w } from "@burdenoff/fe-libs/ui";
|
|
13
13
|
//#region src/billing/modules/coupons/pages/CouponDetailPage.tsx
|
|
14
|
-
var
|
|
14
|
+
var T = [
|
|
15
15
|
{
|
|
16
16
|
key: "userId",
|
|
17
17
|
header: "User ID",
|
|
@@ -82,7 +82,7 @@ var w = [
|
|
|
82
82
|
cell: (e) => new Date(e.usedAt).toLocaleString()
|
|
83
83
|
}
|
|
84
84
|
];
|
|
85
|
-
function
|
|
85
|
+
function E({ status: e }) {
|
|
86
86
|
let { label: t, className: n } = {
|
|
87
87
|
[o.Active]: {
|
|
88
88
|
label: "Active",
|
|
@@ -109,7 +109,7 @@ function T({ status: e }) {
|
|
|
109
109
|
children: t
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
|
-
function
|
|
112
|
+
function D({ 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 E({ label: e, value: t }) {
|
|
|
121
121
|
})]
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
|
-
var
|
|
125
|
-
let { t: o } = S(),
|
|
124
|
+
var O = () => {
|
|
125
|
+
let { t: o } = S(), O = (e, t) => {
|
|
126
126
|
let n = o(e);
|
|
127
127
|
return n === e ? t : n;
|
|
128
|
-
},
|
|
128
|
+
}, k = a(), A = n(), j = window.location.pathname.split("/").filter(Boolean).slice(-1)[0], [M, N] = c("details"), [P, F] = c(0), [I, { data: L, loading: R, error: z }] = r(), { data: B, loading: V } = i({
|
|
129
129
|
variables: {
|
|
130
|
-
couponId:
|
|
130
|
+
couponId: j,
|
|
131
131
|
limit: 20,
|
|
132
|
-
offset:
|
|
132
|
+
offset: P * 20
|
|
133
133
|
},
|
|
134
|
-
skip: !
|
|
134
|
+
skip: !j || M !== "usage"
|
|
135
135
|
});
|
|
136
136
|
if (s(() => {
|
|
137
|
-
|
|
138
|
-
}, [
|
|
139
|
-
if (
|
|
137
|
+
j && I({ variables: { id: j } });
|
|
138
|
+
}, [j, I]), !A.canManageDiscounts) return /* @__PURE__ */ b(e, { message: "You don't have permission to view coupon details." });
|
|
139
|
+
if (R) return /* @__PURE__ */ x("div", {
|
|
140
140
|
className: "p-8",
|
|
141
141
|
children: [/* @__PURE__ */ b(t, {
|
|
142
|
-
title:
|
|
142
|
+
title: O("billing.coupons.detailTitle", "Coupon Details"),
|
|
143
143
|
description: "Loading...",
|
|
144
144
|
actions: /* @__PURE__ */ x("button", {
|
|
145
145
|
type: "button",
|
|
146
|
-
onClick: () =>
|
|
146
|
+
onClick: () => k("/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,90 +152,88 @@ var D = () => {
|
|
|
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 (z || !L?.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: () => k("/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: z ? `Error: ${z.message}` : "Coupon not found"
|
|
169
169
|
})]
|
|
170
170
|
});
|
|
171
|
-
let
|
|
171
|
+
let H = L.getCoupon, U = H.maxTotalUses && H.maxTotalUses > 0 ? Math.round(H.currentUses / H.maxTotalUses * 100) : null, W = (e) => e ? new Date(e).toLocaleDateString(void 0, {
|
|
172
172
|
year: "numeric",
|
|
173
173
|
month: "short",
|
|
174
174
|
day: "numeric"
|
|
175
|
-
}) : null,
|
|
175
|
+
}) : null, G = () => H.type === "PERCENTAGE" ? `${H.value}%` : `${H.value}${H.currency ? ` ${H.currency}` : ""}`;
|
|
176
176
|
return /* @__PURE__ */ x("div", {
|
|
177
177
|
className: "p-8",
|
|
178
178
|
children: [
|
|
179
179
|
/* @__PURE__ */ b(t, {
|
|
180
|
-
title:
|
|
181
|
-
description:
|
|
182
|
-
actions: /* @__PURE__ */
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
children: [/* @__PURE__ */ b(m, { className: "size-4" }), "Edit"]
|
|
194
|
-
})]
|
|
180
|
+
title: H.name || H.code,
|
|
181
|
+
description: H.description || `Coupon code: ${H.code}`,
|
|
182
|
+
actions: /* @__PURE__ */ b(C, {
|
|
183
|
+
primary: {
|
|
184
|
+
label: "Edit",
|
|
185
|
+
onSelect: () => k(`/coupons/${H.id}/edit`),
|
|
186
|
+
icon: /* @__PURE__ */ b(m, { className: "size-4" })
|
|
187
|
+
},
|
|
188
|
+
actions: [{
|
|
189
|
+
label: "Back to coupons",
|
|
190
|
+
onSelect: () => k("/coupons"),
|
|
191
|
+
icon: /* @__PURE__ */ b(l, { className: "size-4" })
|
|
192
|
+
}]
|
|
195
193
|
})
|
|
196
194
|
}),
|
|
197
195
|
/* @__PURE__ */ b("div", {
|
|
198
196
|
className: "mt-6 border-b border-border-subtle flex gap-1",
|
|
199
197
|
children: ["details", "usage"].map((e) => /* @__PURE__ */ x("button", {
|
|
200
198
|
type: "button",
|
|
201
|
-
onClick: () =>
|
|
202
|
-
className: `flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${
|
|
203
|
-
children: [b(e === "details" ? _ : h, { className: "size-4" }), e === "details" ? "Details" : `Usage History${
|
|
199
|
+
onClick: () => N(e),
|
|
200
|
+
className: `flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 -mb-px transition-colors ${M === e ? "border-action-primary-bg text-text-primary" : "border-transparent text-text-muted hover:text-text-primary"}`,
|
|
201
|
+
children: [b(e === "details" ? _ : h, { className: "size-4" }), e === "details" ? "Details" : `Usage History${B ? ` (${B.getCouponUsageHistory.total})` : ""}`]
|
|
204
202
|
}, e))
|
|
205
203
|
}),
|
|
206
|
-
|
|
204
|
+
M === "usage" && /* @__PURE__ */ b("div", {
|
|
207
205
|
className: "mt-6 bg-bg-surface border border-border-subtle rounded-lg overflow-hidden",
|
|
208
|
-
children:
|
|
206
|
+
children: V ? /* @__PURE__ */ b("div", {
|
|
209
207
|
className: "flex items-center justify-center h-40",
|
|
210
208
|
children: /* @__PURE__ */ b("div", { className: "size-6 animate-spin rounded-full border-4 border-action-primary-bg border-t-transparent" })
|
|
211
|
-
}) :
|
|
212
|
-
data:
|
|
209
|
+
}) : B?.getCouponUsageHistory.usages.length ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ b(w, {
|
|
210
|
+
data: B.getCouponUsageHistory.usages,
|
|
213
211
|
rowKey: (e) => e.id,
|
|
214
|
-
columns:
|
|
215
|
-
}), (
|
|
212
|
+
columns: T
|
|
213
|
+
}), (B.getCouponUsageHistory.total ?? 0) > 20 && /* @__PURE__ */ x("div", {
|
|
216
214
|
className: "flex items-center justify-between p-4 border-t border-border-subtle",
|
|
217
215
|
children: [/* @__PURE__ */ x("p", {
|
|
218
216
|
className: "text-sm text-text-muted",
|
|
219
217
|
children: [
|
|
220
|
-
|
|
218
|
+
P * 20 + 1,
|
|
221
219
|
"–",
|
|
222
|
-
Math.min((
|
|
220
|
+
Math.min((P + 1) * 20, B.getCouponUsageHistory.total),
|
|
223
221
|
" ",
|
|
224
222
|
"of ",
|
|
225
|
-
|
|
223
|
+
B.getCouponUsageHistory.total
|
|
226
224
|
]
|
|
227
225
|
}), /* @__PURE__ */ x("div", {
|
|
228
226
|
className: "flex items-center gap-2",
|
|
229
227
|
children: [/* @__PURE__ */ b("button", {
|
|
230
228
|
type: "button",
|
|
231
|
-
onClick: () =>
|
|
232
|
-
disabled:
|
|
229
|
+
onClick: () => F((e) => Math.max(0, e - 1)),
|
|
230
|
+
disabled: P === 0,
|
|
233
231
|
className: "p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40",
|
|
234
232
|
children: /* @__PURE__ */ b(f, { className: "size-4" })
|
|
235
233
|
}), /* @__PURE__ */ b("button", {
|
|
236
234
|
type: "button",
|
|
237
|
-
onClick: () =>
|
|
238
|
-
disabled: !
|
|
235
|
+
onClick: () => F((e) => e + 1),
|
|
236
|
+
disabled: !B.getCouponUsageHistory.hasMore,
|
|
239
237
|
className: "p-1.5 rounded border border-border-subtle hover:bg-bg-sunken disabled:opacity-40",
|
|
240
238
|
children: /* @__PURE__ */ b(p, { className: "size-4" })
|
|
241
239
|
})]
|
|
@@ -245,7 +243,7 @@ var D = () => {
|
|
|
245
243
|
children: "No usage recorded for this coupon yet."
|
|
246
244
|
})
|
|
247
245
|
}),
|
|
248
|
-
|
|
246
|
+
M === "details" && /* @__PURE__ */ x("div", {
|
|
249
247
|
className: "mt-8 grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
250
248
|
children: [
|
|
251
249
|
/* @__PURE__ */ x("div", {
|
|
@@ -261,7 +259,7 @@ var D = () => {
|
|
|
261
259
|
})]
|
|
262
260
|
}), /* @__PURE__ */ b("p", {
|
|
263
261
|
className: "text-lg font-mono font-bold text-text-primary",
|
|
264
|
-
children:
|
|
262
|
+
children: H.code
|
|
265
263
|
})]
|
|
266
264
|
}),
|
|
267
265
|
/* @__PURE__ */ x("div", {
|
|
@@ -276,11 +274,11 @@ var D = () => {
|
|
|
276
274
|
}),
|
|
277
275
|
/* @__PURE__ */ b("p", {
|
|
278
276
|
className: "text-lg font-bold text-text-primary",
|
|
279
|
-
children:
|
|
277
|
+
children: G()
|
|
280
278
|
}),
|
|
281
279
|
/* @__PURE__ */ b("p", {
|
|
282
280
|
className: "text-xs text-text-muted capitalize",
|
|
283
|
-
children:
|
|
281
|
+
children: H.type.replace("_", " ").toLowerCase()
|
|
284
282
|
})
|
|
285
283
|
]
|
|
286
284
|
}),
|
|
@@ -296,13 +294,13 @@ var D = () => {
|
|
|
296
294
|
}),
|
|
297
295
|
/* @__PURE__ */ x("p", {
|
|
298
296
|
className: "text-lg font-bold text-text-primary",
|
|
299
|
-
children: [
|
|
297
|
+
children: [H.currentUses, H.maxTotalUses ? ` / ${H.maxTotalUses}` : ""]
|
|
300
298
|
}),
|
|
301
|
-
|
|
299
|
+
U !== null && /* @__PURE__ */ b("div", {
|
|
302
300
|
className: "mt-1.5 h-1.5 w-full bg-bg-sunken rounded-full overflow-hidden",
|
|
303
301
|
children: /* @__PURE__ */ b("div", {
|
|
304
302
|
className: "h-full bg-action-primary-bg rounded-full",
|
|
305
|
-
style: { width: `${Math.min(
|
|
303
|
+
style: { width: `${Math.min(U, 100)}%` }
|
|
306
304
|
})
|
|
307
305
|
})
|
|
308
306
|
]
|
|
@@ -319,11 +317,11 @@ var D = () => {
|
|
|
319
317
|
}),
|
|
320
318
|
/* @__PURE__ */ b("div", {
|
|
321
319
|
className: "mt-1",
|
|
322
|
-
children: /* @__PURE__ */ b(
|
|
320
|
+
children: /* @__PURE__ */ b(E, { status: H.status })
|
|
323
321
|
}),
|
|
324
|
-
|
|
322
|
+
H.validUntil && /* @__PURE__ */ x("p", {
|
|
325
323
|
className: "text-xs text-text-muted mt-1",
|
|
326
|
-
children: ["Expires ",
|
|
324
|
+
children: ["Expires ", W(H.validUntil)]
|
|
327
325
|
})
|
|
328
326
|
]
|
|
329
327
|
})
|
|
@@ -338,36 +336,36 @@ var D = () => {
|
|
|
338
336
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
339
337
|
children: "Coupon Details"
|
|
340
338
|
}),
|
|
341
|
-
/* @__PURE__ */ b(
|
|
339
|
+
/* @__PURE__ */ b(D, {
|
|
342
340
|
label: "Code",
|
|
343
341
|
value: /* @__PURE__ */ b("span", {
|
|
344
342
|
className: "font-mono",
|
|
345
|
-
children:
|
|
343
|
+
children: H.code
|
|
346
344
|
})
|
|
347
345
|
}),
|
|
348
|
-
/* @__PURE__ */ b(
|
|
346
|
+
/* @__PURE__ */ b(D, {
|
|
349
347
|
label: "Name",
|
|
350
|
-
value:
|
|
348
|
+
value: H.name
|
|
351
349
|
}),
|
|
352
|
-
/* @__PURE__ */ b(
|
|
350
|
+
/* @__PURE__ */ b(D, {
|
|
353
351
|
label: "Description",
|
|
354
|
-
value:
|
|
352
|
+
value: H.description
|
|
355
353
|
}),
|
|
356
|
-
/* @__PURE__ */ b(
|
|
354
|
+
/* @__PURE__ */ b(D, {
|
|
357
355
|
label: "Type",
|
|
358
|
-
value:
|
|
356
|
+
value: H.type.replace("_", " ").toLowerCase()
|
|
359
357
|
}),
|
|
360
|
-
/* @__PURE__ */ b(
|
|
358
|
+
/* @__PURE__ */ b(D, {
|
|
361
359
|
label: "Value",
|
|
362
|
-
value:
|
|
360
|
+
value: G()
|
|
363
361
|
}),
|
|
364
|
-
/* @__PURE__ */ b(
|
|
362
|
+
/* @__PURE__ */ b(D, {
|
|
365
363
|
label: "Scope",
|
|
366
|
-
value:
|
|
364
|
+
value: H.scope
|
|
367
365
|
}),
|
|
368
|
-
/* @__PURE__ */ b(
|
|
366
|
+
/* @__PURE__ */ b(D, {
|
|
369
367
|
label: "Status",
|
|
370
|
-
value: /* @__PURE__ */ b(
|
|
368
|
+
value: /* @__PURE__ */ b(E, { status: H.status })
|
|
371
369
|
})
|
|
372
370
|
]
|
|
373
371
|
}), /* @__PURE__ */ x("div", {
|
|
@@ -377,32 +375,32 @@ var D = () => {
|
|
|
377
375
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
378
376
|
children: "Restrictions"
|
|
379
377
|
}),
|
|
380
|
-
/* @__PURE__ */ b(
|
|
378
|
+
/* @__PURE__ */ b(D, {
|
|
381
379
|
label: "Min Purchase Amount",
|
|
382
|
-
value:
|
|
380
|
+
value: H.minPurchaseAmount == null ? null : `${H.minPurchaseAmount}${H.currency ? ` ${H.currency}` : ""}`
|
|
383
381
|
}),
|
|
384
|
-
/* @__PURE__ */ b(
|
|
382
|
+
/* @__PURE__ */ b(D, {
|
|
385
383
|
label: "Max Discount Amount",
|
|
386
|
-
value:
|
|
384
|
+
value: H.maxDiscountAmount == null ? null : `${H.maxDiscountAmount}${H.currency ? ` ${H.currency}` : ""}`
|
|
387
385
|
}),
|
|
388
|
-
/* @__PURE__ */ b(
|
|
386
|
+
/* @__PURE__ */ b(D, {
|
|
389
387
|
label: "Max Uses Per User",
|
|
390
|
-
value:
|
|
388
|
+
value: H.maxUsesPerUser
|
|
391
389
|
}),
|
|
392
|
-
/* @__PURE__ */ b(
|
|
390
|
+
/* @__PURE__ */ b(D, {
|
|
393
391
|
label: "Restricted Users",
|
|
394
|
-
value:
|
|
392
|
+
value: H.restrictedToUserIds?.length ? /* @__PURE__ */ b("span", {
|
|
395
393
|
className: "font-mono text-xs break-all",
|
|
396
|
-
children:
|
|
394
|
+
children: H.restrictedToUserIds.join(", ")
|
|
397
395
|
}) : "No restrictions"
|
|
398
396
|
}),
|
|
399
|
-
/* @__PURE__ */ b(
|
|
397
|
+
/* @__PURE__ */ b(D, {
|
|
400
398
|
label: "Applicable Products",
|
|
401
|
-
value:
|
|
399
|
+
value: H.applicableProducts?.length ? H.applicableProducts.join(", ") : "All products"
|
|
402
400
|
}),
|
|
403
|
-
/* @__PURE__ */ b(
|
|
401
|
+
/* @__PURE__ */ b(D, {
|
|
404
402
|
label: "Excluded Products",
|
|
405
|
-
value:
|
|
403
|
+
value: H.excludedProducts?.length ? H.excludedProducts.join(", ") : "None"
|
|
406
404
|
})
|
|
407
405
|
]
|
|
408
406
|
})]
|
|
@@ -417,33 +415,33 @@ var D = () => {
|
|
|
417
415
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
418
416
|
children: "Validity"
|
|
419
417
|
}),
|
|
420
|
-
/* @__PURE__ */ b(
|
|
418
|
+
/* @__PURE__ */ b(D, {
|
|
421
419
|
label: "Valid From",
|
|
422
|
-
value:
|
|
420
|
+
value: W(H.validFrom)
|
|
423
421
|
}),
|
|
424
|
-
/* @__PURE__ */ b(
|
|
422
|
+
/* @__PURE__ */ b(D, {
|
|
425
423
|
label: "Valid Until",
|
|
426
|
-
value:
|
|
424
|
+
value: W(H.validUntil) ?? "No expiry"
|
|
427
425
|
})
|
|
428
426
|
]
|
|
429
427
|
}),
|
|
430
|
-
|
|
428
|
+
H.campaignId && /* @__PURE__ */ x("div", {
|
|
431
429
|
className: "bg-bg-surface border border-border-subtle rounded-lg p-6",
|
|
432
430
|
children: [
|
|
433
431
|
/* @__PURE__ */ b("h3", {
|
|
434
432
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
435
433
|
children: "Campaign"
|
|
436
434
|
}),
|
|
437
|
-
/* @__PURE__ */ b(
|
|
435
|
+
/* @__PURE__ */ b(D, {
|
|
438
436
|
label: "Campaign ID",
|
|
439
437
|
value: /* @__PURE__ */ b("span", {
|
|
440
438
|
className: "font-mono text-xs",
|
|
441
|
-
children:
|
|
439
|
+
children: H.campaignId
|
|
442
440
|
})
|
|
443
441
|
}),
|
|
444
|
-
/* @__PURE__ */ b(
|
|
442
|
+
/* @__PURE__ */ b(D, {
|
|
445
443
|
label: "Campaign Name",
|
|
446
|
-
value:
|
|
444
|
+
value: H.campaignName
|
|
447
445
|
})
|
|
448
446
|
]
|
|
449
447
|
}),
|
|
@@ -454,17 +452,17 @@ var D = () => {
|
|
|
454
452
|
className: "text-sm font-semibold text-text-primary uppercase tracking-wide mb-2",
|
|
455
453
|
children: [/* @__PURE__ */ b(g, { className: "size-4 inline mr-1" }), "Audit"]
|
|
456
454
|
}),
|
|
457
|
-
/* @__PURE__ */ b(
|
|
455
|
+
/* @__PURE__ */ b(D, {
|
|
458
456
|
label: "Created",
|
|
459
|
-
value:
|
|
457
|
+
value: W(H.createdAt)
|
|
460
458
|
}),
|
|
461
|
-
/* @__PURE__ */ b(
|
|
459
|
+
/* @__PURE__ */ b(D, {
|
|
462
460
|
label: "Last Updated",
|
|
463
|
-
value:
|
|
461
|
+
value: W(H.updatedAt)
|
|
464
462
|
}),
|
|
465
|
-
/* @__PURE__ */ b(
|
|
463
|
+
/* @__PURE__ */ b(D, {
|
|
466
464
|
label: "Created By",
|
|
467
|
-
value:
|
|
465
|
+
value: H.createdBy ?? null
|
|
468
466
|
})
|
|
469
467
|
]
|
|
470
468
|
})
|
|
@@ -476,6 +474,6 @@ var D = () => {
|
|
|
476
474
|
});
|
|
477
475
|
};
|
|
478
476
|
//#endregion
|
|
479
|
-
export {
|
|
477
|
+
export { O as CouponDetailPage };
|
|
480
478
|
|
|
481
479
|
//# 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 { 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 <div className=\"flex items-center gap-3\">\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 <button\n type=\"button\"\n onClick={() => navigateTo(`/coupons/${coupon.id}/edit`)}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bgHover flex items-center gap-2\"\n >\n <Edit className=\"size-4\" />\n Edit\n </button>\n </div>\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 { 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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"}
|
|
@@ -82,7 +82,7 @@ var k = () => {
|
|
|
82
82
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
83
83
|
children: [
|
|
84
84
|
/* @__PURE__ */ E("div", {
|
|
85
|
-
className: "rounded-card border border-border-
|
|
85
|
+
className: "rounded-card border border-border-seam bg-bg-surface p-5 shadow-[var(--shadow-elevation-1)]",
|
|
86
86
|
children: [
|
|
87
87
|
/* @__PURE__ */ E("div", {
|
|
88
88
|
className: "flex items-center justify-between mb-2",
|
|
@@ -105,7 +105,7 @@ var k = () => {
|
|
|
105
105
|
]
|
|
106
106
|
}),
|
|
107
107
|
/* @__PURE__ */ E("div", {
|
|
108
|
-
className: "rounded-card border border-border-
|
|
108
|
+
className: "rounded-card border border-border-seam bg-bg-surface p-5 shadow-[var(--shadow-elevation-1)]",
|
|
109
109
|
children: [
|
|
110
110
|
/* @__PURE__ */ E("div", {
|
|
111
111
|
className: "flex items-center justify-between mb-2",
|
|
@@ -128,7 +128,7 @@ var k = () => {
|
|
|
128
128
|
]
|
|
129
129
|
}),
|
|
130
130
|
/* @__PURE__ */ E("div", {
|
|
131
|
-
className: "rounded-card border border-border-
|
|
131
|
+
className: "rounded-card border border-border-seam bg-bg-surface p-5 shadow-[var(--shadow-elevation-1)]",
|
|
132
132
|
children: [
|
|
133
133
|
/* @__PURE__ */ E("div", {
|
|
134
134
|
className: "flex items-center justify-between mb-2",
|
|
@@ -151,7 +151,7 @@ var k = () => {
|
|
|
151
151
|
]
|
|
152
152
|
}),
|
|
153
153
|
/* @__PURE__ */ E("div", {
|
|
154
|
-
className: "rounded-card border border-border-
|
|
154
|
+
className: "rounded-card border border-border-seam bg-bg-surface p-5 shadow-[var(--shadow-elevation-1)]",
|
|
155
155
|
children: [
|
|
156
156
|
/* @__PURE__ */ E("div", {
|
|
157
157
|
className: "flex items-center justify-between mb-2",
|
|
@@ -290,7 +290,7 @@ var k = () => {
|
|
|
290
290
|
})
|
|
291
291
|
}),
|
|
292
292
|
/* @__PURE__ */ T("div", {
|
|
293
|
-
className: "bg-bg-surface border border-border-
|
|
293
|
+
className: "bg-bg-surface border border-border-seam rounded-card overflow-hidden shadow-[var(--shadow-elevation-1)]",
|
|
294
294
|
children: K ? /* @__PURE__ */ T("div", {
|
|
295
295
|
className: "p-8 text-center text-text-muted",
|
|
296
296
|
children: "Loading coupons…"
|