@burdenoff/microfe-billing 2026.530.2 → 2026.530.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/billing/BillingAdminRoutes.js +110 -71
  2. package/dist/billing/BillingAdminRoutes.js.map +1 -1
  3. package/dist/billing/BillingRoot.js +81 -73
  4. package/dist/billing/BillingRoot.js.map +1 -1
  5. package/dist/billing/BillingUserRoutes.js +103 -90
  6. package/dist/billing/BillingUserRoutes.js.map +1 -1
  7. package/dist/billing/modules/billing/index.js +2 -1
  8. package/dist/billing/modules/billing/pages/InvoicesListPage.js +135 -126
  9. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  10. package/dist/billing/modules/billing/pages/UserRefundsPage.js +417 -0
  11. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -0
  12. package/dist/billing/modules/billing/pages/index.js +1 -0
  13. package/dist/billing/modules/checkout/hooks/useCheckout.js +163 -161
  14. package/dist/billing/modules/checkout/hooks/useCheckout.js.map +1 -1
  15. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +344 -167
  16. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  17. package/dist/billing/modules/plans/constants/featuredQuotas.js +37 -0
  18. package/dist/billing/modules/plans/constants/featuredQuotas.js.map +1 -0
  19. package/dist/billing/modules/plans/index.js +2 -1
  20. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +205 -0
  21. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -0
  22. package/dist/billing/modules/plans/pages/PlanCreatePage.js +51 -33
  23. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  24. package/dist/billing/modules/plans/pages/PlanEditPage.js +78 -60
  25. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  26. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +246 -126
  27. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  28. package/dist/billing/modules/plans/pages/index.js +1 -0
  29. package/dist/billing/modules/promotions/index.js +4 -0
  30. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +289 -0
  31. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -0
  32. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +168 -0
  33. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -0
  34. package/dist/billing/modules/promotions/pages/index.js +2 -0
  35. package/dist/billing/shared/types/graphql.js.map +1 -1
  36. package/dist/generated/global-operations.js +422 -290
  37. package/dist/generated/global-operations.js.map +1 -1
  38. package/dist/generated/global-types.js +3 -1
  39. package/dist/generated/global-types.js.map +1 -1
  40. package/package.json +1 -1
@@ -4,16 +4,92 @@ import "../../../shared/components/index.js";
4
4
  import { useBillingPermissions as n } from "../../../hooks/useBillingPermissions.js";
5
5
  import { useCreateCouponMutation as r } from "../../../../generated/global-operations.js";
6
6
  import { useBillingNavigate as i } from "../../../hooks/useBillingNavigate.js";
7
- import { useState as a } from "react";
8
- import { ArrowLeft as o, DollarSign as s, Package as c, Percent as l, Save as u, Tag as d } from "lucide-react";
9
- import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
10
- import { useI18n as h } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
+ import { useRef as a, useState as o } from "react";
8
+ import { ArrowLeft as s, Package as c, Percent as l, Save as u, Tag as d, Users as f, X as p } from "lucide-react";
9
+ import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
10
+ import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
11
11
  //#region src/billing/modules/coupons/pages/CreateCouponPage.tsx
12
- var g = () => {
13
- let { t: g } = h(), _ = (e, t) => {
14
- let n = g(e);
12
+ var v = [
13
+ {
14
+ code: "USD",
15
+ symbol: "$",
16
+ name: "US Dollar"
17
+ },
18
+ {
19
+ code: "EUR",
20
+ symbol: "€",
21
+ name: "Euro"
22
+ },
23
+ {
24
+ code: "GBP",
25
+ symbol: "£",
26
+ name: "British Pound"
27
+ },
28
+ {
29
+ code: "INR",
30
+ symbol: "₹",
31
+ name: "Indian Rupee"
32
+ },
33
+ {
34
+ code: "AUD",
35
+ symbol: "A$",
36
+ name: "Australian Dollar"
37
+ },
38
+ {
39
+ code: "CAD",
40
+ symbol: "C$",
41
+ name: "Canadian Dollar"
42
+ },
43
+ {
44
+ code: "SGD",
45
+ symbol: "S$",
46
+ name: "Singapore Dollar"
47
+ },
48
+ {
49
+ code: "JPY",
50
+ symbol: "¥",
51
+ name: "Japanese Yen"
52
+ },
53
+ {
54
+ code: "MXN",
55
+ symbol: "MX$",
56
+ name: "Mexican Peso"
57
+ },
58
+ {
59
+ code: "BRL",
60
+ symbol: "R$",
61
+ name: "Brazilian Real"
62
+ },
63
+ {
64
+ code: "CHF",
65
+ symbol: "Fr",
66
+ name: "Swiss Franc"
67
+ },
68
+ {
69
+ code: "HKD",
70
+ symbol: "HK$",
71
+ name: "Hong Kong Dollar"
72
+ },
73
+ {
74
+ code: "NZD",
75
+ symbol: "NZ$",
76
+ name: "New Zealand Dollar"
77
+ },
78
+ {
79
+ code: "SEK",
80
+ symbol: "kr",
81
+ name: "Swedish Krona"
82
+ },
83
+ {
84
+ code: "KRW",
85
+ symbol: "₩",
86
+ name: "South Korean Won"
87
+ }
88
+ ], y = () => {
89
+ let { t: y } = _(), b = (e, t) => {
90
+ let n = y(e);
15
91
  return n === e ? t : n;
16
- }, v = i(), y = n(), [b, x] = a({
92
+ }, x = i(), S = n(), [C, w] = o(""), T = a(null), [E, D] = o({
17
93
  code: "",
18
94
  name: "",
19
95
  description: "",
@@ -31,138 +107,168 @@ var g = () => {
31
107
  applicableProducts: [],
32
108
  applicableServices: [],
33
109
  campaignName: ""
34
- }), [S, C] = a({}), [w, T] = a(!1), [E] = r();
35
- if (!y.canManageDiscounts) return /* @__PURE__ */ p(e, { message: "You don't have permission to create coupons." });
36
- let D = (e, t) => {
37
- x((n) => ({
110
+ }), [O, k] = o({}), [A, j] = o(!1), M = v.find((e) => e.code === E.currency)?.symbol ?? E.currency, [N] = r();
111
+ if (!S.canManageDiscounts) return /* @__PURE__ */ h(e, { message: "You don't have permission to create coupons." });
112
+ let P = (e, t) => {
113
+ D((n) => ({
38
114
  ...n,
39
115
  [e]: t
40
- })), S[e] && C((t) => {
116
+ })), O[e] && k((t) => {
41
117
  let n = { ...t };
42
118
  return delete n[e], n;
43
119
  });
44
- }, O = () => {
120
+ }, F = () => {
45
121
  let e = {};
46
- return b.code.trim() ? /^[A-Z0-9-_]+$/.test(b.code) ? b.code.length < 3 ? e.code = "Code must be at least 3 characters" : b.code.length > 50 && (e.code = "Code must be at most 50 characters") : e.code = "Code must contain only uppercase letters, numbers, hyphens, and underscores" : e.code = "Coupon code is required", b.name.trim() || (e.name = "Coupon name is required"), b.value <= 0 && (e.value = "Value must be greater than 0"), b.type === "PERCENTAGE" && b.value > 100 && (e.value = "Percentage cannot exceed 100%"), b.validFrom || (e.validFrom = "Start date is required"), b.validUntil && b.validUntil < b.validFrom && (e.validUntil = "End date must be after start date"), C(e), Object.keys(e).length === 0;
122
+ return E.code.trim() ? /^[A-Z0-9-_]+$/.test(E.code) ? E.code.length < 3 ? e.code = "Code must be at least 3 characters" : E.code.length > 50 && (e.code = "Code must be at most 50 characters") : e.code = "Code must contain only uppercase letters, numbers, hyphens, and underscores" : e.code = "Coupon code is required", E.name.trim() || (e.name = "Coupon name is required"), E.value <= 0 && (e.value = "Value must be greater than 0"), E.type === "PERCENTAGE" && E.value > 100 && (e.value = "Percentage cannot exceed 100%"), E.scope === "USER_SPECIFIC" && E.restrictedToUserIds.length === 0 && (e.restrictedToUserIds = "Add at least one user email or ID"), E.validFrom || (e.validFrom = "Start date is required"), E.validUntil && E.validUntil < E.validFrom && (e.validUntil = "End date must be after start date"), k(e), Object.keys(e).length === 0;
123
+ }, I = (e) => {
124
+ let t = e.trim();
125
+ t && (E.restrictedToUserIds.includes(t) || P("restrictedToUserIds", [...E.restrictedToUserIds, t]), w(""));
126
+ }, L = (e) => {
127
+ P("restrictedToUserIds", E.restrictedToUserIds.filter((t) => t !== e));
47
128
  };
48
- return /* @__PURE__ */ m("div", {
129
+ return /* @__PURE__ */ g("div", {
49
130
  className: "max-w-4xl mx-auto p-4 sm:p-6 space-y-6",
50
- children: [/* @__PURE__ */ m("div", {
131
+ children: [/* @__PURE__ */ g("div", {
51
132
  className: "flex items-center gap-4",
52
- children: [/* @__PURE__ */ p("button", {
133
+ children: [/* @__PURE__ */ h("button", {
53
134
  type: "button",
54
- onClick: () => v("/coupons"),
135
+ onClick: () => x("/coupons"),
55
136
  className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground",
56
- children: /* @__PURE__ */ p(o, { className: "size-5" })
57
- }), /* @__PURE__ */ p(t, {
58
- title: _("billing.coupons.createTitle", "Create Coupon"),
137
+ children: /* @__PURE__ */ h(s, { className: "size-5" })
138
+ }), /* @__PURE__ */ h(t, {
139
+ title: b("billing.coupons.createTitle", "Create Coupon"),
59
140
  description: "Create a new discount code or promotional offer",
60
- icon: /* @__PURE__ */ p(d, { className: "size-6" })
141
+ icon: /* @__PURE__ */ h(d, { className: "size-6" })
61
142
  })]
62
- }), /* @__PURE__ */ m("form", {
143
+ }), /* @__PURE__ */ g("form", {
63
144
  onSubmit: async (e) => {
64
- if (e.preventDefault(), O()) {
65
- T(!0);
145
+ if (e.preventDefault(), F()) {
146
+ j(!0);
66
147
  try {
67
- if ((await E({ variables: { input: {
68
- code: b.code,
69
- name: b.name,
70
- description: b.description,
71
- scope: b.scope,
72
- type: b.type,
73
- value: b.value,
74
- currency: b.currency,
75
- minPurchaseAmount: b.minPurchaseAmount,
76
- maxDiscountAmount: b.maxDiscountAmount,
77
- maxTotalUses: b.maxTotalUses,
78
- maxUsesPerUser: b.maxUsesPerUser,
79
- validFrom: new Date(b.validFrom).toISOString(),
80
- validUntil: b.validUntil ? new Date(b.validUntil).toISOString() : void 0,
81
- restrictedToUserIds: b.restrictedToUserIds,
82
- applicableProducts: b.applicableProducts,
83
- applicableServices: b.applicableServices,
148
+ if ((await N({ variables: { input: {
149
+ code: E.code,
150
+ name: E.name,
151
+ description: E.description,
152
+ scope: E.scope,
153
+ type: E.type,
154
+ value: E.value,
155
+ currency: E.currency,
156
+ minPurchaseAmount: E.minPurchaseAmount,
157
+ maxDiscountAmount: E.maxDiscountAmount,
158
+ maxTotalUses: E.maxTotalUses,
159
+ maxUsesPerUser: E.maxUsesPerUser,
160
+ validFrom: new Date(E.validFrom).toISOString(),
161
+ validUntil: E.validUntil ? new Date(E.validUntil).toISOString() : void 0,
162
+ restrictedToUserIds: E.restrictedToUserIds,
163
+ applicableProducts: E.applicableProducts,
164
+ applicableServices: E.applicableServices,
84
165
  excludedProducts: [],
85
166
  excludedServices: [],
86
- campaignName: b.campaignName || void 0
87
- } } })).data?.createCoupon) v("/coupons");
167
+ campaignName: E.campaignName || void 0
168
+ } } })).data?.createCoupon) x("/coupons");
88
169
  else throw Error("Failed to create coupon");
89
170
  } catch (e) {
90
- console.error("Error creating coupon:", e), C({ code: e instanceof Error ? e.message : "Failed to create coupon. Please try again." });
171
+ console.error("Error creating coupon:", e), k({ code: e instanceof Error ? e.message : "Failed to create coupon. Please try again." });
91
172
  } finally {
92
- T(!1);
173
+ j(!1);
93
174
  }
94
175
  }
95
176
  },
96
177
  className: "space-y-6",
97
178
  children: [
98
- /* @__PURE__ */ m("div", {
179
+ /* @__PURE__ */ g("div", {
99
180
  className: "bg-card border border-border rounded-lg p-6 space-y-4",
100
181
  children: [
101
- /* @__PURE__ */ p("h3", {
182
+ /* @__PURE__ */ h("h3", {
102
183
  className: "text-lg font-semibold text-foreground",
103
184
  children: "Basic Information"
104
185
  }),
105
- /* @__PURE__ */ m("div", { children: [
106
- /* @__PURE__ */ p("label", {
186
+ /* @__PURE__ */ g("div", { children: [
187
+ /* @__PURE__ */ h("label", {
107
188
  className: "block text-sm font-medium text-foreground mb-1",
108
189
  children: "Coupon Code *"
109
190
  }),
110
- /* @__PURE__ */ p("input", {
191
+ /* @__PURE__ */ h("input", {
111
192
  type: "text",
112
- value: b.code,
113
- onChange: (e) => D("code", e.target.value.toUpperCase()),
193
+ value: E.code,
194
+ onChange: (e) => P("code", e.target.value.toUpperCase()),
114
195
  placeholder: "e.g., WELCOME20",
115
- className: `w-full px-4 py-2 rounded-lg border ${S.code ? "border-destructive" : "border-border"} bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
196
+ className: `w-full px-4 py-2 rounded-lg border ${O.code ? "border-destructive" : "border-border"} bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
116
197
  }),
117
- S.code && /* @__PURE__ */ p("p", {
198
+ O.code && /* @__PURE__ */ h("p", {
118
199
  className: "text-sm text-destructive mt-1",
119
- children: S.code
200
+ children: O.code
120
201
  }),
121
- /* @__PURE__ */ p("p", {
202
+ /* @__PURE__ */ h("p", {
122
203
  className: "text-xs text-muted-foreground mt-1",
123
204
  children: "Use uppercase letters, numbers, hyphens, and underscores"
124
205
  })
125
206
  ] }),
126
- /* @__PURE__ */ m("div", { children: [
127
- /* @__PURE__ */ p("label", {
207
+ /* @__PURE__ */ g("div", { children: [
208
+ /* @__PURE__ */ h("label", {
128
209
  className: "block text-sm font-medium text-foreground mb-1",
129
210
  children: "Display Name *"
130
211
  }),
131
- /* @__PURE__ */ p("input", {
212
+ /* @__PURE__ */ h("input", {
132
213
  type: "text",
133
- value: b.name,
134
- onChange: (e) => D("name", e.target.value),
214
+ value: E.name,
215
+ onChange: (e) => P("name", e.target.value),
135
216
  placeholder: "e.g., Welcome 20% Off",
136
- className: `w-full px-4 py-2 rounded-lg border ${S.name ? "border-destructive" : "border-border"} bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
217
+ className: `w-full px-4 py-2 rounded-lg border ${O.name ? "border-destructive" : "border-border"} bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
137
218
  }),
138
- S.name && /* @__PURE__ */ p("p", {
219
+ O.name && /* @__PURE__ */ h("p", {
139
220
  className: "text-sm text-destructive mt-1",
140
- children: S.name
221
+ children: O.name
141
222
  })
142
223
  ] }),
143
- /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
224
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
144
225
  className: "block text-sm font-medium text-foreground mb-1",
145
226
  children: "Description"
146
- }), /* @__PURE__ */ p("textarea", {
147
- value: b.description,
148
- onChange: (e) => D("description", e.target.value),
227
+ }), /* @__PURE__ */ h("textarea", {
228
+ value: E.description,
229
+ onChange: (e) => P("description", e.target.value),
149
230
  placeholder: "Optional description for internal use",
150
231
  rows: 3,
151
232
  className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
152
233
  })] })
153
234
  ]
154
235
  }),
155
- /* @__PURE__ */ m("div", {
236
+ /* @__PURE__ */ g("div", {
156
237
  className: "bg-card border border-border rounded-lg p-6 space-y-4",
157
238
  children: [
158
- /* @__PURE__ */ p("h3", {
239
+ /* @__PURE__ */ h("h3", {
159
240
  className: "text-lg font-semibold text-foreground",
160
241
  children: "Discount Configuration"
161
242
  }),
162
- /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
243
+ /* @__PURE__ */ g("div", { children: [
244
+ /* @__PURE__ */ h("label", {
245
+ className: "block text-sm font-medium text-foreground mb-1",
246
+ children: "Coupon Currency *"
247
+ }),
248
+ /* @__PURE__ */ h("select", {
249
+ value: E.currency,
250
+ onChange: (e) => P("currency", e.target.value),
251
+ className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20",
252
+ children: v.map(({ code: e, symbol: t, name: n }) => /* @__PURE__ */ g("option", {
253
+ value: e,
254
+ children: [
255
+ t,
256
+ " ",
257
+ e,
258
+ " — ",
259
+ n
260
+ ]
261
+ }, e))
262
+ }),
263
+ /* @__PURE__ */ h("p", {
264
+ className: "text-xs text-muted-foreground mt-1",
265
+ children: "Amounts below are in this currency. Users paying in a different currency (e.g. INR) will have the amounts automatically converted using live exchange rates at validation time."
266
+ })
267
+ ] }),
268
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
163
269
  className: "block text-sm font-medium text-foreground mb-2",
164
270
  children: "Discount Type *"
165
- }), /* @__PURE__ */ p("div", {
271
+ }), /* @__PURE__ */ h("div", {
166
272
  className: "grid grid-cols-3 gap-3",
167
273
  children: [
168
274
  {
@@ -172,244 +278,315 @@ var g = () => {
172
278
  },
173
279
  {
174
280
  value: "FIXED_AMOUNT",
175
- label: "Fixed Amount",
176
- icon: s
281
+ label: `Fixed (${M})`,
282
+ icon: null
177
283
  },
178
284
  {
179
285
  value: "FREE_SHIPPING",
180
286
  label: "Free Shipping",
181
287
  icon: c
182
288
  }
183
- ].map(({ value: e, label: t, icon: n }) => /* @__PURE__ */ m("button", {
289
+ ].map(({ value: e, label: t, icon: n }) => /* @__PURE__ */ g("button", {
184
290
  type: "button",
185
- onClick: () => D("type", e),
186
- className: `p-4 rounded-lg border-2 transition-colors ${b.type === e ? "border-primary bg-primary/10" : "border-border hover:border-primary/50"}`,
187
- children: [/* @__PURE__ */ p(n, { className: "size-5 mx-auto mb-2" }), /* @__PURE__ */ p("p", {
291
+ onClick: () => P("type", e),
292
+ className: `p-4 rounded-lg border-2 transition-colors ${E.type === e ? "border-primary bg-primary/10" : "border-border hover:border-primary/50"}`,
293
+ children: [n ? /* @__PURE__ */ h(n, { className: "size-5 mx-auto mb-2" }) : /* @__PURE__ */ h("span", {
294
+ className: "block text-lg font-bold mb-2",
295
+ children: M
296
+ }), /* @__PURE__ */ h("p", {
188
297
  className: "text-sm font-medium",
189
298
  children: t
190
299
  })]
191
300
  }, e))
192
301
  })] }),
193
- /* @__PURE__ */ m("div", { children: [
194
- /* @__PURE__ */ p("label", {
302
+ /* @__PURE__ */ g("div", { children: [
303
+ /* @__PURE__ */ h("label", {
195
304
  className: "block text-sm font-medium text-foreground mb-1",
196
305
  children: "Discount Value *"
197
306
  }),
198
- /* @__PURE__ */ p("div", {
307
+ /* @__PURE__ */ h("div", {
199
308
  className: "relative",
200
- children: b.type === "PERCENTAGE" ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(l, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ p("input", {
309
+ children: E.type === "PERCENTAGE" ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(l, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ h("input", {
201
310
  type: "number",
202
- value: b.value,
203
- onChange: (e) => D("value", parseFloat(e.target.value)),
311
+ value: E.value,
312
+ onChange: (e) => P("value", parseFloat(e.target.value)),
204
313
  min: "0",
205
314
  max: "100",
206
315
  step: "0.01",
207
- className: `w-full pl-10 pr-4 py-2 rounded-lg border ${S.value ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
208
- })] }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(s, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ p("input", {
316
+ className: `w-full pl-10 pr-4 py-2 rounded-lg border ${O.value ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
317
+ })] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("span", {
318
+ className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground font-medium",
319
+ children: M
320
+ }), /* @__PURE__ */ h("input", {
209
321
  type: "number",
210
- value: b.value,
211
- onChange: (e) => D("value", parseFloat(e.target.value)),
322
+ value: E.value,
323
+ onChange: (e) => P("value", parseFloat(e.target.value)),
212
324
  min: "0",
213
325
  step: "0.01",
214
- className: `w-full pl-10 pr-4 py-2 rounded-lg border ${S.value ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
326
+ className: `w-full pl-10 pr-4 py-2 rounded-lg border ${O.value ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
215
327
  })] })
216
328
  }),
217
- S.value && /* @__PURE__ */ p("p", {
329
+ O.value && /* @__PURE__ */ h("p", {
218
330
  className: "text-sm text-destructive mt-1",
219
- children: S.value
331
+ children: O.value
220
332
  })
221
333
  ] }),
222
- /* @__PURE__ */ m("div", { children: [
223
- /* @__PURE__ */ p("label", {
334
+ /* @__PURE__ */ g("div", { children: [
335
+ /* @__PURE__ */ g("label", {
224
336
  className: "block text-sm font-medium text-foreground mb-1",
225
- children: "Minimum Purchase Amount"
337
+ children: [
338
+ "Minimum Purchase Amount (",
339
+ E.currency,
340
+ ")"
341
+ ]
226
342
  }),
227
- /* @__PURE__ */ m("div", {
343
+ /* @__PURE__ */ g("div", {
228
344
  className: "relative",
229
- children: [/* @__PURE__ */ p(s, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ p("input", {
345
+ children: [/* @__PURE__ */ h("span", {
346
+ className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground font-medium",
347
+ children: M
348
+ }), /* @__PURE__ */ h("input", {
230
349
  type: "number",
231
- value: b.minPurchaseAmount || "",
232
- onChange: (e) => D("minPurchaseAmount", e.target.value ? parseFloat(e.target.value) : null),
350
+ value: E.minPurchaseAmount || "",
351
+ onChange: (e) => P("minPurchaseAmount", e.target.value ? parseFloat(e.target.value) : null),
233
352
  min: "0",
234
353
  step: "0.01",
235
354
  placeholder: "No minimum",
236
355
  className: "w-full pl-10 pr-4 py-2 rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
237
356
  })]
238
357
  }),
239
- /* @__PURE__ */ p("p", {
358
+ /* @__PURE__ */ g("p", {
240
359
  className: "text-xs text-muted-foreground mt-1",
241
- children: "Order must be at least this amount to use coupon"
360
+ children: [
361
+ "Order must be at least this amount in ",
362
+ E.currency,
363
+ " (auto-converted for other currencies)"
364
+ ]
242
365
  })
243
366
  ] }),
244
- b.type === "PERCENTAGE" && /* @__PURE__ */ m("div", { children: [
245
- /* @__PURE__ */ p("label", {
367
+ E.type === "PERCENTAGE" && /* @__PURE__ */ g("div", { children: [
368
+ /* @__PURE__ */ g("label", {
246
369
  className: "block text-sm font-medium text-foreground mb-1",
247
- children: "Maximum Discount Amount"
370
+ children: [
371
+ "Maximum Discount Amount (",
372
+ E.currency,
373
+ ")"
374
+ ]
248
375
  }),
249
- /* @__PURE__ */ m("div", {
376
+ /* @__PURE__ */ g("div", {
250
377
  className: "relative",
251
- children: [/* @__PURE__ */ p(s, { className: "absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" }), /* @__PURE__ */ p("input", {
378
+ children: [/* @__PURE__ */ h("span", {
379
+ className: "absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground font-medium",
380
+ children: M
381
+ }), /* @__PURE__ */ h("input", {
252
382
  type: "number",
253
- value: b.maxDiscountAmount || "",
254
- onChange: (e) => D("maxDiscountAmount", e.target.value ? parseFloat(e.target.value) : null),
383
+ value: E.maxDiscountAmount || "",
384
+ onChange: (e) => P("maxDiscountAmount", e.target.value ? parseFloat(e.target.value) : null),
255
385
  min: "0",
256
386
  step: "0.01",
257
387
  placeholder: "No maximum",
258
388
  className: "w-full pl-10 pr-4 py-2 rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
259
389
  })]
260
390
  }),
261
- /* @__PURE__ */ p("p", {
391
+ /* @__PURE__ */ g("p", {
262
392
  className: "text-xs text-muted-foreground mt-1",
263
- children: "Cap the discount amount for percentage-based coupons"
393
+ children: [
394
+ "Cap the discount in ",
395
+ E.currency,
396
+ " — auto-converted to the user's payment currency"
397
+ ]
264
398
  })
265
399
  ] })
266
400
  ]
267
401
  }),
268
- /* @__PURE__ */ m("div", {
402
+ /* @__PURE__ */ g("div", {
269
403
  className: "bg-card border border-border rounded-lg p-6 space-y-4",
270
404
  children: [
271
- /* @__PURE__ */ p("h3", {
405
+ /* @__PURE__ */ h("h3", {
272
406
  className: "text-lg font-semibold text-foreground",
273
407
  children: "Usage Limits"
274
408
  }),
275
- /* @__PURE__ */ m("div", { children: [
276
- /* @__PURE__ */ p("label", {
409
+ /* @__PURE__ */ g("div", { children: [
410
+ /* @__PURE__ */ h("label", {
277
411
  className: "block text-sm font-medium text-foreground mb-1",
278
412
  children: "Total Usage Limit"
279
413
  }),
280
- /* @__PURE__ */ p("input", {
414
+ /* @__PURE__ */ h("input", {
281
415
  type: "number",
282
- value: b.maxTotalUses || "",
283
- onChange: (e) => D("maxTotalUses", e.target.value ? parseInt(e.target.value) : null),
416
+ value: E.maxTotalUses || "",
417
+ onChange: (e) => P("maxTotalUses", e.target.value ? parseInt(e.target.value) : null),
284
418
  min: "1",
285
419
  placeholder: "Unlimited",
286
420
  className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
287
421
  }),
288
- /* @__PURE__ */ p("p", {
422
+ /* @__PURE__ */ h("p", {
289
423
  className: "text-xs text-muted-foreground mt-1",
290
424
  children: "Maximum number of times this coupon can be used across all users"
291
425
  })
292
426
  ] }),
293
- /* @__PURE__ */ m("div", { children: [
294
- /* @__PURE__ */ p("label", {
427
+ /* @__PURE__ */ g("div", { children: [
428
+ /* @__PURE__ */ h("label", {
295
429
  className: "block text-sm font-medium text-foreground mb-1",
296
430
  children: "Per-User Limit *"
297
431
  }),
298
- /* @__PURE__ */ p("input", {
432
+ /* @__PURE__ */ h("input", {
299
433
  type: "number",
300
- value: b.maxUsesPerUser,
301
- onChange: (e) => D("maxUsesPerUser", parseInt(e.target.value)),
434
+ value: E.maxUsesPerUser,
435
+ onChange: (e) => P("maxUsesPerUser", parseInt(e.target.value)),
302
436
  min: "1",
303
437
  className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
304
438
  }),
305
- /* @__PURE__ */ p("p", {
439
+ /* @__PURE__ */ h("p", {
306
440
  className: "text-xs text-muted-foreground mt-1",
307
441
  children: "Maximum times a single user can use this coupon"
308
442
  })
309
443
  ] })
310
444
  ]
311
445
  }),
312
- /* @__PURE__ */ m("div", {
446
+ /* @__PURE__ */ g("div", {
313
447
  className: "bg-card border border-border rounded-lg p-6 space-y-4",
314
- children: [/* @__PURE__ */ p("h3", {
448
+ children: [/* @__PURE__ */ h("h3", {
315
449
  className: "text-lg font-semibold text-foreground",
316
450
  children: "Validity Period"
317
- }), /* @__PURE__ */ m("div", {
451
+ }), /* @__PURE__ */ g("div", {
318
452
  className: "grid grid-cols-1 md:grid-cols-2 gap-4",
319
- children: [/* @__PURE__ */ m("div", { children: [
320
- /* @__PURE__ */ p("label", {
453
+ children: [/* @__PURE__ */ g("div", { children: [
454
+ /* @__PURE__ */ h("label", {
321
455
  className: "block text-sm font-medium text-foreground mb-1",
322
456
  children: "Start Date *"
323
457
  }),
324
- /* @__PURE__ */ p("input", {
458
+ /* @__PURE__ */ h("input", {
325
459
  type: "date",
326
- value: b.validFrom,
327
- onChange: (e) => D("validFrom", e.target.value),
328
- className: `w-full px-4 py-2 rounded-lg border ${S.validFrom ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
460
+ value: E.validFrom,
461
+ onChange: (e) => P("validFrom", e.target.value),
462
+ className: `w-full px-4 py-2 rounded-lg border ${O.validFrom ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
329
463
  }),
330
- S.validFrom && /* @__PURE__ */ p("p", {
464
+ O.validFrom && /* @__PURE__ */ h("p", {
331
465
  className: "text-sm text-destructive mt-1",
332
- children: S.validFrom
466
+ children: O.validFrom
333
467
  })
334
- ] }), /* @__PURE__ */ m("div", { children: [
335
- /* @__PURE__ */ p("label", {
468
+ ] }), /* @__PURE__ */ g("div", { children: [
469
+ /* @__PURE__ */ h("label", {
336
470
  className: "block text-sm font-medium text-foreground mb-1",
337
471
  children: "End Date"
338
472
  }),
339
- /* @__PURE__ */ p("input", {
473
+ /* @__PURE__ */ h("input", {
340
474
  type: "date",
341
- value: b.validUntil,
342
- onChange: (e) => D("validUntil", e.target.value),
343
- className: `w-full px-4 py-2 rounded-lg border ${S.validUntil ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
475
+ value: E.validUntil,
476
+ onChange: (e) => P("validUntil", e.target.value),
477
+ className: `w-full px-4 py-2 rounded-lg border ${O.validUntil ? "border-destructive" : "border-border"} bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20`
344
478
  }),
345
- S.validUntil && /* @__PURE__ */ p("p", {
479
+ O.validUntil && /* @__PURE__ */ h("p", {
346
480
  className: "text-sm text-destructive mt-1",
347
- children: S.validUntil
481
+ children: O.validUntil
348
482
  }),
349
- /* @__PURE__ */ p("p", {
483
+ /* @__PURE__ */ h("p", {
350
484
  className: "text-xs text-muted-foreground mt-1",
351
485
  children: "Leave empty for no expiry"
352
486
  })
353
487
  ] })]
354
488
  })]
355
489
  }),
356
- /* @__PURE__ */ m("div", {
490
+ /* @__PURE__ */ g("div", {
357
491
  className: "bg-card border border-border rounded-lg p-6 space-y-4",
358
492
  children: [
359
- /* @__PURE__ */ p("h3", {
493
+ /* @__PURE__ */ h("h3", {
360
494
  className: "text-lg font-semibold text-foreground",
361
495
  children: "Coupon Scope"
362
496
  }),
363
- /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
497
+ /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
364
498
  className: "block text-sm font-medium text-foreground mb-2",
365
499
  children: "Who can use this coupon? *"
366
- }), /* @__PURE__ */ m("select", {
367
- value: b.scope,
368
- onChange: (e) => D("scope", e.target.value),
500
+ }), /* @__PURE__ */ g("select", {
501
+ value: E.scope,
502
+ onChange: (e) => P("scope", e.target.value),
369
503
  className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary/20",
370
504
  children: [
371
- /* @__PURE__ */ p("option", {
505
+ /* @__PURE__ */ h("option", {
372
506
  value: "GENERIC",
373
507
  children: "Anyone (Public)"
374
508
  }),
375
- /* @__PURE__ */ p("option", {
509
+ /* @__PURE__ */ h("option", {
376
510
  value: "USER_SPECIFIC",
377
511
  children: "Specific Users Only"
378
512
  }),
379
- /* @__PURE__ */ p("option", {
513
+ /* @__PURE__ */ h("option", {
380
514
  value: "REFERRAL",
381
515
  children: "Referral Code"
382
516
  }),
383
- /* @__PURE__ */ p("option", {
517
+ /* @__PURE__ */ h("option", {
384
518
  value: "CAMPAIGN",
385
519
  children: "Campaign-Specific"
386
520
  })
387
521
  ]
388
522
  })] }),
389
- b.scope === "CAMPAIGN" && /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
523
+ E.scope === "CAMPAIGN" && /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
390
524
  className: "block text-sm font-medium text-foreground mb-1",
391
525
  children: "Campaign Name"
392
- }), /* @__PURE__ */ p("input", {
526
+ }), /* @__PURE__ */ h("input", {
393
527
  type: "text",
394
- value: b.campaignName,
395
- onChange: (e) => D("campaignName", e.target.value),
528
+ value: E.campaignName,
529
+ onChange: (e) => P("campaignName", e.target.value),
396
530
  placeholder: "e.g., Summer Sale 2024",
397
531
  className: "w-full px-4 py-2 rounded-lg border border-border bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/20"
398
- })] })
532
+ })] }),
533
+ E.scope === "USER_SPECIFIC" && /* @__PURE__ */ g("div", { children: [
534
+ /* @__PURE__ */ h("label", {
535
+ className: "block text-sm font-medium text-foreground mb-1",
536
+ children: /* @__PURE__ */ g("span", {
537
+ className: "flex items-center gap-1.5",
538
+ children: [/* @__PURE__ */ h(f, { className: "size-4" }), "Restricted Users *"]
539
+ })
540
+ }),
541
+ /* @__PURE__ */ g("div", {
542
+ className: `min-h-[42px] flex flex-wrap gap-2 px-3 py-2 rounded-lg border ${O.restrictedToUserIds ? "border-destructive" : "border-border"} bg-background cursor-text`,
543
+ onClick: () => T.current?.focus(),
544
+ children: [E.restrictedToUserIds.map((e) => /* @__PURE__ */ g("span", {
545
+ className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-primary/10 text-primary text-sm font-medium",
546
+ children: [e, /* @__PURE__ */ h("button", {
547
+ type: "button",
548
+ onClick: (t) => {
549
+ t.stopPropagation(), L(e);
550
+ },
551
+ className: "hover:text-destructive",
552
+ children: /* @__PURE__ */ h(p, { className: "size-3" })
553
+ })]
554
+ }, e)), /* @__PURE__ */ h("input", {
555
+ ref: T,
556
+ type: "text",
557
+ value: C,
558
+ onChange: (e) => w(e.target.value),
559
+ onKeyDown: (e) => {
560
+ e.key === "Enter" || e.key === "," ? (e.preventDefault(), I(C)) : e.key === "Backspace" && !C && E.restrictedToUserIds.length > 0 && L(E.restrictedToUserIds[E.restrictedToUserIds.length - 1]);
561
+ },
562
+ onBlur: () => I(C),
563
+ placeholder: E.restrictedToUserIds.length === 0 ? "Enter user email or ID, press Enter to add" : "Add another…",
564
+ className: "flex-1 min-w-[200px] bg-transparent text-foreground placeholder:text-muted-foreground text-sm focus:outline-none"
565
+ })]
566
+ }),
567
+ O.restrictedToUserIds && /* @__PURE__ */ h("p", {
568
+ className: "text-sm text-destructive mt-1",
569
+ children: O.restrictedToUserIds
570
+ }),
571
+ /* @__PURE__ */ h("p", {
572
+ className: "text-xs text-muted-foreground mt-1",
573
+ children: "Type an email or user ID and press Enter or comma to add. Only these users can redeem this coupon."
574
+ })
575
+ ] })
399
576
  ]
400
577
  }),
401
- /* @__PURE__ */ m("div", {
578
+ /* @__PURE__ */ g("div", {
402
579
  className: "flex items-center justify-end gap-3",
403
- children: [/* @__PURE__ */ p("button", {
580
+ children: [/* @__PURE__ */ h("button", {
404
581
  type: "button",
405
- onClick: () => v("/coupons"),
582
+ onClick: () => x("/coupons"),
406
583
  className: "px-6 py-3 rounded-lg border border-border text-foreground hover:bg-muted",
407
584
  children: "Cancel"
408
- }), /* @__PURE__ */ p("button", {
585
+ }), /* @__PURE__ */ h("button", {
409
586
  type: "submit",
410
- disabled: w,
587
+ disabled: A,
411
588
  className: "px-6 py-3 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed",
412
- children: w ? /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", { className: "size-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin" }), "Creating…"] }) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(u, { className: "size-4" }), "Create Coupon"] })
589
+ children: A ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("div", { className: "size-4 border-2 border-primary-foreground border-t-transparent rounded-full animate-spin" }), "Creating…"] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(u, { className: "size-4" }), "Create Coupon"] })
413
590
  })]
414
591
  })
415
592
  ]
@@ -417,6 +594,6 @@ var g = () => {
417
594
  });
418
595
  };
419
596
  //#endregion
420
- export { g as CreateCouponPage };
597
+ export { y as CreateCouponPage };
421
598
 
422
599
  //# sourceMappingURL=CreateCouponPage.js.map