@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.
- package/dist/{BlockNoteEditor-4YCAIEPT.js → BlockNoteEditor-AE3ZTEEH.js} +20 -20
- package/dist/{BlockNoteEditor-4YCAIEPT.js.map → BlockNoteEditor-AE3ZTEEH.js.map} +1 -1
- package/dist/{BlockNoteEditor-YQL2SGFR.mjs → BlockNoteEditor-NEYG5L6W.mjs} +5 -5
- package/dist/{BlockNoteViewer-AEJKJ27Q.mjs → BlockNoteViewer-3OUT5UFY.mjs} +3 -3
- package/dist/{BlockNoteViewer-YL3J7J2Y.js → BlockNoteViewer-4CFKQM7U.js} +4 -4
- package/dist/{BlockNoteViewer-YL3J7J2Y.js.map → BlockNoteViewer-4CFKQM7U.js.map} +1 -1
- package/dist/billing/index.d.mts +186 -25
- package/dist/billing/index.d.ts +186 -25
- package/dist/billing/index.js +1149 -588
- package/dist/billing/index.js.map +1 -1
- package/dist/billing/index.mjs +786 -225
- package/dist/billing/index.mjs.map +1 -1
- package/dist/{chunk-5PPG6PL7.js → chunk-3I5AAJXV.js} +3 -3
- package/dist/{chunk-5PPG6PL7.js.map → chunk-3I5AAJXV.js.map} +1 -1
- package/dist/{chunk-YW4ZCEWB.js → chunk-53BAULDP.js} +4 -4
- package/dist/{chunk-YW4ZCEWB.js.map → chunk-53BAULDP.js.map} +1 -1
- package/dist/{chunk-XCHSX3VC.mjs → chunk-BTPUYUQ3.mjs} +2 -2
- package/dist/{chunk-WC63PJSC.mjs → chunk-EYA2F6AN.mjs} +756 -24
- package/dist/chunk-EYA2F6AN.mjs.map +1 -0
- package/dist/{chunk-NFBOSPNJ.js → chunk-HKZAESS6.js} +954 -222
- package/dist/chunk-HKZAESS6.js.map +1 -0
- package/dist/{chunk-6DC2WVVB.mjs → chunk-KQHBONL4.mjs} +2 -2
- package/dist/{chunk-3NLAXVIN.js → chunk-LQ4DK4JF.js} +1988 -1089
- package/dist/chunk-LQ4DK4JF.js.map +1 -0
- package/dist/{chunk-YNCQSWQW.js → chunk-RL3PL3KV.js} +8 -8
- package/dist/{chunk-YNCQSWQW.js.map → chunk-RL3PL3KV.js.map} +1 -1
- package/dist/{chunk-EUKTBOI2.mjs → chunk-SFYPXCK4.mjs} +3382 -2483
- package/dist/chunk-SFYPXCK4.mjs.map +1 -0
- package/dist/{chunk-QMYQRPQC.mjs → chunk-Y7RR57EW.mjs} +2 -2
- package/dist/client/index.js +5 -5
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +4 -4
- package/dist/components/editors/server.d.mts +15 -0
- package/dist/components/editors/server.d.ts +15 -0
- package/dist/components/editors/server.js +38 -0
- package/dist/components/editors/server.js.map +1 -0
- package/dist/components/editors/server.mjs +38 -0
- package/dist/components/editors/server.mjs.map +1 -0
- package/dist/components/index.d.mts +33 -10
- package/dist/components/index.d.ts +33 -10
- package/dist/components/index.js +7 -5
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +8 -6
- package/dist/contexts/index.d.mts +9 -1
- package/dist/contexts/index.d.ts +9 -1
- package/dist/contexts/index.js +5 -5
- package/dist/contexts/index.mjs +4 -4
- package/dist/core/index.d.mts +242 -3
- package/dist/core/index.d.ts +242 -3
- package/dist/core/index.js +36 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +35 -3
- package/dist/email-automations/index.d.mts +3 -0
- package/dist/email-automations/index.d.ts +3 -0
- package/dist/email-automations/index.js +99 -95
- package/dist/email-automations/index.js.map +1 -1
- package/dist/email-automations/index.mjs +30 -26
- package/dist/email-automations/index.mjs.map +1 -1
- package/dist/features/analytics/index.d.mts +11 -4
- package/dist/features/analytics/index.d.ts +11 -4
- package/dist/features/analytics/index.js +127 -135
- package/dist/features/analytics/index.js.map +1 -1
- package/dist/features/analytics/index.mjs +16 -24
- package/dist/features/analytics/index.mjs.map +1 -1
- package/dist/features/analytics/server.d.mts +5 -2
- package/dist/features/analytics/server.d.ts +5 -2
- package/dist/features/analytics/server.js +7 -7
- package/dist/features/analytics/server.js.map +1 -1
- package/dist/features/analytics/server.mjs +5 -5
- package/dist/features/analytics/server.mjs.map +1 -1
- package/dist/features/blog/index.d.mts +12 -2
- package/dist/features/blog/index.d.ts +12 -2
- package/dist/features/blog/index.js +206 -195
- package/dist/features/blog/index.js.map +1 -1
- package/dist/features/blog/index.mjs +71 -60
- package/dist/features/blog/index.mjs.map +1 -1
- package/dist/features/blog/server.d.mts +4 -1
- package/dist/features/blog/server.d.ts +4 -1
- package/dist/features/blog/server.js +49 -21
- package/dist/features/blog/server.js.map +1 -1
- package/dist/features/blog/server.mjs +36 -8
- package/dist/features/blog/server.mjs.map +1 -1
- package/dist/features/help/index.js +38 -38
- package/dist/features/help/index.mjs +4 -4
- package/dist/features/tokenusage/index.d.mts +1 -3
- package/dist/features/tokenusage/index.d.ts +1 -3
- package/dist/features/tokenusage/index.js +127 -135
- package/dist/features/tokenusage/index.js.map +1 -1
- package/dist/features/tokenusage/index.mjs +10 -18
- package/dist/features/tokenusage/index.mjs.map +1 -1
- package/dist/{stripe-promotion-code.interface-C3qqh3mi.d.ts → format-options-BtX3o0Yu.d.ts} +104 -1
- package/dist/{stripe-promotion-code.interface-ClZ7DxS9.d.mts → format-options-D6c7FNDi.d.mts} +104 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -4
- package/dist/server/index.js +4 -4
- package/dist/server/index.mjs +3 -3
- package/messages/en.json +125 -3
- package/messages/it.json +125 -3
- package/package.json +9 -1
- package/scripts/validate-messages.mjs +1 -0
- package/src/billing/index.ts +1 -0
- package/src/client/index.ts +4 -0
- package/src/components/editors/server/BlockNoteServerContent.tsx +28 -0
- package/src/components/editors/server/__tests__/renderBlockNoteHTML.spec.ts +44 -0
- package/src/components/editors/server/renderBlockNoteHTML.ts +26 -0
- package/src/components/editors/server-entry.ts +7 -0
- package/src/components/index.ts +1 -0
- package/src/components/viewers/BlockNoteStaticViewer.tsx +44 -0
- package/src/core/index.ts +1 -0
- package/src/core/registry/ModuleRegistry.ts +3 -0
- package/src/features/administration/components/AdminIndexContainer.tsx +61 -33
- package/src/features/administration/components/__tests__/AdminIndexContainer.spec.tsx +61 -1
- package/src/features/administration/components/index.ts +2 -1
- package/src/features/administration/contexts/AdministrationContext.tsx +11 -3
- package/src/features/administration/contexts/__tests__/AdministrationContext.spec.tsx +40 -0
- package/src/features/ai-connection/ai-connection.module.ts +2 -0
- package/src/features/ai-connection/contexts/AiConnectionsContext.tsx +3 -16
- package/src/features/ai-connection/contexts/__tests__/AiConnectionsContext.spec.tsx +33 -0
- package/src/features/analytics/__tests__/server-entry.spec.tsx +2 -1
- package/src/features/analytics/analytics.modules.ts +22 -5
- package/src/features/analytics/components/AnalyticsAdminContainer.tsx +4 -3
- package/src/features/analytics/components/AnalyticsAdminPageContainer.tsx +6 -3
- package/src/features/analytics/components/AnalyticsJourneyContainer.tsx +4 -3
- package/src/features/analytics/components/__tests__/AnalyticsJourneyContainer.spec.tsx +11 -0
- package/src/features/analytics/components/__tests__/AnalyticsPageContainers.spec.tsx +12 -1
- package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +6 -3
- package/src/features/analytics/contexts/AnalyticsAdminContext.tsx +8 -17
- package/src/features/analytics/contexts/__tests__/AnalyticsAdminContext.spec.tsx +17 -0
- package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +3 -2
- package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +4 -3
- package/src/features/billing/components/containers/BillingDashboardContainer.tsx +22 -5
- package/src/features/billing/components/utils/__tests__/discount.spec.ts +59 -0
- package/src/features/billing/components/utils/__tests__/url.spec.ts +32 -0
- package/src/features/billing/components/utils/discount.ts +38 -0
- package/src/features/billing/components/utils/index.ts +2 -0
- package/src/features/billing/components/utils/url.ts +12 -0
- package/src/features/billing/contexts/CouponContext.tsx +211 -0
- package/src/features/billing/contexts/index.ts +1 -0
- package/src/features/billing/i18n-keys.ts +79 -0
- package/src/features/billing/stripe-coupon/components/containers/CouponContainer.tsx +38 -0
- package/src/features/billing/stripe-coupon/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-coupon/components/details/CouponDetails.tsx +69 -0
- package/src/features/billing/stripe-coupon/components/details/index.ts +1 -0
- package/src/features/billing/stripe-coupon/components/forms/CouponCodeEditor.tsx +79 -0
- package/src/features/billing/stripe-coupon/components/forms/CouponCodeFields.tsx +192 -0
- package/src/features/billing/stripe-coupon/components/forms/CouponEditor.tsx +333 -0
- package/src/features/billing/stripe-coupon/components/forms/CouponRefresher.tsx +45 -0
- package/src/features/billing/stripe-coupon/components/forms/index.ts +6 -0
- package/src/features/billing/stripe-coupon/components/index.ts +5 -0
- package/src/features/billing/stripe-coupon/components/lists/CouponCodesList.tsx +61 -0
- package/src/features/billing/stripe-coupon/components/lists/CouponsList.tsx +67 -0
- package/src/features/billing/stripe-coupon/components/lists/index.ts +2 -0
- package/src/features/billing/stripe-coupon/components/widgets/CouponCodeActions.tsx +80 -0
- package/src/features/billing/stripe-coupon/components/widgets/index.ts +1 -0
- package/src/features/billing/stripe-coupon/data/__tests__/stripe-coupon-models.spec.ts +114 -0
- package/src/features/billing/stripe-coupon/data/index.ts +10 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-code.fields.ts +8 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-code.interface.ts +44 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-code.service.ts +92 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-code.ts +132 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-offer.interface.ts +17 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon-offer.ts +70 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon.fields.ts +7 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon.interface.ts +51 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon.service.ts +93 -0
- package/src/features/billing/stripe-coupon/data/stripe-coupon.ts +165 -0
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponCodeTableStructure.tsx +154 -0
- package/src/features/billing/stripe-coupon/hooks/useStripeCouponTableStructure.tsx +113 -0
- package/src/features/billing/stripe-coupon/index.ts +5 -0
- package/src/features/billing/stripe-coupon/stripe-coupon-code.module.ts +14 -0
- package/src/features/billing/stripe-coupon/stripe-coupon-offer.module.ts +10 -0
- package/src/features/billing/stripe-coupon/stripe-coupon.module.ts +18 -0
- package/src/features/billing/stripe-coupon/utils/__tests__/coupon-places.spec.ts +19 -0
- package/src/features/billing/stripe-coupon/utils/__tests__/to-promotion-code-result.spec.ts +41 -0
- package/src/features/billing/stripe-coupon/utils/coupon-places.ts +23 -0
- package/src/features/billing/stripe-coupon/utils/format-coupon-discount.ts +36 -0
- package/src/features/billing/stripe-coupon/utils/index.ts +3 -0
- package/src/features/billing/stripe-coupon/utils/to-promotion-code-result.ts +23 -0
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodForm.tsx +24 -8
- package/src/features/billing/stripe-price/stripe-price.module.ts +2 -0
- package/src/features/billing/stripe-product/components/containers/ProductsListContainer.tsx +21 -6
- package/src/features/billing/stripe-product/stripe-product.module.ts +2 -0
- package/src/features/billing/stripe-promotion-code/components/PromoCodeInput.tsx +60 -19
- package/src/features/billing/stripe-promotion-code/data/stripe-promotion-code.interface.ts +2 -0
- package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +24 -5
- package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +21 -2
- package/src/features/billing/stripe-subscription/components/wizards/SubscriptionWizard.tsx +1 -1
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepPaymentMethod.tsx +1 -1
- package/src/features/billing/stripe-subscription/components/wizards/WizardStepReview.tsx +60 -49
- package/src/features/billing/stripe-subscription/components/wizards/__tests__/review-card.spec.ts +34 -0
- package/src/features/billing/stripe-subscription/components/wizards/review-card.ts +24 -0
- package/src/features/billing/stripe-subscription/data/__tests__/stripe-subscription.discount.spec.ts +67 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +14 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +39 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +21 -0
- package/src/features/billing/stripe-subscription/hooks/__tests__/wizard-payment.spec.ts +48 -0
- package/src/features/billing/stripe-subscription/hooks/__tests__/wizard-promotion.spec.ts +132 -0
- package/src/features/billing/stripe-subscription/hooks/useSubscriptionWizard.ts +138 -12
- package/src/features/billing/stripe-subscription/hooks/wizard-payment.ts +30 -0
- package/src/features/billing/stripe-subscription/hooks/wizard-promotion.ts +54 -0
- package/src/features/blog/components/admin/BlogAdminContainer.tsx +13 -6
- package/src/features/blog/components/admin/BlogCategoriesList.tsx +1 -1
- package/src/features/blog/components/admin/BlogCoverImageField.tsx +1 -1
- package/src/features/blog/components/admin/BlogPostContainer.tsx +0 -1
- package/src/features/blog/components/admin/BlogPostEditor.tsx +42 -33
- package/src/features/blog/components/admin/BlogPostTranslationEditor.tsx +12 -4
- package/src/features/blog/components/admin/BlogPostsList.tsx +1 -1
- package/src/features/blog/components/public/BlogPostCard.tsx +2 -9
- package/src/features/blog/components/public/BlogPostMeta.tsx +2 -2
- package/src/features/blog/components/public/BlogPostView.tsx +9 -3
- package/src/features/blog/components/public/__tests__/BlogList.spec.tsx +2 -0
- package/src/features/blog/components/public/__tests__/BlogPostView.spec.tsx +17 -11
- package/src/features/blog/server/fetchers.ts +57 -8
- package/src/features/email-automation/components/containers/EmailAutomationsListContainer.tsx +12 -3
- package/src/features/rbac/contexts/RbacContext.tsx +4 -7
- package/src/features/rbac/contexts/__tests__/RbacContext.spec.tsx +42 -0
- package/src/features/tokenusage/components/TokenUsageAdminContainer.tsx +4 -3
- package/src/features/tokenusage/contexts/TokenUsageAdminContext.tsx +3 -18
- package/src/features/tokenusage/contexts/__tests__/TokenUsageAdminContext.spec.tsx +17 -0
- package/src/features/tokenusage/tokenusage-admin.module.ts +4 -3
- package/src/features/tokenusage/tokenusage.modules.ts +12 -2
- package/src/features/user/contexts/CurrentUserContext.tsx +25 -0
- package/src/features/user/contexts/UserContext.tsx +18 -3
- package/src/features/user/contexts/__tests__/CurrentUserContext.spec.tsx +121 -2
- package/src/features/user/contexts/__tests__/UserContext.spec.tsx +95 -0
- package/dist/chunk-3NLAXVIN.js.map +0 -1
- package/dist/chunk-EUKTBOI2.mjs.map +0 -1
- package/dist/chunk-NFBOSPNJ.js.map +0 -1
- package/dist/chunk-WC63PJSC.mjs.map +0 -1
- /package/dist/{BlockNoteEditor-YQL2SGFR.mjs.map → BlockNoteEditor-NEYG5L6W.mjs.map} +0 -0
- /package/dist/{BlockNoteViewer-AEJKJ27Q.mjs.map → BlockNoteViewer-3OUT5UFY.mjs.map} +0 -0
- /package/dist/{chunk-XCHSX3VC.mjs.map → chunk-BTPUYUQ3.mjs.map} +0 -0
- /package/dist/{chunk-6DC2WVVB.mjs.map → chunk-KQHBONL4.mjs.map} +0 -0
- /package/dist/{chunk-QMYQRPQC.mjs.map → chunk-Y7RR57EW.mjs.map} +0 -0
package/dist/billing/index.mjs
CHANGED
|
@@ -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
|
-
|
|
63
|
-
|
|
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-
|
|
81
|
+
} from "../chunk-SFYPXCK4.mjs";
|
|
69
82
|
import {
|
|
70
83
|
getStripePublishableKey
|
|
71
|
-
} from "../chunk-
|
|
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-
|
|
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:
|
|
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
|
-
] }) :
|
|
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
|
-
] })
|
|
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
|
|
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
|
|
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({
|
|
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(
|
|
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:
|
|
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({
|
|
1522
|
+
function SubscriptionsContainer({
|
|
1523
|
+
onOpenWizard,
|
|
1524
|
+
hasActiveRecurringSubscription,
|
|
1525
|
+
subscriptions: parentSubscriptions,
|
|
1526
|
+
onSubscriptionsChange
|
|
1527
|
+
}) {
|
|
1487
1528
|
const t = useTranslations18();
|
|
1488
|
-
const
|
|
1489
|
-
const [
|
|
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
|
|
1828
|
-
import { useCallback as
|
|
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
|
|
1832
|
-
import { useCallback as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2056
|
+
const selectPrice = useCallback3((price) => {
|
|
1899
2057
|
dispatch({ type: "SELECT_PRICE", price });
|
|
1900
2058
|
}, []);
|
|
1901
|
-
const setInterval =
|
|
2059
|
+
const setInterval = useCallback3((interval) => {
|
|
1902
2060
|
dispatch({ type: "SET_INTERVAL", interval });
|
|
1903
2061
|
}, []);
|
|
1904
|
-
const goToStep =
|
|
2062
|
+
const goToStep = useCallback3((step) => {
|
|
1905
2063
|
dispatch({ type: "SET_STEP", step });
|
|
1906
2064
|
}, []);
|
|
1907
|
-
const
|
|
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
|
-
}, [
|
|
1940
|
-
|
|
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
|
|
2147
|
+
promotionCode: promotionCodeToSend(state.promotionCode)
|
|
1950
2148
|
};
|
|
1951
|
-
await StripeSubscriptionService.
|
|
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
|
|
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 =
|
|
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
|
-
|
|
1983
|
-
}, []);
|
|
1984
|
-
const reset =
|
|
2210
|
+
await goToReview();
|
|
2211
|
+
}, [goToReview]);
|
|
2212
|
+
const reset = useCallback3(() => {
|
|
1985
2213
|
dispatch({ type: "RESET" });
|
|
1986
2214
|
}, []);
|
|
1987
|
-
const validatePromoCode =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
2091
|
-
import { useEffect as useEffect6, useMemo as useMemo2, useState as
|
|
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 =
|
|
2105
|
-
const [products, setProducts] =
|
|
2106
|
-
const [loading, setLoading] =
|
|
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
|
|
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
|
|
2172
|
-
import { useState as
|
|
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 =
|
|
2419
|
+
const t = useTranslations29();
|
|
2184
2420
|
const locale = useI18nLocale();
|
|
2185
|
-
const [code, setCode] =
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
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 (!
|
|
2316
|
-
if (
|
|
2317
|
-
return t("billing.ui.wizard.review.percent_off", { value:
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
2420
|
-
const handleClose =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2767
|
+
import { useTranslations as useTranslations34 } from "next-intl";
|
|
2499
2768
|
import { Activity as Activity3 } from "lucide-react";
|
|
2500
|
-
import { useEffect as
|
|
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
|
|
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 =
|
|
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 =
|
|
2574
|
-
const [meters, setMeters] =
|
|
2575
|
-
const [summaries, setSummaries] =
|
|
2576
|
-
const [loading, setLoading] =
|
|
2577
|
-
const [subscriptions, setSubscriptions] =
|
|
2578
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
2739
|
-
const [data, setData] =
|
|
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] =
|
|
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] =
|
|
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] =
|
|
2762
|
-
const [noCustomerExists, setNoCustomerExists] =
|
|
2763
|
-
const [creatingCustomer, setCreatingCustomer] =
|
|
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] =
|
|
2766
|
-
const [editingSubscription, setEditingSubscription] =
|
|
2767
|
-
const hasMeteredSubscriptions =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3182
|
+
const handleOpenWizard = useCallback5((subscription) => {
|
|
2905
3183
|
setEditingSubscription(subscription || null);
|
|
2906
3184
|
setShowWizard(true);
|
|
2907
3185
|
}, []);
|
|
2908
|
-
const handleWizardClose =
|
|
3186
|
+
const handleWizardClose = useCallback5(() => {
|
|
2909
3187
|
setShowWizard(false);
|
|
2910
3188
|
setEditingSubscription(null);
|
|
2911
3189
|
refreshData();
|
|
2912
3190
|
}, [refreshData]);
|
|
2913
|
-
|
|
3191
|
+
useEffect10(() => {
|
|
2914
3192
|
fetchAllData();
|
|
2915
3193
|
}, [fetchAllData]);
|
|
2916
|
-
|
|
3194
|
+
useEffect10(() => {
|
|
2917
3195
|
const action = searchParams.get("action");
|
|
2918
3196
|
if (action === "subscribe") {
|
|
2919
3197
|
setShowWizard(true);
|
|
2920
|
-
window.history.replaceState(
|
|
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
|
|
3121
|
-
import { createContext, useCallback as
|
|
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
|
|
3126
|
-
import { useState as
|
|
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 =
|
|
3418
|
+
const t = useTranslations38();
|
|
3130
3419
|
const fmt = useBillingFormatOptions();
|
|
3131
3420
|
const { archivePrice, restorePrice } = usePriceContext();
|
|
3132
|
-
const [open, setOpen] =
|
|
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
|
|
3169
|
-
import { useCallback as
|
|
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 =
|
|
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] =
|
|
3479
|
+
const [allFeatures, setAllFeatures] = useState18([]);
|
|
3191
3480
|
const isEdit = !!price;
|
|
3192
3481
|
const targetProductId = productId ?? price?.product?.id ?? contextProductId;
|
|
3193
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
3884
|
+
const t = useTranslations40();
|
|
3596
3885
|
const fmt = useBillingFormatOptions();
|
|
3597
3886
|
const generateUrl = usePageUrlGenerator();
|
|
3598
3887
|
const { hasRole } = useCurrentUserContext();
|
|
3599
|
-
const [price, setPrice] =
|
|
3888
|
+
const [price, setPrice] = useState19(
|
|
3600
3889
|
dehydratedPrice ? rehydrate(Modules.StripePrice, dehydratedPrice) : void 0
|
|
3601
3890
|
);
|
|
3602
|
-
const [priceVersion, setPriceVersion] =
|
|
3603
|
-
const refreshPrices =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
3692
|
-
import { createContext as createContext2, useCallback as
|
|
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
|
|
3697
|
-
import { useState as
|
|
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 =
|
|
3989
|
+
const t = useTranslations41();
|
|
3701
3990
|
const { archiveProduct, restoreProduct } = useProductContext();
|
|
3702
|
-
const [open, setOpen] =
|
|
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
|
|
3738
|
-
import { useCallback as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
4143
|
+
const t = useTranslations43();
|
|
3855
4144
|
const generateUrl = usePageUrlGenerator();
|
|
3856
4145
|
const { hasRole } = useCurrentUserContext();
|
|
3857
|
-
const [product, setProduct] =
|
|
4146
|
+
const [product, setProduct] = useState21(
|
|
3858
4147
|
dehydratedProduct ? rehydrate(Modules.StripeProduct, dehydratedProduct) : void 0
|
|
3859
4148
|
);
|
|
3860
|
-
const [catalogueVersion, setCatalogueVersion] =
|
|
3861
|
-
const refreshCatalogue =
|
|
3862
|
-
const reloadProduct =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
4076
|
-
import { Fragment as Fragment11, useCallback as
|
|
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 =
|
|
4478
|
+
const t = useTranslations45();
|
|
4190
4479
|
const { priceVersion } = usePriceContext();
|
|
4191
4480
|
const importInputRef = useRef4(null);
|
|
4192
|
-
const [seed, setSeed] =
|
|
4193
|
-
const [seedNonce, setSeedNonce] =
|
|
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
|
-
|
|
4488
|
+
useEffect12(() => {
|
|
4200
4489
|
if (priceVersion > 0) void data.refresh();
|
|
4201
4490
|
}, [priceVersion]);
|
|
4202
|
-
const openSeededEditor =
|
|
4491
|
+
const openSeededEditor = useCallback10((next) => {
|
|
4203
4492
|
setSeed(next);
|
|
4204
4493
|
setSeedNonce((nonce) => nonce + 1);
|
|
4205
4494
|
}, []);
|
|
4206
|
-
const onClone =
|
|
4495
|
+
const onClone = useCallback10(
|
|
4207
4496
|
(price) => openSeededEditor(priceToSeed(price)),
|
|
4208
4497
|
[openSeededEditor]
|
|
4209
4498
|
);
|
|
4210
|
-
const onExport =
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
4400
|
-
import { useEffect as
|
|
4401
|
-
import { jsx as
|
|
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 =
|
|
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
|
-
|
|
4747
|
+
useEffect14(() => {
|
|
4411
4748
|
if (catalogueVersion > 0) void data.refresh();
|
|
4412
4749
|
}, [catalogueVersion]);
|
|
4413
|
-
const functions = [/* @__PURE__ */
|
|
4414
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
4774
|
+
import { jsx as jsx53 } from "react/jsx-runtime";
|
|
4438
4775
|
function ProductsListContainer() {
|
|
4439
|
-
|
|
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
|
};
|