@carlonicora/nextjs-jsonapi 5.4.0 → 5.6.0

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 (237) hide show
  1. package/dist/{BlockNoteEditor-4YCAIEPT.js → BlockNoteEditor-AE3ZTEEH.js} +20 -20
  2. package/dist/{BlockNoteEditor-4YCAIEPT.js.map → BlockNoteEditor-AE3ZTEEH.js.map} +1 -1
  3. package/dist/{BlockNoteEditor-YQL2SGFR.mjs → BlockNoteEditor-NEYG5L6W.mjs} +5 -5
  4. package/dist/{BlockNoteViewer-AEJKJ27Q.mjs → BlockNoteViewer-3OUT5UFY.mjs} +3 -3
  5. package/dist/{BlockNoteViewer-YL3J7J2Y.js → BlockNoteViewer-4CFKQM7U.js} +4 -4
  6. package/dist/{BlockNoteViewer-YL3J7J2Y.js.map → BlockNoteViewer-4CFKQM7U.js.map} +1 -1
  7. package/dist/billing/index.d.mts +186 -25
  8. package/dist/billing/index.d.ts +186 -25
  9. package/dist/billing/index.js +1149 -588
  10. package/dist/billing/index.js.map +1 -1
  11. package/dist/billing/index.mjs +786 -225
  12. package/dist/billing/index.mjs.map +1 -1
  13. package/dist/{chunk-5PPG6PL7.js → chunk-3I5AAJXV.js} +3 -3
  14. package/dist/{chunk-5PPG6PL7.js.map → chunk-3I5AAJXV.js.map} +1 -1
  15. package/dist/{chunk-YW4ZCEWB.js → chunk-53BAULDP.js} +4 -4
  16. package/dist/{chunk-YW4ZCEWB.js.map → chunk-53BAULDP.js.map} +1 -1
  17. package/dist/{chunk-XCHSX3VC.mjs → chunk-BTPUYUQ3.mjs} +2 -2
  18. package/dist/{chunk-WC63PJSC.mjs → chunk-EYA2F6AN.mjs} +756 -24
  19. package/dist/chunk-EYA2F6AN.mjs.map +1 -0
  20. package/dist/{chunk-NFBOSPNJ.js → chunk-HKZAESS6.js} +954 -222
  21. package/dist/chunk-HKZAESS6.js.map +1 -0
  22. package/dist/{chunk-6DC2WVVB.mjs → chunk-KQHBONL4.mjs} +2 -2
  23. package/dist/{chunk-3NLAXVIN.js → chunk-LQ4DK4JF.js} +1988 -1089
  24. package/dist/chunk-LQ4DK4JF.js.map +1 -0
  25. package/dist/{chunk-YNCQSWQW.js → chunk-RL3PL3KV.js} +8 -8
  26. package/dist/{chunk-YNCQSWQW.js.map → chunk-RL3PL3KV.js.map} +1 -1
  27. package/dist/{chunk-EUKTBOI2.mjs → chunk-SFYPXCK4.mjs} +3382 -2483
  28. package/dist/chunk-SFYPXCK4.mjs.map +1 -0
  29. package/dist/{chunk-QMYQRPQC.mjs → chunk-Y7RR57EW.mjs} +2 -2
  30. package/dist/client/index.js +5 -5
  31. package/dist/client/index.js.map +1 -1
  32. package/dist/client/index.mjs +4 -4
  33. package/dist/components/editors/server.d.mts +15 -0
  34. package/dist/components/editors/server.d.ts +15 -0
  35. package/dist/components/editors/server.js +38 -0
  36. package/dist/components/editors/server.js.map +1 -0
  37. package/dist/components/editors/server.mjs +38 -0
  38. package/dist/components/editors/server.mjs.map +1 -0
  39. package/dist/components/index.d.mts +33 -10
  40. package/dist/components/index.d.ts +33 -10
  41. package/dist/components/index.js +7 -5
  42. package/dist/components/index.js.map +1 -1
  43. package/dist/components/index.mjs +8 -6
  44. package/dist/contexts/index.d.mts +9 -1
  45. package/dist/contexts/index.d.ts +9 -1
  46. package/dist/contexts/index.js +5 -5
  47. package/dist/contexts/index.mjs +4 -4
  48. package/dist/core/index.d.mts +242 -3
  49. package/dist/core/index.d.ts +242 -3
  50. package/dist/core/index.js +36 -4
  51. package/dist/core/index.js.map +1 -1
  52. package/dist/core/index.mjs +35 -3
  53. package/dist/email-automations/index.d.mts +3 -0
  54. package/dist/email-automations/index.d.ts +3 -0
  55. package/dist/email-automations/index.js +99 -95
  56. package/dist/email-automations/index.js.map +1 -1
  57. package/dist/email-automations/index.mjs +30 -26
  58. package/dist/email-automations/index.mjs.map +1 -1
  59. package/dist/features/analytics/index.d.mts +11 -4
  60. package/dist/features/analytics/index.d.ts +11 -4
  61. package/dist/features/analytics/index.js +127 -135
  62. package/dist/features/analytics/index.js.map +1 -1
  63. package/dist/features/analytics/index.mjs +16 -24
  64. package/dist/features/analytics/index.mjs.map +1 -1
  65. package/dist/features/analytics/server.d.mts +5 -2
  66. package/dist/features/analytics/server.d.ts +5 -2
  67. package/dist/features/analytics/server.js +7 -7
  68. package/dist/features/analytics/server.js.map +1 -1
  69. package/dist/features/analytics/server.mjs +5 -5
  70. package/dist/features/analytics/server.mjs.map +1 -1
  71. package/dist/features/blog/index.d.mts +12 -2
  72. package/dist/features/blog/index.d.ts +12 -2
  73. package/dist/features/blog/index.js +206 -195
  74. package/dist/features/blog/index.js.map +1 -1
  75. package/dist/features/blog/index.mjs +71 -60
  76. package/dist/features/blog/index.mjs.map +1 -1
  77. package/dist/features/blog/server.d.mts +4 -1
  78. package/dist/features/blog/server.d.ts +4 -1
  79. package/dist/features/blog/server.js +49 -21
  80. package/dist/features/blog/server.js.map +1 -1
  81. package/dist/features/blog/server.mjs +36 -8
  82. package/dist/features/blog/server.mjs.map +1 -1
  83. package/dist/features/help/index.js +38 -38
  84. package/dist/features/help/index.mjs +4 -4
  85. package/dist/features/tokenusage/index.d.mts +1 -3
  86. package/dist/features/tokenusage/index.d.ts +1 -3
  87. package/dist/features/tokenusage/index.js +127 -135
  88. package/dist/features/tokenusage/index.js.map +1 -1
  89. package/dist/features/tokenusage/index.mjs +10 -18
  90. package/dist/features/tokenusage/index.mjs.map +1 -1
  91. package/dist/{stripe-promotion-code.interface-C3qqh3mi.d.ts → format-options-BtX3o0Yu.d.ts} +104 -1
  92. package/dist/{stripe-promotion-code.interface-ClZ7DxS9.d.mts → format-options-D6c7FNDi.d.mts} +104 -1
  93. package/dist/index.d.mts +2 -2
  94. package/dist/index.d.ts +2 -2
  95. package/dist/index.js +37 -5
  96. package/dist/index.js.map +1 -1
  97. package/dist/index.mjs +36 -4
  98. package/dist/server/index.js +4 -4
  99. package/dist/server/index.mjs +3 -3
  100. package/messages/en.json +125 -3
  101. package/messages/it.json +125 -3
  102. package/package.json +9 -1
  103. package/scripts/validate-messages.mjs +1 -0
  104. package/src/billing/index.ts +1 -0
  105. package/src/client/index.ts +4 -0
  106. package/src/components/editors/server/BlockNoteServerContent.tsx +28 -0
  107. package/src/components/editors/server/__tests__/renderBlockNoteHTML.spec.ts +44 -0
  108. package/src/components/editors/server/renderBlockNoteHTML.ts +26 -0
  109. package/src/components/editors/server-entry.ts +7 -0
  110. package/src/components/index.ts +1 -0
  111. package/src/components/viewers/BlockNoteStaticViewer.tsx +44 -0
  112. package/src/core/index.ts +1 -0
  113. package/src/core/registry/ModuleRegistry.ts +3 -0
  114. package/src/features/administration/components/AdminIndexContainer.tsx +61 -33
  115. package/src/features/administration/components/__tests__/AdminIndexContainer.spec.tsx +61 -1
  116. package/src/features/administration/components/index.ts +2 -1
  117. package/src/features/administration/contexts/AdministrationContext.tsx +11 -3
  118. package/src/features/administration/contexts/__tests__/AdministrationContext.spec.tsx +40 -0
  119. package/src/features/ai-connection/ai-connection.module.ts +2 -0
  120. package/src/features/ai-connection/contexts/AiConnectionsContext.tsx +3 -16
  121. package/src/features/ai-connection/contexts/__tests__/AiConnectionsContext.spec.tsx +33 -0
  122. package/src/features/analytics/__tests__/server-entry.spec.tsx +2 -1
  123. package/src/features/analytics/analytics.modules.ts +22 -5
  124. package/src/features/analytics/components/AnalyticsAdminContainer.tsx +4 -3
  125. package/src/features/analytics/components/AnalyticsAdminPageContainer.tsx +6 -3
  126. package/src/features/analytics/components/AnalyticsJourneyContainer.tsx +4 -3
  127. package/src/features/analytics/components/__tests__/AnalyticsJourneyContainer.spec.tsx +11 -0
  128. package/src/features/analytics/components/__tests__/AnalyticsPageContainers.spec.tsx +12 -1
  129. package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +6 -3
  130. package/src/features/analytics/contexts/AnalyticsAdminContext.tsx +8 -17
  131. package/src/features/analytics/contexts/__tests__/AnalyticsAdminContext.spec.tsx +17 -0
  132. package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +3 -2
  133. package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +4 -3
  134. package/src/features/billing/components/containers/BillingDashboardContainer.tsx +22 -5
  135. package/src/features/billing/components/utils/__tests__/discount.spec.ts +59 -0
  136. package/src/features/billing/components/utils/__tests__/url.spec.ts +32 -0
  137. package/src/features/billing/components/utils/discount.ts +38 -0
  138. package/src/features/billing/components/utils/index.ts +2 -0
  139. package/src/features/billing/components/utils/url.ts +12 -0
  140. package/src/features/billing/contexts/CouponContext.tsx +211 -0
  141. package/src/features/billing/contexts/index.ts +1 -0
  142. package/src/features/billing/i18n-keys.ts +79 -0
  143. package/src/features/billing/stripe-coupon/components/containers/CouponContainer.tsx +38 -0
  144. package/src/features/billing/stripe-coupon/components/containers/index.ts +1 -0
  145. package/src/features/billing/stripe-coupon/components/details/CouponDetails.tsx +69 -0
  146. package/src/features/billing/stripe-coupon/components/details/index.ts +1 -0
  147. package/src/features/billing/stripe-coupon/components/forms/CouponCodeEditor.tsx +79 -0
  148. package/src/features/billing/stripe-coupon/components/forms/CouponCodeFields.tsx +192 -0
  149. package/src/features/billing/stripe-coupon/components/forms/CouponEditor.tsx +333 -0
  150. package/src/features/billing/stripe-coupon/components/forms/CouponRefresher.tsx +45 -0
  151. package/src/features/billing/stripe-coupon/components/forms/index.ts +6 -0
  152. package/src/features/billing/stripe-coupon/components/index.ts +5 -0
  153. package/src/features/billing/stripe-coupon/components/lists/CouponCodesList.tsx +61 -0
  154. package/src/features/billing/stripe-coupon/components/lists/CouponsList.tsx +67 -0
  155. package/src/features/billing/stripe-coupon/components/lists/index.ts +2 -0
  156. package/src/features/billing/stripe-coupon/components/widgets/CouponCodeActions.tsx +80 -0
  157. package/src/features/billing/stripe-coupon/components/widgets/index.ts +1 -0
  158. package/src/features/billing/stripe-coupon/data/__tests__/stripe-coupon-models.spec.ts +114 -0
  159. package/src/features/billing/stripe-coupon/data/index.ts +10 -0
  160. package/src/features/billing/stripe-coupon/data/stripe-coupon-code.fields.ts +8 -0
  161. package/src/features/billing/stripe-coupon/data/stripe-coupon-code.interface.ts +44 -0
  162. package/src/features/billing/stripe-coupon/data/stripe-coupon-code.service.ts +92 -0
  163. package/src/features/billing/stripe-coupon/data/stripe-coupon-code.ts +132 -0
  164. package/src/features/billing/stripe-coupon/data/stripe-coupon-offer.interface.ts +17 -0
  165. package/src/features/billing/stripe-coupon/data/stripe-coupon-offer.ts +70 -0
  166. package/src/features/billing/stripe-coupon/data/stripe-coupon.fields.ts +7 -0
  167. package/src/features/billing/stripe-coupon/data/stripe-coupon.interface.ts +51 -0
  168. package/src/features/billing/stripe-coupon/data/stripe-coupon.service.ts +93 -0
  169. package/src/features/billing/stripe-coupon/data/stripe-coupon.ts +165 -0
  170. package/src/features/billing/stripe-coupon/hooks/useStripeCouponCodeTableStructure.tsx +154 -0
  171. package/src/features/billing/stripe-coupon/hooks/useStripeCouponTableStructure.tsx +113 -0
  172. package/src/features/billing/stripe-coupon/index.ts +5 -0
  173. package/src/features/billing/stripe-coupon/stripe-coupon-code.module.ts +14 -0
  174. package/src/features/billing/stripe-coupon/stripe-coupon-offer.module.ts +10 -0
  175. package/src/features/billing/stripe-coupon/stripe-coupon.module.ts +18 -0
  176. package/src/features/billing/stripe-coupon/utils/__tests__/coupon-places.spec.ts +19 -0
  177. package/src/features/billing/stripe-coupon/utils/__tests__/to-promotion-code-result.spec.ts +41 -0
  178. package/src/features/billing/stripe-coupon/utils/coupon-places.ts +23 -0
  179. package/src/features/billing/stripe-coupon/utils/format-coupon-discount.ts +36 -0
  180. package/src/features/billing/stripe-coupon/utils/index.ts +3 -0
  181. package/src/features/billing/stripe-coupon/utils/to-promotion-code-result.ts +23 -0
  182. package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +24 -8
  183. package/src/features/billing/stripe-price/stripe-price.module.ts +2 -0
  184. package/src/features/billing/stripe-product/components/containers/ProductsListContainer.tsx +21 -6
  185. package/src/features/billing/stripe-product/stripe-product.module.ts +2 -0
  186. package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +60 -19
  187. package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.interface.ts +2 -0
  188. package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +24 -5
  189. package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +21 -2
  190. package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +1 -1
  191. package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +1 -1
  192. package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +60 -49
  193. package/src/features/billing/stripe-subscription/components/wizards/__tests__/review-card.spec.ts +34 -0
  194. package/src/features/billing/stripe-subscription/components/wizards/review-card.ts +24 -0
  195. package/src/features/billing/stripe-subscription/data/__tests__/stripe-subscription.discount.spec.ts +67 -0
  196. package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +14 -0
  197. package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +39 -0
  198. package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +21 -0
  199. package/src/features/billing/stripe-subscription/hooks/__tests__/wizard-payment.spec.ts +48 -0
  200. package/src/features/billing/stripe-subscription/hooks/__tests__/wizard-promotion.spec.ts +132 -0
  201. package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +138 -12
  202. package/src/features/billing/stripe-subscription/hooks/wizard-payment.ts +30 -0
  203. package/src/features/billing/stripe-subscription/hooks/wizard-promotion.ts +54 -0
  204. package/src/features/blog/components/admin/BlogAdminContainer.tsx +13 -6
  205. package/src/features/blog/components/admin/BlogCategoriesList.tsx +1 -1
  206. package/src/features/blog/components/admin/BlogCoverImageField.tsx +1 -1
  207. package/src/features/blog/components/admin/BlogPostContainer.tsx +0 -1
  208. package/src/features/blog/components/admin/BlogPostEditor.tsx +42 -33
  209. package/src/features/blog/components/admin/BlogPostTranslationEditor.tsx +12 -4
  210. package/src/features/blog/components/admin/BlogPostsList.tsx +1 -1
  211. package/src/features/blog/components/public/BlogPostCard.tsx +2 -9
  212. package/src/features/blog/components/public/BlogPostMeta.tsx +2 -2
  213. package/src/features/blog/components/public/BlogPostView.tsx +9 -3
  214. package/src/features/blog/components/public/__tests__/BlogList.spec.tsx +2 -0
  215. package/src/features/blog/components/public/__tests__/BlogPostView.spec.tsx +17 -11
  216. package/src/features/blog/server/fetchers.ts +57 -8
  217. package/src/features/email-automation/components/containers/EmailAutomationsListContainer.tsx +12 -3
  218. package/src/features/rbac/contexts/RbacContext.tsx +4 -7
  219. package/src/features/rbac/contexts/__tests__/RbacContext.spec.tsx +42 -0
  220. package/src/features/tokenusage/components/TokenUsageAdminContainer.tsx +4 -3
  221. package/src/features/tokenusage/contexts/TokenUsageAdminContext.tsx +3 -18
  222. package/src/features/tokenusage/contexts/__tests__/TokenUsageAdminContext.spec.tsx +17 -0
  223. package/src/features/tokenusage/tokenusage-admin.module.ts +4 -3
  224. package/src/features/tokenusage/tokenusage.modules.ts +12 -2
  225. package/src/features/user/contexts/CurrentUserContext.tsx +25 -0
  226. package/src/features/user/contexts/UserContext.tsx +18 -3
  227. package/src/features/user/contexts/__tests__/CurrentUserContext.spec.tsx +121 -2
  228. package/src/features/user/contexts/__tests__/UserContext.spec.tsx +95 -0
  229. package/dist/chunk-3NLAXVIN.js.map +0 -1
  230. package/dist/chunk-EUKTBOI2.mjs.map +0 -1
  231. package/dist/chunk-NFBOSPNJ.js.map +0 -1
  232. package/dist/chunk-WC63PJSC.mjs.map +0 -1
  233. /package/dist/{BlockNoteEditor-YQL2SGFR.mjs.map → BlockNoteEditor-NEYG5L6W.mjs.map} +0 -0
  234. /package/dist/{BlockNoteViewer-AEJKJ27Q.mjs.map → BlockNoteViewer-3OUT5UFY.mjs.map} +0 -0
  235. /package/dist/{chunk-XCHSX3VC.mjs.map → chunk-BTPUYUQ3.mjs.map} +0 -0
  236. /package/dist/{chunk-6DC2WVVB.mjs.map → chunk-KQHBONL4.mjs.map} +0 -0
  237. /package/dist/{chunk-QMYQRPQC.mjs.map → chunk-Y7RR57EW.mjs.map} +0 -0
@@ -22,6 +22,11 @@ import {
22
22
  Checkbox,
23
23
  ConfirmDialog,
24
24
  ContentListTable,
25
+ CouponCodeActions,
26
+ CouponCodeFields,
27
+ CouponEditor,
28
+ CouponProvider,
29
+ CouponRefresher,
25
30
  DetailField,
26
31
  Dialog,
27
32
  DialogContent,
@@ -56,19 +61,27 @@ import {
56
61
  Tabs,
57
62
  TabsList,
58
63
  TabsTrigger,
64
+ applyDiscount,
65
+ couponCodeDefaults,
66
+ couponCodeSchema,
67
+ couponCurrencyOptions,
59
68
  errorToast,
60
- formatCurrency,
61
69
  formatDate,
62
- formatFixed,
63
- formatInterval,
70
+ optionalDate,
71
+ optionalDecimal,
72
+ optionalPositiveInt,
73
+ promotionCodeDiscount,
74
+ subscriptionDiscount,
75
+ toCouponCodeInput,
64
76
  useBillingFormatOptions,
77
+ useCouponContext,
65
78
  useCurrentUserContext,
66
79
  useDataListRetriever,
67
80
  usePageUrlGenerator
68
- } from "../chunk-EUKTBOI2.mjs";
81
+ } from "../chunk-SFYPXCK4.mjs";
69
82
  import {
70
83
  getStripePublishableKey
71
- } from "../chunk-QMYQRPQC.mjs";
84
+ } from "../chunk-Y7RR57EW.mjs";
72
85
  import {
73
86
  getRoleId
74
87
  } from "../chunk-PW42LRSL.mjs";
@@ -76,6 +89,8 @@ import {
76
89
  FeatureService,
77
90
  InvoiceStatus,
78
91
  Modules,
92
+ StripeCouponCodeService,
93
+ StripeCouponService,
79
94
  StripeCustomerService,
80
95
  StripeInvoiceService,
81
96
  StripePriceService,
@@ -85,14 +100,19 @@ import {
85
100
  StripeUsageService,
86
101
  SubscriptionStatus,
87
102
  cn,
103
+ formatCouponDiscount,
104
+ formatCurrency,
105
+ formatFixed,
106
+ formatInterval,
88
107
  rehydrate,
89
108
  showToast,
109
+ toPromotionCodeResult,
90
110
  useI18nLocale,
91
111
  useI18nRouter
92
- } from "../chunk-WC63PJSC.mjs";
112
+ } from "../chunk-EYA2F6AN.mjs";
113
+ import "../chunk-V5MI7RNB.mjs";
93
114
  import "../chunk-AUXK7QSA.mjs";
94
115
  import "../chunk-PI56A4DG.mjs";
95
- import "../chunk-V5MI7RNB.mjs";
96
116
  import "../chunk-VOXD3ZLY.mjs";
97
117
  import {
98
118
  __name
@@ -166,7 +186,7 @@ function SubscriptionSummaryCard({
166
186
  /* @__PURE__ */ jsx(CardTitle, { children: t("billing.ui.subscriptions.title") }),
167
187
  /* @__PURE__ */ jsx(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
168
188
  ] }),
169
- /* @__PURE__ */ jsx(CardContent, { children: subscriptions.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
189
+ /* @__PURE__ */ jsx(CardContent, { children: !primarySubscription ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
170
190
  /* @__PURE__ */ jsx("p", { className: "text-xl font-bold text-muted-foreground", children: t("billing.ui.cards.subscriptions.empty_title") }),
171
191
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("billing.ui.cards.subscriptions.empty_description") }),
172
192
  /* @__PURE__ */ jsxs(
@@ -185,7 +205,7 @@ function SubscriptionSummaryCard({
185
205
  ]
186
206
  }
187
207
  )
188
- ] }) : primarySubscription ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
208
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
189
209
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
190
210
  /* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: formatPlanName(primarySubscription, t("billing.ui.cards.subscriptions.fallback_name")) }),
191
211
  /* @__PURE__ */ jsx(
@@ -204,7 +224,7 @@ function SubscriptionSummaryCard({
204
224
  date: formatDate(primarySubscription.currentPeriodEnd, fmt)
205
225
  }) }),
206
226
  activeSubscriptions.length > 1 && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("billing.ui.cards.subscriptions.more", { count: activeSubscriptions.length - 1 }) })
207
- ] }) : null })
227
+ ] }) })
208
228
  ] });
209
229
  }
210
230
  __name(SubscriptionSummaryCard, "SubscriptionSummaryCard");
@@ -438,7 +458,7 @@ function InvoicesSummaryCard({ invoices, loading, error, onViewAllClick }) {
438
458
  /* @__PURE__ */ jsx4(CardContent, { children: /* @__PURE__ */ jsx4("p", { className: "text-destructive text-xs/relaxed", children: error }) })
439
459
  ] });
440
460
  }
441
- const latestInvoice = invoices[0];
461
+ const latestInvoice = invoices.find((inv) => inv.status !== "void" /* VOID */) ?? invoices[0];
442
462
  const paidInvoices = invoices.filter((inv) => inv.status === "paid" /* PAID */);
443
463
  const openInvoices = invoices.filter((inv) => inv.status === "open" /* OPEN */);
444
464
  return /* @__PURE__ */ jsxs4(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onViewAllClick, children: [
@@ -540,10 +560,10 @@ function BillingUsageSummaryCard({
540
560
  __name(BillingUsageSummaryCard, "BillingUsageSummaryCard");
541
561
 
542
562
  // src/features/billing/components/containers/BillingDashboardContainer.tsx
543
- import { useTranslations as useTranslations36 } from "next-intl";
563
+ import { useTranslations as useTranslations37 } from "next-intl";
544
564
  import { CreditCard as CreditCard4, Loader2 as Loader23, Wallet as Wallet2 } from "lucide-react";
545
565
  import { useSearchParams } from "next/navigation";
546
- import { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo3, useState as useState14 } from "react";
566
+ import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo3, useState as useState16 } from "react";
547
567
 
548
568
  // src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx
549
569
  import { useTranslations as useTranslations9 } from "next-intl";
@@ -558,7 +578,12 @@ import { useTranslations as useTranslations6 } from "next-intl";
558
578
  import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
559
579
  import { useEffect, useState as useState2 } from "react";
560
580
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
561
- function PaymentMethodForm({ onSuccess, onCancel, isLoading = false }) {
581
+ function PaymentMethodForm({
582
+ onSuccess,
583
+ onCancel,
584
+ isLoading = false,
585
+ alwaysSetDefault = false
586
+ }) {
562
587
  const t = useTranslations6();
563
588
  const stripe = useStripe();
564
589
  const elements = useElements();
@@ -608,7 +633,7 @@ function PaymentMethodForm({ onSuccess, onCancel, isLoading = false }) {
608
633
  setIsSubmitting(false);
609
634
  return;
610
635
  }
611
- if (setAsDefault && confirmedSetupIntent?.payment_method) {
636
+ if ((alwaysSetDefault || setAsDefault) && confirmedSetupIntent?.payment_method) {
612
637
  await StripeCustomerService.setDefaultPaymentMethod({
613
638
  paymentMethodId: typeof confirmedSetupIntent.payment_method === "string" ? confirmedSetupIntent.payment_method : confirmedSetupIntent.payment_method.id
614
639
  });
@@ -647,8 +672,15 @@ function PaymentMethodForm({ onSuccess, onCancel, isLoading = false }) {
647
672
  }
648
673
  }
649
674
  ) }),
650
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-x-2", children: [
651
- /* @__PURE__ */ jsx6(Checkbox, { id: "setAsDefault", checked: setAsDefault, onCheckedChange: (checked) => setSetAsDefault(!!checked) }),
675
+ !alwaysSetDefault && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-x-2", children: [
676
+ /* @__PURE__ */ jsx6(
677
+ Checkbox,
678
+ {
679
+ id: "setAsDefault",
680
+ checked: setAsDefault,
681
+ onCheckedChange: (checked) => setSetAsDefault(!!checked)
682
+ }
683
+ ),
652
684
  /* @__PURE__ */ jsx6(Label, { htmlFor: "setAsDefault", className: "cursor-pointer font-normal", children: t("billing.ui.payment_form.set_default") })
653
685
  ] }),
654
686
  error && /* @__PURE__ */ jsx6(Alert, { variant: "destructive", className: "bg-red-50 border-red-200", children: /* @__PURE__ */ jsx6(AlertDescription, { children: error }) }),
@@ -1426,6 +1458,7 @@ function SubscriptionsList({ subscriptions, onSubscriptionsChange, onChangePlan
1426
1458
  /* @__PURE__ */ jsx18(TableBody, { children: subscriptions.map((subscription) => {
1427
1459
  const price = subscription.price;
1428
1460
  const amount = price?.unitAmount ? formatCurrency(price.unitAmount, price.currency, fmt) : "0";
1461
+ const discountedAmount = price ? applyDiscount(price.unitAmount, subscriptionDiscount(subscription)) : null;
1429
1462
  const period = `${formatDate(subscription.currentPeriodStart, fmt)} - ${formatDate(subscription.currentPeriodEnd, fmt)}`;
1430
1463
  return /* @__PURE__ */ jsxs15(
1431
1464
  TableRow,
@@ -1442,7 +1475,10 @@ function SubscriptionsList({ subscriptions, onSubscriptionsChange, onChangePlan
1442
1475
  ) }),
1443
1476
  /* @__PURE__ */ jsx18(TableCell, { className: "font-medium", children: formatPlanName3(price, t) }),
1444
1477
  /* @__PURE__ */ jsx18(TableCell, { className: "text-muted-foreground text-sm", children: period }),
1445
- /* @__PURE__ */ jsx18(TableCell, { className: "text-end font-medium", children: amount }),
1478
+ /* @__PURE__ */ jsx18(TableCell, { className: "text-end font-medium", children: discountedAmount !== null && price ? /* @__PURE__ */ jsxs15(Fragment4, { children: [
1479
+ /* @__PURE__ */ jsx18("span", { className: "line-through text-muted-foreground me-2", children: amount }),
1480
+ /* @__PURE__ */ jsx18("span", { className: "text-success", children: formatCurrency(discountedAmount, price.currency, fmt) })
1481
+ ] }) : amount }),
1446
1482
  /* @__PURE__ */ jsx18(TableCell, { className: "text-end", children: (subscription.status === "active" /* ACTIVE */ || subscription.status === "trialing" /* TRIALING */) && onChangePlan && /* @__PURE__ */ jsx18(
1447
1483
  Button,
1448
1484
  {
@@ -1483,11 +1519,23 @@ __name(SubscriptionsList, "SubscriptionsList");
1483
1519
 
1484
1520
  // src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx
1485
1521
  import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
1486
- function SubscriptionsContainer({ onOpenWizard, hasActiveRecurringSubscription }) {
1522
+ function SubscriptionsContainer({
1523
+ onOpenWizard,
1524
+ hasActiveRecurringSubscription,
1525
+ subscriptions: parentSubscriptions,
1526
+ onSubscriptionsChange
1527
+ }) {
1487
1528
  const t = useTranslations18();
1488
- const [subscriptions, setSubscriptions] = useState10([]);
1489
- const [loading, setLoading] = useState10(true);
1529
+ const isControlled = parentSubscriptions !== void 0;
1530
+ const [ownSubscriptions, setSubscriptions] = useState10([]);
1531
+ const [ownLoading, setLoading] = useState10(!isControlled);
1532
+ const subscriptions = parentSubscriptions ?? ownSubscriptions;
1533
+ const loading = isControlled ? false : ownLoading;
1490
1534
  const loadSubscriptions = useCallback(async () => {
1535
+ if (isControlled) {
1536
+ onSubscriptionsChange?.();
1537
+ return;
1538
+ }
1491
1539
  setLoading(true);
1492
1540
  try {
1493
1541
  const fetchedSubscriptions = await StripeSubscriptionService.listSubscriptions();
@@ -1497,9 +1545,9 @@ function SubscriptionsContainer({ onOpenWizard, hasActiveRecurringSubscription }
1497
1545
  } finally {
1498
1546
  setLoading(false);
1499
1547
  }
1500
- }, []);
1548
+ }, [isControlled, onSubscriptionsChange]);
1501
1549
  useEffect5(() => {
1502
- loadSubscriptions();
1550
+ if (!isControlled) loadSubscriptions();
1503
1551
  }, []);
1504
1552
  const criticalSubscriptions = subscriptions.filter(
1505
1553
  (sub) => sub.status === "past_due" /* PAST_DUE */ || sub.status === "trialing" /* TRIALING */ && sub.trialEnd && new Date(sub.trialEnd).getTime() - (/* @__PURE__ */ new Date()).getTime() <= 7 * 24 * 60 * 60 * 1e3
@@ -1824,13 +1872,122 @@ function SubscriptionConfirmation({ price, isLoading, onConfirm, onCancel }) {
1824
1872
  __name(SubscriptionConfirmation, "SubscriptionConfirmation");
1825
1873
 
1826
1874
  // src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx
1827
- import { useTranslations as useTranslations31 } from "next-intl";
1828
- import { useCallback as useCallback3, useEffect as useEffect7, useRef as useRef2 } from "react";
1875
+ import { useTranslations as useTranslations32 } from "next-intl";
1876
+ import { useCallback as useCallback4, useEffect as useEffect8, useRef as useRef2 } from "react";
1829
1877
 
1830
1878
  // src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts
1831
- import { useTranslations as useTranslations25 } from "next-intl";
1832
- import { useCallback as useCallback2, useMemo, useReducer, useRef } from "react";
1879
+ import { useTranslations as useTranslations26 } from "next-intl";
1880
+ import { useCallback as useCallback3, useMemo, useReducer, useRef } from "react";
1833
1881
  import { v4 } from "uuid";
1882
+
1883
+ // src/features/billing/stripe-subscription/hooks/wizard-promotion.ts
1884
+ function promotionCodeToSend(code) {
1885
+ if (!code) return void 0;
1886
+ return code.promotionCodeId;
1887
+ }
1888
+ __name(promotionCodeToSend, "promotionCodeToSend");
1889
+ function shouldLookUpAutomatic(code) {
1890
+ return !code || code.automatic === true;
1891
+ }
1892
+ __name(shouldLookUpAutomatic, "shouldLookUpAutomatic");
1893
+ function errorStatus(error) {
1894
+ return error?.status ?? error?.response?.status;
1895
+ }
1896
+ __name(errorStatus, "errorStatus");
1897
+ function errorCode(error) {
1898
+ const body = error?.body;
1899
+ const first = body?.errors?.[0];
1900
+ const code = first?.code ?? first?.meta?.context?.code ?? body?.code;
1901
+ return typeof code === "string" ? code : void 0;
1902
+ }
1903
+ __name(errorCode, "errorCode");
1904
+ function isDiscountSoldOut(error) {
1905
+ return errorStatus(error) === 410 && errorCode(error) === "discount_sold_out";
1906
+ }
1907
+ __name(isDiscountSoldOut, "isDiscountSoldOut");
1908
+ function isDiscountUnavailable(error) {
1909
+ return errorStatus(error) === 422 && errorCode(error) === "discount_unavailable";
1910
+ }
1911
+ __name(isDiscountUnavailable, "isDiscountUnavailable");
1912
+
1913
+ // src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts
1914
+ import { useStripe as useStripe2 } from "@stripe/react-stripe-js";
1915
+ import { useTranslations as useTranslations25 } from "next-intl";
1916
+ import { useCallback as useCallback2, useState as useState11 } from "react";
1917
+ function useConfirmSubscriptionPayment() {
1918
+ const stripe = useStripe2();
1919
+ const t = useTranslations25();
1920
+ const [isConfirming, setIsConfirming] = useState11(false);
1921
+ const confirmPayment = useCallback2(
1922
+ async (clientSecret) => {
1923
+ if (!stripe) {
1924
+ console.error("[useConfirmSubscriptionPayment] Stripe not initialized");
1925
+ return {
1926
+ success: false,
1927
+ error: t("billing.ui.payment_confirm.errors.not_initialized")
1928
+ };
1929
+ }
1930
+ if (!clientSecret) {
1931
+ console.error("[useConfirmSubscriptionPayment] No client secret provided");
1932
+ return {
1933
+ success: false,
1934
+ error: t("billing.ui.payment_confirm.errors.missing_details")
1935
+ };
1936
+ }
1937
+ setIsConfirming(true);
1938
+ try {
1939
+ const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret);
1940
+ if (stripeError) {
1941
+ console.error("[useConfirmSubscriptionPayment] Stripe error:", stripeError);
1942
+ return {
1943
+ success: false,
1944
+ error: stripeError.message || t("billing.ui.payment_confirm.errors.failed")
1945
+ };
1946
+ }
1947
+ if (paymentIntent?.status === "succeeded") {
1948
+ return { success: true };
1949
+ }
1950
+ if (paymentIntent?.status === "requires_action") {
1951
+ return {
1952
+ success: false,
1953
+ error: t("billing.ui.payment_confirm.errors.requires_action")
1954
+ };
1955
+ }
1956
+ return {
1957
+ success: false,
1958
+ error: t("billing.ui.payment_confirm.errors.not_completed")
1959
+ };
1960
+ } catch (err) {
1961
+ console.error("[useConfirmSubscriptionPayment] Unexpected error:", err);
1962
+ return {
1963
+ success: false,
1964
+ error: err.message || t("billing.ui.payment_confirm.errors.unexpected")
1965
+ };
1966
+ } finally {
1967
+ setIsConfirming(false);
1968
+ }
1969
+ },
1970
+ [stripe, t]
1971
+ );
1972
+ return {
1973
+ confirmPayment,
1974
+ isConfirming
1975
+ };
1976
+ }
1977
+ __name(useConfirmSubscriptionPayment, "useConfirmSubscriptionPayment");
1978
+
1979
+ // src/features/billing/stripe-subscription/hooks/wizard-payment.ts
1980
+ function clientSecretToConfirm(meta) {
1981
+ if (!meta?.requiresAction) return null;
1982
+ return meta.clientSecret || null;
1983
+ }
1984
+ __name(clientSecretToConfirm, "clientSecretToConfirm");
1985
+ function subscriptionIdToSync(answered, opened) {
1986
+ return answered?.id || opened?.id || null;
1987
+ }
1988
+ __name(subscriptionIdToSync, "subscriptionIdToSync");
1989
+
1990
+ // src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts
1834
1991
  var initialState = {
1835
1992
  step: "plan-selection",
1836
1993
  selectedPrice: null,
@@ -1876,8 +2033,9 @@ function wizardReducer(state, action) {
1876
2033
  }
1877
2034
  __name(wizardReducer, "wizardReducer");
1878
2035
  function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1879
- const t = useTranslations25();
2036
+ const t = useTranslations26();
1880
2037
  const locale = useI18nLocale();
2038
+ const { confirmPayment } = useConfirmSubscriptionPayment();
1881
2039
  const [state, dispatch] = useReducer(wizardReducer, {
1882
2040
  ...initialState,
1883
2041
  selectedPrice: subscription?.price || null
@@ -1886,7 +2044,7 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1886
2044
  const onCloseRef = useRef(onClose);
1887
2045
  onSuccessRef.current = onSuccess;
1888
2046
  onCloseRef.current = onClose;
1889
- const checkPaymentMethod = useCallback2(async () => {
2047
+ const checkPaymentMethod = useCallback3(async () => {
1890
2048
  try {
1891
2049
  const methods = await StripeCustomerService.listPaymentMethods();
1892
2050
  dispatch({ type: "SET_HAS_PAYMENT_METHOD", hasMethod: methods.length > 0 });
@@ -1895,16 +2053,40 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1895
2053
  dispatch({ type: "SET_HAS_PAYMENT_METHOD", hasMethod: false });
1896
2054
  }
1897
2055
  }, []);
1898
- const selectPrice = useCallback2((price) => {
2056
+ const selectPrice = useCallback3((price) => {
1899
2057
  dispatch({ type: "SELECT_PRICE", price });
1900
2058
  }, []);
1901
- const setInterval = useCallback2((interval) => {
2059
+ const setInterval = useCallback3((interval) => {
1902
2060
  dispatch({ type: "SET_INTERVAL", interval });
1903
2061
  }, []);
1904
- const goToStep = useCallback2((step) => {
2062
+ const goToStep = useCallback3((step) => {
1905
2063
  dispatch({ type: "SET_STEP", step });
1906
2064
  }, []);
1907
- const goToReview = useCallback2(async () => {
2065
+ const lookUpAutomaticCode = useCallback3(async (priceId) => {
2066
+ try {
2067
+ const automaticCode = await StripeCouponCodeService.findAutomatic({ priceId });
2068
+ dispatch({
2069
+ type: "SET_PROMOTION_CODE",
2070
+ code: automaticCode ? toPromotionCodeResult(automaticCode) : null
2071
+ });
2072
+ return true;
2073
+ } catch (error) {
2074
+ console.error("[useSubscriptionWizard] Failed to look up the automatic promotion code:", error);
2075
+ dispatch({ type: "SET_PROMOTION_CODE", code: null });
2076
+ return false;
2077
+ }
2078
+ }, []);
2079
+ const refreshAutomaticCodeOrLeaveReview = useCallback3(
2080
+ async (priceId) => {
2081
+ const found = await lookUpAutomaticCode(priceId);
2082
+ if (!found) {
2083
+ dispatch({ type: "SET_STEP", step: "plan-selection" });
2084
+ dispatch({ type: "SET_ERROR", error: t("billing.ui.wizard.errors.prepare_review") });
2085
+ }
2086
+ },
2087
+ [lookUpAutomaticCode, t]
2088
+ );
2089
+ const goToReview = useCallback3(async () => {
1908
2090
  if (!state.selectedPrice) return;
1909
2091
  dispatch({ type: "SET_PROCESSING", isProcessing: true });
1910
2092
  try {
@@ -1922,6 +2104,13 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1922
2104
  return;
1923
2105
  }
1924
2106
  }
2107
+ if (shouldLookUpAutomatic(state.promotionCode)) {
2108
+ const found = await lookUpAutomaticCode(state.selectedPrice.id);
2109
+ if (!found) {
2110
+ dispatch({ type: "SET_ERROR", error: t("billing.ui.wizard.errors.prepare_review") });
2111
+ return;
2112
+ }
2113
+ }
1925
2114
  if (subscription && state.selectedPrice.id !== subscription.price?.id) {
1926
2115
  const preview = await StripeSubscriptionService.getProrationPreview({
1927
2116
  subscriptionId: subscription.id,
@@ -1936,30 +2125,69 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1936
2125
  } finally {
1937
2126
  dispatch({ type: "SET_PROCESSING", isProcessing: false });
1938
2127
  }
1939
- }, [state.selectedPrice, state.hasPaymentMethod, subscription, checkPaymentMethod, t]);
1940
- const confirmSubscription = useCallback2(async () => {
2128
+ }, [
2129
+ state.selectedPrice,
2130
+ state.hasPaymentMethod,
2131
+ state.promotionCode,
2132
+ subscription,
2133
+ checkPaymentMethod,
2134
+ lookUpAutomaticCode,
2135
+ t
2136
+ ]);
2137
+ const confirmSubscription = useCallback3(async () => {
1941
2138
  if (!state.selectedPrice) return;
1942
2139
  dispatch({ type: "SET_PROCESSING", isProcessing: true });
1943
2140
  dispatch({ type: "SET_ERROR", error: null });
1944
2141
  try {
2142
+ let result;
1945
2143
  if (subscription) {
1946
2144
  const changePlanParams = {
1947
2145
  id: subscription.id,
1948
2146
  newPriceId: state.selectedPrice.id,
1949
- promotionCode: state.promotionCode?.promotionCodeId
2147
+ promotionCode: promotionCodeToSend(state.promotionCode)
1950
2148
  };
1951
- await StripeSubscriptionService.changePlan(changePlanParams);
2149
+ result = await StripeSubscriptionService.changePlanWithMeta(changePlanParams);
1952
2150
  } else {
1953
2151
  const createParams = {
1954
2152
  id: v4(),
1955
2153
  priceId: state.selectedPrice.id,
1956
- promotionCode: state.promotionCode?.promotionCodeId
2154
+ promotionCode: promotionCodeToSend(state.promotionCode)
1957
2155
  };
1958
- await StripeSubscriptionService.createSubscription(createParams);
2156
+ result = await StripeSubscriptionService.createSubscription(createParams);
2157
+ }
2158
+ const clientSecret = clientSecretToConfirm(result.meta);
2159
+ if (clientSecret) {
2160
+ const confirmation = await confirmPayment(clientSecret);
2161
+ if (!confirmation.success) {
2162
+ console.error("[useSubscriptionWizard] Payment not confirmed:", confirmation.error);
2163
+ dispatch({
2164
+ type: "SET_ERROR",
2165
+ error: t("billing.ui.wizard.errors.payment_not_confirmed", { reason: confirmation.error ?? "" })
2166
+ });
2167
+ return;
2168
+ }
2169
+ const subscriptionId = subscriptionIdToSync(result.subscription, subscription);
2170
+ if (subscriptionId) {
2171
+ try {
2172
+ await StripeSubscriptionService.syncSubscription({ subscriptionId });
2173
+ } catch (syncError) {
2174
+ console.error("[useSubscriptionWizard] Subscription sync after payment failed:", syncError);
2175
+ }
2176
+ }
1959
2177
  }
1960
2178
  onSuccessRef.current();
1961
2179
  onCloseRef.current();
1962
2180
  } catch (error) {
2181
+ const soldOut = isDiscountSoldOut(error);
2182
+ if (soldOut || isDiscountUnavailable(error)) {
2183
+ dispatch({
2184
+ type: "SET_ERROR",
2185
+ error: soldOut ? t("billing.ui.wizard.errors.discount_sold_out") : t("billing.ui.wizard.errors.discount_unavailable")
2186
+ });
2187
+ dispatch({ type: "SET_PROMOTION_CODE", code: null });
2188
+ await refreshAutomaticCodeOrLeaveReview(state.selectedPrice.id);
2189
+ return;
2190
+ }
1963
2191
  if (error?.status === 409 || error?.response?.status === 409) {
1964
2192
  dispatch({
1965
2193
  type: "SET_ERROR",
@@ -1976,15 +2204,15 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
1976
2204
  } finally {
1977
2205
  dispatch({ type: "SET_PROCESSING", isProcessing: false });
1978
2206
  }
1979
- }, [state.selectedPrice, state.promotionCode, subscription, t]);
1980
- const handlePaymentMethodSuccess = useCallback2(async () => {
2207
+ }, [state.selectedPrice, state.promotionCode, subscription, refreshAutomaticCodeOrLeaveReview, confirmPayment, t]);
2208
+ const handlePaymentMethodSuccess = useCallback3(async () => {
1981
2209
  dispatch({ type: "SET_HAS_PAYMENT_METHOD", hasMethod: true });
1982
- dispatch({ type: "SET_STEP", step: "review" });
1983
- }, []);
1984
- const reset = useCallback2(() => {
2210
+ await goToReview();
2211
+ }, [goToReview]);
2212
+ const reset = useCallback3(() => {
1985
2213
  dispatch({ type: "RESET" });
1986
2214
  }, []);
1987
- const validatePromoCode = useCallback2(
2215
+ const validatePromoCode = useCallback3(
1988
2216
  async (code) => {
1989
2217
  dispatch({ type: "SET_VALIDATING_PROMO_CODE", isValidating: true });
1990
2218
  dispatch({ type: "SET_PROMO_CODE_ERROR", error: null });
@@ -2014,11 +2242,18 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
2014
2242
  },
2015
2243
  [state.selectedPrice?.id, t, locale]
2016
2244
  );
2017
- const clearPromoCode = useCallback2(() => {
2245
+ const clearPromoCode = useCallback3(async () => {
2018
2246
  dispatch({ type: "SET_PROMOTION_CODE", code: null });
2019
2247
  dispatch({ type: "SET_PROMO_CODE_ERROR", error: null });
2020
2248
  dispatch({ type: "SET_ERROR", error: null });
2021
- }, []);
2249
+ if (!state.selectedPrice) return;
2250
+ dispatch({ type: "SET_PROCESSING", isProcessing: true });
2251
+ try {
2252
+ await refreshAutomaticCodeOrLeaveReview(state.selectedPrice.id);
2253
+ } finally {
2254
+ dispatch({ type: "SET_PROCESSING", isProcessing: false });
2255
+ }
2256
+ }, [state.selectedPrice, refreshAutomaticCodeOrLeaveReview]);
2022
2257
  const actions = useMemo(
2023
2258
  () => ({
2024
2259
  selectPrice,
@@ -2053,7 +2288,7 @@ function useSubscriptionWizard({ subscription, onSuccess, onClose }) {
2053
2288
  __name(useSubscriptionWizard, "useSubscriptionWizard");
2054
2289
 
2055
2290
  // src/features/billing/stripe-subscription/components/wizards/WizardProgressIndicator.tsx
2056
- import { useTranslations as useTranslations26 } from "next-intl";
2291
+ import { useTranslations as useTranslations27 } from "next-intl";
2057
2292
  import { Check as Check3 } from "lucide-react";
2058
2293
  import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
2059
2294
  var STEPS = [
@@ -2066,7 +2301,7 @@ function getStepIndex(step) {
2066
2301
  }
2067
2302
  __name(getStepIndex, "getStepIndex");
2068
2303
  function WizardProgressIndicator({ currentStep }) {
2069
- const t = useTranslations26();
2304
+ const t = useTranslations27();
2070
2305
  const currentIndex = getStepIndex(currentStep);
2071
2306
  return /* @__PURE__ */ jsx26("div", { className: "flex items-center justify-center gap-x-2 py-4", children: STEPS.map((step, index) => {
2072
2307
  const isCompleted = index < currentIndex;
@@ -2087,8 +2322,8 @@ function WizardProgressIndicator({ currentStep }) {
2087
2322
  __name(WizardProgressIndicator, "WizardProgressIndicator");
2088
2323
 
2089
2324
  // src/features/billing/stripe-subscription/components/wizards/WizardStepPlanSelection.tsx
2090
- import { useTranslations as useTranslations27 } from "next-intl";
2091
- import { useEffect as useEffect6, useMemo as useMemo2, useState as useState11 } from "react";
2325
+ import { useTranslations as useTranslations28 } from "next-intl";
2326
+ import { useEffect as useEffect6, useMemo as useMemo2, useState as useState12 } from "react";
2092
2327
  import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
2093
2328
  function WizardStepPlanSelection({
2094
2329
  selectedPrice,
@@ -2101,9 +2336,9 @@ function WizardStepPlanSelection({
2101
2336
  onNext,
2102
2337
  isProcessing
2103
2338
  }) {
2104
- const t = useTranslations27();
2105
- const [products, setProducts] = useState11([]);
2106
- const [loading, setLoading] = useState11(true);
2339
+ const t = useTranslations28();
2340
+ const [products, setProducts] = useState12([]);
2341
+ const [loading, setLoading] = useState12(true);
2107
2342
  useEffect6(() => {
2108
2343
  const loadProducts = /* @__PURE__ */ __name(async () => {
2109
2344
  try {
@@ -2164,12 +2399,13 @@ function WizardStepPlanSelection({
2164
2399
  __name(WizardStepPlanSelection, "WizardStepPlanSelection");
2165
2400
 
2166
2401
  // src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx
2167
- import { useTranslations as useTranslations29 } from "next-intl";
2402
+ import { useTranslations as useTranslations30 } from "next-intl";
2168
2403
  import { AlertCircle } from "lucide-react";
2404
+ import { useEffect as useEffect7, useState as useState14 } from "react";
2169
2405
 
2170
2406
  // src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx
2171
- import { useTranslations as useTranslations28 } from "next-intl";
2172
- import { useState as useState12 } from "react";
2407
+ import { useTranslations as useTranslations29 } from "next-intl";
2408
+ import { useState as useState13 } from "react";
2173
2409
  import { Check as Check4, X, Loader2 as Loader22 } from "lucide-react";
2174
2410
  import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
2175
2411
  function PromoCodeInput({
@@ -2180,9 +2416,19 @@ function PromoCodeInput({
2180
2416
  onRemove,
2181
2417
  disabled = false
2182
2418
  }) {
2183
- const t = useTranslations28();
2419
+ const t = useTranslations29();
2184
2420
  const locale = useI18nLocale();
2185
- const [code, setCode] = useState12("");
2421
+ const [code, setCode] = useState13("");
2422
+ const appliedKey = appliedCode?.valid ? `${appliedCode.automatic ? "auto" : "typed"}:${appliedCode.code ?? ""}` : null;
2423
+ const [previousAppliedKey, setPreviousAppliedKey] = useState13(appliedKey);
2424
+ if (appliedKey !== previousAppliedKey) {
2425
+ setPreviousAppliedKey(appliedKey);
2426
+ if (appliedKey !== null) setCode("");
2427
+ }
2428
+ const handleRemove = /* @__PURE__ */ __name(() => {
2429
+ setCode("");
2430
+ onRemove();
2431
+ }, "handleRemove");
2186
2432
  const handleApply = /* @__PURE__ */ __name(() => {
2187
2433
  if (code.trim()) {
2188
2434
  onApply(code.trim().toUpperCase());
@@ -2214,6 +2460,39 @@ function PromoCodeInput({
2214
2460
  return "";
2215
2461
  }
2216
2462
  }, "formatDuration");
2463
+ const codeInput = /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2464
+ /* @__PURE__ */ jsxs25("div", { className: "flex gap-2", children: [
2465
+ /* @__PURE__ */ jsx28(
2466
+ Input,
2467
+ {
2468
+ placeholder: t("billing.ui.promo_code.placeholder"),
2469
+ value: code,
2470
+ onChange: (e) => setCode(e.target.value.toUpperCase()),
2471
+ onKeyDown: handleKeyDown,
2472
+ disabled: disabled || isValidating,
2473
+ className: "flex-1"
2474
+ }
2475
+ ),
2476
+ /* @__PURE__ */ jsx28(Button, { variant: "outline", onClick: handleApply, disabled: disabled || isValidating || !code.trim(), children: isValidating ? /* @__PURE__ */ jsx28(Loader22, { className: "h-4 w-4 animate-spin" }) : t("billing.ui.promo_code.apply") })
2477
+ ] }),
2478
+ error && /* @__PURE__ */ jsx28("p", { className: "text-destructive text-xs/relaxed", children: error })
2479
+ ] });
2480
+ if (appliedCode?.valid && appliedCode.automatic) {
2481
+ return /* @__PURE__ */ jsxs25("div", { className: "space-y-3", children: [
2482
+ /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2483
+ /* @__PURE__ */ jsxs25("div", { className: "bg-success/15 border-success/30 flex items-center gap-2 rounded-lg border p-3", children: [
2484
+ /* @__PURE__ */ jsx28(Check4, { className: "text-success h-4 w-4" }),
2485
+ /* @__PURE__ */ jsx28("span", { className: "text-success font-medium", children: t("billing.ui.promo_code.automatic_label") }),
2486
+ /* @__PURE__ */ jsx28("span", { className: "text-success text-sm", children: formatDiscount(appliedCode) })
2487
+ ] }),
2488
+ /* @__PURE__ */ jsx28("p", { className: "text-success text-sm", children: formatDuration(appliedCode) })
2489
+ ] }),
2490
+ /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2491
+ /* @__PURE__ */ jsx28("p", { className: "text-muted-foreground text-sm", children: t("billing.ui.promo_code.use_different") }),
2492
+ codeInput
2493
+ ] })
2494
+ ] });
2495
+ }
2217
2496
  if (appliedCode?.valid) {
2218
2497
  return /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2219
2498
  /* @__PURE__ */ jsxs25("div", { className: "bg-success/15 border-success/30 flex items-center justify-between rounded-lg border p-3", children: [
@@ -2227,7 +2506,7 @@ function PromoCodeInput({
2227
2506
  {
2228
2507
  variant: "ghost",
2229
2508
  size: "sm",
2230
- onClick: onRemove,
2509
+ onClick: handleRemove,
2231
2510
  disabled,
2232
2511
  className: "text-success hover:bg-success/25 hover:text-success",
2233
2512
  children: /* @__PURE__ */ jsx28(X, { className: "h-4 w-4" })
@@ -2237,26 +2516,20 @@ function PromoCodeInput({
2237
2516
  /* @__PURE__ */ jsx28("p", { className: "text-success text-sm", children: formatDuration(appliedCode) })
2238
2517
  ] });
2239
2518
  }
2240
- return /* @__PURE__ */ jsxs25("div", { className: "space-y-2", children: [
2241
- /* @__PURE__ */ jsxs25("div", { className: "flex gap-2", children: [
2242
- /* @__PURE__ */ jsx28(
2243
- Input,
2244
- {
2245
- placeholder: t("billing.ui.promo_code.placeholder"),
2246
- value: code,
2247
- onChange: (e) => setCode(e.target.value.toUpperCase()),
2248
- onKeyDown: handleKeyDown,
2249
- disabled: disabled || isValidating,
2250
- className: "flex-1"
2251
- }
2252
- ),
2253
- /* @__PURE__ */ jsx28(Button, { variant: "outline", onClick: handleApply, disabled: disabled || isValidating || !code.trim(), children: isValidating ? /* @__PURE__ */ jsx28(Loader22, { className: "h-4 w-4 animate-spin" }) : t("billing.ui.promo_code.apply") })
2254
- ] }),
2255
- error && /* @__PURE__ */ jsx28("p", { className: "text-destructive text-xs/relaxed", children: error })
2256
- ] });
2519
+ return codeInput;
2257
2520
  }
2258
2521
  __name(PromoCodeInput, "PromoCodeInput");
2259
2522
 
2523
+ // src/features/billing/stripe-subscription/components/wizards/review-card.ts
2524
+ function reviewCard(methods, defaultPaymentMethodId) {
2525
+ if (!methods || methods.length === 0) return null;
2526
+ const method = defaultPaymentMethodId && methods.find((m) => m.id === defaultPaymentMethodId) || methods[0];
2527
+ if (!method.card?.last4) return null;
2528
+ const brand = method.card.brand ? method.card.brand.charAt(0).toUpperCase() + method.card.brand.slice(1) : method.type.charAt(0).toUpperCase() + method.type.slice(1);
2529
+ return { brand, last4: method.card.last4 };
2530
+ }
2531
+ __name(reviewCard, "reviewCard");
2532
+
2260
2533
  // src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx
2261
2534
  import { Fragment as Fragment6, jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
2262
2535
  function WizardStepReview({
@@ -2276,8 +2549,25 @@ function WizardStepReview({
2276
2549
  onRemovePromoCode,
2277
2550
  isTrialUpgrade
2278
2551
  }) {
2279
- const t = useTranslations29();
2552
+ const t = useTranslations30();
2280
2553
  const fmt = useBillingFormatOptions();
2554
+ const [card, setCard] = useState14(null);
2555
+ useEffect7(() => {
2556
+ if (!hasPaymentMethod) {
2557
+ setCard(null);
2558
+ return;
2559
+ }
2560
+ let cancelled = false;
2561
+ Promise.all([StripeCustomerService.listPaymentMethods(), StripeCustomerService.getCustomer()]).then(([methods, customer]) => {
2562
+ if (!cancelled) setCard(reviewCard(methods, customer?.defaultPaymentMethodId));
2563
+ }).catch((err) => {
2564
+ console.error("[WizardStepReview] Failed to load the card on file:", err);
2565
+ if (!cancelled) setCard(null);
2566
+ });
2567
+ return () => {
2568
+ cancelled = true;
2569
+ };
2570
+ }, [hasPaymentMethod]);
2281
2571
  if (!selectedPrice) {
2282
2572
  return /* @__PURE__ */ jsx29("div", { className: "text-center py-8 text-muted-foreground", children: t("billing.ui.wizard.review.no_plan") });
2283
2573
  }
@@ -2287,41 +2577,19 @@ function WizardStepReview({
2287
2577
  const interval = price.recurring?.interval || "month";
2288
2578
  return interval === "year" ? t("billing.ui.wizard.review.interval_yearly") : t("billing.ui.wizard.review.interval_monthly");
2289
2579
  }, "formatInterval");
2290
- const calculateDiscountedPrice = /* @__PURE__ */ __name(() => {
2291
- if (!promotionCode?.valid || !selectedPrice.unitAmount) return null;
2292
- const originalPrice = selectedPrice.unitAmount;
2293
- if (promotionCode.discountType === "percent_off" && promotionCode.discountValue) {
2294
- return originalPrice * (1 - promotionCode.discountValue / 100);
2295
- }
2296
- if (promotionCode.discountType === "amount_off" && promotionCode.discountValue) {
2297
- return Math.max(0, originalPrice - promotionCode.discountValue);
2298
- }
2299
- return null;
2300
- }, "calculateDiscountedPrice");
2301
- const discountedPrice = calculateDiscountedPrice();
2302
- const calculateDiscountedImmediateCharge = /* @__PURE__ */ __name(() => {
2303
- if (!promotionCode?.valid || !prorationPreview?.immediateCharge) return null;
2304
- const originalCharge = prorationPreview.immediateCharge;
2305
- if (promotionCode.discountType === "percent_off" && promotionCode.discountValue) {
2306
- return originalCharge * (1 - promotionCode.discountValue / 100);
2307
- }
2308
- if (promotionCode.discountType === "amount_off" && promotionCode.discountValue) {
2309
- return Math.max(0, originalCharge - promotionCode.discountValue);
2310
- }
2311
- return null;
2312
- }, "calculateDiscountedImmediateCharge");
2313
- const discountedImmediateCharge = calculateDiscountedImmediateCharge();
2580
+ const codeDiscount = promotionCodeDiscount(promotionCode);
2581
+ const carriedDiscount = isChangingPlan && !codeDiscount ? subscriptionDiscount(subscription) : null;
2582
+ const discount = codeDiscount ?? carriedDiscount;
2583
+ const discountedPrice = applyDiscount(selectedPrice.unitAmount, discount);
2584
+ const discountedImmediateCharge = applyDiscount(prorationPreview?.immediateCharge, discount);
2314
2585
  const getDiscountDescription = /* @__PURE__ */ __name(() => {
2315
- if (!promotionCode?.valid) return null;
2316
- if (promotionCode.discountType === "percent_off" && promotionCode.discountValue) {
2317
- return t("billing.ui.wizard.review.percent_off", { value: promotionCode.discountValue });
2318
- }
2319
- if (promotionCode.discountType === "amount_off" && promotionCode.discountValue) {
2320
- return t("billing.ui.wizard.review.amount_off", {
2321
- amount: formatCurrency(promotionCode.discountValue, promotionCode.currency || selectedPrice.currency, fmt)
2322
- });
2586
+ if (!discount) return null;
2587
+ if (discount.discountType === "percent_off") {
2588
+ return t("billing.ui.wizard.review.percent_off", { value: discount.discountValue });
2323
2589
  }
2324
- return null;
2590
+ return t("billing.ui.wizard.review.amount_off", {
2591
+ amount: formatCurrency(discount.discountValue, discount.currency || selectedPrice.currency, fmt)
2592
+ });
2325
2593
  }, "getDiscountDescription");
2326
2594
  const discountDescription = getDiscountDescription();
2327
2595
  return /* @__PURE__ */ jsxs26("div", { className: "space-y-6", children: [
@@ -2336,7 +2604,8 @@ function WizardStepReview({
2336
2604
  discountedPrice !== null ? /* @__PURE__ */ jsxs26(Fragment6, { children: [
2337
2605
  /* @__PURE__ */ jsx29("p", { className: "text-sm text-muted-foreground line-through", children: formatCurrency(selectedPrice.unitAmount || 0, selectedPrice.currency, fmt) }),
2338
2606
  /* @__PURE__ */ jsx29("p", { className: "text-success text-lg font-semibold", children: formatCurrency(discountedPrice, selectedPrice.currency, fmt) }),
2339
- discountDescription && /* @__PURE__ */ jsx29(Badge, { variant: "softGreen", children: discountDescription })
2607
+ discountDescription && /* @__PURE__ */ jsx29(Badge, { variant: "softGreen", children: discountDescription }),
2608
+ carriedDiscount && /* @__PURE__ */ jsx29("p", { className: "text-sm text-muted-foreground", children: t("billing.ui.wizard.review.discount_carries_over") })
2340
2609
  ] }) : /* @__PURE__ */ jsx29("p", { className: "font-semibold text-lg", children: formatCurrency(selectedPrice.unitAmount || 0, selectedPrice.currency, fmt) }),
2341
2610
  /* @__PURE__ */ jsx29("p", { className: "text-sm text-muted-foreground", children: formatInterval2(selectedPrice) })
2342
2611
  ] })
@@ -2348,7 +2617,7 @@ function WizardStepReview({
2348
2617
  className: `${isTrialUpgrade ? "bg-warning/15 border-warning/30" : "bg-primary/10 border-primary/30"} space-y-2 rounded-lg border p-4`,
2349
2618
  children: [
2350
2619
  /* @__PURE__ */ jsx29("h4", { className: `font-medium ${isTrialUpgrade ? "text-warning" : "text-primary"}`, children: isTrialUpgrade ? t("billing.ui.wizard.review.trial_upgrade") : t("billing.ui.wizard.review.proration_summary") }),
2351
- /* @__PURE__ */ jsx29("p", { className: `text-sm ${isTrialUpgrade ? "text-warning" : "text-foreground"}`, children: isTrialUpgrade ? t("billing.ui.wizard.review.trial_upgrade_description") : t("billing.ui.wizard.review.proration_description") }),
2620
+ /* @__PURE__ */ jsx29("p", { className: `text-sm ${isTrialUpgrade ? "text-warning" : "text-foreground"}`, children: isTrialUpgrade ? discountedImmediateCharge !== null ? t("billing.ui.wizard.review.trial_upgrade_description_discounted") : t("billing.ui.wizard.review.trial_upgrade_description") : t("billing.ui.wizard.review.proration_description") }),
2352
2621
  /* @__PURE__ */ jsxs26("div", { className: "flex justify-between text-sm", children: [
2353
2622
  /* @__PURE__ */ jsx29("span", { className: `${isTrialUpgrade ? "text-warning" : "text-muted-foreground"}`, children: isTrialUpgrade ? t("billing.ui.wizard.review.charge_now") : t("billing.ui.wizard.review.due_now") }),
2354
2623
  /* @__PURE__ */ jsx29("span", { className: `font-medium ${isTrialUpgrade ? "text-warning" : "text-foreground"}`, children: discountedImmediateCharge !== null ? /* @__PURE__ */ jsxs26(Fragment6, { children: [
@@ -2376,9 +2645,9 @@ function WizardStepReview({
2376
2645
  /* @__PURE__ */ jsx29("div", { className: "border rounded-lg p-4", children: /* @__PURE__ */ jsxs26("div", { className: "flex justify-between items-center", children: [
2377
2646
  /* @__PURE__ */ jsxs26("div", { children: [
2378
2647
  /* @__PURE__ */ jsx29("h4", { className: "font-medium", children: t("billing.ui.payment_method.title") }),
2379
- /* @__PURE__ */ jsx29("p", { className: "text-sm text-muted-foreground", children: hasPaymentMethod ? t("billing.ui.wizard.review.payment_on_file") : t("billing.ui.wizard.review.no_payment_on_file") })
2648
+ /* @__PURE__ */ jsx29("p", { className: "text-sm text-muted-foreground", children: hasPaymentMethod ? card ? t("billing.ui.wizard.review.card_on_file", { brand: card.brand, last4: card.last4 }) : t("billing.ui.wizard.review.payment_on_file") : t("billing.ui.wizard.review.no_payment_on_file") })
2380
2649
  ] }),
2381
- !hasPaymentMethod && /* @__PURE__ */ jsx29(Button, { variant: "outline", onClick: onAddPaymentMethod, children: t("billing.ui.payment_methods.add") })
2650
+ hasPaymentMethod ? /* @__PURE__ */ jsx29(Button, { variant: "outline", onClick: onAddPaymentMethod, disabled: isProcessing, children: t("billing.ui.wizard.review.use_another_card") }) : /* @__PURE__ */ jsx29(Button, { variant: "outline", onClick: onAddPaymentMethod, children: t("billing.ui.payment_methods.add") })
2382
2651
  ] }) }),
2383
2652
  error && /* @__PURE__ */ jsxs26(Alert, { variant: "destructive", children: [
2384
2653
  /* @__PURE__ */ jsx29(AlertCircle, { className: "h-4 w-4" }),
@@ -2393,16 +2662,16 @@ function WizardStepReview({
2393
2662
  __name(WizardStepReview, "WizardStepReview");
2394
2663
 
2395
2664
  // src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx
2396
- import { useTranslations as useTranslations30 } from "next-intl";
2665
+ import { useTranslations as useTranslations31 } from "next-intl";
2397
2666
  import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
2398
2667
  function WizardStepPaymentMethod({ onBack, onSuccess, isProcessing }) {
2399
- const t = useTranslations30();
2668
+ const t = useTranslations31();
2400
2669
  return /* @__PURE__ */ jsxs27("div", { className: "space-y-6", children: [
2401
2670
  /* @__PURE__ */ jsxs27("div", { className: "text-center", children: [
2402
2671
  /* @__PURE__ */ jsx30(SectionHeader, { children: t("billing.ui.payment_methods.add") }),
2403
2672
  /* @__PURE__ */ jsx30("p", { className: "text-sm text-muted-foreground", children: t("billing.ui.wizard.payment_description") })
2404
2673
  ] }),
2405
- /* @__PURE__ */ jsx30(PaymentMethodForm, { onSuccess, onCancel: onBack, isLoading: isProcessing })
2674
+ /* @__PURE__ */ jsx30(PaymentMethodForm, { onSuccess, onCancel: onBack, isLoading: isProcessing, alwaysSetDefault: true })
2406
2675
  ] });
2407
2676
  }
2408
2677
  __name(WizardStepPaymentMethod, "WizardStepPaymentMethod");
@@ -2416,15 +2685,15 @@ function SubscriptionWizard({
2416
2685
  hasActiveRecurringSubscription,
2417
2686
  subscription
2418
2687
  }) {
2419
- const t = useTranslations31();
2420
- const handleClose = useCallback3(() => onOpenChange(false), [onOpenChange]);
2688
+ const t = useTranslations32();
2689
+ const handleClose = useCallback4(() => onOpenChange(false), [onOpenChange]);
2421
2690
  const { state, actions } = useSubscriptionWizard({
2422
2691
  subscription,
2423
2692
  onSuccess,
2424
2693
  onClose: handleClose
2425
2694
  });
2426
2695
  const hasCheckedRef = useRef2(false);
2427
- useEffect7(() => {
2696
+ useEffect8(() => {
2428
2697
  if (open && !hasCheckedRef.current) {
2429
2698
  hasCheckedRef.current = true;
2430
2699
  actions.checkPaymentMethod();
@@ -2433,7 +2702,7 @@ function SubscriptionWizard({
2433
2702
  hasCheckedRef.current = false;
2434
2703
  }
2435
2704
  }, [open, actions.checkPaymentMethod]);
2436
- useEffect7(() => {
2705
+ useEffect8(() => {
2437
2706
  if (!open) {
2438
2707
  actions.reset();
2439
2708
  }
@@ -2442,7 +2711,7 @@ function SubscriptionWizard({
2442
2711
  const isChangePlanMode = !!subscription;
2443
2712
  const dialogTitle = subscription ? t("billing.ui.wizard.change_title") : isPurchasingAddons ? t("billing.ui.subscriptions.purchase_addons") : t("billing.ui.subscriptions.subscribe");
2444
2713
  const dialogDescription = subscription ? t("billing.ui.wizard.change_description") : isPurchasingAddons ? t("billing.ui.wizard.addons_description") : t("billing.ui.wizard.subscribe_description");
2445
- return /* @__PURE__ */ jsx31(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs28(DialogContent, { className: "max-w-2xl", children: [
2714
+ return /* @__PURE__ */ jsx31(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs28(DialogContent, { className: "max-w-2xl max-h-[90vh] overflow-y-auto", children: [
2446
2715
  /* @__PURE__ */ jsxs28(DialogHeader, { children: [
2447
2716
  /* @__PURE__ */ jsx31(DialogTitle, { children: dialogTitle }),
2448
2717
  /* @__PURE__ */ jsx31(DialogDescription, { children: dialogDescription })
@@ -2495,12 +2764,12 @@ function SubscriptionWizard({
2495
2764
  __name(SubscriptionWizard, "SubscriptionWizard");
2496
2765
 
2497
2766
  // src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
2498
- import { useTranslations as useTranslations33 } from "next-intl";
2767
+ import { useTranslations as useTranslations34 } from "next-intl";
2499
2768
  import { Activity as Activity3 } from "lucide-react";
2500
- import { useEffect as useEffect8, useState as useState13 } from "react";
2769
+ import { useEffect as useEffect9, useState as useState15 } from "react";
2501
2770
 
2502
2771
  // src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx
2503
- import { useTranslations as useTranslations32 } from "next-intl";
2772
+ import { useTranslations as useTranslations33 } from "next-intl";
2504
2773
  import { Activity as Activity2 } from "lucide-react";
2505
2774
  import { jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
2506
2775
  function getProgressColor(percentage) {
@@ -2523,7 +2792,7 @@ function formatDate2(date, { locale, t }) {
2523
2792
  }
2524
2793
  __name(formatDate2, "formatDate");
2525
2794
  function UsageSummaryCard({ meter, summary }) {
2526
- const t = useTranslations32();
2795
+ const t = useTranslations33();
2527
2796
  const fmt = useBillingFormatOptions();
2528
2797
  const currentUsage = summary?.aggregatedValue ?? 0;
2529
2798
  const limit = meter.limit;
@@ -2570,12 +2839,12 @@ __name(UsageSummaryCards, "UsageSummaryCards");
2570
2839
  // src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
2571
2840
  import { jsx as jsx34, jsxs as jsxs30 } from "react/jsx-runtime";
2572
2841
  function UsageContainer() {
2573
- const t = useTranslations33();
2574
- const [meters, setMeters] = useState13([]);
2575
- const [summaries, setSummaries] = useState13({});
2576
- const [loading, setLoading] = useState13(true);
2577
- const [subscriptions, setSubscriptions] = useState13([]);
2578
- useEffect8(() => {
2842
+ const t = useTranslations34();
2843
+ const [meters, setMeters] = useState15([]);
2844
+ const [summaries, setSummaries] = useState15({});
2845
+ const [loading, setLoading] = useState15(true);
2846
+ const [subscriptions, setSubscriptions] = useState15([]);
2847
+ useEffect9(() => {
2579
2848
  loadUsageData();
2580
2849
  }, []);
2581
2850
  const loadUsageData = /* @__PURE__ */ __name(async () => {
@@ -2639,7 +2908,7 @@ function UsageContainer() {
2639
2908
  __name(UsageContainer, "UsageContainer");
2640
2909
 
2641
2910
  // src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx
2642
- import { useTranslations as useTranslations34 } from "next-intl";
2911
+ import { useTranslations as useTranslations35 } from "next-intl";
2643
2912
  import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
2644
2913
  function formatDateTime(date, { locale, t }) {
2645
2914
  if (!date) return t("billing.ui.not_available");
@@ -2658,7 +2927,7 @@ function formatDateTime(date, { locale, t }) {
2658
2927
  }
2659
2928
  __name(formatDateTime, "formatDateTime");
2660
2929
  function UsageHistoryTable({ usageRecords }) {
2661
- const t = useTranslations34();
2930
+ const t = useTranslations35();
2662
2931
  const fmt = useBillingFormatOptions();
2663
2932
  if (usageRecords.length === 0) {
2664
2933
  return /* @__PURE__ */ jsx35("div", { className: "rounded-lg border p-8 text-center", children: /* @__PURE__ */ jsx35("p", { className: "text-muted-foreground", children: t("billing.ui.usage.history_empty") }) });
@@ -2697,12 +2966,21 @@ function BillingDetailModal({ open, onOpenChange, title, children, className })
2697
2966
  }
2698
2967
  __name(BillingDetailModal, "BillingDetailModal");
2699
2968
 
2969
+ // src/features/billing/components/utils/url.ts
2970
+ function urlWithoutParam(params) {
2971
+ const query = new URLSearchParams(params.search);
2972
+ query.delete(params.param);
2973
+ const remaining = query.toString();
2974
+ return `${params.pathname}${remaining ? `?${remaining}` : ""}${params.hash ?? ""}`;
2975
+ }
2976
+ __name(urlWithoutParam, "urlWithoutParam");
2977
+
2700
2978
  // src/features/billing/components/widgets/BillingAlertBanner.tsx
2701
- import { useTranslations as useTranslations35 } from "next-intl";
2979
+ import { useTranslations as useTranslations36 } from "next-intl";
2702
2980
  import { AlertCircle as AlertCircle2 } from "lucide-react";
2703
2981
  import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
2704
2982
  function BillingAlertBanner({ subscription, onUpdatePayment, onAddPayment }) {
2705
- const t = useTranslations35();
2983
+ const t = useTranslations36();
2706
2984
  if (subscription.status === "past_due" /* PAST_DUE */) {
2707
2985
  return /* @__PURE__ */ jsxs33("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-x-3", children: [
2708
2986
  /* @__PURE__ */ jsx37(AlertCircle2, { className: "text-destructive mt-0.5 h-5 w-5" }),
@@ -2735,8 +3013,8 @@ __name(BillingAlertBanner, "BillingAlertBanner");
2735
3013
  // src/features/billing/components/containers/BillingDashboardContainer.tsx
2736
3014
  import { Fragment as Fragment7, jsx as jsx38, jsxs as jsxs34 } from "react/jsx-runtime";
2737
3015
  function BillingDashboardContainer() {
2738
- const t = useTranslations36();
2739
- const [data, setData] = useState14({
3016
+ const t = useTranslations37();
3017
+ const [data, setData] = useState16({
2740
3018
  customer: null,
2741
3019
  subscriptions: [],
2742
3020
  paymentMethods: [],
@@ -2744,27 +3022,27 @@ function BillingDashboardContainer() {
2744
3022
  meters: [],
2745
3023
  meterSummaries: {}
2746
3024
  });
2747
- const [loading, setLoading] = useState14({
3025
+ const [loading, setLoading] = useState16({
2748
3026
  customer: true,
2749
3027
  subscriptions: true,
2750
3028
  paymentMethods: true,
2751
3029
  invoices: true,
2752
3030
  usage: true
2753
3031
  });
2754
- const [errors, setErrors] = useState14({
3032
+ const [errors, setErrors] = useState16({
2755
3033
  customer: null,
2756
3034
  subscriptions: null,
2757
3035
  paymentMethods: null,
2758
3036
  invoices: null,
2759
3037
  usage: null
2760
3038
  });
2761
- const [activeModal, setActiveModal] = useState14(null);
2762
- const [noCustomerExists, setNoCustomerExists] = useState14(false);
2763
- const [creatingCustomer, setCreatingCustomer] = useState14(false);
3039
+ const [activeModal, setActiveModal] = useState16(null);
3040
+ const [noCustomerExists, setNoCustomerExists] = useState16(false);
3041
+ const [creatingCustomer, setCreatingCustomer] = useState16(false);
2764
3042
  const searchParams = useSearchParams();
2765
- const [showWizard, setShowWizard] = useState14(false);
2766
- const [editingSubscription, setEditingSubscription] = useState14(null);
2767
- const hasMeteredSubscriptions = useCallback4(() => {
3043
+ const [showWizard, setShowWizard] = useState16(false);
3044
+ const [editingSubscription, setEditingSubscription] = useState16(null);
3045
+ const hasMeteredSubscriptions = useCallback5(() => {
2768
3046
  return data.subscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
2769
3047
  }, [data.subscriptions]);
2770
3048
  const hasActiveRecurringSubscription = useMemo3(() => {
@@ -2772,7 +3050,7 @@ function BillingDashboardContainer() {
2772
3050
  (sub) => (sub.status === "active" /* ACTIVE */ || sub.status === "trialing" /* TRIALING */) && sub.price?.priceType === "recurring"
2773
3051
  );
2774
3052
  }, [data.subscriptions]);
2775
- const fetchAllData = useCallback4(async () => {
3053
+ const fetchAllData = useCallback5(async () => {
2776
3054
  setNoCustomerExists(false);
2777
3055
  let customer = null;
2778
3056
  try {
@@ -2891,7 +3169,7 @@ function BillingDashboardContainer() {
2891
3169
  setLoading((prev) => ({ ...prev, usage: false }));
2892
3170
  }
2893
3171
  }, "fetchUsageData");
2894
- const refreshData = useCallback4(async () => {
3172
+ const refreshData = useCallback5(async () => {
2895
3173
  setLoading({
2896
3174
  customer: true,
2897
3175
  subscriptions: true,
@@ -2901,23 +3179,32 @@ function BillingDashboardContainer() {
2901
3179
  });
2902
3180
  await fetchAllData();
2903
3181
  }, [fetchAllData]);
2904
- const handleOpenWizard = useCallback4((subscription) => {
3182
+ const handleOpenWizard = useCallback5((subscription) => {
2905
3183
  setEditingSubscription(subscription || null);
2906
3184
  setShowWizard(true);
2907
3185
  }, []);
2908
- const handleWizardClose = useCallback4(() => {
3186
+ const handleWizardClose = useCallback5(() => {
2909
3187
  setShowWizard(false);
2910
3188
  setEditingSubscription(null);
2911
3189
  refreshData();
2912
3190
  }, [refreshData]);
2913
- useEffect9(() => {
3191
+ useEffect10(() => {
2914
3192
  fetchAllData();
2915
3193
  }, [fetchAllData]);
2916
- useEffect9(() => {
3194
+ useEffect10(() => {
2917
3195
  const action = searchParams.get("action");
2918
3196
  if (action === "subscribe") {
2919
3197
  setShowWizard(true);
2920
- window.history.replaceState({}, "", window.location.pathname);
3198
+ window.history.replaceState(
3199
+ window.history.state,
3200
+ "",
3201
+ urlWithoutParam({
3202
+ pathname: window.location.pathname,
3203
+ search: window.location.search,
3204
+ hash: window.location.hash,
3205
+ param: "action"
3206
+ })
3207
+ );
2921
3208
  }
2922
3209
  }, [searchParams]);
2923
3210
  const criticalSubscriptions = data.subscriptions.filter(
@@ -3036,7 +3323,9 @@ function BillingDashboardContainer() {
3036
3323
  SubscriptionsContainer,
3037
3324
  {
3038
3325
  onOpenWizard: handleOpenWizard,
3039
- hasActiveRecurringSubscription
3326
+ hasActiveRecurringSubscription,
3327
+ subscriptions: data.subscriptions,
3328
+ onSubscriptionsChange: refreshData
3040
3329
  }
3041
3330
  )
3042
3331
  }
@@ -3071,7 +3360,7 @@ function BillingDashboardContainer() {
3071
3360
  /* @__PURE__ */ jsx38(
3072
3361
  SubscriptionWizard,
3073
3362
  {
3074
- open: showWizard,
3363
+ open: showWizard && !!data.customer,
3075
3364
  onOpenChange: (open) => !open && handleWizardClose(),
3076
3365
  onSuccess: refreshData,
3077
3366
  hasActiveRecurringSubscription,
@@ -3117,19 +3406,19 @@ function isStripeConfigured() {
3117
3406
  __name(isStripeConfigured, "isStripeConfigured");
3118
3407
 
3119
3408
  // src/features/billing/contexts/PriceContext.tsx
3120
- import { useTranslations as useTranslations39 } from "next-intl";
3121
- import { createContext, useCallback as useCallback6, useContext, useMemo as useMemo6, useState as useState17 } from "react";
3409
+ import { useTranslations as useTranslations40 } from "next-intl";
3410
+ import { createContext, useCallback as useCallback7, useContext, useMemo as useMemo6, useState as useState19 } from "react";
3122
3411
 
3123
3412
  // src/features/billing/stripe-price/components/forms/PriceArchiver.tsx
3124
3413
  import { ArchiveIcon, RotateCcwIcon } from "lucide-react";
3125
- import { useTranslations as useTranslations37 } from "next-intl";
3126
- import { useState as useState15 } from "react";
3414
+ import { useTranslations as useTranslations38 } from "next-intl";
3415
+ import { useState as useState17 } from "react";
3127
3416
  import { Fragment as Fragment9, jsx as jsx40, jsxs as jsxs35 } from "react/jsx-runtime";
3128
3417
  function PriceArchiver({ price }) {
3129
- const t = useTranslations37();
3418
+ const t = useTranslations38();
3130
3419
  const fmt = useBillingFormatOptions();
3131
3420
  const { archivePrice, restorePrice } = usePriceContext();
3132
- const [open, setOpen] = useState15(false);
3421
+ const [open, setOpen] = useState17(false);
3133
3422
  const isArchived = !price.active;
3134
3423
  const scope = isArchived ? "restore" : "archive";
3135
3424
  return /* @__PURE__ */ jsxs35(Fragment9, { children: [
@@ -3165,8 +3454,8 @@ __name(PriceArchiver, "PriceArchiver");
3165
3454
  // src/features/billing/stripe-price/components/forms/PriceEditor.tsx
3166
3455
  import { zodResolver as zodResolver2 } from "@hookform/resolvers/zod";
3167
3456
  import { PlusIcon, XIcon } from "lucide-react";
3168
- import { useTranslations as useTranslations38 } from "next-intl";
3169
- import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo5, useRef as useRef3, useState as useState16 } from "react";
3457
+ import { useTranslations as useTranslations39 } from "next-intl";
3458
+ import { useCallback as useCallback6, useEffect as useEffect11, useMemo as useMemo5, useRef as useRef3, useState as useState18 } from "react";
3170
3459
  import { useForm as useForm2 } from "react-hook-form";
3171
3460
  import { v4 as v42 } from "uuid";
3172
3461
  import { z as z2 } from "zod";
@@ -3183,14 +3472,14 @@ function PriceEditorInternal({
3183
3472
  dialogOpen,
3184
3473
  onDialogOpenChange
3185
3474
  }) {
3186
- const t = useTranslations38();
3475
+ const t = useTranslations39();
3187
3476
  const fmt = useBillingFormatOptions();
3188
3477
  const router = useI18nRouter();
3189
3478
  const { createPrice, updatePrice, productId: contextProductId } = usePriceContext();
3190
- const [allFeatures, setAllFeatures] = useState16([]);
3479
+ const [allFeatures, setAllFeatures] = useState18([]);
3191
3480
  const isEdit = !!price;
3192
3481
  const targetProductId = productId ?? price?.product?.id ?? contextProductId;
3193
- useEffect10(() => {
3482
+ useEffect11(() => {
3194
3483
  const fetchFeatures = /* @__PURE__ */ __name(async () => {
3195
3484
  setAllFeatures(await FeatureService.findMany({}));
3196
3485
  }, "fetchFeatures");
@@ -3239,7 +3528,7 @@ function PriceEditorInternal({
3239
3528
  }),
3240
3529
  [t]
3241
3530
  );
3242
- const resolvePlatformFeatures = useCallback5(
3531
+ const resolvePlatformFeatures = useCallback6(
3243
3532
  (names) => {
3244
3533
  const ids = [];
3245
3534
  const unknown = [];
@@ -3252,7 +3541,7 @@ function PriceEditorInternal({
3252
3541
  },
3253
3542
  [allFeatures]
3254
3543
  );
3255
- const getDefaultValues = useCallback5(() => {
3544
+ const getDefaultValues = useCallback6(() => {
3256
3545
  const coreFeatureIds = allFeatures.filter((feature) => feature.isCore).map((feature) => feature.id);
3257
3546
  if (!price && seed) {
3258
3547
  return {
@@ -3291,14 +3580,14 @@ function PriceEditorInternal({
3291
3580
  defaultValues: getDefaultValues()
3292
3581
  });
3293
3582
  const hasCaughtUpWithFeatures = useRef3(false);
3294
- useEffect10(() => {
3583
+ useEffect11(() => {
3295
3584
  if (isEdit || hasCaughtUpWithFeatures.current || allFeatures.length === 0) return;
3296
3585
  hasCaughtUpWithFeatures.current = true;
3297
3586
  if (form.formState.isDirty) return;
3298
3587
  form.reset(getDefaultValues());
3299
3588
  }, [allFeatures, isEdit, form, getDefaultValues]);
3300
3589
  const warnedUnknownFor = useRef3(void 0);
3301
- useEffect10(() => {
3590
+ useEffect11(() => {
3302
3591
  if (isEdit || !seed || allFeatures.length === 0) return;
3303
3592
  const fingerprint = JSON.stringify(seed.platformFeatures ?? []);
3304
3593
  if (warnedUnknownFor.current === fingerprint) return;
@@ -3592,21 +3881,21 @@ var PriceProvider = /* @__PURE__ */ __name(({
3592
3881
  publishChrome = true,
3593
3882
  productId: productIdProp
3594
3883
  }) => {
3595
- const t = useTranslations39();
3884
+ const t = useTranslations40();
3596
3885
  const fmt = useBillingFormatOptions();
3597
3886
  const generateUrl = usePageUrlGenerator();
3598
3887
  const { hasRole } = useCurrentUserContext();
3599
- const [price, setPrice] = useState17(
3888
+ const [price, setPrice] = useState19(
3600
3889
  dehydratedPrice ? rehydrate(Modules.StripePrice, dehydratedPrice) : void 0
3601
3890
  );
3602
- const [priceVersion, setPriceVersion] = useState17(0);
3603
- const refreshPrices = useCallback6(() => setPriceVersion((value2) => value2 + 1), []);
3891
+ const [priceVersion, setPriceVersion] = useState19(0);
3892
+ const refreshPrices = useCallback7(() => setPriceVersion((value2) => value2 + 1), []);
3604
3893
  const productId = productIdProp ?? price?.product?.id;
3605
- const reloadPrice = useCallback6(async () => {
3894
+ const reloadPrice = useCallback7(async () => {
3606
3895
  if (!price?.id) return;
3607
3896
  setPrice(await StripePriceService.getPrice({ id: price.id }));
3608
3897
  }, [price?.id]);
3609
- const createPrice = useCallback6(
3898
+ const createPrice = useCallback7(
3610
3899
  async (input) => {
3611
3900
  const saved = await StripePriceService.createPrice(input);
3612
3901
  refreshPrices();
@@ -3614,7 +3903,7 @@ var PriceProvider = /* @__PURE__ */ __name(({
3614
3903
  },
3615
3904
  [refreshPrices]
3616
3905
  );
3617
- const updatePrice = useCallback6(
3906
+ const updatePrice = useCallback7(
3618
3907
  async (input) => {
3619
3908
  const saved = await StripePriceService.updatePrice(input);
3620
3909
  setPrice(saved);
@@ -3623,7 +3912,7 @@ var PriceProvider = /* @__PURE__ */ __name(({
3623
3912
  },
3624
3913
  [refreshPrices]
3625
3914
  );
3626
- const archivePrice = useCallback6(
3915
+ const archivePrice = useCallback7(
3627
3916
  async (id) => {
3628
3917
  const target = id ?? price?.id;
3629
3918
  if (!target) return;
@@ -3633,7 +3922,7 @@ var PriceProvider = /* @__PURE__ */ __name(({
3633
3922
  },
3634
3923
  [price?.id, reloadPrice, refreshPrices]
3635
3924
  );
3636
- const restorePrice = useCallback6(
3925
+ const restorePrice = useCallback7(
3637
3926
  async (id) => {
3638
3927
  const target = id ?? price?.id;
3639
3928
  if (!target) return;
@@ -3688,18 +3977,18 @@ var PriceProvider = /* @__PURE__ */ __name(({
3688
3977
  var usePriceContext = /* @__PURE__ */ __name(() => useContext(PriceContext) ?? defaultContextValue, "usePriceContext");
3689
3978
 
3690
3979
  // src/features/billing/contexts/ProductContext.tsx
3691
- import { useTranslations as useTranslations42 } from "next-intl";
3692
- import { createContext as createContext2, useCallback as useCallback8, useContext as useContext2, useMemo as useMemo8, useState as useState19 } from "react";
3980
+ import { useTranslations as useTranslations43 } from "next-intl";
3981
+ import { createContext as createContext2, useCallback as useCallback9, useContext as useContext2, useMemo as useMemo8, useState as useState21 } from "react";
3693
3982
 
3694
3983
  // src/features/billing/stripe-product/components/forms/ProductArchiver.tsx
3695
3984
  import { ArchiveIcon as ArchiveIcon2, RotateCcwIcon as RotateCcwIcon2 } from "lucide-react";
3696
- import { useTranslations as useTranslations40 } from "next-intl";
3697
- import { useState as useState18 } from "react";
3985
+ import { useTranslations as useTranslations41 } from "next-intl";
3986
+ import { useState as useState20 } from "react";
3698
3987
  import { Fragment as Fragment10, jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
3699
3988
  function ProductArchiver({ product }) {
3700
- const t = useTranslations40();
3989
+ const t = useTranslations41();
3701
3990
  const { archiveProduct, restoreProduct } = useProductContext();
3702
- const [open, setOpen] = useState18(false);
3991
+ const [open, setOpen] = useState20(false);
3703
3992
  const isArchived = !product.active;
3704
3993
  const scope = isArchived ? "restore" : "archive";
3705
3994
  return /* @__PURE__ */ jsxs37(Fragment10, { children: [
@@ -3734,8 +4023,8 @@ __name(ProductArchiver, "ProductArchiver");
3734
4023
 
3735
4024
  // src/features/billing/stripe-product/components/forms/ProductEditor.tsx
3736
4025
  import { zodResolver as zodResolver3 } from "@hookform/resolvers/zod";
3737
- import { useTranslations as useTranslations41 } from "next-intl";
3738
- import { useCallback as useCallback7, useMemo as useMemo7 } from "react";
4026
+ import { useTranslations as useTranslations42 } from "next-intl";
4027
+ import { useCallback as useCallback8, useMemo as useMemo7 } from "react";
3739
4028
  import { useForm as useForm3 } from "react-hook-form";
3740
4029
  import { v4 as v43 } from "uuid";
3741
4030
  import { z as z3 } from "zod";
@@ -3750,7 +4039,7 @@ function ProductEditorInternal({
3750
4039
  dialogOpen,
3751
4040
  onDialogOpenChange
3752
4041
  }) {
3753
- const t = useTranslations41();
4042
+ const t = useTranslations42();
3754
4043
  const router = useI18nRouter();
3755
4044
  const { createProduct, updateProduct } = useProductContext();
3756
4045
  const isEdit = !!product;
@@ -3762,7 +4051,7 @@ function ProductEditorInternal({
3762
4051
  }),
3763
4052
  [t]
3764
4053
  );
3765
- const getDefaultValues = useCallback7(
4054
+ const getDefaultValues = useCallback8(
3766
4055
  () => ({
3767
4056
  id: product?.id ?? v43(),
3768
4057
  name: product?.name ?? "",
@@ -3851,19 +4140,19 @@ var defaultContextValue2 = {
3851
4140
  }, "refreshCatalogue")
3852
4141
  };
3853
4142
  var ProductProvider = /* @__PURE__ */ __name(({ children, dehydratedProduct, publishChrome = true }) => {
3854
- const t = useTranslations42();
4143
+ const t = useTranslations43();
3855
4144
  const generateUrl = usePageUrlGenerator();
3856
4145
  const { hasRole } = useCurrentUserContext();
3857
- const [product, setProduct] = useState19(
4146
+ const [product, setProduct] = useState21(
3858
4147
  dehydratedProduct ? rehydrate(Modules.StripeProduct, dehydratedProduct) : void 0
3859
4148
  );
3860
- const [catalogueVersion, setCatalogueVersion] = useState19(0);
3861
- const refreshCatalogue = useCallback8(() => setCatalogueVersion((value2) => value2 + 1), []);
3862
- const reloadProduct = useCallback8(async () => {
4149
+ const [catalogueVersion, setCatalogueVersion] = useState21(0);
4150
+ const refreshCatalogue = useCallback9(() => setCatalogueVersion((value2) => value2 + 1), []);
4151
+ const reloadProduct = useCallback9(async () => {
3863
4152
  if (!product?.id) return;
3864
4153
  setProduct(await StripeProductService.getProduct({ id: product.id }));
3865
4154
  }, [product?.id]);
3866
- const createProduct = useCallback8(
4155
+ const createProduct = useCallback9(
3867
4156
  async (input) => {
3868
4157
  const saved = await StripeProductService.createProduct(input);
3869
4158
  refreshCatalogue();
@@ -3871,7 +4160,7 @@ var ProductProvider = /* @__PURE__ */ __name(({ children, dehydratedProduct, pub
3871
4160
  },
3872
4161
  [refreshCatalogue]
3873
4162
  );
3874
- const updateProduct = useCallback8(
4163
+ const updateProduct = useCallback9(
3875
4164
  async (input) => {
3876
4165
  const saved = await StripeProductService.updateProduct(input);
3877
4166
  setProduct(saved);
@@ -3880,7 +4169,7 @@ var ProductProvider = /* @__PURE__ */ __name(({ children, dehydratedProduct, pub
3880
4169
  },
3881
4170
  [refreshCatalogue]
3882
4171
  );
3883
- const archiveProduct = useCallback8(
4172
+ const archiveProduct = useCallback9(
3884
4173
  async (id) => {
3885
4174
  const target = id ?? product?.id;
3886
4175
  if (!target) return;
@@ -3890,7 +4179,7 @@ var ProductProvider = /* @__PURE__ */ __name(({ children, dehydratedProduct, pub
3890
4179
  },
3891
4180
  [product?.id, reloadProduct, refreshCatalogue]
3892
4181
  );
3893
- const restoreProduct = useCallback8(
4182
+ const restoreProduct = useCallback9(
3894
4183
  async (id) => {
3895
4184
  const target = id ?? product?.id;
3896
4185
  if (!target) return;
@@ -3952,10 +4241,10 @@ var ProductProvider = /* @__PURE__ */ __name(({ children, dehydratedProduct, pub
3952
4241
  var useProductContext = /* @__PURE__ */ __name(() => useContext2(ProductContext) ?? defaultContextValue2, "useProductContext");
3953
4242
 
3954
4243
  // src/features/billing/stripe-price/components/details/PriceDetails.tsx
3955
- import { useTranslations as useTranslations43 } from "next-intl";
4244
+ import { useTranslations as useTranslations44 } from "next-intl";
3956
4245
  import { jsx as jsx46, jsxs as jsxs39 } from "react/jsx-runtime";
3957
4246
  function PriceDetails() {
3958
- const t = useTranslations43();
4247
+ const t = useTranslations44();
3959
4248
  const fmt = useBillingFormatOptions();
3960
4249
  const generateUrl = usePageUrlGenerator();
3961
4250
  const { price } = usePriceContext();
@@ -4072,8 +4361,8 @@ __name(PriceContainer, "PriceContainer");
4072
4361
 
4073
4362
  // src/features/billing/stripe-price/components/lists/PricesList.tsx
4074
4363
  import { DollarSignIcon, UploadIcon } from "lucide-react";
4075
- import { useTranslations as useTranslations44 } from "next-intl";
4076
- import { Fragment as Fragment11, useCallback as useCallback9, useEffect as useEffect11, useMemo as useMemo9, useRef as useRef4, useState as useState20 } from "react";
4364
+ import { useTranslations as useTranslations45 } from "next-intl";
4365
+ import { Fragment as Fragment11, useCallback as useCallback10, useEffect as useEffect12, useMemo as useMemo9, useRef as useRef4, useState as useState22 } from "react";
4077
4366
 
4078
4367
  // src/features/billing/stripe-price/data/stripe-price.transfer.ts
4079
4368
  import { z as z4 } from "zod";
@@ -4186,28 +4475,28 @@ __name(parseStripePriceTransferDocument, "parseStripePriceTransferDocument");
4186
4475
  // src/features/billing/stripe-price/components/lists/PricesList.tsx
4187
4476
  import { Fragment as Fragment12, jsx as jsx48, jsxs as jsxs40 } from "react/jsx-runtime";
4188
4477
  function PricesList({ productId, fullWidth }) {
4189
- const t = useTranslations44();
4478
+ const t = useTranslations45();
4190
4479
  const { priceVersion } = usePriceContext();
4191
4480
  const importInputRef = useRef4(null);
4192
- const [seed, setSeed] = useState20(void 0);
4193
- const [seedNonce, setSeedNonce] = useState20(0);
4481
+ const [seed, setSeed] = useState22(void 0);
4482
+ const [seedNonce, setSeedNonce] = useState22(0);
4194
4483
  const data = useDataListRetriever({
4195
4484
  retriever: /* @__PURE__ */ __name((params) => StripePriceService.listPrices({ ...params, productId }), "retriever"),
4196
4485
  retrieverParams: {},
4197
4486
  module: Modules.StripePrice
4198
4487
  });
4199
- useEffect11(() => {
4488
+ useEffect12(() => {
4200
4489
  if (priceVersion > 0) void data.refresh();
4201
4490
  }, [priceVersion]);
4202
- const openSeededEditor = useCallback9((next) => {
4491
+ const openSeededEditor = useCallback10((next) => {
4203
4492
  setSeed(next);
4204
4493
  setSeedNonce((nonce) => nonce + 1);
4205
4494
  }, []);
4206
- const onClone = useCallback9(
4495
+ const onClone = useCallback10(
4207
4496
  (price) => openSeededEditor(priceToSeed(price)),
4208
4497
  [openSeededEditor]
4209
4498
  );
4210
- const onExport = useCallback9((price) => {
4499
+ const onExport = useCallback10((price) => {
4211
4500
  const text = JSON.stringify(buildStripePriceTransferDocument(price), null, 2);
4212
4501
  const blob = new Blob([text], { type: "application/json" });
4213
4502
  const url = URL.createObjectURL(blob);
@@ -4218,7 +4507,7 @@ function PricesList({ productId, fullWidth }) {
4218
4507
  URL.revokeObjectURL(url);
4219
4508
  }, []);
4220
4509
  const tableContext = useMemo9(() => ({ onClone, onExport }), [onClone, onExport]);
4221
- const onImportFileChange = useCallback9(
4510
+ const onImportFileChange = useCallback10(
4222
4511
  async (event) => {
4223
4512
  const input = event.target;
4224
4513
  const file = input.files?.[0];
@@ -4313,13 +4602,13 @@ function PricesList({ productId, fullWidth }) {
4313
4602
  __name(PricesList, "PricesList");
4314
4603
 
4315
4604
  // src/features/billing/stripe-product/components/containers/ProductContainer.tsx
4316
- import { useTranslations as useTranslations46 } from "next-intl";
4605
+ import { useTranslations as useTranslations47 } from "next-intl";
4317
4606
 
4318
4607
  // src/features/billing/stripe-product/components/details/ProductDetails.tsx
4319
- import { useTranslations as useTranslations45 } from "next-intl";
4608
+ import { useTranslations as useTranslations46 } from "next-intl";
4320
4609
  import { jsx as jsx49, jsxs as jsxs41 } from "react/jsx-runtime";
4321
4610
  function ProductDetails() {
4322
- const t = useTranslations45();
4611
+ const t = useTranslations46();
4323
4612
  const { product } = useProductContext();
4324
4613
  if (!product) return null;
4325
4614
  return /* @__PURE__ */ jsxs41("div", { className: "flex w-full flex-col gap-y-4", children: [
@@ -4363,7 +4652,7 @@ __name(ProductDetails, "ProductDetails");
4363
4652
  // src/features/billing/stripe-product/components/containers/ProductContainer.tsx
4364
4653
  import { jsx as jsx50 } from "react/jsx-runtime";
4365
4654
  function ProductContainer() {
4366
- const t = useTranslations46();
4655
+ const t = useTranslations47();
4367
4656
  const { product } = useProductContext();
4368
4657
  if (!product) return null;
4369
4658
  return /* @__PURE__ */ jsx50(
@@ -4394,24 +4683,72 @@ function ProductContainer() {
4394
4683
  }
4395
4684
  __name(ProductContainer, "ProductContainer");
4396
4685
 
4686
+ // src/features/billing/stripe-product/components/containers/ProductsListContainer.tsx
4687
+ import { useTranslations as useTranslations50 } from "next-intl";
4688
+
4689
+ // src/features/billing/stripe-coupon/components/lists/CouponsList.tsx
4690
+ import { TicketPercentIcon } from "lucide-react";
4691
+ import { useTranslations as useTranslations48 } from "next-intl";
4692
+ import { useEffect as useEffect13 } from "react";
4693
+ import { jsx as jsx51 } from "react/jsx-runtime";
4694
+ function CouponsList({ fullWidth } = {}) {
4695
+ const t = useTranslations48();
4696
+ const { catalogueVersion } = useCouponContext();
4697
+ const data = useDataListRetriever({
4698
+ retriever: /* @__PURE__ */ __name((params) => StripeCouponService.listCoupons(params), "retriever"),
4699
+ retrieverParams: {},
4700
+ module: Modules.StripeCoupon
4701
+ });
4702
+ useEffect13(() => {
4703
+ if (catalogueVersion > 0) void data.refresh();
4704
+ }, [catalogueVersion]);
4705
+ const functions = [/* @__PURE__ */ jsx51(CouponEditor, {}, "create-coupon")];
4706
+ return /* @__PURE__ */ jsx51(
4707
+ ContentListTable,
4708
+ {
4709
+ data,
4710
+ fields: [
4711
+ "name" /* name */,
4712
+ "discount" /* discount */,
4713
+ "places" /* places */,
4714
+ "codes" /* codes */,
4715
+ "status" /* status */
4716
+ ],
4717
+ tableGeneratorType: Modules.StripeCoupon,
4718
+ functions,
4719
+ fullWidth,
4720
+ title: t("billing.admin.coupons.title"),
4721
+ emptyState: /* @__PURE__ */ jsx51(
4722
+ EmptyState,
4723
+ {
4724
+ icon: TicketPercentIcon,
4725
+ title: t("billing.admin.coupons.empty.title"),
4726
+ description: t("billing.admin.coupons.empty.description")
4727
+ }
4728
+ )
4729
+ }
4730
+ );
4731
+ }
4732
+ __name(CouponsList, "CouponsList");
4733
+
4397
4734
  // src/features/billing/stripe-product/components/lists/ProductsList.tsx
4398
4735
  import { PackageIcon } from "lucide-react";
4399
- import { useTranslations as useTranslations47 } from "next-intl";
4400
- import { useEffect as useEffect12 } from "react";
4401
- import { jsx as jsx51 } from "react/jsx-runtime";
4736
+ import { useTranslations as useTranslations49 } from "next-intl";
4737
+ import { useEffect as useEffect14 } from "react";
4738
+ import { jsx as jsx52 } from "react/jsx-runtime";
4402
4739
  function ProductsList({ fullWidth } = {}) {
4403
- const t = useTranslations47();
4740
+ const t = useTranslations49();
4404
4741
  const { catalogueVersion } = useProductContext();
4405
4742
  const data = useDataListRetriever({
4406
4743
  retriever: /* @__PURE__ */ __name((params) => StripeProductService.listProducts(params), "retriever"),
4407
4744
  retrieverParams: {},
4408
4745
  module: Modules.StripeProduct
4409
4746
  });
4410
- useEffect12(() => {
4747
+ useEffect14(() => {
4411
4748
  if (catalogueVersion > 0) void data.refresh();
4412
4749
  }, [catalogueVersion]);
4413
- const functions = [/* @__PURE__ */ jsx51(ProductEditor, {}, "create-product")];
4414
- return /* @__PURE__ */ jsx51(
4750
+ const functions = [/* @__PURE__ */ jsx52(ProductEditor, {}, "create-product")];
4751
+ return /* @__PURE__ */ jsx52(
4415
4752
  ContentListTable,
4416
4753
  {
4417
4754
  data,
@@ -4420,7 +4757,7 @@ function ProductsList({ fullWidth } = {}) {
4420
4757
  functions,
4421
4758
  fullWidth,
4422
4759
  title: t("billing.admin.products.title"),
4423
- emptyState: /* @__PURE__ */ jsx51(
4760
+ emptyState: /* @__PURE__ */ jsx52(
4424
4761
  EmptyState,
4425
4762
  {
4426
4763
  icon: PackageIcon,
@@ -4434,17 +4771,230 @@ function ProductsList({ fullWidth } = {}) {
4434
4771
  __name(ProductsList, "ProductsList");
4435
4772
 
4436
4773
  // src/features/billing/stripe-product/components/containers/ProductsListContainer.tsx
4437
- import { jsx as jsx52 } from "react/jsx-runtime";
4774
+ import { jsx as jsx53 } from "react/jsx-runtime";
4438
4775
  function ProductsListContainer() {
4439
- return /* @__PURE__ */ jsx52(ProductProvider, { children: /* @__PURE__ */ jsx52(RoundPageContainer, { module: Modules.StripeProduct, fullWidth: true, children: /* @__PURE__ */ jsx52(ProductsList, { fullWidth: true }) }) });
4776
+ const t = useTranslations50();
4777
+ return /* @__PURE__ */ jsx53(ProductProvider, { children: /* @__PURE__ */ jsx53(CouponProvider, { publishChrome: false, children: /* @__PURE__ */ jsx53(
4778
+ RoundPageContainer,
4779
+ {
4780
+ module: Modules.StripeProduct,
4781
+ tabs: [
4782
+ { sectionKey: "products", label: t("billing.admin.products.tabs.products"), content: /* @__PURE__ */ jsx53(ProductsList, {}) },
4783
+ { sectionKey: "codes", label: t("billing.admin.products.tabs.codes"), content: /* @__PURE__ */ jsx53(CouponsList, {}) }
4784
+ ]
4785
+ }
4786
+ ) }) });
4440
4787
  }
4441
4788
  __name(ProductsListContainer, "ProductsListContainer");
4789
+
4790
+ // src/features/billing/stripe-coupon/components/containers/CouponContainer.tsx
4791
+ import { useTranslations as useTranslations54 } from "next-intl";
4792
+
4793
+ // src/features/billing/stripe-coupon/components/details/CouponDetails.tsx
4794
+ import { useTranslations as useTranslations51 } from "next-intl";
4795
+ import { jsx as jsx54, jsxs as jsxs42 } from "react/jsx-runtime";
4796
+ function CouponDetails() {
4797
+ const t = useTranslations51();
4798
+ const fmt = useBillingFormatOptions();
4799
+ const { coupon } = useCouponContext();
4800
+ if (!coupon) return null;
4801
+ return /* @__PURE__ */ jsxs42("div", { className: "flex w-full flex-col gap-y-4", children: [
4802
+ /* @__PURE__ */ jsx54(SectionHeader, { children: t("billing.admin.products.tabs.details") }),
4803
+ /* @__PURE__ */ jsx54("p", { className: "text-muted-foreground text-xs/relaxed", children: t("billing.admin.coupons.fixed_notice") }),
4804
+ /* @__PURE__ */ jsxs42("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2", children: [
4805
+ /* @__PURE__ */ jsx54(DetailField, { label: t("billing.admin.coupons.fields.name"), value: coupon.name }),
4806
+ /* @__PURE__ */ jsx54(
4807
+ DetailField,
4808
+ {
4809
+ label: t("billing.admin.coupons.fields.status"),
4810
+ value: coupon.valid ? /* @__PURE__ */ jsx54(Badge, { variant: "softGreen", children: t("billing.admin.coupons.status.active") }) : /* @__PURE__ */ jsx54(Badge, { variant: "softGray", children: t("billing.admin.coupons.status.ended") })
4811
+ }
4812
+ ),
4813
+ /* @__PURE__ */ jsx54(DetailField, { label: t("billing.admin.coupons.fields.discount"), value: formatCouponDiscount(coupon, t, fmt) }),
4814
+ /* @__PURE__ */ jsx54(
4815
+ DetailField,
4816
+ {
4817
+ label: t("billing.admin.coupons.fields.places"),
4818
+ value: /* @__PURE__ */ jsx54("span", { className: "tabular-nums", children: coupon.maxRedemptions !== void 0 ? t("billing.admin.coupons.places.limited", {
4819
+ used: String(coupon.timesRedeemed),
4820
+ limit: String(coupon.maxRedemptions)
4821
+ }) : t("billing.admin.coupons.places.unlimited", { used: String(coupon.timesRedeemed) }) })
4822
+ }
4823
+ ),
4824
+ /* @__PURE__ */ jsx54(
4825
+ DetailField,
4826
+ {
4827
+ label: t("billing.admin.coupons.fields.products"),
4828
+ value: coupon.stripeProductIds.length > 0 ? /* @__PURE__ */ jsx54("span", { className: "tabular-nums", children: coupon.stripeProductIds.join(", ") }) : t("billing.admin.coupons.all_products")
4829
+ }
4830
+ ),
4831
+ /* @__PURE__ */ jsx54(
4832
+ DetailField,
4833
+ {
4834
+ label: t("billing.admin.coupons.fields.redeemBy"),
4835
+ value: coupon.redeemBy ? formatDate(coupon.redeemBy, fmt) : "\u2014"
4836
+ }
4837
+ ),
4838
+ /* @__PURE__ */ jsx54(
4839
+ DetailField,
4840
+ {
4841
+ label: t("billing.admin.coupons.fields.stripeId"),
4842
+ value: /* @__PURE__ */ jsx54("span", { className: "tabular-nums", children: coupon.stripeCouponId })
4843
+ }
4844
+ )
4845
+ ] })
4846
+ ] });
4847
+ }
4848
+ __name(CouponDetails, "CouponDetails");
4849
+
4850
+ // src/features/billing/stripe-coupon/components/lists/CouponCodesList.tsx
4851
+ import { TicketIcon } from "lucide-react";
4852
+ import { useTranslations as useTranslations53 } from "next-intl";
4853
+ import { useEffect as useEffect15 } from "react";
4854
+
4855
+ // src/features/billing/stripe-coupon/components/forms/CouponCodeEditor.tsx
4856
+ import { zodResolver as zodResolver4 } from "@hookform/resolvers/zod";
4857
+ import { useTranslations as useTranslations52 } from "next-intl";
4858
+ import { useCallback as useCallback11, useMemo as useMemo10 } from "react";
4859
+ import { useForm as useForm4 } from "react-hook-form";
4860
+ import { v4 as v44 } from "uuid";
4861
+ import { z as z5 } from "zod";
4862
+ import { jsx as jsx55 } from "react/jsx-runtime";
4863
+ function CouponCodeEditorInternal({
4864
+ couponId,
4865
+ onSuccess,
4866
+ trigger,
4867
+ forceShow,
4868
+ onClose,
4869
+ dialogOpen,
4870
+ onDialogOpenChange
4871
+ }) {
4872
+ const t = useTranslations52();
4873
+ const router = useI18nRouter();
4874
+ const { createCode } = useCouponContext();
4875
+ const formSchema2 = useMemo10(() => z5.object({ id: z5.uuidv4() }).and(couponCodeSchema(t)), [t]);
4876
+ const getDefaultValues = useCallback11(() => ({ id: v44(), ...couponCodeDefaults() }), []);
4877
+ const form = useForm4({
4878
+ resolver: zodResolver4(formSchema2),
4879
+ defaultValues: getDefaultValues()
4880
+ });
4881
+ return /* @__PURE__ */ jsx55(
4882
+ EditorSheet,
4883
+ {
4884
+ form,
4885
+ entityType: t("billing.admin.coupons.codes.entity"),
4886
+ isEdit: false,
4887
+ module: Modules.StripeCouponCode,
4888
+ size: "md",
4889
+ onSuccess: onSuccess ?? (() => {
4890
+ }),
4891
+ onNavigate: (url) => router.push(url),
4892
+ onSubmit: async (values) => await createCode({ id: values.id, couponId, ...toCouponCodeInput(values) }),
4893
+ onReset: getDefaultValues,
4894
+ trigger,
4895
+ forceShow,
4896
+ onClose,
4897
+ dialogOpen,
4898
+ onDialogOpenChange,
4899
+ children: /* @__PURE__ */ jsx55(CouponCodeFields, { form })
4900
+ }
4901
+ );
4902
+ }
4903
+ __name(CouponCodeEditorInternal, "CouponCodeEditorInternal");
4904
+ function CouponCodeEditor(props) {
4905
+ return /* @__PURE__ */ jsx55(CouponCodeEditorInternal, { ...props });
4906
+ }
4907
+ __name(CouponCodeEditor, "CouponCodeEditor");
4908
+
4909
+ // src/features/billing/stripe-coupon/components/lists/CouponCodesList.tsx
4910
+ import { jsx as jsx56 } from "react/jsx-runtime";
4911
+ function CouponCodesList({ couponId }) {
4912
+ const t = useTranslations53();
4913
+ const { catalogueVersion } = useCouponContext();
4914
+ const data = useDataListRetriever({
4915
+ retriever: /* @__PURE__ */ __name((params) => StripeCouponCodeService.listByCoupon({ ...params, couponId }), "retriever"),
4916
+ retrieverParams: {},
4917
+ module: Modules.StripeCouponCode
4918
+ });
4919
+ useEffect15(() => {
4920
+ if (catalogueVersion > 0) void data.refresh();
4921
+ }, [catalogueVersion]);
4922
+ const functions = [/* @__PURE__ */ jsx56(CouponCodeEditor, { couponId }, "create-code")];
4923
+ return /* @__PURE__ */ jsx56(
4924
+ ContentListTable,
4925
+ {
4926
+ data,
4927
+ fields: [
4928
+ "code" /* code */,
4929
+ "places" /* places */,
4930
+ "expiresAt" /* expiresAt */,
4931
+ "automatic" /* automatic */,
4932
+ "status" /* status */,
4933
+ "actions" /* actions */
4934
+ ],
4935
+ tableGeneratorType: Modules.StripeCouponCode,
4936
+ functions,
4937
+ title: t("billing.admin.coupons.codes.title"),
4938
+ emptyState: /* @__PURE__ */ jsx56(
4939
+ EmptyState,
4940
+ {
4941
+ icon: TicketIcon,
4942
+ title: t("billing.admin.coupons.codes.empty.title"),
4943
+ description: t("billing.admin.coupons.codes.empty.description")
4944
+ }
4945
+ )
4946
+ }
4947
+ );
4948
+ }
4949
+ __name(CouponCodesList, "CouponCodesList");
4950
+
4951
+ // src/features/billing/stripe-coupon/components/containers/CouponContainer.tsx
4952
+ import { jsx as jsx57 } from "react/jsx-runtime";
4953
+ function CouponContainer() {
4954
+ const t = useTranslations54();
4955
+ const { coupon } = useCouponContext();
4956
+ if (!coupon) return null;
4957
+ return /* @__PURE__ */ jsx57(
4958
+ RoundPageContainer,
4959
+ {
4960
+ module: Modules.StripeCoupon,
4961
+ id: coupon.id,
4962
+ tabs: [
4963
+ {
4964
+ sectionKey: "details",
4965
+ label: t("billing.admin.products.tabs.details"),
4966
+ content: /* @__PURE__ */ jsx57(CouponDetails, {})
4967
+ },
4968
+ {
4969
+ sectionKey: "codes",
4970
+ label: t("billing.admin.coupons.codes.title"),
4971
+ // No `fillHeight` and no `fullWidth` on the list: a ContentListTable in
4972
+ // a tab keeps its own bordered card and flows with the panel, exactly
4973
+ // as PricesList does inside ProductContainer. The codes list reads the
4974
+ // page's own CouponProvider, so no nested provider is needed.
4975
+ content: /* @__PURE__ */ jsx57(CouponCodesList, { couponId: coupon.id })
4976
+ }
4977
+ ]
4978
+ }
4979
+ );
4980
+ }
4981
+ __name(CouponContainer, "CouponContainer");
4442
4982
  export {
4443
4983
  BillingAlertBanner,
4444
4984
  BillingDashboardContainer,
4445
4985
  BillingDetailModal,
4446
4986
  BillingUsageSummaryCard,
4447
4987
  CancelSubscriptionDialog,
4988
+ CouponCodeActions,
4989
+ CouponCodeEditor,
4990
+ CouponCodeFields,
4991
+ CouponCodesList,
4992
+ CouponContainer,
4993
+ CouponDetails,
4994
+ CouponEditor,
4995
+ CouponProvider,
4996
+ CouponRefresher,
4997
+ CouponsList,
4448
4998
  CustomerInfoCard,
4449
4999
  IntervalToggle,
4450
5000
  InvoiceDetails,
@@ -4492,13 +5042,24 @@ export {
4492
5042
  WizardStepPaymentMethod,
4493
5043
  WizardStepPlanSelection,
4494
5044
  WizardStepReview,
5045
+ applyDiscount,
5046
+ couponCodeDefaults,
5047
+ couponCodeSchema,
5048
+ couponCurrencyOptions,
4495
5049
  formatCurrency,
4496
5050
  formatDate,
4497
5051
  formatFixed,
4498
5052
  formatInterval,
4499
5053
  isStripeConfigured,
5054
+ optionalDate,
5055
+ optionalDecimal,
5056
+ optionalPositiveInt,
4500
5057
  priceLabel,
5058
+ promotionCodeDiscount,
5059
+ subscriptionDiscount,
5060
+ toCouponCodeInput,
4501
5061
  useBillingFormatOptions,
5062
+ useCouponContext,
4502
5063
  usePriceContext,
4503
5064
  useProductContext
4504
5065
  };