@carlonicora/nextjs-jsonapi 1.14.0 → 1.16.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/{ApiResponseInterface-B4QdWh-y.d.mts → ApiResponseInterface-BvWIeLkq.d.ts} +2 -1
- package/dist/{ApiResponseInterface-QLDnxLA9.d.ts → ApiResponseInterface-CAbw0sv7.d.mts} +2 -1
- package/dist/{BlockNoteEditor-436ZHDY3.mjs → BlockNoteEditor-HFX7Z5BQ.mjs} +5 -5
- package/dist/{BlockNoteEditor-WCK43JHX.js → BlockNoteEditor-MBFDWP7X.js} +15 -15
- package/dist/{BlockNoteEditor-WCK43JHX.js.map → BlockNoteEditor-MBFDWP7X.js.map} +1 -1
- package/dist/JsonApiRequest-45CLE65I.js +24 -0
- package/dist/{JsonApiRequest-FXZCYIER.js.map → JsonApiRequest-45CLE65I.js.map} +1 -1
- package/dist/{JsonApiRequest-HFWXMKMA.mjs → JsonApiRequest-6IPS3DZJ.mjs} +2 -2
- package/dist/{chunk-R6K76UTR.js → chunk-2AZLCF6D.js} +1687 -183
- package/dist/chunk-2AZLCF6D.js.map +1 -0
- package/dist/{chunk-2FCG3K64.mjs → chunk-5RAUCUAA.mjs} +3722 -396
- package/dist/chunk-5RAUCUAA.mjs.map +1 -0
- package/dist/{chunk-TGBXBUWM.mjs → chunk-BCKYJQ3K.mjs} +8 -1
- package/dist/chunk-BCKYJQ3K.mjs.map +1 -0
- package/dist/{chunk-A333VMBO.mjs → chunk-BCQSE3EU.mjs} +1654 -150
- package/dist/chunk-BCQSE3EU.mjs.map +1 -0
- package/dist/{chunk-FPZPD4JI.js → chunk-GPGJNTHP.js} +17 -10
- package/dist/chunk-GPGJNTHP.js.map +1 -0
- package/dist/{chunk-45QMJETP.js → chunk-ONB2DAIV.js} +4090 -764
- package/dist/chunk-ONB2DAIV.js.map +1 -0
- package/dist/{chunk-SJIVGCNM.mjs → chunk-POKIJ56Q.mjs} +7 -2
- package/dist/chunk-POKIJ56Q.mjs.map +1 -0
- package/dist/{chunk-6YD42BP6.js → chunk-R5QSSISB.js} +14 -9
- package/dist/chunk-R5QSSISB.js.map +1 -0
- package/dist/client/index.d.mts +5 -5
- package/dist/client/index.d.ts +5 -5
- package/dist/client/index.js +7 -5
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +6 -4
- package/dist/components/index.d.mts +253 -9
- package/dist/components/index.d.ts +253 -9
- package/dist/components/index.js +83 -5
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +82 -4
- package/dist/{config-eceYM5kN.d.ts → config-CWsTwnsK.d.mts} +7 -2
- package/dist/{config-C5tGGrYf.d.mts → config-DEaUbBqR.d.ts} +7 -2
- package/dist/{content.interface-TB2MfJGs.d.ts → content.interface-D_4b4RQt.d.ts} +1 -1
- package/dist/{content.interface-CxBBC7ec.d.mts → content.interface-Dk4UZcJM.d.mts} +1 -1
- package/dist/contexts/index.d.mts +2 -2
- package/dist/contexts/index.d.ts +2 -2
- package/dist/contexts/index.js +5 -5
- package/dist/contexts/index.mjs +4 -4
- package/dist/core/index.d.mts +528 -22
- package/dist/core/index.d.ts +528 -22
- package/dist/core/index.js +53 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +52 -2
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +56 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -3
- package/dist/{notification.interface-lG6UpTpt.d.mts → notification.interface-BllkURRm.d.mts} +1 -2
- package/dist/{notification.interface-lG6UpTpt.d.ts → notification.interface-BllkURRm.d.ts} +1 -2
- package/dist/{s3.service-DP_hsssD.d.mts → s3.service-BEfGqho0.d.ts} +20 -2
- package/dist/{s3.service-Dq-PTUNa.d.ts → s3.service-DIQRYe93.d.mts} +20 -2
- package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
- package/dist/scripts/generate-web-module/generator.js +66 -0
- package/dist/scripts/generate-web-module/generator.js.map +1 -1
- package/dist/scripts/generate-web-module/templates/data/interface.template.js +8 -1
- package/dist/scripts/generate-web-module/templates/data/interface.template.js.map +1 -1
- package/dist/scripts/generate-web-module/templates/data/model.template.js +26 -3
- package/dist/scripts/generate-web-module/templates/data/model.template.js.map +1 -1
- package/dist/scripts/generate-web-module/templates/index.d.ts +8 -0
- package/dist/scripts/generate-web-module/templates/index.d.ts.map +1 -1
- package/dist/scripts/generate-web-module/templates/index.js +18 -1
- package/dist/scripts/generate-web-module/templates/index.js.map +1 -1
- package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js +141 -0
- package/dist/scripts/generate-web-module/templates/project/bootstrapper.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/env.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/env.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/env.template.js +110 -0
- package/dist/scripts/generate-web-module/templates/project/env.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/main-layout.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/main-layout.template.js +101 -0
- package/dist/scripts/generate-web-module/templates/project/main-layout.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/middleware-env.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js +66 -0
- package/dist/scripts/generate-web-module/templates/project/middleware-env.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/settings-container.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-container.template.js +257 -0
- package/dist/scripts/generate-web-module/templates/project/settings-container.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/settings-context.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-context.template.js +124 -0
- package/dist/scripts/generate-web-module/templates/project/settings-context.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js +78 -0
- package/dist/scripts/generate-web-module/templates/project/settings-module-page.template.js.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts +7 -0
- package/dist/scripts/generate-web-module/templates/project/settings-page.template.d.ts.map +1 -0
- package/dist/scripts/generate-web-module/templates/project/settings-page.template.js +75 -0
- package/dist/scripts/generate-web-module/templates/project/settings-page.template.js.map +1 -0
- package/dist/scripts/generate-web-module/types/template-data.interface.d.ts +1 -1
- package/dist/scripts/generate-web-module/types/template-data.interface.d.ts.map +1 -1
- package/dist/server/index.d.mts +4 -4
- package/dist/server/index.d.ts +4 -4
- package/dist/server/index.js +12 -12
- package/dist/server/index.mjs +2 -2
- package/dist/stripe-subscription.interface-C63L6hVg.d.mts +226 -0
- package/dist/stripe-subscription.interface-CUvNDvw5.d.ts +226 -0
- package/dist/{useSocket-Bua6MwLi.d.mts → useSocket-BpenBR2z.d.mts} +1 -1
- package/dist/{useSocket-D5dhUp4m.d.ts → useSocket-D-QYA0Sr.d.ts} +1 -1
- package/package.json +9 -1
- package/scripts/generate-web-module/generator.ts +83 -0
- package/scripts/generate-web-module/templates/data/interface.template.ts +7 -1
- package/scripts/generate-web-module/templates/data/model.template.ts +28 -5
- package/scripts/generate-web-module/templates/index.ts +10 -0
- package/scripts/generate-web-module/templates/project/bootstrapper.template.ts +108 -0
- package/scripts/generate-web-module/templates/project/env.template.ts +77 -0
- package/scripts/generate-web-module/templates/project/main-layout.template.tsx +68 -0
- package/scripts/generate-web-module/templates/project/middleware-env.template.ts +33 -0
- package/scripts/generate-web-module/templates/project/settings-container.template.tsx +224 -0
- package/scripts/generate-web-module/templates/project/settings-context.template.tsx +91 -0
- package/scripts/generate-web-module/templates/project/settings-module-page.template.tsx +45 -0
- package/scripts/generate-web-module/templates/project/settings-page.template.tsx +42 -0
- package/scripts/generate-web-module/types/template-data.interface.ts +1 -1
- package/src/client/config.ts +9 -0
- package/src/components/index.ts +7 -0
- package/src/core/abstracts/AbstractApiData.ts +79 -16
- package/src/core/abstracts/AbstractService.ts +104 -0
- package/src/core/endpoint/EndpointCreator.ts +7 -4
- package/src/core/index.ts +12 -4
- package/src/core/interfaces/ApiResponseInterface.ts +1 -0
- package/src/core/registry/ModuleRegistry.ts +11 -2
- package/src/core/utils/translateResponse.ts +17 -0
- package/src/features/billing/components/cards/BillingUsageSummaryCard.tsx +97 -0
- package/src/features/billing/components/cards/CustomerInfoCard.tsx +112 -0
- package/src/features/billing/components/cards/InvoicesSummaryCard.tsx +114 -0
- package/src/features/billing/components/cards/PaymentMethodSummaryCard.tsx +119 -0
- package/src/features/billing/components/cards/SubscriptionSummaryCard.tsx +146 -0
- package/src/features/billing/components/cards/index.ts +5 -0
- package/src/features/billing/components/containers/BillingDashboardContainer.tsx +427 -0
- package/src/features/billing/components/containers/index.ts +1 -0
- package/src/features/billing/components/index.ts +6 -0
- package/src/features/billing/components/modals/BillingDetailModal.tsx +36 -0
- package/src/features/billing/components/modals/index.ts +1 -0
- package/src/features/billing/components/providers/StripeProvider.tsx +48 -0
- package/src/features/billing/components/providers/index.ts +1 -0
- package/src/features/billing/components/utils/currency.ts +49 -0
- package/src/features/billing/components/utils/date.ts +21 -0
- package/src/features/billing/components/utils/index.ts +2 -0
- package/src/features/billing/components/widgets/BillingAlertBanner.tsx +63 -0
- package/src/features/billing/components/widgets/index.ts +1 -0
- package/src/features/billing/data/Billing.ts +17 -0
- package/src/features/billing/data/billing.service.ts +58 -0
- package/src/features/billing/data/index.ts +5 -0
- package/src/features/billing/index.ts +3 -0
- package/src/features/billing/modules/billing.module.ts +9 -0
- package/src/features/billing/modules/index.ts +1 -0
- package/src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx +79 -0
- package/src/features/billing/stripe-customer/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx +151 -0
- package/src/features/billing/stripe-customer/components/details/index.ts +1 -0
- package/src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx +186 -0
- package/src/features/billing/stripe-customer/components/forms/index.ts +1 -0
- package/src/features/billing/stripe-customer/components/index.ts +4 -0
- package/src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx +19 -0
- package/src/features/billing/stripe-customer/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-customer/data/index.ts +5 -0
- package/src/features/billing/stripe-customer/data/payment-method.interface.ts +27 -0
- package/src/features/billing/stripe-customer/data/payment-method.ts +119 -0
- package/src/features/billing/stripe-customer/data/stripe-customer.interface.ts +16 -0
- package/src/features/billing/stripe-customer/data/stripe-customer.service.ts +128 -0
- package/src/features/billing/stripe-customer/data/stripe-customer.ts +71 -0
- package/src/features/billing/stripe-customer/index.ts +3 -0
- package/src/features/billing/stripe-customer/stripe-customer.module.ts +9 -0
- package/src/features/billing/stripe-customer/stripe-payment-method.module.ts +9 -0
- package/src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx +66 -0
- package/src/features/billing/stripe-invoice/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx +172 -0
- package/src/features/billing/stripe-invoice/components/details/index.ts +1 -0
- package/src/features/billing/stripe-invoice/components/index.ts +4 -0
- package/src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx +84 -0
- package/src/features/billing/stripe-invoice/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx +41 -0
- package/src/features/billing/stripe-invoice/components/widgets/index.ts +1 -0
- package/src/features/billing/stripe-invoice/data/index.ts +3 -0
- package/src/features/billing/stripe-invoice/data/stripe-invoice.interface.ts +65 -0
- package/src/features/billing/stripe-invoice/data/stripe-invoice.service.ts +64 -0
- package/src/features/billing/stripe-invoice/data/stripe-invoice.ts +177 -0
- package/src/features/billing/stripe-invoice/index.ts +2 -0
- package/src/features/billing/stripe-invoice/stripe-invoice.module.ts +9 -0
- package/src/features/billing/stripe-price/components/forms/PriceEditor.tsx +304 -0
- package/src/features/billing/stripe-price/components/forms/index.ts +1 -0
- package/src/features/billing/stripe-price/components/index.ts +2 -0
- package/src/features/billing/stripe-price/components/lists/PricesList.tsx +283 -0
- package/src/features/billing/stripe-price/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-price/data/index.ts +3 -0
- package/src/features/billing/stripe-price/data/stripe-price.interface.ts +48 -0
- package/src/features/billing/stripe-price/data/stripe-price.service.ts +123 -0
- package/src/features/billing/stripe-price/data/stripe-price.ts +156 -0
- package/src/features/billing/stripe-price/index.ts +2 -0
- package/src/features/billing/stripe-price/stripe-price.module.ts +9 -0
- package/src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx +86 -0
- package/src/features/billing/stripe-product/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-product/components/forms/ProductEditor.tsx +100 -0
- package/src/features/billing/stripe-product/components/forms/index.ts +1 -0
- package/src/features/billing/stripe-product/components/index.ts +3 -0
- package/src/features/billing/stripe-product/components/lists/ProductsList.tsx +206 -0
- package/src/features/billing/stripe-product/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-product/data/index.ts +3 -0
- package/src/features/billing/stripe-product/data/stripe-product.interface.ts +18 -0
- package/src/features/billing/stripe-product/data/stripe-product.service.ts +112 -0
- package/src/features/billing/stripe-product/data/stripe-product.ts +74 -0
- package/src/features/billing/stripe-product/index.ts +2 -0
- package/src/features/billing/stripe-product/stripe-product.module.ts +9 -0
- package/src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx +304 -0
- package/src/features/billing/stripe-subscription/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx +223 -0
- package/src/features/billing/stripe-subscription/components/details/index.ts +1 -0
- package/src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx +116 -0
- package/src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx +331 -0
- package/src/features/billing/stripe-subscription/components/forms/index.ts +2 -0
- package/src/features/billing/stripe-subscription/components/index.ts +5 -0
- package/src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx +104 -0
- package/src/features/billing/stripe-subscription/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx +95 -0
- package/src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx +110 -0
- package/src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx +41 -0
- package/src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx +60 -0
- package/src/features/billing/stripe-subscription/components/widgets/index.ts +4 -0
- package/src/features/billing/stripe-subscription/data/index.ts +3 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.interface.ts +66 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.service.ts +193 -0
- package/src/features/billing/stripe-subscription/data/stripe-subscription.ts +135 -0
- package/src/features/billing/stripe-subscription/hooks/index.ts +1 -0
- package/src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts +111 -0
- package/src/features/billing/stripe-subscription/index.ts +5 -0
- package/src/features/billing/stripe-subscription/stripe-subscription.module.ts +9 -0
- package/src/features/billing/stripe-usage/components/containers/UsageContainer.tsx +109 -0
- package/src/features/billing/stripe-usage/components/containers/index.ts +1 -0
- package/src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx +90 -0
- package/src/features/billing/stripe-usage/components/details/index.ts +1 -0
- package/src/features/billing/stripe-usage/components/index.ts +4 -0
- package/src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx +72 -0
- package/src/features/billing/stripe-usage/components/lists/index.ts +1 -0
- package/src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx +19 -0
- package/src/features/billing/stripe-usage/components/widgets/index.ts +1 -0
- package/src/features/billing/stripe-usage/data/index.ts +3 -0
- package/src/features/billing/stripe-usage/data/stripe-usage.interface.ts +55 -0
- package/src/features/billing/stripe-usage/data/stripe-usage.service.ts +129 -0
- package/src/features/billing/stripe-usage/data/stripe-usage.ts +70 -0
- package/src/features/billing/stripe-usage/index.ts +2 -0
- package/src/features/billing/stripe-usage/stripe-usage.module.ts +9 -0
- package/src/features/company/components/forms/CompanyEditor.tsx +2 -2
- package/src/features/company/components/forms/CompanyLicense.tsx +4 -4
- package/src/features/company/contexts/CompanyContext.tsx +2 -2
- package/src/features/feature/components/forms/FormFeatures.tsx +13 -106
- package/src/features/feature/data/feature.interface.ts +1 -1
- package/src/features/feature/data/feature.ts +4 -4
- package/src/features/index.ts +7 -0
- package/src/features/module/data/module.interface.ts +0 -1
- package/src/features/module/data/module.ts +0 -6
- package/src/features/user/components/lists/ContributorsList.tsx +2 -2
- package/src/features/user/components/widgets/UserAvatar.tsx +1 -1
- package/src/index.ts +1 -1
- package/src/shadcnui/custom/link.tsx +16 -6
- package/src/utils/blocknote-diff.util.ts +2 -1
- package/src/utils/blocknote-word-diff-renderer.util.ts +8 -7
- package/dist/AuthComponent-hxOPs9o8.d.mts +0 -11
- package/dist/AuthComponent-hxOPs9o8.d.ts +0 -11
- package/dist/JsonApiRequest-FXZCYIER.js +0 -24
- package/dist/chunk-2FCG3K64.mjs.map +0 -1
- package/dist/chunk-45QMJETP.js.map +0 -1
- package/dist/chunk-6YD42BP6.js.map +0 -1
- package/dist/chunk-A333VMBO.mjs.map +0 -1
- package/dist/chunk-FPZPD4JI.js.map +0 -1
- package/dist/chunk-R6K76UTR.js.map +0 -1
- package/dist/chunk-SJIVGCNM.mjs.map +0 -1
- package/dist/chunk-TGBXBUWM.mjs.map +0 -1
- /package/dist/{BlockNoteEditor-436ZHDY3.mjs.map → BlockNoteEditor-HFX7Z5BQ.mjs.map} +0 -0
- /package/dist/{JsonApiRequest-HFWXMKMA.mjs.map → JsonApiRequest-6IPS3DZJ.mjs.map} +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getApiUrl,
|
|
3
3
|
getAppUrl,
|
|
4
|
+
getI18nLink,
|
|
4
5
|
getRoleId,
|
|
6
|
+
getStripePublishableKey,
|
|
5
7
|
getTrackablePages,
|
|
6
8
|
isDiscordConfigured,
|
|
7
9
|
isInternalAuthConfigured,
|
|
@@ -9,7 +11,7 @@ import {
|
|
|
9
11
|
useI18nLocale,
|
|
10
12
|
useI18nRouter,
|
|
11
13
|
useI18nTranslations
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-POKIJ56Q.mjs";
|
|
13
15
|
import {
|
|
14
16
|
AuthService,
|
|
15
17
|
ClientAbstractService,
|
|
@@ -22,6 +24,12 @@ import {
|
|
|
22
24
|
RehydrationFactory,
|
|
23
25
|
RoleService,
|
|
24
26
|
S3Service,
|
|
27
|
+
StripeCustomerService,
|
|
28
|
+
StripeInvoiceService,
|
|
29
|
+
StripePriceService,
|
|
30
|
+
StripeProductService,
|
|
31
|
+
StripeSubscriptionService,
|
|
32
|
+
StripeUsageService,
|
|
25
33
|
UserService,
|
|
26
34
|
checkPermissions,
|
|
27
35
|
cn,
|
|
@@ -30,7 +38,7 @@ import {
|
|
|
30
38
|
rehydrate,
|
|
31
39
|
useComposedRefs,
|
|
32
40
|
useIsMobile
|
|
33
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-BCQSE3EU.mjs";
|
|
34
42
|
import {
|
|
35
43
|
__name
|
|
36
44
|
} from "./chunk-PAWJFY3S.mjs";
|
|
@@ -4792,11 +4800,11 @@ function KanbanOverlay(props) {
|
|
|
4792
4800
|
__name(KanbanOverlay, "KanbanOverlay");
|
|
4793
4801
|
|
|
4794
4802
|
// src/shadcnui/custom/link.tsx
|
|
4795
|
-
import NextLink from "next/link";
|
|
4796
4803
|
import * as React33 from "react";
|
|
4797
4804
|
import { jsx as jsx46 } from "react/jsx-runtime";
|
|
4798
|
-
var Link2 = React33.forwardRef(({ className, ...props }, ref) => {
|
|
4799
|
-
|
|
4805
|
+
var Link2 = React33.forwardRef(({ className, href, children, ...props }, ref) => {
|
|
4806
|
+
const NextIntlLink = getI18nLink();
|
|
4807
|
+
return /* @__PURE__ */ jsx46(NextIntlLink, { prefetch: false, ref, href, className: cn(`font-medium`, className), ...props, children });
|
|
4800
4808
|
});
|
|
4801
4809
|
Link2.displayName = "Link";
|
|
4802
4810
|
|
|
@@ -5175,7 +5183,7 @@ function UserEditorInternal({ user, propagateChanges, adminCreated, trigger, onR
|
|
|
5175
5183
|
useEffect9(() => {
|
|
5176
5184
|
if (!companyFromContext && userCompany) setCompany(userCompany);
|
|
5177
5185
|
}, [company]);
|
|
5178
|
-
const
|
|
5186
|
+
const formSchema2 = z.object({
|
|
5179
5187
|
id: z.uuidv4(),
|
|
5180
5188
|
name: z.string().min(1, { message: t(`foundations.user.fields.name.error`) }),
|
|
5181
5189
|
email: z.string().min(1, { message: t(`generic.fields.email.error`) }),
|
|
@@ -5188,7 +5196,7 @@ function UserEditorInternal({ user, propagateChanges, adminCreated, trigger, onR
|
|
|
5188
5196
|
avatar: z.string().optional()
|
|
5189
5197
|
});
|
|
5190
5198
|
const form = useForm({
|
|
5191
|
-
resolver: zodResolver(
|
|
5199
|
+
resolver: zodResolver(formSchema2),
|
|
5192
5200
|
defaultValues: {
|
|
5193
5201
|
id: user?.id || v4(),
|
|
5194
5202
|
name: user?.name || "",
|
|
@@ -6331,12 +6339,12 @@ function CompanyConfigurationEditorInternal({ company }) {
|
|
|
6331
6339
|
setOpen(false);
|
|
6332
6340
|
form.reset();
|
|
6333
6341
|
}, "close");
|
|
6334
|
-
const
|
|
6342
|
+
const formSchema2 = z2.object({
|
|
6335
6343
|
isManagedKnowledge: z2.boolean().optional(),
|
|
6336
6344
|
allowPublicBot: z2.boolean().optional()
|
|
6337
6345
|
});
|
|
6338
6346
|
const form = useForm2({
|
|
6339
|
-
resolver: zodResolver2(
|
|
6347
|
+
resolver: zodResolver2(formSchema2),
|
|
6340
6348
|
defaultValues,
|
|
6341
6349
|
shouldUnregister: false
|
|
6342
6350
|
});
|
|
@@ -6510,7 +6518,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
|
|
|
6510
6518
|
const [contentType, setContentType] = useState16(null);
|
|
6511
6519
|
const t = useTranslations22();
|
|
6512
6520
|
const generateUrl = usePageUrlGenerator();
|
|
6513
|
-
const
|
|
6521
|
+
const formSchema2 = z3.object({
|
|
6514
6522
|
id: z3.uuidv4(),
|
|
6515
6523
|
name: z3.string().min(1, {
|
|
6516
6524
|
message: t(`foundations.company.fields.name.error`)
|
|
@@ -6520,7 +6528,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
|
|
|
6520
6528
|
logo: z3.string().optional()
|
|
6521
6529
|
});
|
|
6522
6530
|
const form = useForm3({
|
|
6523
|
-
resolver: zodResolver3(
|
|
6531
|
+
resolver: zodResolver3(formSchema2),
|
|
6524
6532
|
defaultValues: {
|
|
6525
6533
|
id: company?.id || v42(),
|
|
6526
6534
|
name: company?.name || "",
|
|
@@ -6574,7 +6582,7 @@ function CompanyEditorInternal({ company, propagateChanges, onRevalidate }) {
|
|
|
6574
6582
|
if (hasRole(getRoleId().Administrator)) {
|
|
6575
6583
|
setFeatures(allfeatures);
|
|
6576
6584
|
} else {
|
|
6577
|
-
setFeatures(allfeatures.filter((feature) => feature.
|
|
6585
|
+
setFeatures(allfeatures.filter((feature) => feature.isCore));
|
|
6578
6586
|
}
|
|
6579
6587
|
}
|
|
6580
6588
|
__name(fetchFeatures, "fetchFeatures");
|
|
@@ -6735,7 +6743,6 @@ var CompanyProvider = /* @__PURE__ */ __name(({ children, dehydratedCompany }) =
|
|
|
6735
6743
|
if (company && hasRole(getRoleId().Administrator) && hasPermissionToModule({ module: Modules.Company, action: "delete" /* Delete */ }))
|
|
6736
6744
|
functions.push(/* @__PURE__ */ jsx79(CompanyDeleter, { company }, "companyDeleter"));
|
|
6737
6745
|
if (hasRole(getRoleId().Administrator) || hasPermissionToModule({ module: Modules.Company, action: "update" /* Update */ })) {
|
|
6738
|
-
if (company) functions.push(/* @__PURE__ */ jsx79(CompanyConfigurationEditor, { company }, "companyConfigurationEditor"));
|
|
6739
6746
|
functions.push(/* @__PURE__ */ jsx79(CompanyEditor, { company, propagateChanges: setCompany }, "companyEditor"));
|
|
6740
6747
|
}
|
|
6741
6748
|
if (functions.length > 0) response.functions = functions;
|
|
@@ -7664,7 +7671,7 @@ __name(AllowedUsersDetails, "AllowedUsersDetails");
|
|
|
7664
7671
|
import dynamic from "next/dynamic";
|
|
7665
7672
|
import React38 from "react";
|
|
7666
7673
|
import { jsx as jsx97 } from "react/jsx-runtime";
|
|
7667
|
-
var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-
|
|
7674
|
+
var BlockNoteEditor = dynamic(() => import("./BlockNoteEditor-HFX7Z5BQ.mjs"), {
|
|
7668
7675
|
ssr: false
|
|
7669
7676
|
});
|
|
7670
7677
|
var BlockNoteEditorContainer = React38.memo(/* @__PURE__ */ __name(function EditorContainer(props) {
|
|
@@ -7951,7 +7958,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
|
|
|
7951
7958
|
() => new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }),
|
|
7952
7959
|
[locale]
|
|
7953
7960
|
);
|
|
7954
|
-
const
|
|
7961
|
+
const formatDate5 = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
|
|
7955
7962
|
const datePlaceholder = useMemo7(() => {
|
|
7956
7963
|
const parts = dateFormatter.formatToParts(new Date(2e3, 0, 1));
|
|
7957
7964
|
return parts.map((part) => {
|
|
@@ -7970,7 +7977,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
|
|
|
7970
7977
|
return part.value;
|
|
7971
7978
|
}).join("");
|
|
7972
7979
|
}, [dateFormatter]);
|
|
7973
|
-
const [inputValue, setInputValue] = useState28(() => value ?
|
|
7980
|
+
const [inputValue, setInputValue] = useState28(() => value ? formatDate5(value) : "");
|
|
7974
7981
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
7975
7982
|
const yearOptions = Array.from({ length: currentYear - 1900 + 11 }, (_, i) => 1900 + i);
|
|
7976
7983
|
const monthNames = useMemo7(() => {
|
|
@@ -7993,7 +8000,7 @@ var DatePickerPopover = /* @__PURE__ */ __name(({
|
|
|
7993
8000
|
const handleCalendarSelect = /* @__PURE__ */ __name((selectedDate) => {
|
|
7994
8001
|
onSelect(selectedDate);
|
|
7995
8002
|
if (selectedDate) {
|
|
7996
|
-
setInputValue(
|
|
8003
|
+
setInputValue(formatDate5(selectedDate));
|
|
7997
8004
|
setDisplayMonth(selectedDate);
|
|
7998
8005
|
} else {
|
|
7999
8006
|
setInputValue("");
|
|
@@ -8528,7 +8535,7 @@ function FormDate({
|
|
|
8528
8535
|
() => new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }),
|
|
8529
8536
|
[locale]
|
|
8530
8537
|
);
|
|
8531
|
-
const
|
|
8538
|
+
const formatDate5 = /* @__PURE__ */ __name((date) => dateFormatter.format(date), "formatDate");
|
|
8532
8539
|
const datePlaceholder = useMemo8(() => {
|
|
8533
8540
|
const parts = dateFormatter.formatToParts(new Date(2e3, 0, 1));
|
|
8534
8541
|
return parts.map((part) => {
|
|
@@ -8549,7 +8556,7 @@ function FormDate({
|
|
|
8549
8556
|
}, [dateFormatter]);
|
|
8550
8557
|
const [inputValue, setInputValue] = useState31(() => {
|
|
8551
8558
|
const currentValue = form.getValues(id);
|
|
8552
|
-
return currentValue ?
|
|
8559
|
+
return currentValue ? formatDate5(currentValue) : "";
|
|
8553
8560
|
});
|
|
8554
8561
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
8555
8562
|
const yearOptions = Array.from({ length: currentYear - 1900 + 1 }, (_, i) => 1900 + i);
|
|
@@ -8575,7 +8582,7 @@ function FormDate({
|
|
|
8575
8582
|
const handleCalendarSelect = /* @__PURE__ */ __name((selectedDate, field) => {
|
|
8576
8583
|
field.onChange(selectedDate);
|
|
8577
8584
|
if (selectedDate) {
|
|
8578
|
-
setInputValue(
|
|
8585
|
+
setInputValue(formatDate5(selectedDate));
|
|
8579
8586
|
setDisplayMonth(selectedDate);
|
|
8580
8587
|
} else {
|
|
8581
8588
|
setInputValue("");
|
|
@@ -8712,7 +8719,7 @@ function FormDateTime({
|
|
|
8712
8719
|
}),
|
|
8713
8720
|
[locale]
|
|
8714
8721
|
);
|
|
8715
|
-
const
|
|
8722
|
+
const formatDateTime2 = /* @__PURE__ */ __name((date) => dateTimeFormatter.format(date), "formatDateTime");
|
|
8716
8723
|
const [selectedHours, setSelectedHours] = useState32((/* @__PURE__ */ new Date()).getHours());
|
|
8717
8724
|
const [selectedMinutes, setSelectedMinutes] = useState32(roundToNearestFiveMinutes((/* @__PURE__ */ new Date()).getMinutes()));
|
|
8718
8725
|
const hoursOptions = Array.from({ length: 24 }, (_, i) => {
|
|
@@ -8758,7 +8765,7 @@ function FormDateTime({
|
|
|
8758
8765
|
variant: "outline",
|
|
8759
8766
|
className: cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground"),
|
|
8760
8767
|
children: [
|
|
8761
|
-
field.value ?
|
|
8768
|
+
field.value ? formatDateTime2(field.value) : /* @__PURE__ */ jsx110("span", { children: t(`generic.pick_date_time`) }),
|
|
8762
8769
|
/* @__PURE__ */ jsx110(CalendarIcon4, { className: "ml-auto h-4 w-4 opacity-50" })
|
|
8763
8770
|
]
|
|
8764
8771
|
}
|
|
@@ -9371,118 +9378,35 @@ var dropzone = {
|
|
|
9371
9378
|
|
|
9372
9379
|
// src/features/feature/components/forms/FormFeatures.tsx
|
|
9373
9380
|
import { jsx as jsx120, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
9374
|
-
function FormFeatures({
|
|
9375
|
-
form,
|
|
9376
|
-
name,
|
|
9377
|
-
features,
|
|
9378
|
-
featureField = "featureIds",
|
|
9379
|
-
moduleField = "moduleIds"
|
|
9380
|
-
}) {
|
|
9381
|
+
function FormFeatures({ form, name, features, featureField = "featureIds" }) {
|
|
9381
9382
|
const selectedFeatures = form.watch(featureField);
|
|
9382
|
-
const selectedModules = form.watch(moduleField);
|
|
9383
9383
|
const toggleFeature = /* @__PURE__ */ __name((feature, checked) => {
|
|
9384
9384
|
let newFeatureIds = [...selectedFeatures];
|
|
9385
|
-
let newModuleIds = [...selectedModules];
|
|
9386
9385
|
if (checked) {
|
|
9387
9386
|
if (!newFeatureIds.includes(feature.id)) {
|
|
9388
9387
|
newFeatureIds.push(feature.id);
|
|
9389
9388
|
}
|
|
9390
|
-
feature.modules.forEach((module) => {
|
|
9391
|
-
if (!newModuleIds.includes(module.id)) {
|
|
9392
|
-
newModuleIds.push(module.id);
|
|
9393
|
-
}
|
|
9394
|
-
});
|
|
9395
9389
|
} else {
|
|
9396
9390
|
newFeatureIds = newFeatureIds.filter((id) => id !== feature.id);
|
|
9397
|
-
feature.modules.forEach((module) => {
|
|
9398
|
-
newModuleIds = newModuleIds.filter((id) => id !== module.id);
|
|
9399
|
-
});
|
|
9400
9391
|
}
|
|
9401
9392
|
form.setValue(featureField, newFeatureIds);
|
|
9402
|
-
form.setValue(moduleField, newModuleIds);
|
|
9403
9393
|
}, "toggleFeature");
|
|
9404
|
-
const
|
|
9405
|
-
const modulesForFeature = feature.modules.map((m) => m.id);
|
|
9406
|
-
let newModuleIds = [...selectedModules];
|
|
9407
|
-
if (checked) {
|
|
9408
|
-
if (!selectedFeatures.includes(feature.id)) {
|
|
9409
|
-
newModuleIds = newModuleIds.filter((id) => !modulesForFeature.includes(id));
|
|
9410
|
-
newModuleIds.push(module.id);
|
|
9411
|
-
form.setValue(featureField, [...selectedFeatures, feature.id]);
|
|
9412
|
-
} else {
|
|
9413
|
-
if (!newModuleIds.includes(module.id)) {
|
|
9414
|
-
newModuleIds.push(module.id);
|
|
9415
|
-
}
|
|
9416
|
-
}
|
|
9417
|
-
} else {
|
|
9418
|
-
newModuleIds = newModuleIds.filter((id) => id !== module.id);
|
|
9419
|
-
const remaining = feature.modules.filter((m) => newModuleIds.includes(m.id));
|
|
9420
|
-
if (remaining.length === 0) {
|
|
9421
|
-
form.setValue(
|
|
9422
|
-
featureField,
|
|
9423
|
-
selectedFeatures.filter((id) => id !== feature.id)
|
|
9424
|
-
);
|
|
9425
|
-
}
|
|
9426
|
-
}
|
|
9427
|
-
form.setValue(moduleField, newModuleIds);
|
|
9428
|
-
}, "toggleModule");
|
|
9429
|
-
const isFeatureChecked = /* @__PURE__ */ __name((feature) => selectedFeatures.includes(feature.id) || feature.modules.every((module) => selectedModules.includes(module.id)), "isFeatureChecked");
|
|
9394
|
+
const isFeatureChecked = /* @__PURE__ */ __name((feature) => selectedFeatures.includes(feature.id), "isFeatureChecked");
|
|
9430
9395
|
return /* @__PURE__ */ jsxs72("div", { className: "flex w-full flex-col", children: [
|
|
9431
|
-
name && /* @__PURE__ */ jsx120("h2", { className: "mb-
|
|
9432
|
-
features.map((feature) => /* @__PURE__ */
|
|
9433
|
-
|
|
9434
|
-
|
|
9435
|
-
|
|
9436
|
-
|
|
9437
|
-
|
|
9438
|
-
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
/* @__PURE__ */ jsx120(
|
|
9446
|
-
Checkbox,
|
|
9447
|
-
{
|
|
9448
|
-
id: feature.id,
|
|
9449
|
-
checked: isFeatureChecked(feature),
|
|
9450
|
-
onCheckedChange: (val) => {
|
|
9451
|
-
toggleFeature(feature, val === true);
|
|
9452
|
-
}
|
|
9453
|
-
}
|
|
9454
|
-
),
|
|
9455
|
-
/* @__PURE__ */ jsx120(FormLabel, { htmlFor: feature.id, className: "ml-3 cursor-pointer font-normal", children: feature.name })
|
|
9456
|
-
] }),
|
|
9457
|
-
feature.modules.filter((module) => !module.isCore).length > 0 && /* @__PURE__ */ jsx120(AccordionTrigger, { asChild: true, children: /* @__PURE__ */ jsx120("div", { className: "w-full" }) })
|
|
9458
|
-
]
|
|
9459
|
-
}
|
|
9460
|
-
),
|
|
9461
|
-
feature.modules.filter((module) => !module.isCore).length > 0 && /* @__PURE__ */ jsx120(AccordionContent, { className: "pl-6", children: feature.modules.filter((module) => !module.isCore).sort((a, b) => a.name.localeCompare(b.name)).map((module) => /* @__PURE__ */ jsxs72(
|
|
9462
|
-
"div",
|
|
9463
|
-
{
|
|
9464
|
-
className: "flex items-center border-t py-2",
|
|
9465
|
-
onClick: (e) => e.stopPropagation(),
|
|
9466
|
-
children: [
|
|
9467
|
-
/* @__PURE__ */ jsx120(
|
|
9468
|
-
Checkbox,
|
|
9469
|
-
{
|
|
9470
|
-
id: module.id,
|
|
9471
|
-
checked: selectedModules.includes(module.id),
|
|
9472
|
-
onCheckedChange: (val) => {
|
|
9473
|
-
toggleModule(feature, module, val === true);
|
|
9474
|
-
}
|
|
9475
|
-
}
|
|
9476
|
-
),
|
|
9477
|
-
/* @__PURE__ */ jsx120(FormLabel, { htmlFor: module.id, className: "ml-3 cursor-pointer font-normal", children: module.name })
|
|
9478
|
-
]
|
|
9479
|
-
},
|
|
9480
|
-
module.id
|
|
9481
|
-
)) })
|
|
9482
|
-
] })
|
|
9483
|
-
},
|
|
9484
|
-
feature.id
|
|
9485
|
-
)),
|
|
9396
|
+
name && /* @__PURE__ */ jsx120("h2", { className: "mb-4 border-b text-lg font-semibold", children: name }),
|
|
9397
|
+
/* @__PURE__ */ jsx120(ScrollArea, { className: "h-[40vh]", children: /* @__PURE__ */ jsx120("div", { className: "flex flex-col gap-y-2 pr-4", children: features.filter((feature) => !feature.isCore).map((feature) => /* @__PURE__ */ jsxs72("div", { className: "flex items-center", children: [
|
|
9398
|
+
/* @__PURE__ */ jsx120(
|
|
9399
|
+
Checkbox,
|
|
9400
|
+
{
|
|
9401
|
+
id: feature.id,
|
|
9402
|
+
checked: isFeatureChecked(feature),
|
|
9403
|
+
onCheckedChange: (val) => {
|
|
9404
|
+
toggleFeature(feature, val === true);
|
|
9405
|
+
}
|
|
9406
|
+
}
|
|
9407
|
+
),
|
|
9408
|
+
/* @__PURE__ */ jsx120(FormLabel, { htmlFor: feature.id, className: "ml-3 cursor-pointer font-normal", children: feature.name })
|
|
9409
|
+
] }, feature.id)) }) }),
|
|
9486
9410
|
/* @__PURE__ */ jsx120(FormMessage, {})
|
|
9487
9411
|
] });
|
|
9488
9412
|
}
|
|
@@ -9688,7 +9612,7 @@ function useJsonApiGet(params) {
|
|
|
9688
9612
|
setLoading(true);
|
|
9689
9613
|
setError(null);
|
|
9690
9614
|
try {
|
|
9691
|
-
const { JsonApiGet } = await import("./JsonApiRequest-
|
|
9615
|
+
const { JsonApiGet } = await import("./JsonApiRequest-6IPS3DZJ.mjs");
|
|
9692
9616
|
const language = navigator.language.split("-")[0] || "en";
|
|
9693
9617
|
const apiResponse = await JsonApiGet({
|
|
9694
9618
|
classKey: params.classKey,
|
|
@@ -9793,7 +9717,7 @@ function useJsonApiMutation(config) {
|
|
|
9793
9717
|
setLoading(true);
|
|
9794
9718
|
setError(null);
|
|
9795
9719
|
try {
|
|
9796
|
-
const { JsonApiPost, JsonApiPut, JsonApiPatch, JsonApiDelete } = await import("./JsonApiRequest-
|
|
9720
|
+
const { JsonApiPost, JsonApiPut, JsonApiPatch, JsonApiDelete } = await import("./JsonApiRequest-6IPS3DZJ.mjs");
|
|
9797
9721
|
const language = navigator.language.split("-")[0] || "en";
|
|
9798
9722
|
let apiResponse;
|
|
9799
9723
|
switch (config.method) {
|
|
@@ -10455,7 +10379,7 @@ function Register() {
|
|
|
10455
10379
|
const t = useTranslations46();
|
|
10456
10380
|
const { setComponentType } = useAuthContext();
|
|
10457
10381
|
const [showConfirmation, setShowConfirmation] = useState42(false);
|
|
10458
|
-
const
|
|
10382
|
+
const formSchema2 = z5.object({
|
|
10459
10383
|
company: z5.string().min(1, {
|
|
10460
10384
|
message: t(`generic.errors.missing_company_name`)
|
|
10461
10385
|
}),
|
|
@@ -10470,7 +10394,7 @@ function Register() {
|
|
|
10470
10394
|
})
|
|
10471
10395
|
});
|
|
10472
10396
|
const form = useForm5({
|
|
10473
|
-
resolver: zodResolver5(
|
|
10397
|
+
resolver: zodResolver5(formSchema2),
|
|
10474
10398
|
defaultValues: {
|
|
10475
10399
|
company: "",
|
|
10476
10400
|
name: "",
|
|
@@ -10701,7 +10625,7 @@ function AcceptInvitation() {
|
|
|
10701
10625
|
setError(t(`foundations.auth.errors.invalid_invitation_code`));
|
|
10702
10626
|
}
|
|
10703
10627
|
}, []);
|
|
10704
|
-
const
|
|
10628
|
+
const formSchema2 = z6.object({
|
|
10705
10629
|
password: z6.string().min(1, {
|
|
10706
10630
|
message: t(`foundations.user.fields.password.error`)
|
|
10707
10631
|
}),
|
|
@@ -10713,7 +10637,7 @@ function AcceptInvitation() {
|
|
|
10713
10637
|
path: ["passwordRetype"]
|
|
10714
10638
|
});
|
|
10715
10639
|
const form = useForm6({
|
|
10716
|
-
resolver: zodResolver6(
|
|
10640
|
+
resolver: zodResolver6(formSchema2),
|
|
10717
10641
|
defaultValues: {
|
|
10718
10642
|
password: "",
|
|
10719
10643
|
passwordRetype: ""
|
|
@@ -10860,13 +10784,13 @@ function ForgotPassword() {
|
|
|
10860
10784
|
const t = useTranslations50();
|
|
10861
10785
|
const { setComponentType } = useAuthContext();
|
|
10862
10786
|
const [showConfirmation, setShowConfirmation] = useState47(false);
|
|
10863
|
-
const
|
|
10787
|
+
const formSchema2 = z7.object({
|
|
10864
10788
|
email: z7.string().email({
|
|
10865
10789
|
message: t(`generic.errors.invalid_email`)
|
|
10866
10790
|
})
|
|
10867
10791
|
});
|
|
10868
10792
|
const form = useForm7({
|
|
10869
|
-
resolver: zodResolver7(
|
|
10793
|
+
resolver: zodResolver7(formSchema2),
|
|
10870
10794
|
defaultValues: {
|
|
10871
10795
|
email: ""
|
|
10872
10796
|
}
|
|
@@ -10932,14 +10856,14 @@ function Login() {
|
|
|
10932
10856
|
const { setComponentType } = useAuthContext();
|
|
10933
10857
|
const generateUrl = usePageUrlGenerator();
|
|
10934
10858
|
const router = useI18nRouter();
|
|
10935
|
-
const
|
|
10859
|
+
const formSchema2 = z8.object({
|
|
10936
10860
|
email: z8.string().email({
|
|
10937
10861
|
message: t(`generic.errors.invalid_email`)
|
|
10938
10862
|
}),
|
|
10939
10863
|
password: z8.string().min(3, { message: t(`foundations.auth.errors.password_too_short`) })
|
|
10940
10864
|
});
|
|
10941
10865
|
const form = useForm8({
|
|
10942
|
-
resolver: zodResolver8(
|
|
10866
|
+
resolver: zodResolver8(formSchema2),
|
|
10943
10867
|
defaultValues: {
|
|
10944
10868
|
email: "",
|
|
10945
10869
|
password: ""
|
|
@@ -11099,7 +11023,7 @@ function ResetPassword() {
|
|
|
11099
11023
|
setError(t(`foundations.auth.errors.invalid_password_reset_code`));
|
|
11100
11024
|
}
|
|
11101
11025
|
}, []);
|
|
11102
|
-
const
|
|
11026
|
+
const formSchema2 = z9.object({
|
|
11103
11027
|
password: z9.string().min(1, {
|
|
11104
11028
|
message: t(`foundations.user.fields.password.error`)
|
|
11105
11029
|
}),
|
|
@@ -11111,7 +11035,7 @@ function ResetPassword() {
|
|
|
11111
11035
|
path: ["passwordRetype"]
|
|
11112
11036
|
});
|
|
11113
11037
|
const form = useForm9({
|
|
11114
|
-
resolver: zodResolver9(
|
|
11038
|
+
resolver: zodResolver9(formSchema2),
|
|
11115
11039
|
defaultValues: {
|
|
11116
11040
|
password: "",
|
|
11117
11041
|
passwordRetype: ""
|
|
@@ -11154,217 +11078,3580 @@ function ResetPassword() {
|
|
|
11154
11078
|
}
|
|
11155
11079
|
__name(ResetPassword, "ResetPassword");
|
|
11156
11080
|
|
|
11157
|
-
// src/features/
|
|
11158
|
-
import {
|
|
11081
|
+
// src/features/billing/components/cards/SubscriptionSummaryCard.tsx
|
|
11082
|
+
import { ChevronRight, CreditCard } from "lucide-react";
|
|
11159
11083
|
import { jsx as jsx144, jsxs as jsxs86 } from "react/jsx-runtime";
|
|
11160
|
-
function
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
/* @__PURE__ */ jsx144("div", { className: "text-xs", children: content.abstract })
|
|
11181
|
-
] })
|
|
11182
|
-
] }),
|
|
11183
|
-
/* @__PURE__ */ jsx144(ContributorsList, { content })
|
|
11184
|
-
] }) });
|
|
11185
|
-
}
|
|
11186
|
-
__name(ContentsListElement, "ContentsListElement");
|
|
11187
|
-
|
|
11188
|
-
// src/features/content/components/lists/ContentsListById.tsx
|
|
11189
|
-
import { useTranslations as useTranslations54 } from "next-intl";
|
|
11190
|
-
import { jsx as jsx145 } from "react/jsx-runtime";
|
|
11191
|
-
function ContentsListById({ contentIds }) {
|
|
11192
|
-
const t = useTranslations54();
|
|
11193
|
-
const data = useDataListRetriever({
|
|
11194
|
-
module: Modules.Content,
|
|
11195
|
-
retriever: /* @__PURE__ */ __name((params) => ContentService.findMany(params), "retriever"),
|
|
11196
|
-
retrieverParams: { contentIds }
|
|
11084
|
+
function getStatusBadgeVariant(status) {
|
|
11085
|
+
switch (status) {
|
|
11086
|
+
case "active" /* ACTIVE */:
|
|
11087
|
+
return "default";
|
|
11088
|
+
case "trialing" /* TRIALING */:
|
|
11089
|
+
return "secondary";
|
|
11090
|
+
case "past_due" /* PAST_DUE */:
|
|
11091
|
+
case "unpaid" /* UNPAID */:
|
|
11092
|
+
case "canceled" /* CANCELED */:
|
|
11093
|
+
return "destructive";
|
|
11094
|
+
default:
|
|
11095
|
+
return "outline";
|
|
11096
|
+
}
|
|
11097
|
+
}
|
|
11098
|
+
__name(getStatusBadgeVariant, "getStatusBadgeVariant");
|
|
11099
|
+
function formatDate(date) {
|
|
11100
|
+
return new Date(date).toLocaleDateString(void 0, {
|
|
11101
|
+
year: "numeric",
|
|
11102
|
+
month: "short",
|
|
11103
|
+
day: "numeric"
|
|
11197
11104
|
});
|
|
11198
|
-
return /* @__PURE__ */ jsx145(
|
|
11199
|
-
ContentListTable,
|
|
11200
|
-
{
|
|
11201
|
-
data,
|
|
11202
|
-
fields: ["name" /* name */, "authors" /* authors */, "updatedAt" /* updatedAt */],
|
|
11203
|
-
tableGeneratorType: Modules.Content,
|
|
11204
|
-
title: t(`generic.relevant`)
|
|
11205
|
-
}
|
|
11206
|
-
);
|
|
11207
11105
|
}
|
|
11208
|
-
__name(
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
{
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11106
|
+
__name(formatDate, "formatDate");
|
|
11107
|
+
function formatPrice(amount, currency) {
|
|
11108
|
+
if (amount === void 0) return "N/A";
|
|
11109
|
+
const currencyCode = currency?.toUpperCase() || "USD";
|
|
11110
|
+
return new Intl.NumberFormat(void 0, {
|
|
11111
|
+
style: "currency",
|
|
11112
|
+
currency: currencyCode
|
|
11113
|
+
}).format(amount / 100);
|
|
11114
|
+
}
|
|
11115
|
+
__name(formatPrice, "formatPrice");
|
|
11116
|
+
function formatPlanName(subscription) {
|
|
11117
|
+
const productName = subscription.price?.product?.name || "";
|
|
11118
|
+
const nickname = subscription.price?.nickname || "";
|
|
11119
|
+
if (productName && nickname) {
|
|
11120
|
+
return `${productName} - ${nickname}`;
|
|
11121
|
+
}
|
|
11122
|
+
return productName || nickname || "Subscription";
|
|
11123
|
+
}
|
|
11124
|
+
__name(formatPlanName, "formatPlanName");
|
|
11125
|
+
function SubscriptionSummaryCard({
|
|
11126
|
+
subscriptions,
|
|
11127
|
+
loading,
|
|
11128
|
+
error,
|
|
11129
|
+
onManageClick
|
|
11130
|
+
}) {
|
|
11131
|
+
if (loading) {
|
|
11132
|
+
return /* @__PURE__ */ jsxs86(Card, { children: [
|
|
11133
|
+
/* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11134
|
+
/* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
|
|
11135
|
+
/* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
|
|
11136
|
+
] }),
|
|
11137
|
+
/* @__PURE__ */ jsxs86(CardContent, { children: [
|
|
11138
|
+
/* @__PURE__ */ jsx144(Skeleton, { className: "h-6 w-32 mb-2" }),
|
|
11139
|
+
/* @__PURE__ */ jsx144(Skeleton, { className: "h-4 w-24 mb-1" }),
|
|
11140
|
+
/* @__PURE__ */ jsx144(Skeleton, { className: "h-4 w-40" })
|
|
11141
|
+
] })
|
|
11142
|
+
] });
|
|
11143
|
+
}
|
|
11144
|
+
if (error) {
|
|
11145
|
+
return /* @__PURE__ */ jsxs86(Card, { children: [
|
|
11146
|
+
/* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11147
|
+
/* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
|
|
11148
|
+
/* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
|
|
11149
|
+
] }),
|
|
11150
|
+
/* @__PURE__ */ jsx144(CardContent, { children: /* @__PURE__ */ jsx144("p", { className: "text-sm text-destructive", children: error }) })
|
|
11151
|
+
] });
|
|
11152
|
+
}
|
|
11153
|
+
const activeSubscriptions = subscriptions.filter(
|
|
11154
|
+
(sub) => sub.status === "active" /* ACTIVE */ || sub.status === "trialing" /* TRIALING */
|
|
11228
11155
|
);
|
|
11156
|
+
const primarySubscription = activeSubscriptions[0];
|
|
11157
|
+
return /* @__PURE__ */ jsxs86(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onManageClick, children: [
|
|
11158
|
+
/* @__PURE__ */ jsxs86(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11159
|
+
/* @__PURE__ */ jsx144(CardTitle, { className: "text-sm font-medium", children: "Subscriptions" }),
|
|
11160
|
+
/* @__PURE__ */ jsx144(CreditCard, { className: "h-4 w-4 text-muted-foreground" })
|
|
11161
|
+
] }),
|
|
11162
|
+
/* @__PURE__ */ jsx144(CardContent, { children: subscriptions.length === 0 ? /* @__PURE__ */ jsxs86("div", { className: "space-y-2", children: [
|
|
11163
|
+
/* @__PURE__ */ jsx144("p", { className: "text-xl font-bold text-muted-foreground", children: "No active plan" }),
|
|
11164
|
+
/* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: "Subscribe to get started" }),
|
|
11165
|
+
/* @__PURE__ */ jsxs86(
|
|
11166
|
+
Button,
|
|
11167
|
+
{
|
|
11168
|
+
variant: "outline",
|
|
11169
|
+
size: "sm",
|
|
11170
|
+
className: "mt-2",
|
|
11171
|
+
onClick: (e) => {
|
|
11172
|
+
e.stopPropagation();
|
|
11173
|
+
onManageClick();
|
|
11174
|
+
},
|
|
11175
|
+
children: [
|
|
11176
|
+
"View Plans",
|
|
11177
|
+
/* @__PURE__ */ jsx144(ChevronRight, { className: "h-4 w-4 ml-1" })
|
|
11178
|
+
]
|
|
11179
|
+
}
|
|
11180
|
+
)
|
|
11181
|
+
] }) : primarySubscription ? /* @__PURE__ */ jsxs86("div", { className: "space-y-2", children: [
|
|
11182
|
+
/* @__PURE__ */ jsxs86("div", { className: "flex items-center gap-2", children: [
|
|
11183
|
+
/* @__PURE__ */ jsx144("p", { className: "text-xl font-bold", children: formatPlanName(primarySubscription) }),
|
|
11184
|
+
/* @__PURE__ */ jsx144(Badge, { variant: primarySubscription.cancelAtPeriodEnd ? "secondary" : getStatusBadgeVariant(primarySubscription.status), children: primarySubscription.cancelAtPeriodEnd ? "Canceling" : primarySubscription.status })
|
|
11185
|
+
] }),
|
|
11186
|
+
/* @__PURE__ */ jsxs86("p", { className: "text-sm text-muted-foreground", children: [
|
|
11187
|
+
formatPrice(primarySubscription.price?.unitAmount, primarySubscription.price?.currency),
|
|
11188
|
+
primarySubscription.price?.recurring && /* @__PURE__ */ jsxs86("span", { children: [
|
|
11189
|
+
"/",
|
|
11190
|
+
primarySubscription.price.recurring.interval
|
|
11191
|
+
] })
|
|
11192
|
+
] }),
|
|
11193
|
+
/* @__PURE__ */ jsx144("p", { className: "text-xs text-muted-foreground", children: primarySubscription.cancelAtPeriodEnd ? `Cancels on ${formatDate(primarySubscription.currentPeriodEnd)}` : `Renews on ${formatDate(primarySubscription.currentPeriodEnd)}` }),
|
|
11194
|
+
activeSubscriptions.length > 1 && /* @__PURE__ */ jsxs86("p", { className: "text-xs text-muted-foreground", children: [
|
|
11195
|
+
"+",
|
|
11196
|
+
activeSubscriptions.length - 1,
|
|
11197
|
+
" more subscription(s)"
|
|
11198
|
+
] })
|
|
11199
|
+
] }) : null })
|
|
11200
|
+
] });
|
|
11229
11201
|
}
|
|
11230
|
-
__name(
|
|
11231
|
-
|
|
11232
|
-
// src/features/
|
|
11233
|
-
import {
|
|
11234
|
-
import { jsx as
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11202
|
+
__name(SubscriptionSummaryCard, "SubscriptionSummaryCard");
|
|
11203
|
+
|
|
11204
|
+
// src/features/billing/components/cards/PaymentMethodSummaryCard.tsx
|
|
11205
|
+
import { Wallet, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
11206
|
+
import { jsx as jsx145, jsxs as jsxs87 } from "react/jsx-runtime";
|
|
11207
|
+
function getCardBrandIcon(brand) {
|
|
11208
|
+
const brandMap = {
|
|
11209
|
+
visa: "Visa",
|
|
11210
|
+
mastercard: "Mastercard",
|
|
11211
|
+
amex: "Amex",
|
|
11212
|
+
discover: "Discover",
|
|
11213
|
+
diners: "Diners",
|
|
11214
|
+
jcb: "JCB",
|
|
11215
|
+
unionpay: "UnionPay"
|
|
11216
|
+
};
|
|
11217
|
+
return brandMap[brand.toLowerCase()] || brand;
|
|
11218
|
+
}
|
|
11219
|
+
__name(getCardBrandIcon, "getCardBrandIcon");
|
|
11220
|
+
function PaymentMethodSummaryCard({
|
|
11221
|
+
paymentMethods,
|
|
11222
|
+
defaultPaymentMethodId,
|
|
11223
|
+
loading,
|
|
11224
|
+
error,
|
|
11225
|
+
onManageClick
|
|
11226
|
+
}) {
|
|
11227
|
+
if (loading) {
|
|
11228
|
+
return /* @__PURE__ */ jsxs87(Card, { children: [
|
|
11229
|
+
/* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11230
|
+
/* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
|
|
11231
|
+
/* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
|
|
11232
|
+
] }),
|
|
11233
|
+
/* @__PURE__ */ jsxs87(CardContent, { children: [
|
|
11234
|
+
/* @__PURE__ */ jsx145(Skeleton, { className: "h-6 w-32 mb-2" }),
|
|
11235
|
+
/* @__PURE__ */ jsx145(Skeleton, { className: "h-4 w-24" })
|
|
11236
|
+
] })
|
|
11237
|
+
] });
|
|
11238
11238
|
}
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11239
|
+
if (error) {
|
|
11240
|
+
return /* @__PURE__ */ jsxs87(Card, { children: [
|
|
11241
|
+
/* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11242
|
+
/* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
|
|
11243
|
+
/* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
|
|
11244
|
+
] }),
|
|
11245
|
+
/* @__PURE__ */ jsx145(CardContent, { children: /* @__PURE__ */ jsx145("p", { className: "text-sm text-destructive", children: error }) })
|
|
11246
|
+
] });
|
|
11242
11247
|
}
|
|
11243
|
-
|
|
11244
|
-
|
|
11248
|
+
const defaultMethod = paymentMethods.find((pm) => pm.id === defaultPaymentMethodId) || paymentMethods[0];
|
|
11249
|
+
return /* @__PURE__ */ jsxs87(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onManageClick, children: [
|
|
11250
|
+
/* @__PURE__ */ jsxs87(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11251
|
+
/* @__PURE__ */ jsx145(CardTitle, { className: "text-sm font-medium", children: "Payment Method" }),
|
|
11252
|
+
/* @__PURE__ */ jsx145(Wallet, { className: "h-4 w-4 text-muted-foreground" })
|
|
11253
|
+
] }),
|
|
11254
|
+
/* @__PURE__ */ jsx145(CardContent, { children: paymentMethods.length === 0 ? /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
|
|
11255
|
+
/* @__PURE__ */ jsx145("p", { className: "text-xl font-bold text-muted-foreground", children: "No payment method" }),
|
|
11256
|
+
/* @__PURE__ */ jsx145("p", { className: "text-xs text-muted-foreground", children: "Add a card to enable subscriptions" }),
|
|
11257
|
+
/* @__PURE__ */ jsxs87(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: (e) => {
|
|
11258
|
+
e.stopPropagation();
|
|
11259
|
+
onManageClick();
|
|
11260
|
+
}, children: [
|
|
11261
|
+
"Add Card",
|
|
11262
|
+
/* @__PURE__ */ jsx145(ChevronRight2, { className: "h-4 w-4 ml-1" })
|
|
11263
|
+
] })
|
|
11264
|
+
] }) : defaultMethod?.card ? /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
|
|
11265
|
+
/* @__PURE__ */ jsxs87("p", { className: "text-xl font-bold", children: [
|
|
11266
|
+
getCardBrandIcon(defaultMethod.card.brand),
|
|
11267
|
+
" ****",
|
|
11268
|
+
defaultMethod.card.last4
|
|
11269
|
+
] }),
|
|
11270
|
+
/* @__PURE__ */ jsxs87("p", { className: "text-sm text-muted-foreground", children: [
|
|
11271
|
+
"Expires ",
|
|
11272
|
+
String(defaultMethod.card.expMonth).padStart(2, "0"),
|
|
11273
|
+
"/",
|
|
11274
|
+
defaultMethod.card.expYear
|
|
11275
|
+
] }),
|
|
11276
|
+
paymentMethods.length > 1 && /* @__PURE__ */ jsxs87("p", { className: "text-xs text-muted-foreground", children: [
|
|
11277
|
+
"+",
|
|
11278
|
+
paymentMethods.length - 1,
|
|
11279
|
+
" more card(s)"
|
|
11280
|
+
] })
|
|
11281
|
+
] }) : /* @__PURE__ */ jsxs87("div", { className: "space-y-2", children: [
|
|
11282
|
+
/* @__PURE__ */ jsx145("p", { className: "text-xl font-bold", children: defaultMethod?.type || "Payment Method" }),
|
|
11283
|
+
paymentMethods.length > 1 && /* @__PURE__ */ jsxs87("p", { className: "text-xs text-muted-foreground", children: [
|
|
11284
|
+
"+",
|
|
11285
|
+
paymentMethods.length - 1,
|
|
11286
|
+
" more method(s)"
|
|
11287
|
+
] })
|
|
11288
|
+
] }) })
|
|
11289
|
+
] });
|
|
11290
|
+
}
|
|
11291
|
+
__name(PaymentMethodSummaryCard, "PaymentMethodSummaryCard");
|
|
11292
|
+
|
|
11293
|
+
// src/features/billing/components/cards/CustomerInfoCard.tsx
|
|
11294
|
+
import { ExternalLink, User } from "lucide-react";
|
|
11295
|
+
import { useState as useState49 } from "react";
|
|
11296
|
+
import { jsx as jsx146, jsxs as jsxs88 } from "react/jsx-runtime";
|
|
11297
|
+
function formatBalance(balance, currency) {
|
|
11298
|
+
if (balance === void 0 || balance === 0) return "$0.00";
|
|
11299
|
+
const currencyCode = currency?.toUpperCase() || "USD";
|
|
11300
|
+
const displayBalance = -balance;
|
|
11301
|
+
return new Intl.NumberFormat(void 0, {
|
|
11302
|
+
style: "currency",
|
|
11303
|
+
currency: currencyCode
|
|
11304
|
+
}).format(displayBalance / 100);
|
|
11305
|
+
}
|
|
11306
|
+
__name(formatBalance, "formatBalance");
|
|
11307
|
+
function CustomerInfoCard({ customer, loading, error }) {
|
|
11308
|
+
const [portalLoading, setPortalLoading] = useState49(false);
|
|
11309
|
+
const handlePortalClick = /* @__PURE__ */ __name(async (e) => {
|
|
11310
|
+
e.stopPropagation();
|
|
11311
|
+
setPortalLoading(true);
|
|
11312
|
+
try {
|
|
11313
|
+
const { url } = await StripeCustomerService.createPortalSession();
|
|
11314
|
+
window.open(url, "_blank");
|
|
11315
|
+
} catch (err) {
|
|
11316
|
+
console.error("[CustomerInfoCard] Failed to create portal session:", err);
|
|
11317
|
+
} finally {
|
|
11318
|
+
setPortalLoading(false);
|
|
11319
|
+
}
|
|
11320
|
+
}, "handlePortalClick");
|
|
11321
|
+
if (loading) {
|
|
11322
|
+
return /* @__PURE__ */ jsxs88(Card, { children: [
|
|
11323
|
+
/* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11324
|
+
/* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
|
|
11325
|
+
/* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
|
|
11326
|
+
] }),
|
|
11327
|
+
/* @__PURE__ */ jsxs88(CardContent, { children: [
|
|
11328
|
+
/* @__PURE__ */ jsx146(Skeleton, { className: "h-6 w-32 mb-2" }),
|
|
11329
|
+
/* @__PURE__ */ jsx146(Skeleton, { className: "h-4 w-48 mb-1" }),
|
|
11330
|
+
/* @__PURE__ */ jsx146(Skeleton, { className: "h-4 w-24" })
|
|
11331
|
+
] })
|
|
11332
|
+
] });
|
|
11245
11333
|
}
|
|
11246
|
-
|
|
11247
|
-
|
|
11334
|
+
if (error) {
|
|
11335
|
+
return /* @__PURE__ */ jsxs88(Card, { children: [
|
|
11336
|
+
/* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11337
|
+
/* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
|
|
11338
|
+
/* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
|
|
11339
|
+
] }),
|
|
11340
|
+
/* @__PURE__ */ jsx146(CardContent, { children: /* @__PURE__ */ jsx146("p", { className: "text-sm text-destructive", children: error }) })
|
|
11341
|
+
] });
|
|
11248
11342
|
}
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
/* @__PURE__ */
|
|
11253
|
-
/* @__PURE__ */
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
)
|
|
11261
|
-
] }) });
|
|
11262
|
-
}
|
|
11263
|
-
return this.props.children;
|
|
11343
|
+
if (!customer) {
|
|
11344
|
+
return /* @__PURE__ */ jsxs88(Card, { children: [
|
|
11345
|
+
/* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11346
|
+
/* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
|
|
11347
|
+
/* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
|
|
11348
|
+
] }),
|
|
11349
|
+
/* @__PURE__ */ jsxs88(CardContent, { children: [
|
|
11350
|
+
/* @__PURE__ */ jsx146("p", { className: "text-xl font-bold text-muted-foreground", children: "Not set up" }),
|
|
11351
|
+
/* @__PURE__ */ jsx146("p", { className: "text-xs text-muted-foreground", children: "Billing account will be created when you subscribe" })
|
|
11352
|
+
] })
|
|
11353
|
+
] });
|
|
11264
11354
|
}
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11355
|
+
return /* @__PURE__ */ jsxs88(Card, { children: [
|
|
11356
|
+
/* @__PURE__ */ jsxs88(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11357
|
+
/* @__PURE__ */ jsx146(CardTitle, { className: "text-sm font-medium", children: "Billing Account" }),
|
|
11358
|
+
/* @__PURE__ */ jsx146(User, { className: "h-4 w-4 text-muted-foreground" })
|
|
11359
|
+
] }),
|
|
11360
|
+
/* @__PURE__ */ jsx146(CardContent, { children: /* @__PURE__ */ jsxs88("div", { className: "space-y-2", children: [
|
|
11361
|
+
customer.name && /* @__PURE__ */ jsx146("p", { className: "text-xl font-bold", children: customer.name }),
|
|
11362
|
+
customer.email && /* @__PURE__ */ jsx146("p", { className: "text-sm text-muted-foreground", children: customer.email }),
|
|
11363
|
+
customer.balance !== void 0 && customer.balance !== 0 && /* @__PURE__ */ jsxs88("p", { className: "text-sm", children: [
|
|
11364
|
+
/* @__PURE__ */ jsx146("span", { className: "text-muted-foreground", children: "Credit Balance: " }),
|
|
11365
|
+
/* @__PURE__ */ jsx146("span", { className: customer.balance < 0 ? "text-green-600" : "text-destructive", children: formatBalance(customer.balance, customer.currency) })
|
|
11366
|
+
] }),
|
|
11367
|
+
/* @__PURE__ */ jsxs88(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: handlePortalClick, disabled: portalLoading, children: [
|
|
11368
|
+
portalLoading ? "Loading..." : "Manage in Stripe Portal",
|
|
11369
|
+
/* @__PURE__ */ jsx146(ExternalLink, { className: "h-4 w-4 ml-1" })
|
|
11370
|
+
] })
|
|
11371
|
+
] }) })
|
|
11372
|
+
] });
|
|
11373
|
+
}
|
|
11374
|
+
__name(CustomerInfoCard, "CustomerInfoCard");
|
|
11375
|
+
|
|
11376
|
+
// src/features/billing/components/cards/InvoicesSummaryCard.tsx
|
|
11377
|
+
import { ChevronRight as ChevronRight3, ReceiptIcon } from "lucide-react";
|
|
11378
|
+
import { jsx as jsx147, jsxs as jsxs89 } from "react/jsx-runtime";
|
|
11379
|
+
function getStatusBadgeVariant2(status) {
|
|
11380
|
+
switch (status) {
|
|
11381
|
+
case "paid" /* PAID */:
|
|
11382
|
+
return "default";
|
|
11383
|
+
case "open" /* OPEN */:
|
|
11384
|
+
return "secondary";
|
|
11385
|
+
case "uncollectible" /* UNCOLLECTIBLE */:
|
|
11386
|
+
case "void" /* VOID */:
|
|
11387
|
+
return "destructive";
|
|
11388
|
+
default:
|
|
11389
|
+
return "outline";
|
|
11390
|
+
}
|
|
11391
|
+
}
|
|
11392
|
+
__name(getStatusBadgeVariant2, "getStatusBadgeVariant");
|
|
11393
|
+
function formatDate2(date) {
|
|
11394
|
+
return new Date(date).toLocaleDateString(void 0, {
|
|
11395
|
+
year: "numeric",
|
|
11396
|
+
month: "short",
|
|
11397
|
+
day: "numeric"
|
|
11281
11398
|
});
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11399
|
+
}
|
|
11400
|
+
__name(formatDate2, "formatDate");
|
|
11401
|
+
function formatAmount(amount, currency) {
|
|
11402
|
+
const currencyCode = currency?.toUpperCase() || "USD";
|
|
11403
|
+
return new Intl.NumberFormat(void 0, {
|
|
11404
|
+
style: "currency",
|
|
11405
|
+
currency: currencyCode
|
|
11406
|
+
}).format(amount / 100);
|
|
11407
|
+
}
|
|
11408
|
+
__name(formatAmount, "formatAmount");
|
|
11409
|
+
function InvoicesSummaryCard({ invoices, loading, error, onViewAllClick }) {
|
|
11410
|
+
if (loading) {
|
|
11411
|
+
return /* @__PURE__ */ jsxs89(Card, { children: [
|
|
11412
|
+
/* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11413
|
+
/* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
|
|
11414
|
+
/* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
|
|
11415
|
+
] }),
|
|
11416
|
+
/* @__PURE__ */ jsxs89(CardContent, { children: [
|
|
11417
|
+
/* @__PURE__ */ jsx147(Skeleton, { className: "h-6 w-24 mb-2" }),
|
|
11418
|
+
/* @__PURE__ */ jsx147(Skeleton, { className: "h-4 w-32 mb-1" }),
|
|
11419
|
+
/* @__PURE__ */ jsx147(Skeleton, { className: "h-4 w-20" })
|
|
11420
|
+
] })
|
|
11421
|
+
] });
|
|
11422
|
+
}
|
|
11423
|
+
if (error) {
|
|
11424
|
+
return /* @__PURE__ */ jsxs89(Card, { children: [
|
|
11425
|
+
/* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11426
|
+
/* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
|
|
11427
|
+
/* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
|
|
11428
|
+
] }),
|
|
11429
|
+
/* @__PURE__ */ jsx147(CardContent, { children: /* @__PURE__ */ jsx147("p", { className: "text-sm text-destructive", children: error }) })
|
|
11430
|
+
] });
|
|
11431
|
+
}
|
|
11432
|
+
const latestInvoice = invoices[0];
|
|
11433
|
+
const paidInvoices = invoices.filter((inv) => inv.status === "paid" /* PAID */);
|
|
11434
|
+
const openInvoices = invoices.filter((inv) => inv.status === "open" /* OPEN */);
|
|
11435
|
+
return /* @__PURE__ */ jsxs89(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onViewAllClick, children: [
|
|
11436
|
+
/* @__PURE__ */ jsxs89(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11437
|
+
/* @__PURE__ */ jsx147(CardTitle, { className: "text-sm font-medium", children: "Recent Invoices" }),
|
|
11438
|
+
/* @__PURE__ */ jsx147(ReceiptIcon, { className: "h-4 w-4 text-muted-foreground" })
|
|
11291
11439
|
] }),
|
|
11292
|
-
/* @__PURE__ */
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
/* @__PURE__ */ jsx148("p", { className: "text-sm", children: t.rich(`foundations.notification.${notification.notificationType}.description`, {
|
|
11300
|
-
strong: /* @__PURE__ */ __name((chunks) => /* @__PURE__ */ jsx148("strong", { children: chunks }), "strong"),
|
|
11301
|
-
actor: notificationData.actor?.name ?? "",
|
|
11302
|
-
title: notificationData.title
|
|
11303
|
-
}) }),
|
|
11304
|
-
/* @__PURE__ */ jsx148("div", { className: "text-muted-foreground mt-1 w-full text-xs", children: new Date(notification.createdAt).toLocaleString() })
|
|
11440
|
+
/* @__PURE__ */ jsx147(CardContent, { children: invoices.length === 0 ? /* @__PURE__ */ jsxs89("div", { className: "space-y-2", children: [
|
|
11441
|
+
/* @__PURE__ */ jsx147("p", { className: "text-xl font-bold text-muted-foreground", children: "No invoices yet" }),
|
|
11442
|
+
/* @__PURE__ */ jsx147("p", { className: "text-xs text-muted-foreground", children: "Invoices will appear after your first billing cycle" })
|
|
11443
|
+
] }) : latestInvoice ? /* @__PURE__ */ jsxs89("div", { className: "space-y-2", children: [
|
|
11444
|
+
/* @__PURE__ */ jsxs89("div", { className: "flex items-center gap-2", children: [
|
|
11445
|
+
/* @__PURE__ */ jsx147("p", { className: "text-xl font-bold", children: formatAmount(latestInvoice.total, latestInvoice.currency) }),
|
|
11446
|
+
/* @__PURE__ */ jsx147(Badge, { variant: getStatusBadgeVariant2(latestInvoice.status), children: latestInvoice.status })
|
|
11305
11447
|
] }),
|
|
11306
|
-
/* @__PURE__ */
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
|
|
11317
|
-
|
|
11318
|
-
|
|
11319
|
-
children: /* @__PURE__ */ jsx148(ArchiveIcon, { className: "h-4 w-4 cursor-pointer" })
|
|
11320
|
-
}
|
|
11321
|
-
) }),
|
|
11322
|
-
/* @__PURE__ */ jsx148(TooltipContent, { children: t(`foundations.notification.buttons.archive`) })
|
|
11448
|
+
/* @__PURE__ */ jsx147("p", { className: "text-sm text-muted-foreground", children: latestInvoice.stripeInvoiceNumber || `Invoice from ${formatDate2(latestInvoice.periodStart)}` }),
|
|
11449
|
+
/* @__PURE__ */ jsxs89("div", { className: "flex items-center gap-4 text-xs text-muted-foreground", children: [
|
|
11450
|
+
paidInvoices.length > 0 && /* @__PURE__ */ jsxs89("span", { children: [
|
|
11451
|
+
paidInvoices.length,
|
|
11452
|
+
" paid"
|
|
11453
|
+
] }),
|
|
11454
|
+
openInvoices.length > 0 && /* @__PURE__ */ jsxs89("span", { className: "text-orange-600", children: [
|
|
11455
|
+
openInvoices.length,
|
|
11456
|
+
" open"
|
|
11457
|
+
] }),
|
|
11458
|
+
/* @__PURE__ */ jsxs89("span", { className: "flex items-center", children: [
|
|
11459
|
+
"View all",
|
|
11460
|
+
/* @__PURE__ */ jsx147(ChevronRight3, { className: "h-3 w-3 ml-1" })
|
|
11323
11461
|
] })
|
|
11324
11462
|
] })
|
|
11325
|
-
] })
|
|
11326
|
-
|
|
11463
|
+
] }) : null })
|
|
11464
|
+
] });
|
|
11327
11465
|
}
|
|
11328
|
-
__name(
|
|
11329
|
-
|
|
11330
|
-
// src/features/
|
|
11331
|
-
import {
|
|
11332
|
-
|
|
11333
|
-
|
|
11334
|
-
|
|
11466
|
+
__name(InvoicesSummaryCard, "InvoicesSummaryCard");
|
|
11467
|
+
|
|
11468
|
+
// src/features/billing/components/cards/BillingUsageSummaryCard.tsx
|
|
11469
|
+
import { Activity, ChevronRight as ChevronRight4 } from "lucide-react";
|
|
11470
|
+
import { jsx as jsx148, jsxs as jsxs90 } from "react/jsx-runtime";
|
|
11471
|
+
function formatNumber(value) {
|
|
11472
|
+
return new Intl.NumberFormat(void 0, {
|
|
11473
|
+
notation: "compact",
|
|
11474
|
+
compactDisplay: "short"
|
|
11475
|
+
}).format(value);
|
|
11476
|
+
}
|
|
11477
|
+
__name(formatNumber, "formatNumber");
|
|
11478
|
+
function BillingUsageSummaryCard({
|
|
11479
|
+
meters,
|
|
11480
|
+
summaries,
|
|
11481
|
+
loading,
|
|
11482
|
+
error,
|
|
11483
|
+
onViewDetailsClick
|
|
11484
|
+
}) {
|
|
11485
|
+
if (loading) {
|
|
11486
|
+
return /* @__PURE__ */ jsxs90(Card, { children: [
|
|
11487
|
+
/* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11488
|
+
/* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
|
|
11489
|
+
/* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
|
|
11490
|
+
] }),
|
|
11491
|
+
/* @__PURE__ */ jsxs90(CardContent, { children: [
|
|
11492
|
+
/* @__PURE__ */ jsx148(Skeleton, { className: "h-6 w-24 mb-2" }),
|
|
11493
|
+
/* @__PURE__ */ jsx148(Skeleton, { className: "h-4 w-32" })
|
|
11494
|
+
] })
|
|
11495
|
+
] });
|
|
11496
|
+
}
|
|
11335
11497
|
if (error) {
|
|
11336
|
-
return /* @__PURE__ */
|
|
11337
|
-
/* @__PURE__ */
|
|
11338
|
-
"
|
|
11339
|
-
|
|
11498
|
+
return /* @__PURE__ */ jsxs90(Card, { children: [
|
|
11499
|
+
/* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11500
|
+
/* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
|
|
11501
|
+
/* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
|
|
11340
11502
|
] }),
|
|
11341
|
-
/* @__PURE__ */
|
|
11342
|
-
] })
|
|
11503
|
+
/* @__PURE__ */ jsx148(CardContent, { children: /* @__PURE__ */ jsx148("p", { className: "text-sm text-destructive", children: error }) })
|
|
11504
|
+
] });
|
|
11343
11505
|
}
|
|
11344
|
-
const
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
|
|
11349
|
-
|
|
11350
|
-
|
|
11351
|
-
|
|
11352
|
-
|
|
11353
|
-
|
|
11354
|
-
|
|
11355
|
-
}
|
|
11356
|
-
|
|
11357
|
-
|
|
11358
|
-
|
|
11506
|
+
const totalUsage = Object.values(summaries).reduce((acc, summary) => {
|
|
11507
|
+
return acc + (summary?.aggregatedValue || 0);
|
|
11508
|
+
}, 0);
|
|
11509
|
+
const primaryMeter = meters.find((m) => summaries[m.id]?.aggregatedValue);
|
|
11510
|
+
const primarySummary = primaryMeter ? summaries[primaryMeter.id] : null;
|
|
11511
|
+
return /* @__PURE__ */ jsxs90(Card, { className: "cursor-pointer hover:bg-accent/50 transition-colors", onClick: onViewDetailsClick, children: [
|
|
11512
|
+
/* @__PURE__ */ jsxs90(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2", children: [
|
|
11513
|
+
/* @__PURE__ */ jsx148(CardTitle, { className: "text-sm font-medium", children: "Usage This Month" }),
|
|
11514
|
+
/* @__PURE__ */ jsx148(Activity, { className: "h-4 w-4 text-muted-foreground" })
|
|
11515
|
+
] }),
|
|
11516
|
+
/* @__PURE__ */ jsx148(CardContent, { children: meters.length === 0 ? /* @__PURE__ */ jsxs90("div", { className: "space-y-2", children: [
|
|
11517
|
+
/* @__PURE__ */ jsx148("p", { className: "text-xl font-bold text-muted-foreground", children: "No meters" }),
|
|
11518
|
+
/* @__PURE__ */ jsx148("p", { className: "text-xs text-muted-foreground", children: "No usage meters are configured" })
|
|
11519
|
+
] }) : /* @__PURE__ */ jsxs90("div", { className: "space-y-2", children: [
|
|
11520
|
+
/* @__PURE__ */ jsxs90("p", { className: "text-xl font-bold", children: [
|
|
11521
|
+
formatNumber(totalUsage),
|
|
11522
|
+
" units"
|
|
11523
|
+
] }),
|
|
11524
|
+
primaryMeter && primarySummary && /* @__PURE__ */ jsxs90("p", { className: "text-sm text-muted-foreground", children: [
|
|
11525
|
+
primaryMeter.displayName,
|
|
11526
|
+
": ",
|
|
11527
|
+
formatNumber(primarySummary.aggregatedValue)
|
|
11528
|
+
] }),
|
|
11529
|
+
meters.length > 1 && /* @__PURE__ */ jsxs90("p", { className: "text-xs text-muted-foreground", children: [
|
|
11530
|
+
"Across ",
|
|
11531
|
+
meters.length,
|
|
11532
|
+
" meters"
|
|
11533
|
+
] }),
|
|
11534
|
+
/* @__PURE__ */ jsxs90("span", { className: "flex items-center text-xs text-muted-foreground", children: [
|
|
11535
|
+
"View details",
|
|
11536
|
+
/* @__PURE__ */ jsx148(ChevronRight4, { className: "h-3 w-3 ml-1" })
|
|
11537
|
+
] })
|
|
11538
|
+
] }) })
|
|
11539
|
+
] });
|
|
11540
|
+
}
|
|
11541
|
+
__name(BillingUsageSummaryCard, "BillingUsageSummaryCard");
|
|
11542
|
+
|
|
11543
|
+
// src/features/billing/components/containers/BillingDashboardContainer.tsx
|
|
11544
|
+
import { CreditCard as CreditCard4, Loader2 as Loader24, Wallet as Wallet2 } from "lucide-react";
|
|
11545
|
+
import { useCallback as useCallback18, useEffect as useEffect47, useState as useState62 } from "react";
|
|
11546
|
+
|
|
11547
|
+
// src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx
|
|
11548
|
+
import { CreditCard as CreditCard2 } from "lucide-react";
|
|
11549
|
+
import { useEffect as useEffect42, useState as useState52 } from "react";
|
|
11550
|
+
|
|
11551
|
+
// src/features/billing/stripe-customer/components/forms/PaymentMethodEditor.tsx
|
|
11552
|
+
import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
|
|
11553
|
+
import { useEffect as useEffect40, useState as useState50 } from "react";
|
|
11554
|
+
import { jsx as jsx149, jsxs as jsxs91 } from "react/jsx-runtime";
|
|
11555
|
+
function PaymentMethodEditor({ open, onOpenChange, onSuccess }) {
|
|
11556
|
+
const stripe = useStripe();
|
|
11557
|
+
const elements = useElements();
|
|
11558
|
+
const [setupIntent, setSetupIntent] = useState50(null);
|
|
11559
|
+
const [loading, setLoading] = useState50(true);
|
|
11560
|
+
const [isSubmitting, setIsSubmitting] = useState50(false);
|
|
11561
|
+
const [error, setError] = useState50(null);
|
|
11562
|
+
const [setAsDefault, setSetAsDefault] = useState50(true);
|
|
11563
|
+
useEffect40(() => {
|
|
11564
|
+
const fetchSetupIntent = /* @__PURE__ */ __name(async () => {
|
|
11565
|
+
setLoading(true);
|
|
11566
|
+
try {
|
|
11567
|
+
const intent = await StripeCustomerService.createSetupIntent();
|
|
11568
|
+
setSetupIntent(intent);
|
|
11569
|
+
} catch (err) {
|
|
11570
|
+
console.error("[PaymentMethodEditor] Failed to create setup intent:", err);
|
|
11571
|
+
setError("Failed to initialize payment form. Please try again.");
|
|
11572
|
+
} finally {
|
|
11573
|
+
setLoading(false);
|
|
11574
|
+
}
|
|
11575
|
+
}, "fetchSetupIntent");
|
|
11576
|
+
if (open) {
|
|
11577
|
+
fetchSetupIntent();
|
|
11578
|
+
}
|
|
11579
|
+
}, [open]);
|
|
11580
|
+
const handleSubmit = /* @__PURE__ */ __name(async (e) => {
|
|
11581
|
+
e.preventDefault();
|
|
11582
|
+
if (!stripe || !elements || !setupIntent) {
|
|
11583
|
+
return;
|
|
11584
|
+
}
|
|
11585
|
+
setIsSubmitting(true);
|
|
11586
|
+
setError(null);
|
|
11587
|
+
try {
|
|
11588
|
+
const cardElement = elements.getElement(CardElement);
|
|
11589
|
+
if (!cardElement) {
|
|
11590
|
+
throw new Error("Card element not found");
|
|
11591
|
+
}
|
|
11592
|
+
const { error: stripeError, setupIntent: confirmedSetupIntent } = await stripe.confirmCardSetup(
|
|
11593
|
+
setupIntent.clientSecret,
|
|
11594
|
+
{
|
|
11595
|
+
payment_method: {
|
|
11596
|
+
card: cardElement
|
|
11597
|
+
}
|
|
11598
|
+
}
|
|
11599
|
+
);
|
|
11600
|
+
if (stripeError) {
|
|
11601
|
+
console.error("[PaymentMethodEditor] Stripe error:", stripeError);
|
|
11602
|
+
setError(stripeError.message || "Failed to add payment method. Please check your card details.");
|
|
11603
|
+
setIsSubmitting(false);
|
|
11604
|
+
return;
|
|
11605
|
+
}
|
|
11606
|
+
if (setAsDefault && confirmedSetupIntent?.payment_method) {
|
|
11607
|
+
await StripeCustomerService.setDefaultPaymentMethod({
|
|
11608
|
+
paymentMethodId: typeof confirmedSetupIntent.payment_method === "string" ? confirmedSetupIntent.payment_method : confirmedSetupIntent.payment_method.id
|
|
11609
|
+
});
|
|
11610
|
+
}
|
|
11611
|
+
onSuccess();
|
|
11612
|
+
onOpenChange(false);
|
|
11613
|
+
} catch (err) {
|
|
11614
|
+
console.error("[PaymentMethodEditor] Error:", err);
|
|
11615
|
+
setError(err.message || "An unexpected error occurred. Please try again.");
|
|
11616
|
+
} finally {
|
|
11617
|
+
setIsSubmitting(false);
|
|
11618
|
+
}
|
|
11619
|
+
}, "handleSubmit");
|
|
11620
|
+
return /* @__PURE__ */ jsx149(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs91(DialogContent, { className: "max-w-md", children: [
|
|
11621
|
+
/* @__PURE__ */ jsxs91(DialogHeader, { children: [
|
|
11622
|
+
/* @__PURE__ */ jsx149(DialogTitle, { children: "Add Payment Method" }),
|
|
11623
|
+
/* @__PURE__ */ jsx149(DialogDescription, { children: "Add a new payment method to your account. Your card information is securely processed by Stripe." })
|
|
11624
|
+
] }),
|
|
11625
|
+
loading && /* @__PURE__ */ jsx149("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx149("p", { className: "text-muted-foreground", children: "Loading payment form..." }) }),
|
|
11626
|
+
!loading && setupIntent && /* @__PURE__ */ jsxs91("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
|
|
11627
|
+
/* @__PURE__ */ jsx149("div", { className: "rounded-md border border-gray-300 p-3", children: /* @__PURE__ */ jsx149(
|
|
11628
|
+
CardElement,
|
|
11629
|
+
{
|
|
11630
|
+
options: {
|
|
11631
|
+
style: {
|
|
11632
|
+
base: {
|
|
11633
|
+
fontSize: "16px",
|
|
11634
|
+
color: "#424770",
|
|
11635
|
+
"::placeholder": {
|
|
11636
|
+
color: "#aab7c4"
|
|
11637
|
+
}
|
|
11638
|
+
},
|
|
11639
|
+
invalid: {
|
|
11640
|
+
color: "#9e2146"
|
|
11641
|
+
}
|
|
11642
|
+
}
|
|
11643
|
+
}
|
|
11644
|
+
}
|
|
11645
|
+
) }),
|
|
11646
|
+
/* @__PURE__ */ jsxs91("div", { className: "flex items-center gap-x-2", children: [
|
|
11647
|
+
/* @__PURE__ */ jsx149(
|
|
11648
|
+
Checkbox,
|
|
11649
|
+
{
|
|
11650
|
+
id: "setAsDefault",
|
|
11651
|
+
checked: setAsDefault,
|
|
11652
|
+
onCheckedChange: (checked) => setSetAsDefault(!!checked)
|
|
11653
|
+
}
|
|
11654
|
+
),
|
|
11655
|
+
/* @__PURE__ */ jsx149(Label3, { htmlFor: "setAsDefault", className: "text-sm font-normal", children: "Set as default payment method" })
|
|
11656
|
+
] }),
|
|
11657
|
+
error && /* @__PURE__ */ jsx149(Alert, { variant: "destructive", className: "bg-red-50 border-red-200", children: /* @__PURE__ */ jsx149(AlertDescription, { children: error }) }),
|
|
11658
|
+
/* @__PURE__ */ jsxs91("div", { className: "flex justify-end gap-x-2", children: [
|
|
11659
|
+
/* @__PURE__ */ jsx149(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Cancel" }),
|
|
11660
|
+
/* @__PURE__ */ jsx149(Button, { type: "submit", disabled: !stripe || isSubmitting, children: isSubmitting ? "Processing..." : "Add Card" })
|
|
11661
|
+
] })
|
|
11662
|
+
] }),
|
|
11663
|
+
!loading && !setupIntent && error && /* @__PURE__ */ jsx149(Alert, { variant: "destructive", className: "bg-red-50 border-red-200", children: /* @__PURE__ */ jsx149(AlertDescription, { children: error }) })
|
|
11664
|
+
] }) });
|
|
11665
|
+
}
|
|
11666
|
+
__name(PaymentMethodEditor, "PaymentMethodEditor");
|
|
11667
|
+
|
|
11668
|
+
// src/features/billing/stripe-customer/components/details/PaymentMethodCard.tsx
|
|
11669
|
+
import { MoreVertical } from "lucide-react";
|
|
11670
|
+
import { useEffect as useEffect41, useState as useState51 } from "react";
|
|
11671
|
+
import { Fragment as Fragment28, jsx as jsx150, jsxs as jsxs92 } from "react/jsx-runtime";
|
|
11672
|
+
var brandIcons = {
|
|
11673
|
+
visa: "\u{1F4B3}",
|
|
11674
|
+
mastercard: "\u{1F4B3}",
|
|
11675
|
+
amex: "\u{1F4B3}",
|
|
11676
|
+
discover: "\u{1F4B3}"
|
|
11677
|
+
};
|
|
11678
|
+
function PaymentMethodCard({ paymentMethod, onUpdate }) {
|
|
11679
|
+
const [loading, setLoading] = useState51(false);
|
|
11680
|
+
const [customer, setCustomer] = useState51(null);
|
|
11681
|
+
const [showRemoveDialog, setShowRemoveDialog] = useState51(false);
|
|
11682
|
+
useEffect41(() => {
|
|
11683
|
+
const loadCustomer = /* @__PURE__ */ __name(async () => {
|
|
11684
|
+
try {
|
|
11685
|
+
const fetchedCustomer = await StripeCustomerService.getCustomer();
|
|
11686
|
+
setCustomer(fetchedCustomer);
|
|
11687
|
+
} catch (error) {
|
|
11688
|
+
console.error("[PaymentMethodCard] Failed to load customer:", error);
|
|
11689
|
+
}
|
|
11690
|
+
}, "loadCustomer");
|
|
11691
|
+
loadCustomer();
|
|
11692
|
+
}, []);
|
|
11693
|
+
const isDefault = customer?.defaultPaymentMethodId === paymentMethod.id;
|
|
11694
|
+
const brand = paymentMethod.card?.brand || "card";
|
|
11695
|
+
const last4 = paymentMethod.card?.last4 || "****";
|
|
11696
|
+
const expMonth = paymentMethod.card?.expMonth || 0;
|
|
11697
|
+
const expYear = paymentMethod.card?.expYear || 0;
|
|
11698
|
+
const brandIcon = brandIcons[brand.toLowerCase()] || "\u{1F4B3}";
|
|
11699
|
+
const handleSetDefault = /* @__PURE__ */ __name(async () => {
|
|
11700
|
+
setLoading(true);
|
|
11701
|
+
try {
|
|
11702
|
+
await StripeCustomerService.setDefaultPaymentMethod({ paymentMethodId: paymentMethod.id });
|
|
11703
|
+
onUpdate();
|
|
11704
|
+
} catch (error) {
|
|
11705
|
+
console.error("[PaymentMethodCard] Failed to set as default:", error);
|
|
11706
|
+
} finally {
|
|
11707
|
+
setLoading(false);
|
|
11708
|
+
}
|
|
11709
|
+
}, "handleSetDefault");
|
|
11710
|
+
const handleRemove = /* @__PURE__ */ __name(async () => {
|
|
11711
|
+
setLoading(true);
|
|
11712
|
+
try {
|
|
11713
|
+
await StripeCustomerService.removePaymentMethod({ paymentMethodId: paymentMethod.id });
|
|
11714
|
+
setShowRemoveDialog(false);
|
|
11715
|
+
onUpdate();
|
|
11716
|
+
} catch (error) {
|
|
11717
|
+
console.error("[PaymentMethodCard] Failed to remove:", error);
|
|
11718
|
+
setLoading(false);
|
|
11719
|
+
}
|
|
11720
|
+
}, "handleRemove");
|
|
11721
|
+
return /* @__PURE__ */ jsxs92(Fragment28, { children: [
|
|
11722
|
+
/* @__PURE__ */ jsxs92(Card, { className: "relative", children: [
|
|
11723
|
+
isDefault && /* @__PURE__ */ jsx150(Badge, { className: "absolute right-2 top-2 bg-green-100 text-green-800 hover:bg-green-100", children: "Default" }),
|
|
11724
|
+
/* @__PURE__ */ jsxs92(CardHeader, { className: "flex flex-row items-center justify-between pb-2", children: [
|
|
11725
|
+
/* @__PURE__ */ jsxs92("div", { className: "flex items-center gap-x-2", children: [
|
|
11726
|
+
/* @__PURE__ */ jsx150("span", { className: "text-2xl", children: brandIcon }),
|
|
11727
|
+
/* @__PURE__ */ jsx150("span", { className: "text-sm font-medium capitalize", children: brand })
|
|
11728
|
+
] }),
|
|
11729
|
+
/* @__PURE__ */ jsxs92(DropdownMenu, { children: [
|
|
11730
|
+
/* @__PURE__ */ jsx150(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx150(Button, { variant: "ghost", size: "sm", disabled: loading, className: "h-8 w-8 p-0", children: /* @__PURE__ */ jsx150(MoreVertical, { className: "h-4 w-4" }) }) }),
|
|
11731
|
+
/* @__PURE__ */ jsxs92(DropdownMenuContent, { align: "end", children: [
|
|
11732
|
+
!isDefault && /* @__PURE__ */ jsx150(DropdownMenuItem, { onClick: handleSetDefault, disabled: loading, children: "Set as Default" }),
|
|
11733
|
+
/* @__PURE__ */ jsx150(DropdownMenuItem, { onClick: () => setShowRemoveDialog(true), disabled: loading, className: "text-red-600", children: "Remove" })
|
|
11734
|
+
] })
|
|
11735
|
+
] })
|
|
11736
|
+
] }),
|
|
11737
|
+
/* @__PURE__ */ jsx150(CardContent, { children: /* @__PURE__ */ jsxs92("div", { className: "flex flex-col gap-y-1", children: [
|
|
11738
|
+
/* @__PURE__ */ jsxs92("p", { className: "text-lg font-semibold", children: [
|
|
11739
|
+
"\u2022\u2022\u2022\u2022 ",
|
|
11740
|
+
last4
|
|
11741
|
+
] }),
|
|
11742
|
+
/* @__PURE__ */ jsxs92("p", { className: "text-sm text-muted-foreground", children: [
|
|
11743
|
+
"Expires ",
|
|
11744
|
+
String(expMonth).padStart(2, "0"),
|
|
11745
|
+
"/",
|
|
11746
|
+
expYear
|
|
11747
|
+
] })
|
|
11748
|
+
] }) })
|
|
11749
|
+
] }),
|
|
11750
|
+
/* @__PURE__ */ jsx150(AlertDialog, { open: showRemoveDialog, onOpenChange: setShowRemoveDialog, children: /* @__PURE__ */ jsxs92(AlertDialogContent, { children: [
|
|
11751
|
+
/* @__PURE__ */ jsxs92(AlertDialogHeader, { children: [
|
|
11752
|
+
/* @__PURE__ */ jsx150(AlertDialogTitle, { children: "Remove Payment Method" }),
|
|
11753
|
+
/* @__PURE__ */ jsxs92(AlertDialogDescription, { children: [
|
|
11754
|
+
"Are you sure you want to remove this payment method? This action cannot be undone.",
|
|
11755
|
+
isDefault && " This is your default payment method."
|
|
11756
|
+
] })
|
|
11757
|
+
] }),
|
|
11758
|
+
/* @__PURE__ */ jsxs92(AlertDialogFooter, { children: [
|
|
11759
|
+
/* @__PURE__ */ jsx150(AlertDialogCancel, { disabled: loading, children: "Cancel" }),
|
|
11760
|
+
/* @__PURE__ */ jsx150(AlertDialogAction, { onClick: handleRemove, disabled: loading, className: "bg-red-600 hover:bg-red-700", children: loading ? "Removing..." : "Remove" })
|
|
11761
|
+
] })
|
|
11762
|
+
] }) })
|
|
11763
|
+
] });
|
|
11764
|
+
}
|
|
11765
|
+
__name(PaymentMethodCard, "PaymentMethodCard");
|
|
11766
|
+
|
|
11767
|
+
// src/features/billing/stripe-customer/components/lists/PaymentMethodsList.tsx
|
|
11768
|
+
import { jsx as jsx151 } from "react/jsx-runtime";
|
|
11769
|
+
function PaymentMethodsList({ paymentMethods, onUpdate }) {
|
|
11770
|
+
return /* @__PURE__ */ jsx151("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3", children: paymentMethods.map((paymentMethod) => /* @__PURE__ */ jsx151(PaymentMethodCard, { paymentMethod, onUpdate }, paymentMethod.id)) });
|
|
11771
|
+
}
|
|
11772
|
+
__name(PaymentMethodsList, "PaymentMethodsList");
|
|
11773
|
+
|
|
11774
|
+
// src/features/billing/stripe-customer/components/containers/PaymentMethodsContainer.tsx
|
|
11775
|
+
import { jsx as jsx152, jsxs as jsxs93 } from "react/jsx-runtime";
|
|
11776
|
+
function PaymentMethodsContainer() {
|
|
11777
|
+
const [paymentMethods, setPaymentMethods] = useState52([]);
|
|
11778
|
+
const [loading, setLoading] = useState52(true);
|
|
11779
|
+
const [showAddPaymentMethod, setShowAddPaymentMethod] = useState52(false);
|
|
11780
|
+
const loadPaymentMethods = /* @__PURE__ */ __name(async () => {
|
|
11781
|
+
setLoading(true);
|
|
11782
|
+
try {
|
|
11783
|
+
const fetchedPaymentMethods = await StripeCustomerService.listPaymentMethods();
|
|
11784
|
+
setPaymentMethods(fetchedPaymentMethods);
|
|
11785
|
+
} catch (error) {
|
|
11786
|
+
console.error("[PaymentMethodsContainer] Failed to load payment methods:", error);
|
|
11787
|
+
} finally {
|
|
11788
|
+
setLoading(false);
|
|
11789
|
+
}
|
|
11790
|
+
}, "loadPaymentMethods");
|
|
11791
|
+
useEffect42(() => {
|
|
11792
|
+
loadPaymentMethods();
|
|
11793
|
+
}, []);
|
|
11794
|
+
if (loading) {
|
|
11795
|
+
return /* @__PURE__ */ jsx152("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx152("p", { className: "text-muted-foreground", children: "Loading payment methods..." }) });
|
|
11796
|
+
}
|
|
11797
|
+
return /* @__PURE__ */ jsxs93("div", { className: "flex w-full flex-col gap-y-6", children: [
|
|
11798
|
+
/* @__PURE__ */ jsxs93("div", { className: "flex items-center justify-between", children: [
|
|
11799
|
+
/* @__PURE__ */ jsxs93("div", { className: "flex items-center gap-x-3", children: [
|
|
11800
|
+
/* @__PURE__ */ jsx152(CreditCard2, { className: "h-8 w-8" }),
|
|
11801
|
+
/* @__PURE__ */ jsx152("h1", { className: "text-3xl font-bold", children: "Payment Methods" })
|
|
11802
|
+
] }),
|
|
11803
|
+
/* @__PURE__ */ jsx152(Button, { onClick: () => setShowAddPaymentMethod(true), children: "Add Payment Method" })
|
|
11804
|
+
] }),
|
|
11805
|
+
paymentMethods.length === 0 && /* @__PURE__ */ jsxs93("div", { className: "flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed border-gray-300 bg-muted/50 p-12", children: [
|
|
11806
|
+
/* @__PURE__ */ jsx152(CreditCard2, { className: "h-16 w-16 text-muted-foreground" }),
|
|
11807
|
+
/* @__PURE__ */ jsxs93("div", { className: "text-center", children: [
|
|
11808
|
+
/* @__PURE__ */ jsx152("h3", { className: "mb-2 text-xl font-semibold", children: "No payment methods" }),
|
|
11809
|
+
/* @__PURE__ */ jsx152("p", { className: "mb-4 text-muted-foreground", children: "Add a payment method to enable subscriptions and secure checkout." }),
|
|
11810
|
+
/* @__PURE__ */ jsx152(Button, { onClick: () => setShowAddPaymentMethod(true), children: "Add Your First Card" })
|
|
11811
|
+
] })
|
|
11812
|
+
] }),
|
|
11813
|
+
paymentMethods.length > 0 && /* @__PURE__ */ jsx152(PaymentMethodsList, { paymentMethods, onUpdate: loadPaymentMethods }),
|
|
11814
|
+
showAddPaymentMethod && /* @__PURE__ */ jsx152(
|
|
11815
|
+
PaymentMethodEditor,
|
|
11816
|
+
{
|
|
11817
|
+
open: showAddPaymentMethod,
|
|
11818
|
+
onOpenChange: setShowAddPaymentMethod,
|
|
11819
|
+
onSuccess: loadPaymentMethods
|
|
11820
|
+
}
|
|
11821
|
+
)
|
|
11822
|
+
] });
|
|
11823
|
+
}
|
|
11824
|
+
__name(PaymentMethodsContainer, "PaymentMethodsContainer");
|
|
11825
|
+
|
|
11826
|
+
// src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx
|
|
11827
|
+
import { useEffect as useEffect43, useState as useState54 } from "react";
|
|
11828
|
+
|
|
11829
|
+
// src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx
|
|
11830
|
+
import { useState as useState53 } from "react";
|
|
11831
|
+
|
|
11832
|
+
// src/features/billing/components/utils/currency.ts
|
|
11833
|
+
function formatInterval(price) {
|
|
11834
|
+
if (price.priceType === "one_time" || !price.recurring) {
|
|
11835
|
+
return "one-time";
|
|
11836
|
+
}
|
|
11837
|
+
const { interval, intervalCount } = price.recurring;
|
|
11838
|
+
if (intervalCount === 1) {
|
|
11839
|
+
return `/${interval}`;
|
|
11840
|
+
}
|
|
11841
|
+
const pluralInterval = interval === "day" ? "days" : interval === "week" ? "weeks" : interval === "month" ? "months" : "years";
|
|
11842
|
+
return `/${intervalCount} ${pluralInterval}`;
|
|
11843
|
+
}
|
|
11844
|
+
__name(formatInterval, "formatInterval");
|
|
11845
|
+
function formatCurrency(amount, currency) {
|
|
11846
|
+
if (amount === void 0) return "$0.00";
|
|
11847
|
+
const dollars = amount / 100;
|
|
11848
|
+
try {
|
|
11849
|
+
return new Intl.NumberFormat("en-US", {
|
|
11850
|
+
style: "currency",
|
|
11851
|
+
currency: currency.toUpperCase(),
|
|
11852
|
+
minimumFractionDigits: 2,
|
|
11853
|
+
maximumFractionDigits: 2
|
|
11854
|
+
}).format(dollars);
|
|
11855
|
+
} catch (error) {
|
|
11856
|
+
console.error("Error formatting currency:", error);
|
|
11857
|
+
return `$${dollars.toFixed(2)}`;
|
|
11858
|
+
}
|
|
11859
|
+
}
|
|
11860
|
+
__name(formatCurrency, "formatCurrency");
|
|
11861
|
+
|
|
11862
|
+
// src/features/billing/components/utils/date.ts
|
|
11863
|
+
function formatDate3(date) {
|
|
11864
|
+
if (!date) return "N/A";
|
|
11865
|
+
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
11866
|
+
try {
|
|
11867
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
11868
|
+
month: "short",
|
|
11869
|
+
day: "numeric",
|
|
11870
|
+
year: "numeric"
|
|
11871
|
+
}).format(dateObj);
|
|
11872
|
+
} catch (error) {
|
|
11873
|
+
console.error("Error formatting date:", error);
|
|
11874
|
+
return "Invalid Date";
|
|
11875
|
+
}
|
|
11876
|
+
}
|
|
11877
|
+
__name(formatDate3, "formatDate");
|
|
11878
|
+
|
|
11879
|
+
// src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx
|
|
11880
|
+
import { Download, ExternalLink as ExternalLink2, RefreshCw as RefreshCw2 } from "lucide-react";
|
|
11881
|
+
|
|
11882
|
+
// src/features/billing/stripe-invoice/components/widgets/InvoiceStatusBadge.tsx
|
|
11883
|
+
import { jsx as jsx153 } from "react/jsx-runtime";
|
|
11884
|
+
var statusConfig = {
|
|
11885
|
+
["draft" /* DRAFT */]: {
|
|
11886
|
+
label: "Draft",
|
|
11887
|
+
color: "bg-gray-100 text-gray-800"
|
|
11888
|
+
},
|
|
11889
|
+
["open" /* OPEN */]: {
|
|
11890
|
+
label: "Open",
|
|
11891
|
+
color: "bg-blue-100 text-blue-800"
|
|
11892
|
+
},
|
|
11893
|
+
["paid" /* PAID */]: {
|
|
11894
|
+
label: "Paid",
|
|
11895
|
+
color: "bg-green-100 text-green-800"
|
|
11896
|
+
},
|
|
11897
|
+
["void" /* VOID */]: {
|
|
11898
|
+
label: "Void",
|
|
11899
|
+
color: "bg-gray-100 text-gray-800"
|
|
11900
|
+
},
|
|
11901
|
+
["uncollectible" /* UNCOLLECTIBLE */]: {
|
|
11902
|
+
label: "Uncollectible",
|
|
11903
|
+
color: "bg-red-100 text-red-800"
|
|
11904
|
+
}
|
|
11905
|
+
};
|
|
11906
|
+
function InvoiceStatusBadge({ status }) {
|
|
11907
|
+
const config = statusConfig[status] || statusConfig["draft" /* DRAFT */];
|
|
11908
|
+
return /* @__PURE__ */ jsx153("span", { className: `${config.color} text-xs px-2 py-1 rounded-full font-medium`, children: config.label });
|
|
11909
|
+
}
|
|
11910
|
+
__name(InvoiceStatusBadge, "InvoiceStatusBadge");
|
|
11911
|
+
|
|
11912
|
+
// src/features/billing/stripe-invoice/components/details/InvoiceDetails.tsx
|
|
11913
|
+
import { jsx as jsx154, jsxs as jsxs94 } from "react/jsx-runtime";
|
|
11914
|
+
function InvoiceDetails({ invoice, open, onOpenChange, onInvoiceChange }) {
|
|
11915
|
+
const handleDownloadPDF = /* @__PURE__ */ __name(() => {
|
|
11916
|
+
if (invoice.stripePdfUrl) {
|
|
11917
|
+
window.open(invoice.stripePdfUrl, "_blank");
|
|
11918
|
+
}
|
|
11919
|
+
}, "handleDownloadPDF");
|
|
11920
|
+
const handleRetryPayment = /* @__PURE__ */ __name(async () => {
|
|
11921
|
+
}, "handleRetryPayment");
|
|
11922
|
+
const handleViewInStripe = /* @__PURE__ */ __name(() => {
|
|
11923
|
+
if (invoice.stripeHostedInvoiceUrl) {
|
|
11924
|
+
window.open(invoice.stripeHostedInvoiceUrl, "_blank");
|
|
11925
|
+
}
|
|
11926
|
+
}, "handleViewInStripe");
|
|
11927
|
+
const getInvoiceNumber = /* @__PURE__ */ __name(() => {
|
|
11928
|
+
if (invoice.stripeInvoiceNumber) {
|
|
11929
|
+
return invoice.stripeInvoiceNumber;
|
|
11930
|
+
}
|
|
11931
|
+
return invoice.stripeInvoiceId.slice(-8);
|
|
11932
|
+
}, "getInvoiceNumber");
|
|
11933
|
+
const productName = invoice.subscription?.price?.product?.name || "Subscription";
|
|
11934
|
+
return /* @__PURE__ */ jsx154(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs94(DialogContent, { className: "max-w-2xl", children: [
|
|
11935
|
+
/* @__PURE__ */ jsxs94(DialogHeader, { children: [
|
|
11936
|
+
/* @__PURE__ */ jsxs94(DialogTitle, { children: [
|
|
11937
|
+
"Invoice ",
|
|
11938
|
+
getInvoiceNumber()
|
|
11939
|
+
] }),
|
|
11940
|
+
/* @__PURE__ */ jsx154(DialogDescription, { children: formatDate3(invoice.periodStart) })
|
|
11941
|
+
] }),
|
|
11942
|
+
/* @__PURE__ */ jsxs94("div", { className: "space-y-6", children: [
|
|
11943
|
+
/* @__PURE__ */ jsxs94("div", { className: "flex items-center gap-x-3", children: [
|
|
11944
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Status:" }),
|
|
11945
|
+
/* @__PURE__ */ jsx154(InvoiceStatusBadge, { status: invoice.status })
|
|
11946
|
+
] }),
|
|
11947
|
+
/* @__PURE__ */ jsxs94("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
11948
|
+
/* @__PURE__ */ jsxs94("div", { children: [
|
|
11949
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Billing Period:" }),
|
|
11950
|
+
/* @__PURE__ */ jsxs94("p", { className: "font-medium", children: [
|
|
11951
|
+
formatDate3(invoice.periodStart),
|
|
11952
|
+
" - ",
|
|
11953
|
+
formatDate3(invoice.periodEnd)
|
|
11954
|
+
] })
|
|
11955
|
+
] }),
|
|
11956
|
+
invoice.dueDate && /* @__PURE__ */ jsxs94("div", { children: [
|
|
11957
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Due Date:" }),
|
|
11958
|
+
/* @__PURE__ */ jsx154("p", { className: "font-medium", children: formatDate3(invoice.dueDate) })
|
|
11959
|
+
] }),
|
|
11960
|
+
invoice.paidAt && /* @__PURE__ */ jsxs94("div", { children: [
|
|
11961
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Paid Date:" }),
|
|
11962
|
+
/* @__PURE__ */ jsx154("p", { className: "font-medium", children: formatDate3(invoice.paidAt) })
|
|
11963
|
+
] }),
|
|
11964
|
+
/* @__PURE__ */ jsxs94("div", { children: [
|
|
11965
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Attempt Count:" }),
|
|
11966
|
+
/* @__PURE__ */ jsx154("p", { className: "font-medium", children: invoice.attemptCount })
|
|
11967
|
+
] })
|
|
11968
|
+
] }),
|
|
11969
|
+
/* @__PURE__ */ jsxs94("div", { children: [
|
|
11970
|
+
/* @__PURE__ */ jsx154("h4", { className: "text-sm font-medium text-muted-foreground mb-2", children: "Line Items" }),
|
|
11971
|
+
/* @__PURE__ */ jsx154("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs94("table", { className: "w-full", children: [
|
|
11972
|
+
/* @__PURE__ */ jsx154("thead", { className: "bg-muted", children: /* @__PURE__ */ jsxs94("tr", { children: [
|
|
11973
|
+
/* @__PURE__ */ jsx154("th", { className: "text-left p-3 text-sm font-medium", children: "Description" }),
|
|
11974
|
+
/* @__PURE__ */ jsx154("th", { className: "text-right p-3 text-sm font-medium", children: "Amount" })
|
|
11975
|
+
] }) }),
|
|
11976
|
+
/* @__PURE__ */ jsx154("tbody", { children: /* @__PURE__ */ jsxs94("tr", { className: "border-t", children: [
|
|
11977
|
+
/* @__PURE__ */ jsx154("td", { className: "p-3", children: productName }),
|
|
11978
|
+
/* @__PURE__ */ jsx154("td", { className: "p-3 text-right", children: formatCurrency(invoice.subtotal, invoice.currency) })
|
|
11979
|
+
] }) })
|
|
11980
|
+
] }) })
|
|
11981
|
+
] }),
|
|
11982
|
+
/* @__PURE__ */ jsxs94("div", { className: "space-y-2 border-t pt-4", children: [
|
|
11983
|
+
/* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
|
|
11984
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Subtotal:" }),
|
|
11985
|
+
/* @__PURE__ */ jsx154("span", { className: "font-medium", children: formatCurrency(invoice.subtotal, invoice.currency) })
|
|
11986
|
+
] }),
|
|
11987
|
+
invoice.tax !== void 0 && invoice.tax > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
|
|
11988
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Tax:" }),
|
|
11989
|
+
/* @__PURE__ */ jsx154("span", { className: "font-medium", children: formatCurrency(invoice.tax, invoice.currency) })
|
|
11990
|
+
] }),
|
|
11991
|
+
/* @__PURE__ */ jsxs94("div", { className: "flex justify-between text-lg font-semibold border-t pt-2", children: [
|
|
11992
|
+
/* @__PURE__ */ jsx154("span", { children: "Total:" }),
|
|
11993
|
+
/* @__PURE__ */ jsx154("span", { children: formatCurrency(invoice.total, invoice.currency) })
|
|
11994
|
+
] }),
|
|
11995
|
+
invoice.amountPaid > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
|
|
11996
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Amount Paid:" }),
|
|
11997
|
+
/* @__PURE__ */ jsx154("span", { className: "font-medium text-green-600", children: formatCurrency(invoice.amountPaid, invoice.currency) })
|
|
11998
|
+
] }),
|
|
11999
|
+
invoice.amountRemaining > 0 && /* @__PURE__ */ jsxs94("div", { className: "flex justify-between", children: [
|
|
12000
|
+
/* @__PURE__ */ jsx154("span", { className: "text-sm font-medium text-muted-foreground", children: "Amount Due:" }),
|
|
12001
|
+
/* @__PURE__ */ jsx154("span", { className: "font-medium text-red-600", children: formatCurrency(invoice.amountRemaining, invoice.currency) })
|
|
12002
|
+
] })
|
|
12003
|
+
] }),
|
|
12004
|
+
/* @__PURE__ */ jsxs94("div", { className: "flex flex-wrap gap-2 pt-4 border-t", children: [
|
|
12005
|
+
invoice.stripePdfUrl && /* @__PURE__ */ jsxs94(Button, { variant: "outline", onClick: handleDownloadPDF, children: [
|
|
12006
|
+
/* @__PURE__ */ jsx154(Download, { className: "mr-2 h-4 w-4" }),
|
|
12007
|
+
"Download PDF"
|
|
12008
|
+
] }),
|
|
12009
|
+
invoice.status === "open" /* OPEN */ && invoice.attempted && /* @__PURE__ */ jsxs94(Button, { variant: "default", onClick: handleRetryPayment, children: [
|
|
12010
|
+
/* @__PURE__ */ jsx154(RefreshCw2, { className: "mr-2 h-4 w-4" }),
|
|
12011
|
+
"Retry Payment"
|
|
12012
|
+
] }),
|
|
12013
|
+
invoice.stripeHostedInvoiceUrl && /* @__PURE__ */ jsxs94(Button, { variant: "outline", onClick: handleViewInStripe, children: [
|
|
12014
|
+
/* @__PURE__ */ jsx154(ExternalLink2, { className: "mr-2 h-4 w-4" }),
|
|
12015
|
+
"View in Stripe"
|
|
12016
|
+
] })
|
|
12017
|
+
] })
|
|
12018
|
+
] })
|
|
12019
|
+
] }) });
|
|
12020
|
+
}
|
|
12021
|
+
__name(InvoiceDetails, "InvoiceDetails");
|
|
12022
|
+
|
|
12023
|
+
// src/features/billing/stripe-invoice/components/lists/InvoicesList.tsx
|
|
12024
|
+
import { Fragment as Fragment29, jsx as jsx155, jsxs as jsxs95 } from "react/jsx-runtime";
|
|
12025
|
+
function InvoicesList({ invoices, onInvoicesChange }) {
|
|
12026
|
+
const [selectedInvoice, setSelectedInvoice] = useState53(null);
|
|
12027
|
+
const handleRowClick = /* @__PURE__ */ __name((invoice) => {
|
|
12028
|
+
setSelectedInvoice(invoice);
|
|
12029
|
+
}, "handleRowClick");
|
|
12030
|
+
const getInvoiceNumber = /* @__PURE__ */ __name((invoice) => {
|
|
12031
|
+
if (invoice.stripeInvoiceNumber) {
|
|
12032
|
+
return invoice.stripeInvoiceNumber;
|
|
12033
|
+
}
|
|
12034
|
+
return invoice.stripeInvoiceId.slice(-8);
|
|
12035
|
+
}, "getInvoiceNumber");
|
|
12036
|
+
return /* @__PURE__ */ jsxs95(Fragment29, { children: [
|
|
12037
|
+
/* @__PURE__ */ jsx155("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs95(Table, { children: [
|
|
12038
|
+
/* @__PURE__ */ jsx155(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs95(TableRow, { children: [
|
|
12039
|
+
/* @__PURE__ */ jsx155(TableHead, { children: "Invoice #" }),
|
|
12040
|
+
/* @__PURE__ */ jsx155(TableHead, { children: "Date" }),
|
|
12041
|
+
/* @__PURE__ */ jsx155(TableHead, { children: "Status" }),
|
|
12042
|
+
/* @__PURE__ */ jsx155(TableHead, { className: "text-right", children: "Amount" }),
|
|
12043
|
+
/* @__PURE__ */ jsx155(TableHead, { children: "Period" })
|
|
12044
|
+
] }) }),
|
|
12045
|
+
/* @__PURE__ */ jsx155(TableBody, { children: invoices.map((invoice) => {
|
|
12046
|
+
const invoiceNumber = getInvoiceNumber(invoice);
|
|
12047
|
+
const date = formatDate3(invoice.periodStart);
|
|
12048
|
+
const amount = formatCurrency(invoice.total, invoice.currency);
|
|
12049
|
+
const period = `${formatDate3(invoice.periodStart)} - ${formatDate3(invoice.periodEnd)}`;
|
|
12050
|
+
return /* @__PURE__ */ jsxs95(
|
|
12051
|
+
TableRow,
|
|
12052
|
+
{
|
|
12053
|
+
onClick: () => handleRowClick(invoice),
|
|
12054
|
+
className: "cursor-pointer hover:bg-muted/50",
|
|
12055
|
+
children: [
|
|
12056
|
+
/* @__PURE__ */ jsx155(TableCell, { className: "font-medium", children: invoiceNumber }),
|
|
12057
|
+
/* @__PURE__ */ jsx155(TableCell, { className: "text-muted-foreground text-sm", children: date }),
|
|
12058
|
+
/* @__PURE__ */ jsx155(TableCell, { children: /* @__PURE__ */ jsx155(InvoiceStatusBadge, { status: invoice.status }) }),
|
|
12059
|
+
/* @__PURE__ */ jsx155(TableCell, { className: "text-right font-medium", children: amount }),
|
|
12060
|
+
/* @__PURE__ */ jsx155(TableCell, { className: "text-muted-foreground text-sm", children: period })
|
|
12061
|
+
]
|
|
12062
|
+
},
|
|
12063
|
+
invoice.id
|
|
12064
|
+
);
|
|
12065
|
+
}) })
|
|
12066
|
+
] }) }),
|
|
12067
|
+
selectedInvoice && /* @__PURE__ */ jsx155(
|
|
12068
|
+
InvoiceDetails,
|
|
12069
|
+
{
|
|
12070
|
+
invoice: selectedInvoice,
|
|
12071
|
+
open: !!selectedInvoice,
|
|
12072
|
+
onOpenChange: (open) => !open && setSelectedInvoice(null),
|
|
12073
|
+
onInvoiceChange: () => {
|
|
12074
|
+
onInvoicesChange();
|
|
12075
|
+
setSelectedInvoice(null);
|
|
12076
|
+
}
|
|
12077
|
+
}
|
|
12078
|
+
)
|
|
12079
|
+
] });
|
|
12080
|
+
}
|
|
12081
|
+
__name(InvoicesList, "InvoicesList");
|
|
12082
|
+
|
|
12083
|
+
// src/features/billing/stripe-invoice/components/containers/InvoicesContainer.tsx
|
|
12084
|
+
import { jsx as jsx156, jsxs as jsxs96 } from "react/jsx-runtime";
|
|
12085
|
+
function InvoicesContainer() {
|
|
12086
|
+
const [invoices, setInvoices] = useState54([]);
|
|
12087
|
+
const [loading, setLoading] = useState54(true);
|
|
12088
|
+
const [statusFilter, setStatusFilter] = useState54("all");
|
|
12089
|
+
const loadInvoices = /* @__PURE__ */ __name(async () => {
|
|
12090
|
+
setLoading(true);
|
|
12091
|
+
try {
|
|
12092
|
+
const params = statusFilter !== "all" ? { status: statusFilter } : void 0;
|
|
12093
|
+
const data = await StripeInvoiceService.listInvoices(params);
|
|
12094
|
+
setInvoices(data);
|
|
12095
|
+
} catch (error) {
|
|
12096
|
+
console.error("[InvoicesContainer] Failed to load invoices:", error);
|
|
12097
|
+
setInvoices([]);
|
|
12098
|
+
} finally {
|
|
12099
|
+
setLoading(false);
|
|
12100
|
+
}
|
|
12101
|
+
}, "loadInvoices");
|
|
12102
|
+
useEffect43(() => {
|
|
12103
|
+
loadInvoices();
|
|
12104
|
+
}, [statusFilter]);
|
|
12105
|
+
const handleFilterChange = /* @__PURE__ */ __name((value) => {
|
|
12106
|
+
setStatusFilter(value);
|
|
12107
|
+
}, "handleFilterChange");
|
|
12108
|
+
return /* @__PURE__ */ jsxs96("div", { className: "space-y-4", children: [
|
|
12109
|
+
/* @__PURE__ */ jsx156(Tabs, { value: statusFilter, onValueChange: handleFilterChange, children: /* @__PURE__ */ jsxs96(TabsList, { children: [
|
|
12110
|
+
/* @__PURE__ */ jsx156(TabsTrigger, { value: "all", children: "All" }),
|
|
12111
|
+
/* @__PURE__ */ jsx156(TabsTrigger, { value: "paid" /* PAID */, children: "Paid" }),
|
|
12112
|
+
/* @__PURE__ */ jsx156(TabsTrigger, { value: "open" /* OPEN */, children: "Open" }),
|
|
12113
|
+
/* @__PURE__ */ jsx156(TabsTrigger, { value: "void" /* VOID */, children: "Void" }),
|
|
12114
|
+
/* @__PURE__ */ jsx156(TabsTrigger, { value: "uncollectible" /* UNCOLLECTIBLE */, children: "Uncollectible" })
|
|
12115
|
+
] }) }),
|
|
12116
|
+
loading && /* @__PURE__ */ jsx156("div", { className: "text-center py-8 text-muted-foreground", children: "Loading invoices..." }),
|
|
12117
|
+
!loading && invoices.length === 0 && /* @__PURE__ */ jsxs96("div", { className: "border border-dashed border-gray-300 rounded-lg p-8 text-center", children: [
|
|
12118
|
+
/* @__PURE__ */ jsx156("p", { className: "text-lg font-medium text-muted-foreground mb-2", children: "No invoices yet" }),
|
|
12119
|
+
/* @__PURE__ */ jsx156("p", { className: "text-sm text-muted-foreground", children: "Invoices will appear here after your first billing cycle" })
|
|
12120
|
+
] }),
|
|
12121
|
+
!loading && invoices.length > 0 && /* @__PURE__ */ jsx156(InvoicesList, { invoices, onInvoicesChange: loadInvoices })
|
|
12122
|
+
] });
|
|
12123
|
+
}
|
|
12124
|
+
__name(InvoicesContainer, "InvoicesContainer");
|
|
12125
|
+
|
|
12126
|
+
// src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx
|
|
12127
|
+
import { CheckCircle as CheckCircle2, CreditCard as CreditCard3, Loader2 as Loader23 } from "lucide-react";
|
|
12128
|
+
import { useEffect as useEffect45, useState as useState60 } from "react";
|
|
12129
|
+
import { v4 as v46 } from "uuid";
|
|
12130
|
+
|
|
12131
|
+
// src/features/billing/stripe-subscription/hooks/useConfirmSubscriptionPayment.ts
|
|
12132
|
+
import { useStripe as useStripe2 } from "@stripe/react-stripe-js";
|
|
12133
|
+
import { useCallback as useCallback17, useState as useState55 } from "react";
|
|
12134
|
+
function useConfirmSubscriptionPayment() {
|
|
12135
|
+
const stripe = useStripe2();
|
|
12136
|
+
const [isConfirming, setIsConfirming] = useState55(false);
|
|
12137
|
+
const confirmPayment = useCallback17(
|
|
12138
|
+
async (clientSecret) => {
|
|
12139
|
+
if (!stripe) {
|
|
12140
|
+
console.error("[useConfirmSubscriptionPayment] Stripe not initialized");
|
|
12141
|
+
return {
|
|
12142
|
+
success: false,
|
|
12143
|
+
error: "Payment system not initialized. Please refresh the page and try again."
|
|
12144
|
+
};
|
|
12145
|
+
}
|
|
12146
|
+
if (!clientSecret) {
|
|
12147
|
+
console.error("[useConfirmSubscriptionPayment] No client secret provided");
|
|
12148
|
+
return {
|
|
12149
|
+
success: false,
|
|
12150
|
+
error: "Payment confirmation failed. Missing payment details."
|
|
12151
|
+
};
|
|
12152
|
+
}
|
|
12153
|
+
setIsConfirming(true);
|
|
12154
|
+
try {
|
|
12155
|
+
const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(clientSecret);
|
|
12156
|
+
if (stripeError) {
|
|
12157
|
+
console.error("[useConfirmSubscriptionPayment] Stripe error:", stripeError);
|
|
12158
|
+
return {
|
|
12159
|
+
success: false,
|
|
12160
|
+
error: stripeError.message || "Payment confirmation failed. Please try again."
|
|
12161
|
+
};
|
|
12162
|
+
}
|
|
12163
|
+
if (paymentIntent?.status === "succeeded") {
|
|
12164
|
+
return { success: true };
|
|
12165
|
+
}
|
|
12166
|
+
if (paymentIntent?.status === "requires_action") {
|
|
12167
|
+
return {
|
|
12168
|
+
success: false,
|
|
12169
|
+
error: "Additional authentication required. Please complete the verification."
|
|
12170
|
+
};
|
|
12171
|
+
}
|
|
12172
|
+
return {
|
|
12173
|
+
success: false,
|
|
12174
|
+
error: "Payment could not be completed. Please try again."
|
|
12175
|
+
};
|
|
12176
|
+
} catch (err) {
|
|
12177
|
+
console.error("[useConfirmSubscriptionPayment] Unexpected error:", err);
|
|
12178
|
+
return {
|
|
12179
|
+
success: false,
|
|
12180
|
+
error: err.message || "An unexpected error occurred during payment confirmation."
|
|
12181
|
+
};
|
|
12182
|
+
} finally {
|
|
12183
|
+
setIsConfirming(false);
|
|
12184
|
+
}
|
|
12185
|
+
},
|
|
12186
|
+
[stripe]
|
|
12187
|
+
);
|
|
12188
|
+
return {
|
|
12189
|
+
confirmPayment,
|
|
12190
|
+
isConfirming
|
|
12191
|
+
};
|
|
12192
|
+
}
|
|
12193
|
+
__name(useConfirmSubscriptionPayment, "useConfirmSubscriptionPayment");
|
|
12194
|
+
|
|
12195
|
+
// src/features/billing/stripe-subscription/components/forms/CancelSubscriptionDialog.tsx
|
|
12196
|
+
import { zodResolver as zodResolver10 } from "@hookform/resolvers/zod";
|
|
12197
|
+
import { useState as useState56 } from "react";
|
|
12198
|
+
import { useForm as useForm10 } from "react-hook-form";
|
|
12199
|
+
import { z as z10 } from "zod";
|
|
12200
|
+
import { jsx as jsx157, jsxs as jsxs97 } from "react/jsx-runtime";
|
|
12201
|
+
var formSchema = z10.object({
|
|
12202
|
+
cancelImmediately: z10.boolean(),
|
|
12203
|
+
reason: z10.string().optional()
|
|
12204
|
+
});
|
|
12205
|
+
function CancelSubscriptionDialog({
|
|
12206
|
+
subscription,
|
|
12207
|
+
open,
|
|
12208
|
+
onOpenChange,
|
|
12209
|
+
onSuccess
|
|
12210
|
+
}) {
|
|
12211
|
+
const [isSubmitting, setIsSubmitting] = useState56(false);
|
|
12212
|
+
const form = useForm10({
|
|
12213
|
+
resolver: zodResolver10(formSchema),
|
|
12214
|
+
defaultValues: {
|
|
12215
|
+
cancelImmediately: false,
|
|
12216
|
+
reason: ""
|
|
12217
|
+
}
|
|
12218
|
+
});
|
|
12219
|
+
const cancelImmediately = form.watch("cancelImmediately");
|
|
12220
|
+
const onSubmit = /* @__PURE__ */ __name(async (values) => {
|
|
12221
|
+
setIsSubmitting(true);
|
|
12222
|
+
try {
|
|
12223
|
+
await StripeSubscriptionService.cancelSubscription({
|
|
12224
|
+
id: subscription.id,
|
|
12225
|
+
cancelImmediately: values.cancelImmediately
|
|
12226
|
+
});
|
|
12227
|
+
onSuccess();
|
|
12228
|
+
onOpenChange(false);
|
|
12229
|
+
} catch (error) {
|
|
12230
|
+
console.error("[CancelSubscriptionDialog] Failed to cancel subscription:", error);
|
|
12231
|
+
} finally {
|
|
12232
|
+
setIsSubmitting(false);
|
|
12233
|
+
}
|
|
12234
|
+
}, "onSubmit");
|
|
12235
|
+
const periodEndDate = formatDate3(subscription.currentPeriodEnd);
|
|
12236
|
+
return /* @__PURE__ */ jsx157(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs97(DialogContent, { className: "max-w-md", children: [
|
|
12237
|
+
/* @__PURE__ */ jsxs97(DialogHeader, { children: [
|
|
12238
|
+
/* @__PURE__ */ jsx157(DialogTitle, { children: "Cancel Subscription" }),
|
|
12239
|
+
/* @__PURE__ */ jsx157(DialogDescription, { children: "Are you sure you want to cancel this subscription? This action cannot be undone." })
|
|
12240
|
+
] }),
|
|
12241
|
+
/* @__PURE__ */ jsx157(Form, { ...form, children: /* @__PURE__ */ jsxs97("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
|
|
12242
|
+
/* @__PURE__ */ jsx157(FormCheckbox, { form, id: "cancelImmediately", name: "Cancel Immediately" }),
|
|
12243
|
+
cancelImmediately ? /* @__PURE__ */ jsx157("div", { className: "bg-red-50 border border-red-200 rounded-lg p-3 text-sm text-red-800", children: "Your subscription will be canceled immediately and you will lose access right away." }) : /* @__PURE__ */ jsxs97("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-3 text-sm text-blue-800", children: [
|
|
12244
|
+
"Your subscription will remain active until ",
|
|
12245
|
+
periodEndDate,
|
|
12246
|
+
". You can continue using the service until then."
|
|
12247
|
+
] }),
|
|
12248
|
+
/* @__PURE__ */ jsx157(
|
|
12249
|
+
FormTextarea,
|
|
12250
|
+
{
|
|
12251
|
+
form,
|
|
12252
|
+
id: "reason",
|
|
12253
|
+
name: "Reason (Optional)",
|
|
12254
|
+
placeholder: "Let us know why you're canceling...",
|
|
12255
|
+
className: "min-h-24"
|
|
12256
|
+
}
|
|
12257
|
+
),
|
|
12258
|
+
/* @__PURE__ */ jsxs97("div", { className: "flex gap-x-2 justify-end pt-2", children: [
|
|
12259
|
+
/* @__PURE__ */ jsx157(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Keep Subscription" }),
|
|
12260
|
+
/* @__PURE__ */ jsx157(Button, { type: "submit", variant: "destructive", disabled: isSubmitting, children: isSubmitting ? "Canceling..." : "Confirm Cancellation" })
|
|
12261
|
+
] })
|
|
12262
|
+
] }) })
|
|
12263
|
+
] }) });
|
|
12264
|
+
}
|
|
12265
|
+
__name(CancelSubscriptionDialog, "CancelSubscriptionDialog");
|
|
12266
|
+
|
|
12267
|
+
// src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx
|
|
12268
|
+
import { CheckCircle, Loader2 as Loader22 } from "lucide-react";
|
|
12269
|
+
import { useEffect as useEffect44, useState as useState57 } from "react";
|
|
12270
|
+
import { v4 as v45 } from "uuid";
|
|
12271
|
+
|
|
12272
|
+
// src/features/billing/stripe-subscription/components/widgets/PricingCard.tsx
|
|
12273
|
+
import { Check } from "lucide-react";
|
|
12274
|
+
import { jsx as jsx158, jsxs as jsxs98 } from "react/jsx-runtime";
|
|
12275
|
+
function PricingCard({ price, isCurrentPlan = false, isSelected = false, isDisabled = false, isLoading = false, onSelect }) {
|
|
12276
|
+
const description = price.description || price.nickname || "Standard";
|
|
12277
|
+
const features = price.features || [];
|
|
12278
|
+
const formattedPrice = formatCurrency(price.unitAmount, price.currency);
|
|
12279
|
+
const interval = formatInterval(price);
|
|
12280
|
+
const handleKeyDown = /* @__PURE__ */ __name((e) => {
|
|
12281
|
+
if ((e.key === "Enter" || e.key === " ") && !isDisabled && !isCurrentPlan) {
|
|
12282
|
+
e.preventDefault();
|
|
12283
|
+
onSelect(price);
|
|
12284
|
+
}
|
|
12285
|
+
}, "handleKeyDown");
|
|
12286
|
+
const handleClick = /* @__PURE__ */ __name(() => {
|
|
12287
|
+
if (!isDisabled && !isCurrentPlan && !isLoading) {
|
|
12288
|
+
onSelect(price);
|
|
12289
|
+
}
|
|
12290
|
+
}, "handleClick");
|
|
12291
|
+
return /* @__PURE__ */ jsxs98(
|
|
12292
|
+
Card,
|
|
12293
|
+
{
|
|
12294
|
+
role: "radio",
|
|
12295
|
+
"aria-checked": isSelected,
|
|
12296
|
+
"aria-label": `${description} plan at ${formattedPrice} ${interval}`,
|
|
12297
|
+
tabIndex: isDisabled ? -1 : 0,
|
|
12298
|
+
onKeyDown: handleKeyDown,
|
|
12299
|
+
onClick: handleClick,
|
|
12300
|
+
className: cn(
|
|
12301
|
+
"relative cursor-pointer transition-all duration-200 flex flex-col h-full",
|
|
12302
|
+
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
12303
|
+
isCurrentPlan && "bg-muted/30",
|
|
12304
|
+
isSelected && !isCurrentPlan && "ring-2 ring-primary",
|
|
12305
|
+
!isDisabled && !isCurrentPlan && "hover:shadow-md hover:border-primary/50",
|
|
12306
|
+
isDisabled && "opacity-50 pointer-events-none",
|
|
12307
|
+
isLoading && "pointer-events-none"
|
|
12308
|
+
),
|
|
12309
|
+
children: [
|
|
12310
|
+
isCurrentPlan && /* @__PURE__ */ jsx158(Badge, { variant: "secondary", className: "absolute top-2 right-2", children: "Current" }),
|
|
12311
|
+
/* @__PURE__ */ jsx158(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx158("h3", { className: "font-semibold text-lg", children: description }) }),
|
|
12312
|
+
/* @__PURE__ */ jsxs98(CardContent, { className: "pb-4 grow", children: [
|
|
12313
|
+
/* @__PURE__ */ jsxs98("div", { className: "mb-4", children: [
|
|
12314
|
+
/* @__PURE__ */ jsx158("span", { className: "text-3xl font-bold", children: formattedPrice }),
|
|
12315
|
+
/* @__PURE__ */ jsx158("span", { className: "text-muted-foreground ml-1", children: interval })
|
|
12316
|
+
] }),
|
|
12317
|
+
features.length > 0 && /* @__PURE__ */ jsx158("ul", { className: "space-y-2", children: features.map((feature, index) => /* @__PURE__ */ jsxs98("li", { className: "flex items-start gap-2", children: [
|
|
12318
|
+
/* @__PURE__ */ jsx158(Check, { className: "h-4 w-4 text-green-500 mt-0.5 shrink-0" }),
|
|
12319
|
+
/* @__PURE__ */ jsx158("span", { className: "text-sm text-muted-foreground", children: feature })
|
|
12320
|
+
] }, index)) })
|
|
12321
|
+
] }),
|
|
12322
|
+
/* @__PURE__ */ jsx158(CardFooter, { children: /* @__PURE__ */ jsx158(
|
|
12323
|
+
Button,
|
|
12324
|
+
{
|
|
12325
|
+
variant: isCurrentPlan ? "secondary" : isSelected ? "default" : "outline",
|
|
12326
|
+
className: "w-full",
|
|
12327
|
+
disabled: isDisabled || isCurrentPlan || isLoading,
|
|
12328
|
+
children: isLoading ? "Processing..." : isCurrentPlan ? "Current Plan" : isSelected ? "Selected" : "Select Plan"
|
|
12329
|
+
}
|
|
12330
|
+
) })
|
|
12331
|
+
]
|
|
12332
|
+
}
|
|
12333
|
+
);
|
|
12334
|
+
}
|
|
12335
|
+
__name(PricingCard, "PricingCard");
|
|
12336
|
+
|
|
12337
|
+
// src/features/billing/stripe-subscription/components/widgets/PricingCardsGrid.tsx
|
|
12338
|
+
import { jsx as jsx159, jsxs as jsxs99 } from "react/jsx-runtime";
|
|
12339
|
+
function PricingCardsGrid({
|
|
12340
|
+
products,
|
|
12341
|
+
pricesByProduct,
|
|
12342
|
+
currentPriceId,
|
|
12343
|
+
selectedPriceId,
|
|
12344
|
+
loadingPriceId,
|
|
12345
|
+
loading = false,
|
|
12346
|
+
onSelectPrice
|
|
12347
|
+
}) {
|
|
12348
|
+
if (loading) {
|
|
12349
|
+
return /* @__PURE__ */ jsx159(PricingCardsGridSkeleton, {});
|
|
12350
|
+
}
|
|
12351
|
+
if (products.length === 0) {
|
|
12352
|
+
return /* @__PURE__ */ jsx159("div", { className: "text-center py-8 text-muted-foreground", children: "No plans available" });
|
|
12353
|
+
}
|
|
12354
|
+
return /* @__PURE__ */ jsx159("div", { className: "space-y-8", role: "radiogroup", "aria-label": "Available pricing plans", children: products.map((product) => {
|
|
12355
|
+
const prices = pricesByProduct.get(product.id) || [];
|
|
12356
|
+
if (prices.length === 0) return null;
|
|
12357
|
+
const sortedPrices = [...prices].sort((a, b) => (a.unitAmount ?? 0) - (b.unitAmount ?? 0));
|
|
12358
|
+
return /* @__PURE__ */ jsxs99("div", { className: "space-y-4", children: [
|
|
12359
|
+
/* @__PURE__ */ jsx159("h3", { className: "text-lg font-semibold", children: product.name }),
|
|
12360
|
+
/* @__PURE__ */ jsx159("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: sortedPrices.map((price) => /* @__PURE__ */ jsx159(
|
|
12361
|
+
PricingCard,
|
|
12362
|
+
{
|
|
12363
|
+
price,
|
|
12364
|
+
isCurrentPlan: price.stripePriceId === currentPriceId,
|
|
12365
|
+
isSelected: price.stripePriceId === selectedPriceId,
|
|
12366
|
+
isLoading: price.stripePriceId === loadingPriceId,
|
|
12367
|
+
onSelect: onSelectPrice
|
|
12368
|
+
},
|
|
12369
|
+
price.stripePriceId
|
|
12370
|
+
)) })
|
|
12371
|
+
] }, product.id);
|
|
12372
|
+
}) });
|
|
12373
|
+
}
|
|
12374
|
+
__name(PricingCardsGrid, "PricingCardsGrid");
|
|
12375
|
+
function PricingCardsGridSkeleton() {
|
|
12376
|
+
return /* @__PURE__ */ jsx159("div", { className: "space-y-8", children: [1, 2].map((productIndex) => /* @__PURE__ */ jsxs99("div", { className: "space-y-4", children: [
|
|
12377
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-6 w-32" }),
|
|
12378
|
+
/* @__PURE__ */ jsx159("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [1, 2, 3].map((cardIndex) => /* @__PURE__ */ jsxs99(Card, { className: "animate-pulse", children: [
|
|
12379
|
+
/* @__PURE__ */ jsx159(CardHeader, { className: "pb-2", children: /* @__PURE__ */ jsx159(Skeleton, { className: "h-5 w-24" }) }),
|
|
12380
|
+
/* @__PURE__ */ jsxs99(CardContent, { className: "pb-4", children: [
|
|
12381
|
+
/* @__PURE__ */ jsxs99("div", { className: "mb-4", children: [
|
|
12382
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-9 w-20 inline-block" }),
|
|
12383
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-12 inline-block ml-2" })
|
|
12384
|
+
] }),
|
|
12385
|
+
/* @__PURE__ */ jsxs99("div", { className: "space-y-2", children: [
|
|
12386
|
+
/* @__PURE__ */ jsxs99("div", { className: "flex items-center gap-2", children: [
|
|
12387
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-4 rounded-full" }),
|
|
12388
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-32" })
|
|
12389
|
+
] }),
|
|
12390
|
+
/* @__PURE__ */ jsxs99("div", { className: "flex items-center gap-2", children: [
|
|
12391
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-4 rounded-full" }),
|
|
12392
|
+
/* @__PURE__ */ jsx159(Skeleton, { className: "h-4 w-28" })
|
|
12393
|
+
] })
|
|
12394
|
+
] })
|
|
12395
|
+
] }),
|
|
12396
|
+
/* @__PURE__ */ jsx159(CardFooter, { children: /* @__PURE__ */ jsx159(Skeleton, { className: "h-9 w-full" }) })
|
|
12397
|
+
] }, cardIndex)) })
|
|
12398
|
+
] }, productIndex)) });
|
|
12399
|
+
}
|
|
12400
|
+
__name(PricingCardsGridSkeleton, "PricingCardsGridSkeleton");
|
|
12401
|
+
|
|
12402
|
+
// src/features/billing/stripe-subscription/components/widgets/ProrationPreview.tsx
|
|
12403
|
+
import { jsx as jsx160, jsxs as jsxs100 } from "react/jsx-runtime";
|
|
12404
|
+
function ProrationPreview({ preview }) {
|
|
12405
|
+
return /* @__PURE__ */ jsxs100("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4", children: [
|
|
12406
|
+
/* @__PURE__ */ jsx160("h4", { className: "font-semibold text-blue-900 mb-3", children: "Proration Breakdown" }),
|
|
12407
|
+
/* @__PURE__ */ jsxs100("div", { className: "space-y-2", children: [
|
|
12408
|
+
preview.lineItems.map((item, index) => /* @__PURE__ */ jsxs100("div", { className: "flex justify-between text-sm", children: [
|
|
12409
|
+
/* @__PURE__ */ jsx160("span", { className: "text-blue-800", children: item.description }),
|
|
12410
|
+
/* @__PURE__ */ jsx160("span", { className: `font-medium ${item.amount < 0 ? "text-green-600" : "text-blue-900"}`, children: formatCurrency(item.amount, preview.currency) })
|
|
12411
|
+
] }, index)),
|
|
12412
|
+
/* @__PURE__ */ jsx160("div", { className: "border-t border-blue-200 pt-2 mt-2", children: /* @__PURE__ */ jsxs100("div", { className: "flex justify-between font-semibold", children: [
|
|
12413
|
+
/* @__PURE__ */ jsx160("span", { className: "text-blue-900", children: "Net Due Today" }),
|
|
12414
|
+
/* @__PURE__ */ jsx160("span", { className: "text-blue-900", children: formatCurrency(preview.immediateCharge, preview.currency) })
|
|
12415
|
+
] }) }),
|
|
12416
|
+
preview.lineItems.length > 0 && preview.lineItems[0].period && /* @__PURE__ */ jsxs100("div", { className: "text-xs text-blue-700 mt-2", children: [
|
|
12417
|
+
"Next invoice on ",
|
|
12418
|
+
formatDate3(preview.lineItems[0].period.end),
|
|
12419
|
+
" for",
|
|
12420
|
+
" ",
|
|
12421
|
+
formatCurrency(preview.amountDue, preview.currency)
|
|
12422
|
+
] })
|
|
12423
|
+
] })
|
|
12424
|
+
] });
|
|
12425
|
+
}
|
|
12426
|
+
__name(ProrationPreview, "ProrationPreview");
|
|
12427
|
+
|
|
12428
|
+
// src/features/billing/stripe-subscription/components/forms/SubscriptionEditor.tsx
|
|
12429
|
+
import { jsx as jsx161, jsxs as jsxs101 } from "react/jsx-runtime";
|
|
12430
|
+
function SubscriptionEditor({
|
|
12431
|
+
subscription,
|
|
12432
|
+
open,
|
|
12433
|
+
onOpenChange,
|
|
12434
|
+
onSuccess,
|
|
12435
|
+
onAddPaymentMethod
|
|
12436
|
+
}) {
|
|
12437
|
+
const { confirmPayment, isConfirming } = useConfirmSubscriptionPayment();
|
|
12438
|
+
const [products, setProducts] = useState57([]);
|
|
12439
|
+
const [pricesByProduct, setPricesByProduct] = useState57(/* @__PURE__ */ new Map());
|
|
12440
|
+
const [loading, setLoading] = useState57(true);
|
|
12441
|
+
const [selectedPriceId, setSelectedPriceId] = useState57(null);
|
|
12442
|
+
const [loadingPriceId, setLoadingPriceId] = useState57(null);
|
|
12443
|
+
const [prorationPreview, setProrationPreview] = useState57(null);
|
|
12444
|
+
const [loadingProration, setLoadingProration] = useState57(false);
|
|
12445
|
+
const [hasPaymentMethod, setHasPaymentMethod] = useState57(true);
|
|
12446
|
+
const [loadingPaymentMethods, setLoadingPaymentMethods] = useState57(true);
|
|
12447
|
+
const [paymentRequiredError, setPaymentRequiredError] = useState57(false);
|
|
12448
|
+
const [paymentConfirmationState, setPaymentConfirmationState] = useState57("idle");
|
|
12449
|
+
const [paymentError, setPaymentError] = useState57(null);
|
|
12450
|
+
const currentPriceId = subscription?.price?.id;
|
|
12451
|
+
const isEditMode = !!subscription;
|
|
12452
|
+
useEffect44(() => {
|
|
12453
|
+
const checkPaymentMethods = /* @__PURE__ */ __name(async () => {
|
|
12454
|
+
if (subscription) {
|
|
12455
|
+
setLoadingPaymentMethods(false);
|
|
12456
|
+
return;
|
|
12457
|
+
}
|
|
12458
|
+
setLoadingPaymentMethods(true);
|
|
12459
|
+
try {
|
|
12460
|
+
const paymentMethods = await StripeCustomerService.listPaymentMethods();
|
|
12461
|
+
const hasMethod = paymentMethods.length > 0;
|
|
12462
|
+
setHasPaymentMethod(hasMethod);
|
|
12463
|
+
} catch (error) {
|
|
12464
|
+
console.error("[SubscriptionEditor] Failed to check payment methods:", error);
|
|
12465
|
+
setHasPaymentMethod(false);
|
|
12466
|
+
} finally {
|
|
12467
|
+
setLoadingPaymentMethods(false);
|
|
12468
|
+
}
|
|
12469
|
+
}, "checkPaymentMethods");
|
|
12470
|
+
if (open) {
|
|
12471
|
+
checkPaymentMethods();
|
|
12472
|
+
}
|
|
12473
|
+
}, [open, subscription]);
|
|
12474
|
+
useEffect44(() => {
|
|
12475
|
+
const loadData = /* @__PURE__ */ __name(async () => {
|
|
12476
|
+
setLoading(true);
|
|
12477
|
+
try {
|
|
12478
|
+
const fetchedProducts = await StripeProductService.listProducts({ active: true });
|
|
12479
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
12480
|
+
for (const product of fetchedProducts) {
|
|
12481
|
+
if (product.stripePrices && product.stripePrices.length > 0) {
|
|
12482
|
+
grouped.set(product.id, product.stripePrices);
|
|
12483
|
+
}
|
|
12484
|
+
}
|
|
12485
|
+
setProducts(fetchedProducts);
|
|
12486
|
+
setPricesByProduct(grouped);
|
|
12487
|
+
} catch (error) {
|
|
12488
|
+
console.error("[SubscriptionEditor] Failed to load products/prices:", error);
|
|
12489
|
+
} finally {
|
|
12490
|
+
setLoading(false);
|
|
12491
|
+
}
|
|
12492
|
+
}, "loadData");
|
|
12493
|
+
if (open) {
|
|
12494
|
+
loadData();
|
|
12495
|
+
}
|
|
12496
|
+
}, [open]);
|
|
12497
|
+
useEffect44(() => {
|
|
12498
|
+
const loadProration = /* @__PURE__ */ __name(async () => {
|
|
12499
|
+
if (!subscription || !selectedPriceId || selectedPriceId === currentPriceId) {
|
|
12500
|
+
setProrationPreview(null);
|
|
12501
|
+
return;
|
|
12502
|
+
}
|
|
12503
|
+
setLoadingProration(true);
|
|
12504
|
+
try {
|
|
12505
|
+
const preview = await StripeSubscriptionService.getProrationPreview({
|
|
12506
|
+
subscriptionId: subscription.id,
|
|
12507
|
+
newPriceId: selectedPriceId
|
|
12508
|
+
});
|
|
12509
|
+
setProrationPreview(preview);
|
|
12510
|
+
} catch (error) {
|
|
12511
|
+
console.error("[SubscriptionEditor] Failed to load proration preview:", error);
|
|
12512
|
+
setProrationPreview(null);
|
|
12513
|
+
} finally {
|
|
12514
|
+
setLoadingProration(false);
|
|
12515
|
+
}
|
|
12516
|
+
}, "loadProration");
|
|
12517
|
+
loadProration();
|
|
12518
|
+
}, [selectedPriceId, subscription, currentPriceId]);
|
|
12519
|
+
const handleSelectPrice = /* @__PURE__ */ __name(async (price) => {
|
|
12520
|
+
const priceId = price.id;
|
|
12521
|
+
if (isEditMode) {
|
|
12522
|
+
setSelectedPriceId(priceId);
|
|
12523
|
+
} else {
|
|
12524
|
+
setLoadingPriceId(priceId);
|
|
12525
|
+
setSelectedPriceId(priceId);
|
|
12526
|
+
setPaymentError(null);
|
|
12527
|
+
setPaymentConfirmationState("idle");
|
|
12528
|
+
try {
|
|
12529
|
+
const result = await StripeSubscriptionService.createSubscription({
|
|
12530
|
+
id: v45(),
|
|
12531
|
+
priceId
|
|
12532
|
+
});
|
|
12533
|
+
if (result.meta.requiresAction && result.meta.clientSecret) {
|
|
12534
|
+
setPaymentConfirmationState("confirming");
|
|
12535
|
+
const confirmation = await confirmPayment(result.meta.clientSecret);
|
|
12536
|
+
if (!confirmation.success) {
|
|
12537
|
+
console.error("[SubscriptionEditor] Payment confirmation failed:", confirmation.error);
|
|
12538
|
+
setPaymentConfirmationState("error");
|
|
12539
|
+
setPaymentError(confirmation.error || "Payment confirmation failed");
|
|
12540
|
+
setLoadingPriceId(null);
|
|
12541
|
+
return;
|
|
12542
|
+
}
|
|
12543
|
+
await StripeSubscriptionService.syncSubscription({
|
|
12544
|
+
subscriptionId: result.subscription.id
|
|
12545
|
+
});
|
|
12546
|
+
}
|
|
12547
|
+
setPaymentConfirmationState("success");
|
|
12548
|
+
setTimeout(() => {
|
|
12549
|
+
onSuccess();
|
|
12550
|
+
onOpenChange(false);
|
|
12551
|
+
}, 1e3);
|
|
12552
|
+
} catch (error) {
|
|
12553
|
+
console.error("[SubscriptionEditor] Failed to create subscription:", error);
|
|
12554
|
+
if (error?.status === 402 || error?.response?.status === 402) {
|
|
12555
|
+
setPaymentRequiredError(true);
|
|
12556
|
+
setHasPaymentMethod(false);
|
|
12557
|
+
} else {
|
|
12558
|
+
setPaymentConfirmationState("error");
|
|
12559
|
+
setPaymentError(error?.message || "Failed to create subscription");
|
|
12560
|
+
}
|
|
12561
|
+
setLoadingPriceId(null);
|
|
12562
|
+
}
|
|
12563
|
+
}
|
|
12564
|
+
}, "handleSelectPrice");
|
|
12565
|
+
const handleConfirmPlanChange = /* @__PURE__ */ __name(async () => {
|
|
12566
|
+
if (!subscription || !selectedPriceId) return;
|
|
12567
|
+
setLoadingPriceId(selectedPriceId);
|
|
12568
|
+
try {
|
|
12569
|
+
await StripeSubscriptionService.changePlan({
|
|
12570
|
+
id: subscription.id,
|
|
12571
|
+
newPriceId: selectedPriceId
|
|
12572
|
+
});
|
|
12573
|
+
onSuccess();
|
|
12574
|
+
onOpenChange(false);
|
|
12575
|
+
} catch (error) {
|
|
12576
|
+
console.error("[SubscriptionEditor] Failed to change plan:", error);
|
|
12577
|
+
} finally {
|
|
12578
|
+
setLoadingPriceId(null);
|
|
12579
|
+
}
|
|
12580
|
+
}, "handleConfirmPlanChange");
|
|
12581
|
+
const handleCancel = /* @__PURE__ */ __name(() => {
|
|
12582
|
+
setSelectedPriceId(null);
|
|
12583
|
+
setProrationPreview(null);
|
|
12584
|
+
}, "handleCancel");
|
|
12585
|
+
return /* @__PURE__ */ jsx161(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs101(DialogContent, { className: "max-w-4xl max-h-[90vh] overflow-y-auto", children: [
|
|
12586
|
+
/* @__PURE__ */ jsxs101(DialogHeader, { children: [
|
|
12587
|
+
/* @__PURE__ */ jsx161(DialogTitle, { children: subscription ? "Change Plan" : "Subscribe to a Plan" }),
|
|
12588
|
+
/* @__PURE__ */ jsx161(DialogDescription, { children: subscription ? "Select a new plan to switch to. You'll see a proration preview before confirming." : "Choose a plan to start your subscription." })
|
|
12589
|
+
] }),
|
|
12590
|
+
loadingPaymentMethods && !subscription ? /* @__PURE__ */ jsx161("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx161("div", { className: "text-muted-foreground", children: "Checking payment methods..." }) }) : !hasPaymentMethod && !subscription ? /* @__PURE__ */ jsxs101(Alert, { variant: "destructive", children: [
|
|
12591
|
+
/* @__PURE__ */ jsx161(AlertTitle, { children: "Payment Method Required" }),
|
|
12592
|
+
/* @__PURE__ */ jsxs101(AlertDescription, { className: "mt-2", children: [
|
|
12593
|
+
/* @__PURE__ */ jsx161("p", { className: "mb-4", children: paymentRequiredError ? "Your subscription could not be created because no payment method is on file." : "You need to add a payment method before you can subscribe to a plan." }),
|
|
12594
|
+
onAddPaymentMethod && /* @__PURE__ */ jsx161(Button, { onClick: onAddPaymentMethod, variant: "outline", children: "Add Payment Method" })
|
|
12595
|
+
] })
|
|
12596
|
+
] }) : paymentConfirmationState === "confirming" || isConfirming ? /* @__PURE__ */ jsxs101("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
|
|
12597
|
+
/* @__PURE__ */ jsx161(Loader22, { className: "h-8 w-8 animate-spin text-primary" }),
|
|
12598
|
+
/* @__PURE__ */ jsxs101("div", { className: "text-center", children: [
|
|
12599
|
+
/* @__PURE__ */ jsx161("p", { className: "font-medium", children: "Processing payment..." }),
|
|
12600
|
+
/* @__PURE__ */ jsx161("p", { className: "text-sm text-muted-foreground", children: "Please complete any verification if prompted." })
|
|
12601
|
+
] })
|
|
12602
|
+
] }) : paymentConfirmationState === "success" ? /* @__PURE__ */ jsxs101("div", { className: "flex flex-col items-center justify-center py-12 space-y-4", children: [
|
|
12603
|
+
/* @__PURE__ */ jsx161(CheckCircle, { className: "h-12 w-12 text-green-500" }),
|
|
12604
|
+
/* @__PURE__ */ jsxs101("div", { className: "text-center", children: [
|
|
12605
|
+
/* @__PURE__ */ jsx161("p", { className: "font-medium text-green-600", children: "Payment successful!" }),
|
|
12606
|
+
/* @__PURE__ */ jsx161("p", { className: "text-sm text-muted-foreground", children: "Your subscription is now active." })
|
|
12607
|
+
] })
|
|
12608
|
+
] }) : paymentConfirmationState === "error" ? /* @__PURE__ */ jsx161("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs101(Alert, { variant: "destructive", children: [
|
|
12609
|
+
/* @__PURE__ */ jsx161(AlertTitle, { children: "Payment Failed" }),
|
|
12610
|
+
/* @__PURE__ */ jsxs101(AlertDescription, { className: "mt-2", children: [
|
|
12611
|
+
/* @__PURE__ */ jsx161("p", { className: "mb-4", children: paymentError || "We couldn't process your payment. Please try again." }),
|
|
12612
|
+
/* @__PURE__ */ jsx161(
|
|
12613
|
+
Button,
|
|
12614
|
+
{
|
|
12615
|
+
onClick: () => {
|
|
12616
|
+
setPaymentConfirmationState("idle");
|
|
12617
|
+
setPaymentError(null);
|
|
12618
|
+
setLoadingPriceId(null);
|
|
12619
|
+
},
|
|
12620
|
+
variant: "outline",
|
|
12621
|
+
children: "Try Again"
|
|
12622
|
+
}
|
|
12623
|
+
)
|
|
12624
|
+
] })
|
|
12625
|
+
] }) }) : /* @__PURE__ */ jsxs101("div", { className: "space-y-6", children: [
|
|
12626
|
+
/* @__PURE__ */ jsx161(
|
|
12627
|
+
PricingCardsGrid,
|
|
12628
|
+
{
|
|
12629
|
+
products,
|
|
12630
|
+
pricesByProduct,
|
|
12631
|
+
currentPriceId,
|
|
12632
|
+
selectedPriceId: selectedPriceId ?? void 0,
|
|
12633
|
+
loadingPriceId: loadingPriceId ?? void 0,
|
|
12634
|
+
loading,
|
|
12635
|
+
onSelectPrice: handleSelectPrice
|
|
12636
|
+
}
|
|
12637
|
+
),
|
|
12638
|
+
isEditMode && loadingProration && /* @__PURE__ */ jsx161("div", { className: "bg-muted/50 rounded-lg p-4 text-sm text-muted-foreground text-center", children: "Loading proration preview..." }),
|
|
12639
|
+
isEditMode && prorationPreview && !loadingProration && /* @__PURE__ */ jsxs101("div", { className: "space-y-4", children: [
|
|
12640
|
+
/* @__PURE__ */ jsx161(ProrationPreview, { preview: prorationPreview }),
|
|
12641
|
+
/* @__PURE__ */ jsxs101("div", { className: "flex justify-end gap-3", children: [
|
|
12642
|
+
/* @__PURE__ */ jsx161(Button, { variant: "outline", onClick: handleCancel, disabled: !!loadingPriceId, children: "Cancel" }),
|
|
12643
|
+
/* @__PURE__ */ jsx161(Button, { onClick: handleConfirmPlanChange, disabled: !!loadingPriceId, children: loadingPriceId ? "Processing..." : "Confirm Plan Change" })
|
|
12644
|
+
] })
|
|
12645
|
+
] })
|
|
12646
|
+
] })
|
|
12647
|
+
] }) });
|
|
12648
|
+
}
|
|
12649
|
+
__name(SubscriptionEditor, "SubscriptionEditor");
|
|
12650
|
+
|
|
12651
|
+
// src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx
|
|
12652
|
+
import { useState as useState59 } from "react";
|
|
12653
|
+
|
|
12654
|
+
// src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx
|
|
12655
|
+
import { useState as useState58 } from "react";
|
|
12656
|
+
|
|
12657
|
+
// src/features/billing/stripe-subscription/components/widgets/SubscriptionStatusBadge.tsx
|
|
12658
|
+
import { jsx as jsx162 } from "react/jsx-runtime";
|
|
12659
|
+
var statusConfig2 = {
|
|
12660
|
+
["active" /* ACTIVE */]: {
|
|
12661
|
+
label: "Active",
|
|
12662
|
+
color: "bg-green-100 text-green-800"
|
|
12663
|
+
},
|
|
12664
|
+
["trialing" /* TRIALING */]: {
|
|
12665
|
+
label: "Trial",
|
|
12666
|
+
color: "bg-blue-100 text-blue-800"
|
|
12667
|
+
},
|
|
12668
|
+
["past_due" /* PAST_DUE */]: {
|
|
12669
|
+
label: "Past Due",
|
|
12670
|
+
color: "bg-red-100 text-red-800"
|
|
12671
|
+
},
|
|
12672
|
+
["canceled" /* CANCELED */]: {
|
|
12673
|
+
label: "Canceled",
|
|
12674
|
+
color: "bg-gray-100 text-gray-800"
|
|
12675
|
+
},
|
|
12676
|
+
["paused" /* PAUSED */]: {
|
|
12677
|
+
label: "Paused",
|
|
12678
|
+
color: "bg-yellow-100 text-yellow-800"
|
|
12679
|
+
},
|
|
12680
|
+
["unpaid" /* UNPAID */]: {
|
|
12681
|
+
label: "Unpaid",
|
|
12682
|
+
color: "bg-orange-100 text-orange-800"
|
|
12683
|
+
},
|
|
12684
|
+
["incomplete" /* INCOMPLETE */]: {
|
|
12685
|
+
label: "Incomplete",
|
|
12686
|
+
color: "bg-gray-100 text-gray-800"
|
|
12687
|
+
},
|
|
12688
|
+
["incomplete_expired" /* INCOMPLETE_EXPIRED */]: {
|
|
12689
|
+
label: "Expired",
|
|
12690
|
+
color: "bg-gray-100 text-gray-800"
|
|
12691
|
+
}
|
|
12692
|
+
};
|
|
12693
|
+
var cancelingConfig = {
|
|
12694
|
+
label: "Canceling",
|
|
12695
|
+
color: "bg-amber-100 text-amber-800"
|
|
12696
|
+
};
|
|
12697
|
+
function SubscriptionStatusBadge({ status, cancelAtPeriodEnd }) {
|
|
12698
|
+
const config = cancelAtPeriodEnd ? cancelingConfig : statusConfig2[status] || statusConfig2["canceled" /* CANCELED */];
|
|
12699
|
+
return /* @__PURE__ */ jsx162("span", { className: `${config.color} text-xs px-2 py-1 rounded-full font-medium`, children: config.label });
|
|
12700
|
+
}
|
|
12701
|
+
__name(SubscriptionStatusBadge, "SubscriptionStatusBadge");
|
|
12702
|
+
|
|
12703
|
+
// src/features/billing/stripe-subscription/components/details/SubscriptionDetails.tsx
|
|
12704
|
+
import { Fragment as Fragment30, jsx as jsx163, jsxs as jsxs102 } from "react/jsx-runtime";
|
|
12705
|
+
function formatPlanName2(price) {
|
|
12706
|
+
if (!price) return "N/A";
|
|
12707
|
+
const productName = price.product?.name || "";
|
|
12708
|
+
const nickname = price.nickname || "";
|
|
12709
|
+
let interval = "";
|
|
12710
|
+
if (price.recurring?.interval) {
|
|
12711
|
+
const intervalMap = {
|
|
12712
|
+
day: "Daily",
|
|
12713
|
+
week: "Weekly",
|
|
12714
|
+
month: "Monthly",
|
|
12715
|
+
year: "Yearly"
|
|
12716
|
+
};
|
|
12717
|
+
interval = intervalMap[price.recurring.interval] || price.recurring.interval;
|
|
12718
|
+
}
|
|
12719
|
+
const parts = [productName, nickname].filter(Boolean);
|
|
12720
|
+
const planLabel = parts.join(" - ");
|
|
12721
|
+
return interval ? `${planLabel} (${interval})` : planLabel || "N/A";
|
|
12722
|
+
}
|
|
12723
|
+
__name(formatPlanName2, "formatPlanName");
|
|
12724
|
+
function formatBillingAmount(price) {
|
|
12725
|
+
if (!price?.unitAmount) return "N/A";
|
|
12726
|
+
return formatCurrency(price.unitAmount, price.currency);
|
|
12727
|
+
}
|
|
12728
|
+
__name(formatBillingAmount, "formatBillingAmount");
|
|
12729
|
+
function SubscriptionDetails({
|
|
12730
|
+
subscription,
|
|
12731
|
+
open,
|
|
12732
|
+
onOpenChange,
|
|
12733
|
+
onSubscriptionChange
|
|
12734
|
+
}) {
|
|
12735
|
+
const [showEdit, setShowEdit] = useState58(false);
|
|
12736
|
+
const [showCancel, setShowCancel] = useState58(false);
|
|
12737
|
+
const [isProcessing, setIsProcessing] = useState58(false);
|
|
12738
|
+
const handlePause = /* @__PURE__ */ __name(async () => {
|
|
12739
|
+
setIsProcessing(true);
|
|
12740
|
+
try {
|
|
12741
|
+
await StripeSubscriptionService.pauseSubscription({ subscriptionId: subscription.id });
|
|
12742
|
+
onSubscriptionChange();
|
|
12743
|
+
} catch (error) {
|
|
12744
|
+
console.error("[SubscriptionDetails] Failed to pause subscription:", error);
|
|
12745
|
+
} finally {
|
|
12746
|
+
setIsProcessing(false);
|
|
12747
|
+
}
|
|
12748
|
+
}, "handlePause");
|
|
12749
|
+
const handleResume = /* @__PURE__ */ __name(async () => {
|
|
12750
|
+
setIsProcessing(true);
|
|
12751
|
+
try {
|
|
12752
|
+
await StripeSubscriptionService.resumeSubscription({ subscriptionId: subscription.id });
|
|
12753
|
+
onSubscriptionChange();
|
|
12754
|
+
} catch (error) {
|
|
12755
|
+
console.error("[SubscriptionDetails] Failed to resume subscription:", error);
|
|
12756
|
+
} finally {
|
|
12757
|
+
setIsProcessing(false);
|
|
12758
|
+
}
|
|
12759
|
+
}, "handleResume");
|
|
12760
|
+
const handleManageViaPortal = /* @__PURE__ */ __name(async () => {
|
|
12761
|
+
try {
|
|
12762
|
+
const { url } = await StripeCustomerService.createPortalSession();
|
|
12763
|
+
window.open(url, "_blank");
|
|
12764
|
+
} catch (error) {
|
|
12765
|
+
console.error("[SubscriptionDetails] Failed to create portal session:", error);
|
|
12766
|
+
}
|
|
12767
|
+
}, "handleManageViaPortal");
|
|
12768
|
+
const canPause = subscription.status === "active" /* ACTIVE */;
|
|
12769
|
+
const canResume = subscription.status === "paused" /* PAUSED */;
|
|
12770
|
+
const canCancel = subscription.status === "active" /* ACTIVE */ || subscription.status === "trialing" /* TRIALING */ || subscription.status === "paused" /* PAUSED */;
|
|
12771
|
+
return /* @__PURE__ */ jsxs102(Fragment30, { children: [
|
|
12772
|
+
/* @__PURE__ */ jsx163(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs102(DialogContent, { className: "max-w-2xl", children: [
|
|
12773
|
+
/* @__PURE__ */ jsxs102(DialogHeader, { children: [
|
|
12774
|
+
/* @__PURE__ */ jsx163(DialogTitle, { children: "Subscription Details" }),
|
|
12775
|
+
/* @__PURE__ */ jsx163(DialogDescription, { children: "View and manage your subscription" })
|
|
12776
|
+
] }),
|
|
12777
|
+
/* @__PURE__ */ jsxs102("div", { className: "space-y-6", children: [
|
|
12778
|
+
/* @__PURE__ */ jsxs102("div", { className: "flex items-center gap-x-3", children: [
|
|
12779
|
+
/* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Status:" }),
|
|
12780
|
+
/* @__PURE__ */ jsx163(SubscriptionStatusBadge, { status: subscription.status, cancelAtPeriodEnd: subscription.cancelAtPeriodEnd })
|
|
12781
|
+
] }),
|
|
12782
|
+
/* @__PURE__ */ jsxs102("div", { className: "space-y-2", children: [
|
|
12783
|
+
/* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
|
|
12784
|
+
/* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Plan:" }),
|
|
12785
|
+
/* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatPlanName2(subscription.price) })
|
|
12786
|
+
] }),
|
|
12787
|
+
/* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
|
|
12788
|
+
/* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Billing Amount:" }),
|
|
12789
|
+
/* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatBillingAmount(subscription.price) })
|
|
12790
|
+
] })
|
|
12791
|
+
] }),
|
|
12792
|
+
/* @__PURE__ */ jsx163("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
|
|
12793
|
+
/* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Current Period:" }),
|
|
12794
|
+
/* @__PURE__ */ jsxs102("span", { className: "font-medium", children: [
|
|
12795
|
+
formatDate3(subscription.currentPeriodStart),
|
|
12796
|
+
" - ",
|
|
12797
|
+
formatDate3(subscription.currentPeriodEnd)
|
|
12798
|
+
] })
|
|
12799
|
+
] }) }),
|
|
12800
|
+
subscription.trialEnd && /* @__PURE__ */ jsxs102("div", { className: "flex justify-between", children: [
|
|
12801
|
+
/* @__PURE__ */ jsx163("span", { className: "text-sm font-medium text-muted-foreground", children: "Trial Ends:" }),
|
|
12802
|
+
/* @__PURE__ */ jsx163("span", { className: "font-medium", children: formatDate3(subscription.trialEnd) })
|
|
12803
|
+
] }),
|
|
12804
|
+
subscription.cancelAtPeriodEnd && /* @__PURE__ */ jsx163("div", { className: "bg-yellow-50 border border-yellow-200 rounded-lg p-3", children: /* @__PURE__ */ jsxs102("p", { className: "text-sm text-yellow-800", children: [
|
|
12805
|
+
"This subscription will be canceled at the end of the current period on",
|
|
12806
|
+
" ",
|
|
12807
|
+
formatDate3(subscription.currentPeriodEnd),
|
|
12808
|
+
"."
|
|
12809
|
+
] }) }),
|
|
12810
|
+
/* @__PURE__ */ jsxs102("div", { className: "flex flex-wrap gap-2 pt-4 border-t", children: [
|
|
12811
|
+
/* @__PURE__ */ jsx163(Button, { variant: "default", onClick: () => setShowEdit(true), children: "Change Plan" }),
|
|
12812
|
+
canPause && /* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handlePause, disabled: isProcessing, children: isProcessing ? "Pausing..." : "Pause" }),
|
|
12813
|
+
canResume && /* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handleResume, disabled: isProcessing, children: isProcessing ? "Resuming..." : "Resume" }),
|
|
12814
|
+
canCancel && /* @__PURE__ */ jsx163(Button, { variant: "destructive", onClick: () => setShowCancel(true), children: "Cancel" }),
|
|
12815
|
+
/* @__PURE__ */ jsx163(Button, { variant: "outline", onClick: handleManageViaPortal, children: "Manage via Portal" })
|
|
12816
|
+
] })
|
|
12817
|
+
] })
|
|
12818
|
+
] }) }),
|
|
12819
|
+
showEdit && /* @__PURE__ */ jsx163(
|
|
12820
|
+
SubscriptionEditor,
|
|
12821
|
+
{
|
|
12822
|
+
subscription,
|
|
12823
|
+
open: showEdit,
|
|
12824
|
+
onOpenChange: setShowEdit,
|
|
12825
|
+
onSuccess: () => {
|
|
12826
|
+
onSubscriptionChange();
|
|
12827
|
+
setShowEdit(false);
|
|
12828
|
+
}
|
|
12829
|
+
}
|
|
12830
|
+
),
|
|
12831
|
+
showCancel && /* @__PURE__ */ jsx163(
|
|
12832
|
+
CancelSubscriptionDialog,
|
|
12833
|
+
{
|
|
12834
|
+
subscription,
|
|
12835
|
+
open: showCancel,
|
|
12836
|
+
onOpenChange: setShowCancel,
|
|
12837
|
+
onSuccess: () => {
|
|
12838
|
+
onSubscriptionChange();
|
|
12839
|
+
setShowCancel(false);
|
|
12840
|
+
}
|
|
12841
|
+
}
|
|
12842
|
+
)
|
|
12843
|
+
] });
|
|
12844
|
+
}
|
|
12845
|
+
__name(SubscriptionDetails, "SubscriptionDetails");
|
|
12846
|
+
|
|
12847
|
+
// src/features/billing/stripe-subscription/components/lists/SubscriptionsList.tsx
|
|
12848
|
+
import { Fragment as Fragment31, jsx as jsx164, jsxs as jsxs103 } from "react/jsx-runtime";
|
|
12849
|
+
function formatPlanName3(price) {
|
|
12850
|
+
if (!price) return "N/A";
|
|
12851
|
+
const productName = price.product?.name || "";
|
|
12852
|
+
const nickname = price.nickname || "";
|
|
12853
|
+
let interval = "";
|
|
12854
|
+
if (price.recurring?.interval) {
|
|
12855
|
+
const intervalMap = {
|
|
12856
|
+
day: "Daily",
|
|
12857
|
+
week: "Weekly",
|
|
12858
|
+
month: "Monthly",
|
|
12859
|
+
year: "Yearly"
|
|
12860
|
+
};
|
|
12861
|
+
interval = intervalMap[price.recurring.interval] || price.recurring.interval;
|
|
12862
|
+
}
|
|
12863
|
+
const parts = [productName, nickname].filter(Boolean);
|
|
12864
|
+
const planLabel = parts.join(" - ");
|
|
12865
|
+
return interval ? `${planLabel} (${interval})` : planLabel || "N/A";
|
|
12866
|
+
}
|
|
12867
|
+
__name(formatPlanName3, "formatPlanName");
|
|
12868
|
+
function SubscriptionsList({ subscriptions, onSubscriptionsChange }) {
|
|
12869
|
+
const [selectedSub, setSelectedSub] = useState59(null);
|
|
12870
|
+
const handleRowClick = /* @__PURE__ */ __name((subscription) => {
|
|
12871
|
+
setSelectedSub(subscription);
|
|
12872
|
+
}, "handleRowClick");
|
|
12873
|
+
return /* @__PURE__ */ jsxs103(Fragment31, { children: [
|
|
12874
|
+
/* @__PURE__ */ jsx164("div", { className: "border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxs103(Table, { children: [
|
|
12875
|
+
/* @__PURE__ */ jsx164(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs103(TableRow, { children: [
|
|
12876
|
+
/* @__PURE__ */ jsx164(TableHead, { children: "Status" }),
|
|
12877
|
+
/* @__PURE__ */ jsx164(TableHead, { children: "Plan" }),
|
|
12878
|
+
/* @__PURE__ */ jsx164(TableHead, { children: "Period" }),
|
|
12879
|
+
/* @__PURE__ */ jsx164(TableHead, { className: "text-right", children: "Amount" })
|
|
12880
|
+
] }) }),
|
|
12881
|
+
/* @__PURE__ */ jsx164(TableBody, { children: subscriptions.map((subscription) => {
|
|
12882
|
+
const price = subscription.price;
|
|
12883
|
+
const amount = price?.unitAmount ? formatCurrency(price.unitAmount, price.currency) : "N/A";
|
|
12884
|
+
const period = `${formatDate3(subscription.currentPeriodStart)} - ${formatDate3(subscription.currentPeriodEnd)}`;
|
|
12885
|
+
return /* @__PURE__ */ jsxs103(
|
|
12886
|
+
TableRow,
|
|
12887
|
+
{
|
|
12888
|
+
onClick: () => handleRowClick(subscription),
|
|
12889
|
+
className: "cursor-pointer hover:bg-muted/50",
|
|
12890
|
+
children: [
|
|
12891
|
+
/* @__PURE__ */ jsx164(TableCell, { children: /* @__PURE__ */ jsx164(SubscriptionStatusBadge, { status: subscription.status, cancelAtPeriodEnd: subscription.cancelAtPeriodEnd }) }),
|
|
12892
|
+
/* @__PURE__ */ jsx164(TableCell, { className: "font-medium", children: formatPlanName3(price) }),
|
|
12893
|
+
/* @__PURE__ */ jsx164(TableCell, { className: "text-muted-foreground text-sm", children: period }),
|
|
12894
|
+
/* @__PURE__ */ jsx164(TableCell, { className: "text-right font-medium", children: amount })
|
|
12895
|
+
]
|
|
12896
|
+
},
|
|
12897
|
+
subscription.id
|
|
12898
|
+
);
|
|
12899
|
+
}) })
|
|
12900
|
+
] }) }),
|
|
12901
|
+
selectedSub && /* @__PURE__ */ jsx164(
|
|
12902
|
+
SubscriptionDetails,
|
|
12903
|
+
{
|
|
12904
|
+
subscription: selectedSub,
|
|
12905
|
+
open: !!selectedSub,
|
|
12906
|
+
onOpenChange: (open) => !open && setSelectedSub(null),
|
|
12907
|
+
onSubscriptionChange: () => {
|
|
12908
|
+
onSubscriptionsChange();
|
|
12909
|
+
setSelectedSub(null);
|
|
12910
|
+
}
|
|
12911
|
+
}
|
|
12912
|
+
)
|
|
12913
|
+
] });
|
|
12914
|
+
}
|
|
12915
|
+
__name(SubscriptionsList, "SubscriptionsList");
|
|
12916
|
+
|
|
12917
|
+
// src/features/billing/stripe-subscription/components/containers/SubscriptionsContainer.tsx
|
|
12918
|
+
import { Fragment as Fragment32, jsx as jsx165, jsxs as jsxs104 } from "react/jsx-runtime";
|
|
12919
|
+
function SubscriptionsContainer() {
|
|
12920
|
+
const { confirmPayment, isConfirming } = useConfirmSubscriptionPayment();
|
|
12921
|
+
const [subscriptions, setSubscriptions] = useState60([]);
|
|
12922
|
+
const [loading, setLoading] = useState60(true);
|
|
12923
|
+
const [showCreateSubscription, setShowCreateSubscription] = useState60(false);
|
|
12924
|
+
const [showPaymentMethodEditor, setShowPaymentMethodEditor] = useState60(false);
|
|
12925
|
+
const [products, setProducts] = useState60([]);
|
|
12926
|
+
const [pricesByProduct, setPricesByProduct] = useState60(/* @__PURE__ */ new Map());
|
|
12927
|
+
const [loadingPricing, setLoadingPricing] = useState60(false);
|
|
12928
|
+
const [hasPaymentMethod, setHasPaymentMethod] = useState60(null);
|
|
12929
|
+
const [pendingPriceId, setPendingPriceId] = useState60(null);
|
|
12930
|
+
const [creatingSubscription, setCreatingSubscription] = useState60(false);
|
|
12931
|
+
const [paymentConfirmationState, setPaymentConfirmationState] = useState60("idle");
|
|
12932
|
+
const [paymentError, setPaymentError] = useState60(null);
|
|
12933
|
+
const loadSubscriptions = /* @__PURE__ */ __name(async () => {
|
|
12934
|
+
setLoading(true);
|
|
12935
|
+
try {
|
|
12936
|
+
const fetchedSubscriptions = await StripeSubscriptionService.listSubscriptions();
|
|
12937
|
+
setSubscriptions(fetchedSubscriptions);
|
|
12938
|
+
} catch (error) {
|
|
12939
|
+
console.error("[SubscriptionsContainer] Failed to load subscriptions:", error);
|
|
12940
|
+
} finally {
|
|
12941
|
+
setLoading(false);
|
|
12942
|
+
}
|
|
12943
|
+
}, "loadSubscriptions");
|
|
12944
|
+
const loadPricingData = /* @__PURE__ */ __name(async () => {
|
|
12945
|
+
setLoadingPricing(true);
|
|
12946
|
+
try {
|
|
12947
|
+
const fetchedProducts = await StripeProductService.listProducts({ active: true });
|
|
12948
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
12949
|
+
for (const product of fetchedProducts) {
|
|
12950
|
+
if (product.stripePrices && product.stripePrices.length > 0) {
|
|
12951
|
+
grouped.set(product.id, product.stripePrices);
|
|
12952
|
+
}
|
|
12953
|
+
}
|
|
12954
|
+
setProducts(fetchedProducts);
|
|
12955
|
+
setPricesByProduct(grouped);
|
|
12956
|
+
} catch (error) {
|
|
12957
|
+
console.error("[SubscriptionsContainer] Failed to load pricing data:", error);
|
|
12958
|
+
} finally {
|
|
12959
|
+
setLoadingPricing(false);
|
|
12960
|
+
}
|
|
12961
|
+
}, "loadPricingData");
|
|
12962
|
+
const checkPaymentMethod = /* @__PURE__ */ __name(async () => {
|
|
12963
|
+
try {
|
|
12964
|
+
const paymentMethods = await StripeCustomerService.listPaymentMethods();
|
|
12965
|
+
const hasMethod = paymentMethods.length > 0;
|
|
12966
|
+
setHasPaymentMethod(hasMethod);
|
|
12967
|
+
} catch (error) {
|
|
12968
|
+
console.error("[SubscriptionsContainer] Failed to check payment methods:", error);
|
|
12969
|
+
setHasPaymentMethod(false);
|
|
12970
|
+
}
|
|
12971
|
+
}, "checkPaymentMethod");
|
|
12972
|
+
const createSubscriptionWithPrice = /* @__PURE__ */ __name(async (priceId) => {
|
|
12973
|
+
setCreatingSubscription(true);
|
|
12974
|
+
setPaymentError(null);
|
|
12975
|
+
setPaymentConfirmationState("idle");
|
|
12976
|
+
try {
|
|
12977
|
+
const result = await StripeSubscriptionService.createSubscription({
|
|
12978
|
+
id: v46(),
|
|
12979
|
+
priceId
|
|
12980
|
+
});
|
|
12981
|
+
if (result.meta.requiresAction && result.meta.clientSecret) {
|
|
12982
|
+
setPaymentConfirmationState("confirming");
|
|
12983
|
+
const confirmation = await confirmPayment(result.meta.clientSecret);
|
|
12984
|
+
if (!confirmation.success) {
|
|
12985
|
+
console.error("[SubscriptionsContainer] Payment confirmation failed:", confirmation.error);
|
|
12986
|
+
setPaymentConfirmationState("error");
|
|
12987
|
+
setPaymentError(confirmation.error || "Payment confirmation failed");
|
|
12988
|
+
setCreatingSubscription(false);
|
|
12989
|
+
return;
|
|
12990
|
+
}
|
|
12991
|
+
await StripeSubscriptionService.syncSubscription({
|
|
12992
|
+
subscriptionId: result.subscription.id
|
|
12993
|
+
});
|
|
12994
|
+
}
|
|
12995
|
+
setPaymentConfirmationState("success");
|
|
12996
|
+
await loadSubscriptions();
|
|
12997
|
+
} catch (error) {
|
|
12998
|
+
console.error("[SubscriptionsContainer] Failed to create subscription:", error);
|
|
12999
|
+
if (error?.status === 402 || error?.response?.status === 402) {
|
|
13000
|
+
setPendingPriceId(priceId);
|
|
13001
|
+
setHasPaymentMethod(false);
|
|
13002
|
+
setShowPaymentMethodEditor(true);
|
|
13003
|
+
} else {
|
|
13004
|
+
setPaymentConfirmationState("error");
|
|
13005
|
+
setPaymentError(error?.message || "Failed to create subscription");
|
|
13006
|
+
}
|
|
13007
|
+
} finally {
|
|
13008
|
+
setCreatingSubscription(false);
|
|
13009
|
+
}
|
|
13010
|
+
}, "createSubscriptionWithPrice");
|
|
13011
|
+
const handleSelectPrice = /* @__PURE__ */ __name(async (price) => {
|
|
13012
|
+
const priceId = price.id;
|
|
13013
|
+
if (!hasPaymentMethod) {
|
|
13014
|
+
setPendingPriceId(priceId);
|
|
13015
|
+
setShowPaymentMethodEditor(true);
|
|
13016
|
+
return;
|
|
13017
|
+
}
|
|
13018
|
+
await createSubscriptionWithPrice(priceId);
|
|
13019
|
+
}, "handleSelectPrice");
|
|
13020
|
+
const handlePaymentMethodSuccess = /* @__PURE__ */ __name(async () => {
|
|
13021
|
+
setShowPaymentMethodEditor(false);
|
|
13022
|
+
setHasPaymentMethod(true);
|
|
13023
|
+
if (pendingPriceId) {
|
|
13024
|
+
await createSubscriptionWithPrice(pendingPriceId);
|
|
13025
|
+
setPendingPriceId(null);
|
|
13026
|
+
}
|
|
13027
|
+
}, "handlePaymentMethodSuccess");
|
|
13028
|
+
useEffect45(() => {
|
|
13029
|
+
loadSubscriptions();
|
|
13030
|
+
}, []);
|
|
13031
|
+
useEffect45(() => {
|
|
13032
|
+
if (!loading && subscriptions.length === 0) {
|
|
13033
|
+
loadPricingData();
|
|
13034
|
+
checkPaymentMethod();
|
|
13035
|
+
}
|
|
13036
|
+
}, [loading, subscriptions.length]);
|
|
13037
|
+
const criticalSubscriptions = subscriptions.filter(
|
|
13038
|
+
(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
|
|
13039
|
+
);
|
|
13040
|
+
if (loading) {
|
|
13041
|
+
return /* @__PURE__ */ jsx165("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx165("p", { className: "text-muted-foreground", children: "Loading subscriptions..." }) });
|
|
13042
|
+
}
|
|
13043
|
+
return /* @__PURE__ */ jsxs104("div", { className: "flex w-full flex-col gap-y-6", children: [
|
|
13044
|
+
/* @__PURE__ */ jsxs104("div", { className: "flex items-center justify-between", children: [
|
|
13045
|
+
/* @__PURE__ */ jsxs104("div", { className: "flex items-center gap-x-3", children: [
|
|
13046
|
+
/* @__PURE__ */ jsx165(CreditCard3, { className: "h-8 w-8" }),
|
|
13047
|
+
/* @__PURE__ */ jsx165("h1", { className: "text-3xl font-bold", children: "Subscriptions" })
|
|
13048
|
+
] }),
|
|
13049
|
+
subscriptions.length > 0 && /* @__PURE__ */ jsx165(Button, { onClick: () => setShowCreateSubscription(true), children: "Subscribe to a Plan" })
|
|
13050
|
+
] }),
|
|
13051
|
+
criticalSubscriptions.map((subscription) => /* @__PURE__ */ jsx165(BillingAlertBanner, { subscription }, subscription.id)),
|
|
13052
|
+
subscriptions.length === 0 && /* @__PURE__ */ jsxs104("div", { className: "space-y-6", children: [
|
|
13053
|
+
(paymentConfirmationState === "confirming" || isConfirming) && /* @__PURE__ */ jsxs104("div", { className: "flex flex-col items-center justify-center py-12 space-y-4 bg-muted/50 rounded-lg", children: [
|
|
13054
|
+
/* @__PURE__ */ jsx165(Loader23, { className: "h-8 w-8 animate-spin text-primary" }),
|
|
13055
|
+
/* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
|
|
13056
|
+
/* @__PURE__ */ jsx165("p", { className: "font-medium", children: "Processing payment..." }),
|
|
13057
|
+
/* @__PURE__ */ jsx165("p", { className: "text-sm text-muted-foreground", children: "Please complete any verification if prompted." })
|
|
13058
|
+
] })
|
|
13059
|
+
] }),
|
|
13060
|
+
paymentConfirmationState === "success" && /* @__PURE__ */ jsxs104("div", { className: "flex flex-col items-center justify-center py-8 space-y-4 bg-green-50 rounded-lg border border-green-200", children: [
|
|
13061
|
+
/* @__PURE__ */ jsx165(CheckCircle2, { className: "h-12 w-12 text-green-500" }),
|
|
13062
|
+
/* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
|
|
13063
|
+
/* @__PURE__ */ jsx165("p", { className: "font-medium text-green-600", children: "Payment successful!" }),
|
|
13064
|
+
/* @__PURE__ */ jsx165("p", { className: "text-sm text-muted-foreground", children: "Your subscription is now active." })
|
|
13065
|
+
] })
|
|
13066
|
+
] }),
|
|
13067
|
+
paymentConfirmationState === "error" && /* @__PURE__ */ jsxs104(Alert, { variant: "destructive", children: [
|
|
13068
|
+
/* @__PURE__ */ jsx165(AlertTitle, { children: "Payment Failed" }),
|
|
13069
|
+
/* @__PURE__ */ jsxs104(AlertDescription, { className: "mt-2", children: [
|
|
13070
|
+
/* @__PURE__ */ jsx165("p", { className: "mb-4", children: paymentError || "We couldn't process your payment. Please try again." }),
|
|
13071
|
+
/* @__PURE__ */ jsx165(
|
|
13072
|
+
Button,
|
|
13073
|
+
{
|
|
13074
|
+
onClick: () => {
|
|
13075
|
+
setPaymentConfirmationState("idle");
|
|
13076
|
+
setPaymentError(null);
|
|
13077
|
+
},
|
|
13078
|
+
variant: "outline",
|
|
13079
|
+
children: "Try Again"
|
|
13080
|
+
}
|
|
13081
|
+
)
|
|
13082
|
+
] })
|
|
13083
|
+
] }),
|
|
13084
|
+
paymentConfirmationState === "idle" && !isConfirming && /* @__PURE__ */ jsxs104(Fragment32, { children: [
|
|
13085
|
+
/* @__PURE__ */ jsxs104("div", { className: "text-center", children: [
|
|
13086
|
+
/* @__PURE__ */ jsx165(CreditCard3, { className: "text-muted-foreground mx-auto h-16 w-16 mb-4" }),
|
|
13087
|
+
/* @__PURE__ */ jsx165("h3", { className: "mb-2 text-xl font-semibold", children: "Choose Your Plan" }),
|
|
13088
|
+
/* @__PURE__ */ jsx165("p", { className: "text-muted-foreground mb-6", children: "Select a subscription plan to get started with our services." })
|
|
13089
|
+
] }),
|
|
13090
|
+
/* @__PURE__ */ jsx165(
|
|
13091
|
+
PricingCardsGrid,
|
|
13092
|
+
{
|
|
13093
|
+
products,
|
|
13094
|
+
pricesByProduct,
|
|
13095
|
+
loading: loadingPricing,
|
|
13096
|
+
loadingPriceId: creatingSubscription ? pendingPriceId ?? void 0 : void 0,
|
|
13097
|
+
onSelectPrice: handleSelectPrice
|
|
13098
|
+
}
|
|
13099
|
+
)
|
|
13100
|
+
] })
|
|
13101
|
+
] }),
|
|
13102
|
+
subscriptions.length > 0 && /* @__PURE__ */ jsx165(SubscriptionsList, { subscriptions, onSubscriptionsChange: loadSubscriptions }),
|
|
13103
|
+
showCreateSubscription && /* @__PURE__ */ jsx165(
|
|
13104
|
+
SubscriptionEditor,
|
|
13105
|
+
{
|
|
13106
|
+
open: showCreateSubscription,
|
|
13107
|
+
onOpenChange: setShowCreateSubscription,
|
|
13108
|
+
onSuccess: loadSubscriptions,
|
|
13109
|
+
onAddPaymentMethod: () => {
|
|
13110
|
+
setShowCreateSubscription(false);
|
|
13111
|
+
setShowPaymentMethodEditor(true);
|
|
13112
|
+
}
|
|
13113
|
+
}
|
|
13114
|
+
),
|
|
13115
|
+
showPaymentMethodEditor && /* @__PURE__ */ jsx165(
|
|
13116
|
+
PaymentMethodEditor,
|
|
13117
|
+
{
|
|
13118
|
+
open: showPaymentMethodEditor,
|
|
13119
|
+
onOpenChange: (open) => {
|
|
13120
|
+
setShowPaymentMethodEditor(open);
|
|
13121
|
+
if (!open) {
|
|
13122
|
+
setPendingPriceId(null);
|
|
13123
|
+
}
|
|
13124
|
+
},
|
|
13125
|
+
onSuccess: handlePaymentMethodSuccess
|
|
13126
|
+
}
|
|
13127
|
+
)
|
|
13128
|
+
] });
|
|
13129
|
+
}
|
|
13130
|
+
__name(SubscriptionsContainer, "SubscriptionsContainer");
|
|
13131
|
+
|
|
13132
|
+
// src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
|
|
13133
|
+
import { Activity as Activity3 } from "lucide-react";
|
|
13134
|
+
import { useEffect as useEffect46, useState as useState61 } from "react";
|
|
13135
|
+
|
|
13136
|
+
// src/features/billing/stripe-usage/components/details/UsageSummaryCard.tsx
|
|
13137
|
+
import { Activity as Activity2 } from "lucide-react";
|
|
13138
|
+
import { jsx as jsx166, jsxs as jsxs105 } from "react/jsx-runtime";
|
|
13139
|
+
function getProgressColor(percentage) {
|
|
13140
|
+
if (percentage === null) return "bg-blue-500";
|
|
13141
|
+
if (percentage >= 90) return "bg-red-500";
|
|
13142
|
+
if (percentage >= 75) return "bg-orange-500";
|
|
13143
|
+
return "bg-green-500";
|
|
13144
|
+
}
|
|
13145
|
+
__name(getProgressColor, "getProgressColor");
|
|
13146
|
+
function formatDate4(date) {
|
|
13147
|
+
if (!date) return "N/A";
|
|
13148
|
+
try {
|
|
13149
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
13150
|
+
month: "short",
|
|
13151
|
+
day: "numeric"
|
|
13152
|
+
}).format(new Date(date));
|
|
13153
|
+
} catch (error) {
|
|
13154
|
+
return "Invalid Date";
|
|
13155
|
+
}
|
|
13156
|
+
}
|
|
13157
|
+
__name(formatDate4, "formatDate");
|
|
13158
|
+
function UsageSummaryCard({ meter, summary }) {
|
|
13159
|
+
const currentUsage = summary?.aggregatedValue ?? 0;
|
|
13160
|
+
const limit = meter.limit;
|
|
13161
|
+
const percentage = limit && limit > 0 ? currentUsage / limit * 100 : null;
|
|
13162
|
+
const progressColor = getProgressColor(percentage);
|
|
13163
|
+
const progressWidth = percentage !== null ? Math.min(percentage, 100) : 0;
|
|
13164
|
+
const displayName = meter.displayName || meter.eventName;
|
|
13165
|
+
const hasLimit = limit !== null && limit !== void 0;
|
|
13166
|
+
return /* @__PURE__ */ jsxs105(Card, { children: [
|
|
13167
|
+
/* @__PURE__ */ jsxs105(CardHeader, { className: "flex flex-row items-center gap-x-3 pb-3", children: [
|
|
13168
|
+
/* @__PURE__ */ jsx166("div", { className: "flex h-10 w-10 items-center justify-center rounded-lg bg-blue-100 text-blue-600", children: /* @__PURE__ */ jsx166(Activity2, { className: "h-5 w-5" }) }),
|
|
13169
|
+
/* @__PURE__ */ jsxs105("div", { className: "flex flex-col", children: [
|
|
13170
|
+
/* @__PURE__ */ jsx166("h3", { className: "font-semibold", children: displayName }),
|
|
13171
|
+
/* @__PURE__ */ jsx166("p", { className: "text-xs text-gray-500", children: meter.id })
|
|
13172
|
+
] })
|
|
13173
|
+
] }),
|
|
13174
|
+
/* @__PURE__ */ jsxs105(CardContent, { className: "flex flex-col gap-y-4", children: [
|
|
13175
|
+
/* @__PURE__ */ jsxs105("div", { children: [
|
|
13176
|
+
/* @__PURE__ */ jsx166("p", { className: "text-3xl font-bold", children: currentUsage.toLocaleString() }),
|
|
13177
|
+
hasLimit && /* @__PURE__ */ jsxs105("p", { className: "text-sm text-gray-500", children: [
|
|
13178
|
+
"of ",
|
|
13179
|
+
limit.toLocaleString(),
|
|
13180
|
+
" used"
|
|
13181
|
+
] })
|
|
13182
|
+
] }),
|
|
13183
|
+
hasLimit ? /* @__PURE__ */ jsxs105("div", { className: "flex flex-col gap-y-2", children: [
|
|
13184
|
+
/* @__PURE__ */ jsx166("div", { className: "h-2 w-full overflow-hidden rounded-full bg-gray-200", children: /* @__PURE__ */ jsx166("div", { className: `h-full transition-all ${progressColor}`, style: { width: `${progressWidth}%` } }) }),
|
|
13185
|
+
/* @__PURE__ */ jsxs105("p", { className: "text-sm text-gray-500", children: [
|
|
13186
|
+
percentage?.toFixed(1),
|
|
13187
|
+
"% used"
|
|
13188
|
+
] })
|
|
13189
|
+
] }) : /* @__PURE__ */ jsx166("p", { className: "text-sm text-gray-500", children: "No limit set" }),
|
|
13190
|
+
summary && summary.start && summary.end && /* @__PURE__ */ jsx166("div", { className: "border-t pt-3", children: /* @__PURE__ */ jsxs105("p", { className: "text-xs text-gray-500", children: [
|
|
13191
|
+
"Period: ",
|
|
13192
|
+
formatDate4(summary.start),
|
|
13193
|
+
" - ",
|
|
13194
|
+
formatDate4(summary.end)
|
|
13195
|
+
] }) })
|
|
13196
|
+
] })
|
|
13197
|
+
] });
|
|
13198
|
+
}
|
|
13199
|
+
__name(UsageSummaryCard, "UsageSummaryCard");
|
|
13200
|
+
|
|
13201
|
+
// src/features/billing/stripe-usage/components/widgets/UsageSummaryCards.tsx
|
|
13202
|
+
import { jsx as jsx167 } from "react/jsx-runtime";
|
|
13203
|
+
function UsageSummaryCards({ meters, summaries }) {
|
|
13204
|
+
return /* @__PURE__ */ jsx167("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", children: meters.map((meter) => /* @__PURE__ */ jsx167(UsageSummaryCard, { meter, summary: summaries[meter.id] || null }, meter.id)) });
|
|
13205
|
+
}
|
|
13206
|
+
__name(UsageSummaryCards, "UsageSummaryCards");
|
|
13207
|
+
|
|
13208
|
+
// src/features/billing/stripe-usage/components/containers/UsageContainer.tsx
|
|
13209
|
+
import { jsx as jsx168, jsxs as jsxs106 } from "react/jsx-runtime";
|
|
13210
|
+
function UsageContainer() {
|
|
13211
|
+
const [meters, setMeters] = useState61([]);
|
|
13212
|
+
const [summaries, setSummaries] = useState61({});
|
|
13213
|
+
const [loading, setLoading] = useState61(true);
|
|
13214
|
+
const [subscriptions, setSubscriptions] = useState61([]);
|
|
13215
|
+
useEffect46(() => {
|
|
13216
|
+
loadUsageData();
|
|
13217
|
+
}, []);
|
|
13218
|
+
const loadUsageData = /* @__PURE__ */ __name(async () => {
|
|
13219
|
+
setLoading(true);
|
|
13220
|
+
try {
|
|
13221
|
+
const fetchedSubscriptions = await StripeSubscriptionService.listSubscriptions();
|
|
13222
|
+
setSubscriptions(fetchedSubscriptions);
|
|
13223
|
+
const hasMeteredSubscriptions2 = fetchedSubscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
|
|
13224
|
+
if (!hasMeteredSubscriptions2) {
|
|
13225
|
+
setLoading(false);
|
|
13226
|
+
return;
|
|
13227
|
+
}
|
|
13228
|
+
const fetchedMeters = await StripeUsageService.listMeters();
|
|
13229
|
+
setMeters(fetchedMeters);
|
|
13230
|
+
const summariesMap = {};
|
|
13231
|
+
const now = /* @__PURE__ */ new Date();
|
|
13232
|
+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
13233
|
+
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
13234
|
+
for (const meter of fetchedMeters) {
|
|
13235
|
+
try {
|
|
13236
|
+
const meterSummaries = await StripeUsageService.getMeterSummaries({
|
|
13237
|
+
meterId: meter.id,
|
|
13238
|
+
startTime: startOfMonth,
|
|
13239
|
+
endTime: endOfMonth
|
|
13240
|
+
});
|
|
13241
|
+
summariesMap[meter.id] = meterSummaries.length > 0 ? meterSummaries[0] : null;
|
|
13242
|
+
} catch (error) {
|
|
13243
|
+
console.error(`[UsageContainer] Failed to load summaries for meter ${meter.id}:`, error);
|
|
13244
|
+
summariesMap[meter.id] = null;
|
|
13245
|
+
}
|
|
13246
|
+
}
|
|
13247
|
+
setSummaries(summariesMap);
|
|
13248
|
+
} catch (error) {
|
|
13249
|
+
console.error("[UsageContainer] Failed to load usage data:", error);
|
|
13250
|
+
} finally {
|
|
13251
|
+
setLoading(false);
|
|
13252
|
+
}
|
|
13253
|
+
}, "loadUsageData");
|
|
13254
|
+
const hasMeteredSubscriptions = subscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
|
|
13255
|
+
if (!loading && !hasMeteredSubscriptions) {
|
|
13256
|
+
return null;
|
|
13257
|
+
}
|
|
13258
|
+
if (loading) {
|
|
13259
|
+
return /* @__PURE__ */ jsx168("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx168("p", { className: "text-muted-foreground", children: "Loading usage data..." }) });
|
|
13260
|
+
}
|
|
13261
|
+
return /* @__PURE__ */ jsxs106("div", { className: "flex w-full flex-col gap-y-6", children: [
|
|
13262
|
+
/* @__PURE__ */ jsxs106("div", { className: "flex items-center gap-x-3", children: [
|
|
13263
|
+
/* @__PURE__ */ jsx168(Activity3, { className: "h-8 w-8" }),
|
|
13264
|
+
/* @__PURE__ */ jsx168("h1", { className: "text-3xl font-bold", children: "Usage Tracking" })
|
|
13265
|
+
] }),
|
|
13266
|
+
meters.length === 0 && /* @__PURE__ */ jsxs106("div", { className: "bg-muted/50 flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed border-gray-300 p-12", children: [
|
|
13267
|
+
/* @__PURE__ */ jsx168(Activity3, { className: "text-muted-foreground h-16 w-16" }),
|
|
13268
|
+
/* @__PURE__ */ jsxs106("div", { className: "text-center", children: [
|
|
13269
|
+
/* @__PURE__ */ jsx168("h3", { className: "mb-2 text-xl font-semibold", children: "No usage meters configured" }),
|
|
13270
|
+
/* @__PURE__ */ jsx168("p", { className: "text-muted-foreground", children: "Usage tracking will appear here when you have metered subscriptions with configured meters." })
|
|
13271
|
+
] })
|
|
13272
|
+
] }),
|
|
13273
|
+
meters.length > 0 && /* @__PURE__ */ jsx168(UsageSummaryCards, { meters, summaries })
|
|
13274
|
+
] });
|
|
13275
|
+
}
|
|
13276
|
+
__name(UsageContainer, "UsageContainer");
|
|
13277
|
+
|
|
13278
|
+
// src/features/billing/stripe-usage/components/lists/UsageHistoryTable.tsx
|
|
13279
|
+
import { jsx as jsx169, jsxs as jsxs107 } from "react/jsx-runtime";
|
|
13280
|
+
function formatDateTime(date) {
|
|
13281
|
+
if (!date) return "N/A";
|
|
13282
|
+
const dateObj = typeof date === "string" ? new Date(date) : date;
|
|
13283
|
+
try {
|
|
13284
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
13285
|
+
month: "short",
|
|
13286
|
+
day: "numeric",
|
|
13287
|
+
year: "numeric",
|
|
13288
|
+
hour: "numeric",
|
|
13289
|
+
minute: "2-digit"
|
|
13290
|
+
}).format(dateObj);
|
|
13291
|
+
} catch (error) {
|
|
13292
|
+
return "Invalid Date";
|
|
13293
|
+
}
|
|
13294
|
+
}
|
|
13295
|
+
__name(formatDateTime, "formatDateTime");
|
|
13296
|
+
function UsageHistoryTable({ usageRecords }) {
|
|
13297
|
+
if (usageRecords.length === 0) {
|
|
13298
|
+
return /* @__PURE__ */ jsx169("div", { className: "rounded-lg border p-8 text-center", children: /* @__PURE__ */ jsx169("p", { className: "text-muted-foreground", children: "No usage history available." }) });
|
|
13299
|
+
}
|
|
13300
|
+
return /* @__PURE__ */ jsxs107("div", { className: "flex w-full flex-col gap-y-4", children: [
|
|
13301
|
+
/* @__PURE__ */ jsx169("h2", { className: "text-xl font-semibold", children: "Usage History" }),
|
|
13302
|
+
/* @__PURE__ */ jsx169("div", { className: "overflow-hidden rounded-lg border", children: /* @__PURE__ */ jsxs107(Table, { children: [
|
|
13303
|
+
/* @__PURE__ */ jsx169(TableHeader, { className: "bg-muted", children: /* @__PURE__ */ jsxs107(TableRow, { children: [
|
|
13304
|
+
/* @__PURE__ */ jsx169(TableHead, { children: "Date & Time" }),
|
|
13305
|
+
/* @__PURE__ */ jsx169(TableHead, { children: "Meter Event" }),
|
|
13306
|
+
/* @__PURE__ */ jsx169(TableHead, { className: "text-right", children: "Quantity" }),
|
|
13307
|
+
/* @__PURE__ */ jsx169(TableHead, { children: "Event ID" })
|
|
13308
|
+
] }) }),
|
|
13309
|
+
/* @__PURE__ */ jsx169(TableBody, { children: usageRecords.map((record) => {
|
|
13310
|
+
const dateTime = formatDateTime(record.timestamp);
|
|
13311
|
+
const quantity = record.quantity.toLocaleString();
|
|
13312
|
+
return /* @__PURE__ */ jsxs107(TableRow, { children: [
|
|
13313
|
+
/* @__PURE__ */ jsx169(TableCell, { className: "font-medium", children: dateTime }),
|
|
13314
|
+
/* @__PURE__ */ jsx169(TableCell, { className: "text-muted-foreground", children: record.meterEventName }),
|
|
13315
|
+
/* @__PURE__ */ jsx169(TableCell, { className: "text-right font-medium", children: quantity }),
|
|
13316
|
+
/* @__PURE__ */ jsx169(TableCell, { className: "text-muted-foreground text-sm font-mono", children: record.stripeEventId })
|
|
13317
|
+
] }, record.id);
|
|
13318
|
+
}) })
|
|
13319
|
+
] }) })
|
|
13320
|
+
] });
|
|
13321
|
+
}
|
|
13322
|
+
__name(UsageHistoryTable, "UsageHistoryTable");
|
|
13323
|
+
|
|
13324
|
+
// src/features/billing/components/modals/BillingDetailModal.tsx
|
|
13325
|
+
import { jsx as jsx170, jsxs as jsxs108 } from "react/jsx-runtime";
|
|
13326
|
+
function BillingDetailModal({
|
|
13327
|
+
open,
|
|
13328
|
+
onOpenChange,
|
|
13329
|
+
title,
|
|
13330
|
+
children,
|
|
13331
|
+
className
|
|
13332
|
+
}) {
|
|
13333
|
+
return /* @__PURE__ */ jsx170(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs108(DialogContent, { className: className ?? "max-w-4xl max-h-[90vh] overflow-y-auto", children: [
|
|
13334
|
+
/* @__PURE__ */ jsx170(DialogHeader, { children: /* @__PURE__ */ jsx170(DialogTitle, { children: title }) }),
|
|
13335
|
+
children
|
|
13336
|
+
] }) });
|
|
13337
|
+
}
|
|
13338
|
+
__name(BillingDetailModal, "BillingDetailModal");
|
|
13339
|
+
|
|
13340
|
+
// src/features/billing/components/widgets/BillingAlertBanner.tsx
|
|
13341
|
+
import { AlertCircle } from "lucide-react";
|
|
13342
|
+
import { jsx as jsx171, jsxs as jsxs109 } from "react/jsx-runtime";
|
|
13343
|
+
function BillingAlertBanner({ subscription, onUpdatePayment, onAddPayment }) {
|
|
13344
|
+
if (subscription.status === "past_due" /* PAST_DUE */) {
|
|
13345
|
+
return /* @__PURE__ */ jsxs109("div", { className: "bg-red-50 border border-red-200 rounded-lg p-4 flex items-start gap-x-3", children: [
|
|
13346
|
+
/* @__PURE__ */ jsx171(AlertCircle, { className: "h-5 w-5 text-red-600 mt-0.5" }),
|
|
13347
|
+
/* @__PURE__ */ jsxs109("div", { className: "flex-1", children: [
|
|
13348
|
+
/* @__PURE__ */ jsx171("h3", { className: "font-semibold text-red-900", children: "Payment Failed" }),
|
|
13349
|
+
/* @__PURE__ */ jsx171("p", { className: "text-sm text-red-700 mt-1", children: "Your last payment failed. Please update your payment method to avoid service interruption." })
|
|
13350
|
+
] }),
|
|
13351
|
+
onUpdatePayment && /* @__PURE__ */ jsx171(Button, { variant: "outline", size: "sm", onClick: onUpdatePayment, className: "border-red-300 text-red-700", children: "Update Payment Method" })
|
|
13352
|
+
] });
|
|
13353
|
+
}
|
|
13354
|
+
if (subscription.status === "trialing" /* TRIALING */ && subscription.trialEnd) {
|
|
13355
|
+
const trialEnd = new Date(subscription.trialEnd);
|
|
13356
|
+
const now = /* @__PURE__ */ new Date();
|
|
13357
|
+
const daysRemaining = Math.ceil((trialEnd.getTime() - now.getTime()) / (1e3 * 60 * 60 * 24));
|
|
13358
|
+
if (daysRemaining <= 7) {
|
|
13359
|
+
return /* @__PURE__ */ jsxs109("div", { className: "bg-yellow-50 border border-yellow-200 rounded-lg p-4 flex items-start gap-x-3", children: [
|
|
13360
|
+
/* @__PURE__ */ jsx171(AlertCircle, { className: "h-5 w-5 text-yellow-600 mt-0.5" }),
|
|
13361
|
+
/* @__PURE__ */ jsxs109("div", { className: "flex-1", children: [
|
|
13362
|
+
/* @__PURE__ */ jsx171("h3", { className: "font-semibold text-yellow-900", children: "Trial Ending Soon" }),
|
|
13363
|
+
/* @__PURE__ */ jsxs109("p", { className: "text-sm text-yellow-700 mt-1", children: [
|
|
13364
|
+
"Your trial ends in ",
|
|
13365
|
+
daysRemaining,
|
|
13366
|
+
" ",
|
|
13367
|
+
daysRemaining === 1 ? "day" : "days",
|
|
13368
|
+
". Add a payment method to continue your subscription."
|
|
13369
|
+
] })
|
|
13370
|
+
] }),
|
|
13371
|
+
onAddPayment && /* @__PURE__ */ jsx171(Button, { variant: "outline", size: "sm", onClick: onAddPayment, className: "border-yellow-300 text-yellow-700", children: "Add Payment Method" })
|
|
13372
|
+
] });
|
|
13373
|
+
}
|
|
13374
|
+
}
|
|
13375
|
+
return null;
|
|
13376
|
+
}
|
|
13377
|
+
__name(BillingAlertBanner, "BillingAlertBanner");
|
|
13378
|
+
|
|
13379
|
+
// src/features/billing/components/containers/BillingDashboardContainer.tsx
|
|
13380
|
+
import { Fragment as Fragment33, jsx as jsx172, jsxs as jsxs110 } from "react/jsx-runtime";
|
|
13381
|
+
function BillingDashboardContainer() {
|
|
13382
|
+
const [data, setData] = useState62({
|
|
13383
|
+
customer: null,
|
|
13384
|
+
subscriptions: [],
|
|
13385
|
+
paymentMethods: [],
|
|
13386
|
+
invoices: [],
|
|
13387
|
+
meters: [],
|
|
13388
|
+
meterSummaries: {}
|
|
13389
|
+
});
|
|
13390
|
+
const [loading, setLoading] = useState62({
|
|
13391
|
+
customer: true,
|
|
13392
|
+
subscriptions: true,
|
|
13393
|
+
paymentMethods: true,
|
|
13394
|
+
invoices: true,
|
|
13395
|
+
usage: true
|
|
13396
|
+
});
|
|
13397
|
+
const [errors, setErrors] = useState62({
|
|
13398
|
+
customer: null,
|
|
13399
|
+
subscriptions: null,
|
|
13400
|
+
paymentMethods: null,
|
|
13401
|
+
invoices: null,
|
|
13402
|
+
usage: null
|
|
13403
|
+
});
|
|
13404
|
+
const [activeModal, setActiveModal] = useState62(null);
|
|
13405
|
+
const [noCustomerExists, setNoCustomerExists] = useState62(false);
|
|
13406
|
+
const [creatingCustomer, setCreatingCustomer] = useState62(false);
|
|
13407
|
+
const hasMeteredSubscriptions = useCallback18(() => {
|
|
13408
|
+
return data.subscriptions.some((sub) => sub.price?.recurring?.usageType === "metered");
|
|
13409
|
+
}, [data.subscriptions]);
|
|
13410
|
+
const fetchAllData = useCallback18(async () => {
|
|
13411
|
+
setNoCustomerExists(false);
|
|
13412
|
+
let customer = null;
|
|
13413
|
+
try {
|
|
13414
|
+
customer = await StripeCustomerService.getCustomer();
|
|
13415
|
+
setData((prev) => ({ ...prev, customer }));
|
|
13416
|
+
setErrors((prev) => ({ ...prev, customer: null }));
|
|
13417
|
+
setNoCustomerExists(false);
|
|
13418
|
+
} catch (error) {
|
|
13419
|
+
console.error("[BillingDashboard] Failed to load customer:", error);
|
|
13420
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
13421
|
+
if (errorMessage.includes("Not Found") || errorMessage.includes("not found")) {
|
|
13422
|
+
setNoCustomerExists(true);
|
|
13423
|
+
setLoading({
|
|
13424
|
+
customer: false,
|
|
13425
|
+
subscriptions: false,
|
|
13426
|
+
paymentMethods: false,
|
|
13427
|
+
invoices: false,
|
|
13428
|
+
usage: false
|
|
13429
|
+
});
|
|
13430
|
+
return;
|
|
13431
|
+
}
|
|
13432
|
+
setErrors((prev) => ({ ...prev, customer: "Failed to load billing account" }));
|
|
13433
|
+
} finally {
|
|
13434
|
+
setLoading((prev) => ({ ...prev, customer: false }));
|
|
13435
|
+
}
|
|
13436
|
+
if (customer) {
|
|
13437
|
+
const fetchSubscriptions = /* @__PURE__ */ __name(async () => {
|
|
13438
|
+
try {
|
|
13439
|
+
const subscriptions2 = await StripeSubscriptionService.listSubscriptions();
|
|
13440
|
+
setData((prev) => ({ ...prev, subscriptions: subscriptions2 }));
|
|
13441
|
+
setErrors((prev) => ({ ...prev, subscriptions: null }));
|
|
13442
|
+
return subscriptions2;
|
|
13443
|
+
} catch (error) {
|
|
13444
|
+
console.error("[BillingDashboard] Failed to load subscriptions:", error);
|
|
13445
|
+
setErrors((prev) => ({ ...prev, subscriptions: "Failed to load subscriptions" }));
|
|
13446
|
+
return [];
|
|
13447
|
+
} finally {
|
|
13448
|
+
setLoading((prev) => ({ ...prev, subscriptions: false }));
|
|
13449
|
+
}
|
|
13450
|
+
}, "fetchSubscriptions");
|
|
13451
|
+
const fetchPaymentMethods = /* @__PURE__ */ __name(async () => {
|
|
13452
|
+
try {
|
|
13453
|
+
const paymentMethods = await StripeCustomerService.listPaymentMethods();
|
|
13454
|
+
setData((prev) => ({ ...prev, paymentMethods }));
|
|
13455
|
+
setErrors((prev) => ({ ...prev, paymentMethods: null }));
|
|
13456
|
+
} catch (error) {
|
|
13457
|
+
console.error("[BillingDashboard] Failed to load payment methods:", error);
|
|
13458
|
+
setErrors((prev) => ({ ...prev, paymentMethods: "Failed to load payment methods" }));
|
|
13459
|
+
} finally {
|
|
13460
|
+
setLoading((prev) => ({ ...prev, paymentMethods: false }));
|
|
13461
|
+
}
|
|
13462
|
+
}, "fetchPaymentMethods");
|
|
13463
|
+
const fetchInvoices = /* @__PURE__ */ __name(async () => {
|
|
13464
|
+
try {
|
|
13465
|
+
const invoices = await StripeInvoiceService.listInvoices();
|
|
13466
|
+
setData((prev) => ({ ...prev, invoices }));
|
|
13467
|
+
setErrors((prev) => ({ ...prev, invoices: null }));
|
|
13468
|
+
} catch (error) {
|
|
13469
|
+
console.error("[BillingDashboard] Failed to load invoices:", error);
|
|
13470
|
+
setErrors((prev) => ({ ...prev, invoices: "Failed to load invoices" }));
|
|
13471
|
+
} finally {
|
|
13472
|
+
setLoading((prev) => ({ ...prev, invoices: false }));
|
|
13473
|
+
}
|
|
13474
|
+
}, "fetchInvoices");
|
|
13475
|
+
const [subscriptions] = await Promise.all([fetchSubscriptions(), fetchPaymentMethods(), fetchInvoices()]);
|
|
13476
|
+
const hasMetered = subscriptions.some(
|
|
13477
|
+
(sub) => sub.price?.recurring?.usageType === "metered"
|
|
13478
|
+
);
|
|
13479
|
+
if (hasMetered) {
|
|
13480
|
+
await fetchUsageData();
|
|
13481
|
+
} else {
|
|
13482
|
+
setLoading((prev) => ({ ...prev, usage: false }));
|
|
13483
|
+
}
|
|
13484
|
+
}
|
|
13485
|
+
}, []);
|
|
13486
|
+
const handleCreateCustomer = /* @__PURE__ */ __name(async () => {
|
|
13487
|
+
setCreatingCustomer(true);
|
|
13488
|
+
try {
|
|
13489
|
+
await StripeCustomerService.createCustomer();
|
|
13490
|
+
setNoCustomerExists(false);
|
|
13491
|
+
await fetchAllData();
|
|
13492
|
+
} catch (error) {
|
|
13493
|
+
console.error("[BillingDashboard] Failed to create customer:", error);
|
|
13494
|
+
setErrors((prev) => ({ ...prev, customer: "Failed to set up billing" }));
|
|
13495
|
+
} finally {
|
|
13496
|
+
setCreatingCustomer(false);
|
|
13497
|
+
}
|
|
13498
|
+
}, "handleCreateCustomer");
|
|
13499
|
+
const fetchUsageData = /* @__PURE__ */ __name(async () => {
|
|
13500
|
+
try {
|
|
13501
|
+
const meters = await StripeUsageService.listMeters();
|
|
13502
|
+
setData((prev) => ({ ...prev, meters }));
|
|
13503
|
+
const summariesMap = {};
|
|
13504
|
+
const now = /* @__PURE__ */ new Date();
|
|
13505
|
+
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
13506
|
+
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999);
|
|
13507
|
+
for (const meter of meters) {
|
|
13508
|
+
try {
|
|
13509
|
+
const meterSummaries = await StripeUsageService.getMeterSummaries({
|
|
13510
|
+
meterId: meter.id,
|
|
13511
|
+
startTime: startOfMonth,
|
|
13512
|
+
endTime: endOfMonth
|
|
13513
|
+
});
|
|
13514
|
+
summariesMap[meter.id] = meterSummaries.length > 0 ? meterSummaries[0] : null;
|
|
13515
|
+
} catch (error) {
|
|
13516
|
+
console.error(`[BillingDashboard] Failed to load summaries for meter ${meter.id}:`, error);
|
|
13517
|
+
summariesMap[meter.id] = null;
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13520
|
+
setData((prev) => ({ ...prev, meterSummaries: summariesMap }));
|
|
13521
|
+
setErrors((prev) => ({ ...prev, usage: null }));
|
|
13522
|
+
} catch (error) {
|
|
13523
|
+
console.error("[BillingDashboard] Failed to load usage data:", error);
|
|
13524
|
+
setErrors((prev) => ({ ...prev, usage: "Failed to load usage data" }));
|
|
13525
|
+
} finally {
|
|
13526
|
+
setLoading((prev) => ({ ...prev, usage: false }));
|
|
13527
|
+
}
|
|
13528
|
+
}, "fetchUsageData");
|
|
13529
|
+
const refreshData = useCallback18(async () => {
|
|
13530
|
+
setLoading({
|
|
13531
|
+
customer: true,
|
|
13532
|
+
subscriptions: true,
|
|
13533
|
+
paymentMethods: true,
|
|
13534
|
+
invoices: true,
|
|
13535
|
+
usage: true
|
|
13536
|
+
});
|
|
13537
|
+
await fetchAllData();
|
|
13538
|
+
}, [fetchAllData]);
|
|
13539
|
+
useEffect47(() => {
|
|
13540
|
+
fetchAllData();
|
|
13541
|
+
}, [fetchAllData]);
|
|
13542
|
+
const criticalSubscriptions = data.subscriptions.filter(
|
|
13543
|
+
(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
|
|
13544
|
+
);
|
|
13545
|
+
const handleModalClose = /* @__PURE__ */ __name((open) => {
|
|
13546
|
+
if (!open) {
|
|
13547
|
+
setActiveModal(null);
|
|
13548
|
+
refreshData();
|
|
13549
|
+
}
|
|
13550
|
+
}, "handleModalClose");
|
|
13551
|
+
const getModalTitle = /* @__PURE__ */ __name((type) => {
|
|
13552
|
+
switch (type) {
|
|
13553
|
+
case "subscriptions":
|
|
13554
|
+
return "Manage Subscriptions";
|
|
13555
|
+
case "payment-methods":
|
|
13556
|
+
return "Payment Methods";
|
|
13557
|
+
case "invoices":
|
|
13558
|
+
return "Invoice History";
|
|
13559
|
+
case "usage":
|
|
13560
|
+
return "Usage Tracking";
|
|
13561
|
+
default:
|
|
13562
|
+
return "";
|
|
13563
|
+
}
|
|
13564
|
+
}, "getModalTitle");
|
|
13565
|
+
const isInitialLoading = loading.customer && !noCustomerExists && !data.customer;
|
|
13566
|
+
return /* @__PURE__ */ jsxs110("div", { className: "flex w-full flex-col gap-y-6", children: [
|
|
13567
|
+
/* @__PURE__ */ jsxs110("div", { className: "flex items-center gap-x-3", children: [
|
|
13568
|
+
/* @__PURE__ */ jsx172(Wallet2, { className: "h-8 w-8" }),
|
|
13569
|
+
/* @__PURE__ */ jsx172("h1", { className: "text-3xl font-bold", children: "Billing" })
|
|
13570
|
+
] }),
|
|
13571
|
+
isInitialLoading && /* @__PURE__ */ jsx172(Card, { children: /* @__PURE__ */ jsx172(CardContent, { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsx172(Loader24, { className: "h-8 w-8 animate-spin text-muted-foreground" }) }) }),
|
|
13572
|
+
noCustomerExists && !isInitialLoading && /* @__PURE__ */ jsxs110(Card, { children: [
|
|
13573
|
+
/* @__PURE__ */ jsxs110(CardHeader, { className: "text-center", children: [
|
|
13574
|
+
/* @__PURE__ */ jsx172("div", { className: "mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx172(CreditCard4, { className: "h-8 w-8 text-primary" }) }),
|
|
13575
|
+
/* @__PURE__ */ jsx172(CardTitle, { children: "Set Up Billing" }),
|
|
13576
|
+
/* @__PURE__ */ jsx172(CardDescription, { children: "Your company doesn't have a billing account yet. Set one up to manage subscriptions, payment methods, and view invoices." })
|
|
13577
|
+
] }),
|
|
13578
|
+
/* @__PURE__ */ jsx172(CardContent, { className: "flex justify-center pb-8", children: /* @__PURE__ */ jsx172(Button, { onClick: handleCreateCustomer, disabled: creatingCustomer, size: "lg", children: creatingCustomer ? /* @__PURE__ */ jsxs110(Fragment33, { children: [
|
|
13579
|
+
/* @__PURE__ */ jsx172(Loader24, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
13580
|
+
"Setting up..."
|
|
13581
|
+
] }) : "Set Up Billing Account" }) }),
|
|
13582
|
+
errors.customer && /* @__PURE__ */ jsx172(CardContent, { className: "pt-0", children: /* @__PURE__ */ jsx172("p", { className: "text-center text-sm text-destructive", children: errors.customer }) })
|
|
13583
|
+
] }),
|
|
13584
|
+
!noCustomerExists && !isInitialLoading && /* @__PURE__ */ jsxs110(Fragment33, { children: [
|
|
13585
|
+
criticalSubscriptions.map((subscription) => /* @__PURE__ */ jsx172(
|
|
13586
|
+
BillingAlertBanner,
|
|
13587
|
+
{
|
|
13588
|
+
subscription,
|
|
13589
|
+
onUpdatePayment: () => setActiveModal("payment-methods"),
|
|
13590
|
+
onAddPayment: () => setActiveModal("payment-methods")
|
|
13591
|
+
},
|
|
13592
|
+
subscription.id
|
|
13593
|
+
)),
|
|
13594
|
+
/* @__PURE__ */ jsxs110("div", { className: "grid gap-4 md:grid-cols-2", children: [
|
|
13595
|
+
/* @__PURE__ */ jsx172(
|
|
13596
|
+
SubscriptionSummaryCard,
|
|
13597
|
+
{
|
|
13598
|
+
subscriptions: data.subscriptions,
|
|
13599
|
+
loading: loading.subscriptions,
|
|
13600
|
+
error: errors.subscriptions || void 0,
|
|
13601
|
+
onManageClick: () => setActiveModal("subscriptions")
|
|
13602
|
+
}
|
|
13603
|
+
),
|
|
13604
|
+
/* @__PURE__ */ jsx172(
|
|
13605
|
+
PaymentMethodSummaryCard,
|
|
13606
|
+
{
|
|
13607
|
+
paymentMethods: data.paymentMethods,
|
|
13608
|
+
defaultPaymentMethodId: data.customer?.defaultPaymentMethodId,
|
|
13609
|
+
loading: loading.paymentMethods,
|
|
13610
|
+
error: errors.paymentMethods || void 0,
|
|
13611
|
+
onManageClick: () => setActiveModal("payment-methods")
|
|
13612
|
+
}
|
|
13613
|
+
),
|
|
13614
|
+
/* @__PURE__ */ jsx172(
|
|
13615
|
+
CustomerInfoCard,
|
|
13616
|
+
{
|
|
13617
|
+
customer: data.customer,
|
|
13618
|
+
loading: loading.customer,
|
|
13619
|
+
error: errors.customer || void 0
|
|
13620
|
+
}
|
|
13621
|
+
),
|
|
13622
|
+
/* @__PURE__ */ jsx172(
|
|
13623
|
+
InvoicesSummaryCard,
|
|
13624
|
+
{
|
|
13625
|
+
invoices: data.invoices,
|
|
13626
|
+
loading: loading.invoices,
|
|
13627
|
+
error: errors.invoices || void 0,
|
|
13628
|
+
onViewAllClick: () => setActiveModal("invoices")
|
|
13629
|
+
}
|
|
13630
|
+
),
|
|
13631
|
+
hasMeteredSubscriptions() && /* @__PURE__ */ jsx172(
|
|
13632
|
+
BillingUsageSummaryCard,
|
|
13633
|
+
{
|
|
13634
|
+
meters: data.meters,
|
|
13635
|
+
summaries: data.meterSummaries,
|
|
13636
|
+
loading: loading.usage,
|
|
13637
|
+
error: errors.usage || void 0,
|
|
13638
|
+
onViewDetailsClick: () => setActiveModal("usage")
|
|
13639
|
+
}
|
|
13640
|
+
)
|
|
13641
|
+
] }),
|
|
13642
|
+
/* @__PURE__ */ jsx172(
|
|
13643
|
+
BillingDetailModal,
|
|
13644
|
+
{
|
|
13645
|
+
open: activeModal === "subscriptions",
|
|
13646
|
+
onOpenChange: handleModalClose,
|
|
13647
|
+
title: getModalTitle("subscriptions"),
|
|
13648
|
+
children: /* @__PURE__ */ jsx172(SubscriptionsContainer, {})
|
|
13649
|
+
}
|
|
13650
|
+
),
|
|
13651
|
+
/* @__PURE__ */ jsx172(
|
|
13652
|
+
BillingDetailModal,
|
|
13653
|
+
{
|
|
13654
|
+
open: activeModal === "payment-methods",
|
|
13655
|
+
onOpenChange: handleModalClose,
|
|
13656
|
+
title: getModalTitle("payment-methods"),
|
|
13657
|
+
children: /* @__PURE__ */ jsx172(PaymentMethodsContainer, {})
|
|
13658
|
+
}
|
|
13659
|
+
),
|
|
13660
|
+
/* @__PURE__ */ jsx172(
|
|
13661
|
+
BillingDetailModal,
|
|
13662
|
+
{
|
|
13663
|
+
open: activeModal === "invoices",
|
|
13664
|
+
onOpenChange: handleModalClose,
|
|
13665
|
+
title: getModalTitle("invoices"),
|
|
13666
|
+
children: /* @__PURE__ */ jsx172(InvoicesContainer, {})
|
|
13667
|
+
}
|
|
13668
|
+
),
|
|
13669
|
+
/* @__PURE__ */ jsx172(
|
|
13670
|
+
BillingDetailModal,
|
|
13671
|
+
{
|
|
13672
|
+
open: activeModal === "usage",
|
|
13673
|
+
onOpenChange: handleModalClose,
|
|
13674
|
+
title: getModalTitle("usage"),
|
|
13675
|
+
children: /* @__PURE__ */ jsx172(UsageContainer, {})
|
|
13676
|
+
}
|
|
13677
|
+
)
|
|
13678
|
+
] })
|
|
13679
|
+
] });
|
|
13680
|
+
}
|
|
13681
|
+
__name(BillingDashboardContainer, "BillingDashboardContainer");
|
|
13682
|
+
|
|
13683
|
+
// src/features/billing/components/providers/StripeProvider.tsx
|
|
13684
|
+
import { Elements } from "@stripe/react-stripe-js";
|
|
13685
|
+
import { loadStripe } from "@stripe/stripe-js";
|
|
13686
|
+
import { useMemo as useMemo18 } from "react";
|
|
13687
|
+
import { Fragment as Fragment34, jsx as jsx173 } from "react/jsx-runtime";
|
|
13688
|
+
var stripePromiseCache = null;
|
|
13689
|
+
function getStripePromise(publishableKey) {
|
|
13690
|
+
if (!publishableKey) {
|
|
13691
|
+
return Promise.resolve(null);
|
|
13692
|
+
}
|
|
13693
|
+
if (stripePromiseCache?.key === publishableKey) {
|
|
13694
|
+
return stripePromiseCache.promise;
|
|
13695
|
+
}
|
|
13696
|
+
const promise = loadStripe(publishableKey);
|
|
13697
|
+
stripePromiseCache = { key: publishableKey, promise };
|
|
13698
|
+
return promise;
|
|
13699
|
+
}
|
|
13700
|
+
__name(getStripePromise, "getStripePromise");
|
|
13701
|
+
function StripeProvider({ children }) {
|
|
13702
|
+
const publishableKey = getStripePublishableKey();
|
|
13703
|
+
const stripePromise = useMemo18(() => getStripePromise(publishableKey), [publishableKey]);
|
|
13704
|
+
const options = useMemo18(() => ({}), []);
|
|
13705
|
+
if (!publishableKey) {
|
|
13706
|
+
return /* @__PURE__ */ jsx173(Fragment34, { children });
|
|
13707
|
+
}
|
|
13708
|
+
return /* @__PURE__ */ jsx173(Elements, { stripe: stripePromise, options, children });
|
|
13709
|
+
}
|
|
13710
|
+
__name(StripeProvider, "StripeProvider");
|
|
13711
|
+
function isStripeConfigured() {
|
|
13712
|
+
return !!getStripePublishableKey();
|
|
13713
|
+
}
|
|
13714
|
+
__name(isStripeConfigured, "isStripeConfigured");
|
|
13715
|
+
|
|
13716
|
+
// src/features/billing/stripe-price/components/forms/PriceEditor.tsx
|
|
13717
|
+
import { zodResolver as zodResolver11 } from "@hookform/resolvers/zod";
|
|
13718
|
+
import { AlertCircle as AlertCircle2, PlusIcon, XIcon as XIcon5 } from "lucide-react";
|
|
13719
|
+
import { useState as useState63 } from "react";
|
|
13720
|
+
import { useForm as useForm11 } from "react-hook-form";
|
|
13721
|
+
import { v4 as v47 } from "uuid";
|
|
13722
|
+
import { z as z11 } from "zod";
|
|
13723
|
+
import { jsx as jsx174, jsxs as jsxs111 } from "react/jsx-runtime";
|
|
13724
|
+
function PriceEditor({ productId, price, open, onOpenChange, onSuccess }) {
|
|
13725
|
+
const [isSubmitting, setIsSubmitting] = useState63(false);
|
|
13726
|
+
const formSchema2 = z11.object({
|
|
13727
|
+
unitAmount: z11.preprocess(
|
|
13728
|
+
(val) => typeof val === "string" ? parseFloat(val) : val,
|
|
13729
|
+
z11.number().min(0, { message: "Amount must be 0 or greater" })
|
|
13730
|
+
),
|
|
13731
|
+
currency: z11.string().min(1, { message: "Currency is required" }),
|
|
13732
|
+
interval: z11.enum(["one_time", "day", "week", "month", "year"]),
|
|
13733
|
+
intervalCount: z11.preprocess(
|
|
13734
|
+
(val) => val === "" || val === void 0 ? void 0 : typeof val === "string" ? parseInt(val, 10) : val,
|
|
13735
|
+
z11.number().min(1).optional()
|
|
13736
|
+
),
|
|
13737
|
+
usageType: z11.enum(["licensed", "metered"]).optional(),
|
|
13738
|
+
nickname: z11.string().optional(),
|
|
13739
|
+
active: z11.boolean(),
|
|
13740
|
+
description: z11.string().optional(),
|
|
13741
|
+
features: z11.array(z11.string())
|
|
13742
|
+
});
|
|
13743
|
+
const isEditMode = !!price;
|
|
13744
|
+
const defaultUnitAmount = price?.unitAmount ? price.unitAmount / 100 : 0;
|
|
13745
|
+
const form = useForm11({
|
|
13746
|
+
resolver: zodResolver11(formSchema2),
|
|
13747
|
+
defaultValues: {
|
|
13748
|
+
unitAmount: defaultUnitAmount,
|
|
13749
|
+
currency: price?.currency || "usd",
|
|
13750
|
+
interval: price?.priceType === "one_time" ? "one_time" : price?.recurring?.interval || "month",
|
|
13751
|
+
intervalCount: price?.recurring?.intervalCount || 1,
|
|
13752
|
+
usageType: price?.recurring?.usageType || "licensed",
|
|
13753
|
+
nickname: price?.nickname || "",
|
|
13754
|
+
active: price?.active ?? true,
|
|
13755
|
+
description: price?.description || "",
|
|
13756
|
+
features: price?.features || []
|
|
13757
|
+
}
|
|
13758
|
+
});
|
|
13759
|
+
const watchInterval = form.watch("interval");
|
|
13760
|
+
const isRecurring = watchInterval !== "one_time";
|
|
13761
|
+
const onSubmit = /* @__PURE__ */ __name(async (values) => {
|
|
13762
|
+
setIsSubmitting(true);
|
|
13763
|
+
try {
|
|
13764
|
+
const unitAmountInCents = Math.round(values.unitAmount * 100);
|
|
13765
|
+
if (isEditMode) {
|
|
13766
|
+
await StripePriceService.updatePrice({
|
|
13767
|
+
id: price.id,
|
|
13768
|
+
nickname: values.nickname || void 0,
|
|
13769
|
+
description: values.description || void 0,
|
|
13770
|
+
features: values.features.filter((f) => f.trim()) || void 0
|
|
13771
|
+
});
|
|
13772
|
+
} else {
|
|
13773
|
+
const createInput = {
|
|
13774
|
+
id: v47(),
|
|
13775
|
+
productId,
|
|
13776
|
+
currency: values.currency,
|
|
13777
|
+
unitAmount: unitAmountInCents
|
|
13778
|
+
};
|
|
13779
|
+
if (isRecurring) {
|
|
13780
|
+
createInput.recurring = {
|
|
13781
|
+
interval: values.interval,
|
|
13782
|
+
intervalCount: values.intervalCount || 1,
|
|
13783
|
+
usageType: values.usageType || "licensed"
|
|
13784
|
+
};
|
|
13785
|
+
}
|
|
13786
|
+
if (values.nickname) {
|
|
13787
|
+
createInput.nickname = values.nickname;
|
|
13788
|
+
}
|
|
13789
|
+
if (values.description) {
|
|
13790
|
+
createInput.description = values.description;
|
|
13791
|
+
}
|
|
13792
|
+
const filteredFeatures = values.features.filter((f) => f.trim());
|
|
13793
|
+
if (filteredFeatures.length > 0) {
|
|
13794
|
+
createInput.features = filteredFeatures;
|
|
13795
|
+
}
|
|
13796
|
+
await StripePriceService.createPrice(createInput);
|
|
13797
|
+
}
|
|
13798
|
+
onSuccess();
|
|
13799
|
+
onOpenChange(false);
|
|
13800
|
+
} catch (error) {
|
|
13801
|
+
console.error("[PriceEditor] Failed to save price:", error);
|
|
13802
|
+
} finally {
|
|
13803
|
+
setIsSubmitting(false);
|
|
13804
|
+
}
|
|
13805
|
+
}, "onSubmit");
|
|
13806
|
+
const currencyOptions = [
|
|
13807
|
+
{ id: "usd", text: "USD ($)" },
|
|
13808
|
+
{ id: "eur", text: "EUR (\u20AC)" },
|
|
13809
|
+
{ id: "gbp", text: "GBP (\xA3)" }
|
|
13810
|
+
];
|
|
13811
|
+
const intervalOptions = [
|
|
13812
|
+
{ id: "one_time", text: "One-time" },
|
|
13813
|
+
{ id: "day", text: "Daily" },
|
|
13814
|
+
{ id: "week", text: "Weekly" },
|
|
13815
|
+
{ id: "month", text: "Monthly" },
|
|
13816
|
+
{ id: "year", text: "Yearly" }
|
|
13817
|
+
];
|
|
13818
|
+
const usageTypeOptions = [
|
|
13819
|
+
{ id: "licensed", text: "Licensed (per unit)" },
|
|
13820
|
+
{ id: "metered", text: "Metered (usage-based)" }
|
|
13821
|
+
];
|
|
13822
|
+
return /* @__PURE__ */ jsx174(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs111(DialogContent, { className: "max-w-2xl", children: [
|
|
13823
|
+
/* @__PURE__ */ jsxs111(DialogHeader, { children: [
|
|
13824
|
+
/* @__PURE__ */ jsx174(DialogTitle, { children: isEditMode ? "Edit Price" : "Create Price" }),
|
|
13825
|
+
/* @__PURE__ */ jsx174(DialogDescription, { children: isEditMode ? "Update the price details. Note: Only nickname and active status can be changed." : "Create a new price for this product" })
|
|
13826
|
+
] }),
|
|
13827
|
+
isEditMode && /* @__PURE__ */ jsxs111("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4 flex gap-x-3", children: [
|
|
13828
|
+
/* @__PURE__ */ jsx174(AlertCircle2, { className: "h-5 w-5 text-blue-600 flex-shrink-0 mt-0.5" }),
|
|
13829
|
+
/* @__PURE__ */ jsxs111("div", { className: "text-sm text-blue-800", children: [
|
|
13830
|
+
/* @__PURE__ */ jsx174("p", { className: "font-semibold mb-1", children: "Stripe Price Immutability" }),
|
|
13831
|
+
/* @__PURE__ */ jsx174("p", { children: "Due to Stripe's architecture, only the nickname and active status can be modified after creation. To change amount, currency, or billing interval, create a new price." })
|
|
13832
|
+
] })
|
|
13833
|
+
] }),
|
|
13834
|
+
/* @__PURE__ */ jsx174(Form, { ...form, children: /* @__PURE__ */ jsxs111("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
|
|
13835
|
+
/* @__PURE__ */ jsxs111("div", { className: "grid grid-cols-2 gap-x-4", children: [
|
|
13836
|
+
/* @__PURE__ */ jsx174(
|
|
13837
|
+
FormInput,
|
|
13838
|
+
{
|
|
13839
|
+
form,
|
|
13840
|
+
id: "unitAmount",
|
|
13841
|
+
name: "Amount (in dollars)",
|
|
13842
|
+
placeholder: "9.99",
|
|
13843
|
+
disabled: isEditMode,
|
|
13844
|
+
isRequired: true
|
|
13845
|
+
}
|
|
13846
|
+
),
|
|
13847
|
+
/* @__PURE__ */ jsx174(FormSelect, { form, id: "currency", name: "Currency", values: currencyOptions, disabled: isEditMode })
|
|
13848
|
+
] }),
|
|
13849
|
+
/* @__PURE__ */ jsx174(
|
|
13850
|
+
FormSelect,
|
|
13851
|
+
{
|
|
13852
|
+
form,
|
|
13853
|
+
id: "interval",
|
|
13854
|
+
name: "Billing Interval",
|
|
13855
|
+
values: intervalOptions,
|
|
13856
|
+
disabled: isEditMode
|
|
13857
|
+
}
|
|
13858
|
+
),
|
|
13859
|
+
isRecurring && /* @__PURE__ */ jsxs111("div", { className: "grid grid-cols-2 gap-x-4", children: [
|
|
13860
|
+
/* @__PURE__ */ jsx174(
|
|
13861
|
+
FormInput,
|
|
13862
|
+
{
|
|
13863
|
+
form,
|
|
13864
|
+
id: "intervalCount",
|
|
13865
|
+
name: "Interval Count",
|
|
13866
|
+
placeholder: "1",
|
|
13867
|
+
type: "number",
|
|
13868
|
+
disabled: isEditMode
|
|
13869
|
+
}
|
|
13870
|
+
),
|
|
13871
|
+
/* @__PURE__ */ jsx174(
|
|
13872
|
+
FormSelect,
|
|
13873
|
+
{
|
|
13874
|
+
form,
|
|
13875
|
+
id: "usageType",
|
|
13876
|
+
name: "Usage Type",
|
|
13877
|
+
values: usageTypeOptions,
|
|
13878
|
+
disabled: isEditMode
|
|
13879
|
+
}
|
|
13880
|
+
)
|
|
13881
|
+
] }),
|
|
13882
|
+
/* @__PURE__ */ jsx174(
|
|
13883
|
+
FormInput,
|
|
13884
|
+
{
|
|
13885
|
+
form,
|
|
13886
|
+
id: "nickname",
|
|
13887
|
+
name: "Nickname (optional)",
|
|
13888
|
+
placeholder: "e.g., Standard Plan, Pro Tier"
|
|
13889
|
+
}
|
|
13890
|
+
),
|
|
13891
|
+
/* @__PURE__ */ jsx174(
|
|
13892
|
+
FormTextarea,
|
|
13893
|
+
{
|
|
13894
|
+
form,
|
|
13895
|
+
id: "description",
|
|
13896
|
+
name: "Description (optional)",
|
|
13897
|
+
placeholder: "Describe what this price tier includes...",
|
|
13898
|
+
className: "min-h-24"
|
|
13899
|
+
}
|
|
13900
|
+
),
|
|
13901
|
+
/* @__PURE__ */ jsxs111(FormItem, { children: [
|
|
13902
|
+
/* @__PURE__ */ jsx174(FormLabel, { children: "Features (optional)" }),
|
|
13903
|
+
/* @__PURE__ */ jsxs111("div", { className: "space-y-2", children: [
|
|
13904
|
+
form.watch("features").map((_, index) => /* @__PURE__ */ jsxs111("div", { className: "flex gap-2", children: [
|
|
13905
|
+
/* @__PURE__ */ jsx174(FormControl, { children: /* @__PURE__ */ jsx174(
|
|
13906
|
+
Input,
|
|
13907
|
+
{
|
|
13908
|
+
...form.register(`features.${index}`),
|
|
13909
|
+
placeholder: `Feature ${index + 1}`,
|
|
13910
|
+
className: "flex-1"
|
|
13911
|
+
}
|
|
13912
|
+
) }),
|
|
13913
|
+
/* @__PURE__ */ jsx174(
|
|
13914
|
+
Button,
|
|
13915
|
+
{
|
|
13916
|
+
type: "button",
|
|
13917
|
+
variant: "outline",
|
|
13918
|
+
size: "icon",
|
|
13919
|
+
onClick: () => {
|
|
13920
|
+
const currentFeatures = form.getValues("features");
|
|
13921
|
+
form.setValue(
|
|
13922
|
+
"features",
|
|
13923
|
+
currentFeatures.filter((_2, i) => i !== index)
|
|
13924
|
+
);
|
|
13925
|
+
},
|
|
13926
|
+
children: /* @__PURE__ */ jsx174(XIcon5, { className: "h-4 w-4" })
|
|
13927
|
+
}
|
|
13928
|
+
)
|
|
13929
|
+
] }, index)),
|
|
13930
|
+
/* @__PURE__ */ jsxs111(
|
|
13931
|
+
Button,
|
|
13932
|
+
{
|
|
13933
|
+
type: "button",
|
|
13934
|
+
variant: "outline",
|
|
13935
|
+
size: "sm",
|
|
13936
|
+
onClick: () => {
|
|
13937
|
+
const currentFeatures = form.getValues("features");
|
|
13938
|
+
form.setValue("features", [...currentFeatures, ""]);
|
|
13939
|
+
},
|
|
13940
|
+
className: "mt-2",
|
|
13941
|
+
children: [
|
|
13942
|
+
/* @__PURE__ */ jsx174(PlusIcon, { className: "h-4 w-4 mr-2" }),
|
|
13943
|
+
"Add Feature"
|
|
13944
|
+
]
|
|
13945
|
+
}
|
|
13946
|
+
)
|
|
13947
|
+
] })
|
|
13948
|
+
] }),
|
|
13949
|
+
/* @__PURE__ */ jsx174(FormCheckbox, { form, id: "active", name: "Active" }),
|
|
13950
|
+
/* @__PURE__ */ jsx174(CommonEditorButtons, { isEdit: isEditMode, form, disabled: isSubmitting, setOpen: onOpenChange })
|
|
13951
|
+
] }) })
|
|
13952
|
+
] }) });
|
|
13953
|
+
}
|
|
13954
|
+
__name(PriceEditor, "PriceEditor");
|
|
13955
|
+
|
|
13956
|
+
// src/features/billing/stripe-price/components/lists/PricesList.tsx
|
|
13957
|
+
import { Archive, DollarSign, Edit, RotateCcw } from "lucide-react";
|
|
13958
|
+
import { useEffect as useEffect48, useState as useState64 } from "react";
|
|
13959
|
+
import { jsx as jsx175, jsxs as jsxs112 } from "react/jsx-runtime";
|
|
13960
|
+
function PricesList({ productId, onPricesChange }) {
|
|
13961
|
+
const [prices, setPrices] = useState64([]);
|
|
13962
|
+
const [loading, setLoading] = useState64(true);
|
|
13963
|
+
const [showCreatePrice, setShowCreatePrice] = useState64(false);
|
|
13964
|
+
const [editingPrice, setEditingPrice] = useState64(null);
|
|
13965
|
+
const [priceToArchive, setPriceToArchive] = useState64(null);
|
|
13966
|
+
const [priceToReactivate, setPriceToReactivate] = useState64(null);
|
|
13967
|
+
const [archivingPriceId, setArchivingPriceId] = useState64(null);
|
|
13968
|
+
const [reactivatingPriceId, setReactivatingPriceId] = useState64(null);
|
|
13969
|
+
const loadPrices = /* @__PURE__ */ __name(async () => {
|
|
13970
|
+
setLoading(true);
|
|
13971
|
+
try {
|
|
13972
|
+
const fetchedPrices = await StripePriceService.listPrices({ productId });
|
|
13973
|
+
setPrices(fetchedPrices);
|
|
13974
|
+
} catch (error) {
|
|
13975
|
+
console.error("[PricesList] Failed to load prices:", error);
|
|
13976
|
+
} finally {
|
|
13977
|
+
setLoading(false);
|
|
13978
|
+
}
|
|
13979
|
+
}, "loadPrices");
|
|
13980
|
+
useEffect48(() => {
|
|
13981
|
+
loadPrices();
|
|
13982
|
+
}, [productId]);
|
|
13983
|
+
const handleArchive = /* @__PURE__ */ __name(async () => {
|
|
13984
|
+
if (!priceToArchive) {
|
|
13985
|
+
return;
|
|
13986
|
+
}
|
|
13987
|
+
setArchivingPriceId(priceToArchive.id);
|
|
13988
|
+
try {
|
|
13989
|
+
await StripePriceService.archivePrice({ id: priceToArchive.id });
|
|
13990
|
+
setPriceToArchive(null);
|
|
13991
|
+
await loadPrices();
|
|
13992
|
+
onPricesChange();
|
|
13993
|
+
} catch (error) {
|
|
13994
|
+
console.error("[PricesList] Failed to archive price:", error);
|
|
13995
|
+
} finally {
|
|
13996
|
+
setArchivingPriceId(null);
|
|
13997
|
+
}
|
|
13998
|
+
}, "handleArchive");
|
|
13999
|
+
const handleReactivate = /* @__PURE__ */ __name(async () => {
|
|
14000
|
+
if (!priceToReactivate) {
|
|
14001
|
+
return;
|
|
14002
|
+
}
|
|
14003
|
+
setReactivatingPriceId(priceToReactivate.id);
|
|
14004
|
+
try {
|
|
14005
|
+
await StripePriceService.reactivatePrice({ id: priceToReactivate.id });
|
|
14006
|
+
setPriceToReactivate(null);
|
|
14007
|
+
await loadPrices();
|
|
14008
|
+
onPricesChange();
|
|
14009
|
+
} catch (error) {
|
|
14010
|
+
console.error("[PricesList] Failed to reactivate price:", error);
|
|
14011
|
+
} finally {
|
|
14012
|
+
setReactivatingPriceId(null);
|
|
14013
|
+
}
|
|
14014
|
+
}, "handleReactivate");
|
|
14015
|
+
const formatInterval2 = /* @__PURE__ */ __name((price) => {
|
|
14016
|
+
if (price.priceType === "one_time") {
|
|
14017
|
+
return "one-time";
|
|
14018
|
+
}
|
|
14019
|
+
if (price.recurring) {
|
|
14020
|
+
const count = price.recurring.intervalCount;
|
|
14021
|
+
const interval = price.recurring.interval;
|
|
14022
|
+
if (count === 1) {
|
|
14023
|
+
return `/ ${interval}`;
|
|
14024
|
+
} else {
|
|
14025
|
+
return `/ ${count} ${interval}s`;
|
|
14026
|
+
}
|
|
14027
|
+
}
|
|
14028
|
+
return "";
|
|
14029
|
+
}, "formatInterval");
|
|
14030
|
+
if (loading) {
|
|
14031
|
+
return /* @__PURE__ */ jsx175("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx175("p", { className: "text-muted-foreground", children: "Loading prices..." }) });
|
|
14032
|
+
}
|
|
14033
|
+
return /* @__PURE__ */ jsxs112("div", { className: "flex flex-col gap-y-4", children: [
|
|
14034
|
+
/* @__PURE__ */ jsxs112("div", { className: "flex items-center justify-between mb-4", children: [
|
|
14035
|
+
/* @__PURE__ */ jsx175("h4", { className: "text-lg font-semibold", children: "Prices" }),
|
|
14036
|
+
/* @__PURE__ */ jsx175(Button, { size: "sm", onClick: () => setShowCreatePrice(true), children: "Add Price" })
|
|
14037
|
+
] }),
|
|
14038
|
+
prices.length === 0 && /* @__PURE__ */ jsxs112("div", { className: "bg-background flex flex-col items-center justify-center gap-y-3 rounded-lg border border-dashed p-8", children: [
|
|
14039
|
+
/* @__PURE__ */ jsx175(DollarSign, { className: "text-muted-foreground h-12 w-12" }),
|
|
14040
|
+
/* @__PURE__ */ jsx175("p", { className: "text-muted-foreground text-sm", children: "No prices yet. Add a price to enable subscriptions." }),
|
|
14041
|
+
/* @__PURE__ */ jsx175(Button, { size: "sm", onClick: () => setShowCreatePrice(true), children: "Add Price" })
|
|
14042
|
+
] }),
|
|
14043
|
+
prices.length > 0 && /* @__PURE__ */ jsx175("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: prices.map((price) => {
|
|
14044
|
+
const isArchiving = archivingPriceId === price.id;
|
|
14045
|
+
const isReactivating = reactivatingPriceId === price.id;
|
|
14046
|
+
return /* @__PURE__ */ jsxs112("div", { className: "border rounded-lg bg-white p-4 hover:shadow-sm transition-shadow", children: [
|
|
14047
|
+
/* @__PURE__ */ jsxs112("div", { className: "flex items-start justify-between mb-3", children: [
|
|
14048
|
+
/* @__PURE__ */ jsx175(DollarSign, { className: "h-5 w-5 text-primary" }),
|
|
14049
|
+
/* @__PURE__ */ jsxs112("div", { className: "flex gap-1", children: [
|
|
14050
|
+
/* @__PURE__ */ jsx175(Button, { variant: "ghost", size: "sm", onClick: () => setEditingPrice(price), className: "h-8 w-8 p-0", children: /* @__PURE__ */ jsx175(Edit, { className: "h-4 w-4" }) }),
|
|
14051
|
+
price.active ? /* @__PURE__ */ jsx175(
|
|
14052
|
+
Button,
|
|
14053
|
+
{
|
|
14054
|
+
variant: "ghost",
|
|
14055
|
+
size: "sm",
|
|
14056
|
+
onClick: () => setPriceToArchive(price),
|
|
14057
|
+
className: "h-8 w-8 p-0",
|
|
14058
|
+
disabled: isArchiving,
|
|
14059
|
+
children: /* @__PURE__ */ jsx175(Archive, { className: "h-4 w-4" })
|
|
14060
|
+
}
|
|
14061
|
+
) : /* @__PURE__ */ jsx175(
|
|
14062
|
+
Button,
|
|
14063
|
+
{
|
|
14064
|
+
variant: "ghost",
|
|
14065
|
+
size: "sm",
|
|
14066
|
+
onClick: () => setPriceToReactivate(price),
|
|
14067
|
+
className: "h-8 w-8 p-0",
|
|
14068
|
+
disabled: isReactivating,
|
|
14069
|
+
children: /* @__PURE__ */ jsx175(RotateCcw, { className: "h-4 w-4" })
|
|
14070
|
+
}
|
|
14071
|
+
)
|
|
14072
|
+
] })
|
|
14073
|
+
] }),
|
|
14074
|
+
/* @__PURE__ */ jsx175("div", { className: "mb-2", children: /* @__PURE__ */ jsxs112("div", { className: "text-2xl font-bold", children: [
|
|
14075
|
+
formatCurrency(price.unitAmount, price.currency),
|
|
14076
|
+
" ",
|
|
14077
|
+
/* @__PURE__ */ jsx175("span", { className: "text-muted-foreground text-sm font-normal", children: formatInterval2(price) })
|
|
14078
|
+
] }) }),
|
|
14079
|
+
price.metadata?.nickname && /* @__PURE__ */ jsx175("p", { className: "text-sm font-medium mb-2", children: price.metadata.nickname }),
|
|
14080
|
+
/* @__PURE__ */ jsxs112("div", { className: "flex flex-wrap gap-2", children: [
|
|
14081
|
+
price.active ? /* @__PURE__ */ jsx175("span", { className: "bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full font-medium", children: "Active" }) : /* @__PURE__ */ jsx175("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium", children: "Inactive" }),
|
|
14082
|
+
price.recurring?.usageType === "metered" && /* @__PURE__ */ jsx175("span", { className: "bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded-full font-medium", children: "Metered" }),
|
|
14083
|
+
/* @__PURE__ */ jsx175("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium uppercase", children: price.currency })
|
|
14084
|
+
] })
|
|
14085
|
+
] }, price.id);
|
|
14086
|
+
}) }),
|
|
14087
|
+
showCreatePrice && /* @__PURE__ */ jsx175(
|
|
14088
|
+
PriceEditor,
|
|
14089
|
+
{
|
|
14090
|
+
productId,
|
|
14091
|
+
open: showCreatePrice,
|
|
14092
|
+
onOpenChange: setShowCreatePrice,
|
|
14093
|
+
onSuccess: () => {
|
|
14094
|
+
loadPrices();
|
|
14095
|
+
onPricesChange();
|
|
14096
|
+
}
|
|
14097
|
+
}
|
|
14098
|
+
),
|
|
14099
|
+
editingPrice && /* @__PURE__ */ jsx175(
|
|
14100
|
+
PriceEditor,
|
|
14101
|
+
{
|
|
14102
|
+
productId,
|
|
14103
|
+
price: editingPrice,
|
|
14104
|
+
open: !!editingPrice,
|
|
14105
|
+
onOpenChange: (open) => !open && setEditingPrice(null),
|
|
14106
|
+
onSuccess: () => {
|
|
14107
|
+
loadPrices();
|
|
14108
|
+
onPricesChange();
|
|
14109
|
+
setEditingPrice(null);
|
|
14110
|
+
}
|
|
14111
|
+
}
|
|
14112
|
+
),
|
|
14113
|
+
/* @__PURE__ */ jsx175(AlertDialog, { open: !!priceToArchive, onOpenChange: (open) => !open && setPriceToArchive(null), children: /* @__PURE__ */ jsxs112(AlertDialogContent, { children: [
|
|
14114
|
+
/* @__PURE__ */ jsxs112(AlertDialogHeader, { children: [
|
|
14115
|
+
/* @__PURE__ */ jsx175(AlertDialogTitle, { children: "Archive Price" }),
|
|
14116
|
+
/* @__PURE__ */ jsxs112(AlertDialogDescription, { children: [
|
|
14117
|
+
"Are you sure you want to archive the price for",
|
|
14118
|
+
" ",
|
|
14119
|
+
priceToArchive && `${formatCurrency(priceToArchive.unitAmount, priceToArchive.currency)} ${formatInterval2(priceToArchive)}`,
|
|
14120
|
+
"? This will prevent new subscriptions but existing ones will continue."
|
|
14121
|
+
] })
|
|
14122
|
+
] }),
|
|
14123
|
+
/* @__PURE__ */ jsxs112(AlertDialogFooter, { children: [
|
|
14124
|
+
/* @__PURE__ */ jsx175(AlertDialogCancel, { disabled: !!archivingPriceId, children: "Cancel" }),
|
|
14125
|
+
/* @__PURE__ */ jsx175(
|
|
14126
|
+
AlertDialogAction,
|
|
14127
|
+
{
|
|
14128
|
+
onClick: handleArchive,
|
|
14129
|
+
disabled: !!archivingPriceId,
|
|
14130
|
+
className: "bg-red-600 hover:bg-red-700",
|
|
14131
|
+
children: archivingPriceId ? "Archiving..." : "Archive"
|
|
14132
|
+
}
|
|
14133
|
+
)
|
|
14134
|
+
] })
|
|
14135
|
+
] }) }),
|
|
14136
|
+
/* @__PURE__ */ jsx175(AlertDialog, { open: !!priceToReactivate, onOpenChange: (open) => !open && setPriceToReactivate(null), children: /* @__PURE__ */ jsxs112(AlertDialogContent, { children: [
|
|
14137
|
+
/* @__PURE__ */ jsxs112(AlertDialogHeader, { children: [
|
|
14138
|
+
/* @__PURE__ */ jsx175(AlertDialogTitle, { children: "Reactivate Price" }),
|
|
14139
|
+
/* @__PURE__ */ jsxs112(AlertDialogDescription, { children: [
|
|
14140
|
+
"Are you sure you want to reactivate the price for",
|
|
14141
|
+
" ",
|
|
14142
|
+
priceToReactivate && `${formatCurrency(priceToReactivate.unitAmount, priceToReactivate.currency)} ${formatInterval2(priceToReactivate)}`,
|
|
14143
|
+
"? This will allow new subscriptions again."
|
|
14144
|
+
] })
|
|
14145
|
+
] }),
|
|
14146
|
+
/* @__PURE__ */ jsxs112(AlertDialogFooter, { children: [
|
|
14147
|
+
/* @__PURE__ */ jsx175(AlertDialogCancel, { disabled: !!reactivatingPriceId, children: "Cancel" }),
|
|
14148
|
+
/* @__PURE__ */ jsx175(
|
|
14149
|
+
AlertDialogAction,
|
|
14150
|
+
{
|
|
14151
|
+
onClick: handleReactivate,
|
|
14152
|
+
disabled: !!reactivatingPriceId,
|
|
14153
|
+
className: "bg-green-600 hover:bg-green-700",
|
|
14154
|
+
children: reactivatingPriceId ? "Reactivating..." : "Reactivate"
|
|
14155
|
+
}
|
|
14156
|
+
)
|
|
14157
|
+
] })
|
|
14158
|
+
] }) })
|
|
14159
|
+
] });
|
|
14160
|
+
}
|
|
14161
|
+
__name(PricesList, "PricesList");
|
|
14162
|
+
|
|
14163
|
+
// src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx
|
|
14164
|
+
import { Package as Package2 } from "lucide-react";
|
|
14165
|
+
import { useEffect as useEffect49, useState as useState67 } from "react";
|
|
14166
|
+
|
|
14167
|
+
// src/features/billing/stripe-product/components/forms/ProductEditor.tsx
|
|
14168
|
+
import { zodResolver as zodResolver12 } from "@hookform/resolvers/zod";
|
|
14169
|
+
import { useState as useState65 } from "react";
|
|
14170
|
+
import { useForm as useForm12 } from "react-hook-form";
|
|
14171
|
+
import { v4 as v48 } from "uuid";
|
|
14172
|
+
import { z as z12 } from "zod";
|
|
14173
|
+
import { jsx as jsx176, jsxs as jsxs113 } from "react/jsx-runtime";
|
|
14174
|
+
function ProductEditor({ product, open, onOpenChange, onSuccess }) {
|
|
14175
|
+
const [isSubmitting, setIsSubmitting] = useState65(false);
|
|
14176
|
+
const formSchema2 = z12.object({
|
|
14177
|
+
name: z12.string().min(1, { message: "Product name is required" }),
|
|
14178
|
+
description: z12.string().optional(),
|
|
14179
|
+
active: z12.boolean()
|
|
14180
|
+
});
|
|
14181
|
+
const form = useForm12({
|
|
14182
|
+
resolver: zodResolver12(formSchema2),
|
|
14183
|
+
defaultValues: {
|
|
14184
|
+
name: product?.name || "",
|
|
14185
|
+
description: product?.description || "",
|
|
14186
|
+
active: product?.active ?? true
|
|
14187
|
+
}
|
|
14188
|
+
});
|
|
14189
|
+
const onSubmit = /* @__PURE__ */ __name(async (values) => {
|
|
14190
|
+
setIsSubmitting(true);
|
|
14191
|
+
try {
|
|
14192
|
+
if (product) {
|
|
14193
|
+
await StripeProductService.updateProduct({
|
|
14194
|
+
id: product.id,
|
|
14195
|
+
name: values.name,
|
|
14196
|
+
description: values.description,
|
|
14197
|
+
active: values.active
|
|
14198
|
+
});
|
|
14199
|
+
} else {
|
|
14200
|
+
await StripeProductService.createProduct({
|
|
14201
|
+
id: v48(),
|
|
14202
|
+
name: values.name,
|
|
14203
|
+
description: values.description,
|
|
14204
|
+
active: values.active
|
|
14205
|
+
});
|
|
14206
|
+
}
|
|
14207
|
+
onSuccess();
|
|
14208
|
+
onOpenChange(false);
|
|
14209
|
+
} catch (error) {
|
|
14210
|
+
console.error("[ProductEditor] Failed to save product:", error);
|
|
14211
|
+
} finally {
|
|
14212
|
+
setIsSubmitting(false);
|
|
14213
|
+
}
|
|
14214
|
+
}, "onSubmit");
|
|
14215
|
+
return /* @__PURE__ */ jsx176(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs113(DialogContent, { className: "max-w-2xl", children: [
|
|
14216
|
+
/* @__PURE__ */ jsxs113(DialogHeader, { children: [
|
|
14217
|
+
/* @__PURE__ */ jsx176(DialogTitle, { children: product ? "Edit Product" : "Create Product" }),
|
|
14218
|
+
/* @__PURE__ */ jsx176(DialogDescription, { children: product ? `Update the details for ${product.name}` : "Create a new product to offer to your customers" })
|
|
14219
|
+
] }),
|
|
14220
|
+
/* @__PURE__ */ jsx176(Form, { ...form, children: /* @__PURE__ */ jsxs113("form", { onSubmit: form.handleSubmit(onSubmit), className: "flex flex-col gap-y-4", children: [
|
|
14221
|
+
/* @__PURE__ */ jsx176(FormInput, { form, id: "name", name: "Product Name", placeholder: "Enter product name", isRequired: true }),
|
|
14222
|
+
/* @__PURE__ */ jsx176(
|
|
14223
|
+
FormTextarea,
|
|
14224
|
+
{
|
|
14225
|
+
form,
|
|
14226
|
+
id: "description",
|
|
14227
|
+
name: "Description",
|
|
14228
|
+
placeholder: "Enter product description (optional)",
|
|
14229
|
+
className: "min-h-32"
|
|
14230
|
+
}
|
|
14231
|
+
),
|
|
14232
|
+
/* @__PURE__ */ jsx176(FormCheckbox, { form, id: "active", name: "Active" }),
|
|
14233
|
+
/* @__PURE__ */ jsx176(CommonEditorButtons, { isEdit: !!product, form, disabled: isSubmitting, setOpen: onOpenChange })
|
|
14234
|
+
] }) })
|
|
14235
|
+
] }) });
|
|
14236
|
+
}
|
|
14237
|
+
__name(ProductEditor, "ProductEditor");
|
|
14238
|
+
|
|
14239
|
+
// src/features/billing/stripe-product/components/lists/ProductsList.tsx
|
|
14240
|
+
import { Archive as Archive2, ChevronDown as ChevronDown3, ChevronUp as ChevronUp2, Edit as Edit2, Package, RefreshCw as RefreshCw3 } from "lucide-react";
|
|
14241
|
+
import { useState as useState66 } from "react";
|
|
14242
|
+
import { jsx as jsx177, jsxs as jsxs114 } from "react/jsx-runtime";
|
|
14243
|
+
function ProductsList({ products, onProductsChange }) {
|
|
14244
|
+
const [expandedProductId, setExpandedProductId] = useState66(null);
|
|
14245
|
+
const [editingProduct, setEditingProduct] = useState66(null);
|
|
14246
|
+
const [archivingProductId, setArchivingProductId] = useState66(null);
|
|
14247
|
+
const [reactivatingProductId, setReactivatingProductId] = useState66(null);
|
|
14248
|
+
const [productToArchive, setProductToArchive] = useState66(null);
|
|
14249
|
+
const [productToReactivate, setProductToReactivate] = useState66(null);
|
|
14250
|
+
const handleArchive = /* @__PURE__ */ __name(async () => {
|
|
14251
|
+
if (!productToArchive) {
|
|
14252
|
+
return;
|
|
14253
|
+
}
|
|
14254
|
+
setArchivingProductId(productToArchive.id);
|
|
14255
|
+
try {
|
|
14256
|
+
const archivedProduct = await StripeProductService.archiveProduct({ id: productToArchive.id });
|
|
14257
|
+
setProductToArchive(null);
|
|
14258
|
+
onProductsChange();
|
|
14259
|
+
} catch (error) {
|
|
14260
|
+
console.error("[ProductsList] Failed to archive product:", error);
|
|
14261
|
+
} finally {
|
|
14262
|
+
setArchivingProductId(null);
|
|
14263
|
+
}
|
|
14264
|
+
}, "handleArchive");
|
|
14265
|
+
const handleReactivate = /* @__PURE__ */ __name(async () => {
|
|
14266
|
+
if (!productToReactivate) {
|
|
14267
|
+
return;
|
|
14268
|
+
}
|
|
14269
|
+
setReactivatingProductId(productToReactivate.id);
|
|
14270
|
+
try {
|
|
14271
|
+
const reactivatedProduct = await StripeProductService.reactivateProduct({ id: productToReactivate.id });
|
|
14272
|
+
setProductToReactivate(null);
|
|
14273
|
+
onProductsChange();
|
|
14274
|
+
} catch (error) {
|
|
14275
|
+
} finally {
|
|
14276
|
+
setReactivatingProductId(null);
|
|
14277
|
+
}
|
|
14278
|
+
}, "handleReactivate");
|
|
14279
|
+
const toggleExpand = /* @__PURE__ */ __name((productId) => {
|
|
14280
|
+
setExpandedProductId(expandedProductId === productId ? null : productId);
|
|
14281
|
+
}, "toggleExpand");
|
|
14282
|
+
return /* @__PURE__ */ jsxs114("div", { className: "flex flex-col gap-y-4", children: [
|
|
14283
|
+
products.map((product) => {
|
|
14284
|
+
const isExpanded = expandedProductId === product.id;
|
|
14285
|
+
const isArchiving = archivingProductId === product.id;
|
|
14286
|
+
const isReactivating = reactivatingProductId === product.id;
|
|
14287
|
+
return /* @__PURE__ */ jsxs114("div", { className: "border rounded-lg bg-white shadow-sm hover:shadow-md transition-shadow", children: [
|
|
14288
|
+
/* @__PURE__ */ jsxs114("div", { className: "flex items-center justify-between p-6", children: [
|
|
14289
|
+
/* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-4 flex-1", children: [
|
|
14290
|
+
/* @__PURE__ */ jsx177(Package, { className: "h-6 w-6 text-primary" }),
|
|
14291
|
+
/* @__PURE__ */ jsxs114("div", { className: "flex-1", children: [
|
|
14292
|
+
/* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-3", children: [
|
|
14293
|
+
/* @__PURE__ */ jsx177("h3", { className: "text-lg font-semibold", children: product.name }),
|
|
14294
|
+
product.active ? /* @__PURE__ */ jsx177("span", { className: "bg-green-100 text-green-800 text-xs px-2 py-1 rounded-full font-medium", children: "Active" }) : /* @__PURE__ */ jsx177("span", { className: "bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full font-medium", children: "Inactive" })
|
|
14295
|
+
] }),
|
|
14296
|
+
product.description && /* @__PURE__ */ jsx177("p", { className: "text-muted-foreground text-sm mt-1", children: product.description })
|
|
14297
|
+
] })
|
|
14298
|
+
] }),
|
|
14299
|
+
/* @__PURE__ */ jsxs114("div", { className: "flex items-center gap-x-2", children: [
|
|
14300
|
+
/* @__PURE__ */ jsxs114(Button, { variant: "outline", size: "sm", onClick: () => setEditingProduct(product), children: [
|
|
14301
|
+
/* @__PURE__ */ jsx177(Edit2, { className: "h-4 w-4 mr-1" }),
|
|
14302
|
+
"Edit"
|
|
14303
|
+
] }),
|
|
14304
|
+
product.active ? /* @__PURE__ */ jsxs114(
|
|
14305
|
+
Button,
|
|
14306
|
+
{
|
|
14307
|
+
variant: "outline",
|
|
14308
|
+
size: "sm",
|
|
14309
|
+
onClick: () => setProductToArchive(product),
|
|
14310
|
+
disabled: isArchiving,
|
|
14311
|
+
children: [
|
|
14312
|
+
/* @__PURE__ */ jsx177(Archive2, { className: "h-4 w-4 mr-1" }),
|
|
14313
|
+
isArchiving ? "Archiving..." : "Archive"
|
|
14314
|
+
]
|
|
14315
|
+
}
|
|
14316
|
+
) : /* @__PURE__ */ jsxs114(
|
|
14317
|
+
Button,
|
|
14318
|
+
{
|
|
14319
|
+
variant: "outline",
|
|
14320
|
+
size: "sm",
|
|
14321
|
+
onClick: () => setProductToReactivate(product),
|
|
14322
|
+
disabled: isReactivating,
|
|
14323
|
+
children: [
|
|
14324
|
+
/* @__PURE__ */ jsx177(RefreshCw3, { className: "h-4 w-4 mr-1" }),
|
|
14325
|
+
isReactivating ? "Reactivating..." : "Reactivate"
|
|
14326
|
+
]
|
|
14327
|
+
}
|
|
14328
|
+
),
|
|
14329
|
+
/* @__PURE__ */ jsx177(Button, { variant: "ghost", size: "sm", onClick: () => toggleExpand(product.id), children: isExpanded ? /* @__PURE__ */ jsx177(ChevronUp2, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx177(ChevronDown3, { className: "h-5 w-5" }) })
|
|
14330
|
+
] })
|
|
14331
|
+
] }),
|
|
14332
|
+
isExpanded && /* @__PURE__ */ jsx177("div", { className: "border-t bg-muted/30 p-6", children: /* @__PURE__ */ jsx177(PricesList, { productId: product.id, onPricesChange: onProductsChange }) })
|
|
14333
|
+
] }, product.id);
|
|
14334
|
+
}),
|
|
14335
|
+
editingProduct && /* @__PURE__ */ jsx177(
|
|
14336
|
+
ProductEditor,
|
|
14337
|
+
{
|
|
14338
|
+
product: editingProduct,
|
|
14339
|
+
open: !!editingProduct,
|
|
14340
|
+
onOpenChange: (open) => !open && setEditingProduct(null),
|
|
14341
|
+
onSuccess: () => {
|
|
14342
|
+
onProductsChange();
|
|
14343
|
+
setEditingProduct(null);
|
|
14344
|
+
}
|
|
14345
|
+
}
|
|
14346
|
+
),
|
|
14347
|
+
/* @__PURE__ */ jsx177(AlertDialog, { open: !!productToArchive, onOpenChange: (open) => !open && setProductToArchive(null), children: /* @__PURE__ */ jsxs114(AlertDialogContent, { children: [
|
|
14348
|
+
/* @__PURE__ */ jsxs114(AlertDialogHeader, { children: [
|
|
14349
|
+
/* @__PURE__ */ jsx177(AlertDialogTitle, { children: "Archive Product" }),
|
|
14350
|
+
/* @__PURE__ */ jsxs114(AlertDialogDescription, { children: [
|
|
14351
|
+
'Are you sure you want to archive "',
|
|
14352
|
+
productToArchive?.name,
|
|
14353
|
+
'"? This will deactivate it and it will no longer be available for new subscriptions.'
|
|
14354
|
+
] })
|
|
14355
|
+
] }),
|
|
14356
|
+
/* @__PURE__ */ jsxs114(AlertDialogFooter, { children: [
|
|
14357
|
+
/* @__PURE__ */ jsx177(AlertDialogCancel, { disabled: !!archivingProductId, children: "Cancel" }),
|
|
14358
|
+
/* @__PURE__ */ jsx177(
|
|
14359
|
+
AlertDialogAction,
|
|
14360
|
+
{
|
|
14361
|
+
onClick: handleArchive,
|
|
14362
|
+
disabled: !!archivingProductId,
|
|
14363
|
+
className: "bg-red-600 hover:bg-red-700",
|
|
14364
|
+
children: archivingProductId ? "Archiving..." : "Archive"
|
|
14365
|
+
}
|
|
14366
|
+
)
|
|
14367
|
+
] })
|
|
14368
|
+
] }) }),
|
|
14369
|
+
/* @__PURE__ */ jsx177(AlertDialog, { open: !!productToReactivate, onOpenChange: (open) => !open && setProductToReactivate(null), children: /* @__PURE__ */ jsxs114(AlertDialogContent, { children: [
|
|
14370
|
+
/* @__PURE__ */ jsxs114(AlertDialogHeader, { children: [
|
|
14371
|
+
/* @__PURE__ */ jsx177(AlertDialogTitle, { children: "Reactivate Product" }),
|
|
14372
|
+
/* @__PURE__ */ jsxs114(AlertDialogDescription, { children: [
|
|
14373
|
+
'Are you sure you want to reactivate "',
|
|
14374
|
+
productToReactivate?.name,
|
|
14375
|
+
'"? This will make it available for new subscriptions again.'
|
|
14376
|
+
] })
|
|
14377
|
+
] }),
|
|
14378
|
+
/* @__PURE__ */ jsxs114(AlertDialogFooter, { children: [
|
|
14379
|
+
/* @__PURE__ */ jsx177(AlertDialogCancel, { disabled: !!reactivatingProductId, children: "Cancel" }),
|
|
14380
|
+
/* @__PURE__ */ jsx177(
|
|
14381
|
+
AlertDialogAction,
|
|
14382
|
+
{
|
|
14383
|
+
onClick: handleReactivate,
|
|
14384
|
+
disabled: !!reactivatingProductId,
|
|
14385
|
+
className: "bg-green-600 hover:bg-green-700",
|
|
14386
|
+
children: reactivatingProductId ? "Reactivating..." : "Reactivate"
|
|
14387
|
+
}
|
|
14388
|
+
)
|
|
14389
|
+
] })
|
|
14390
|
+
] }) })
|
|
14391
|
+
] });
|
|
14392
|
+
}
|
|
14393
|
+
__name(ProductsList, "ProductsList");
|
|
14394
|
+
|
|
14395
|
+
// src/features/billing/stripe-product/components/containers/ProductsAdminContainer.tsx
|
|
14396
|
+
import { jsx as jsx178, jsxs as jsxs115 } from "react/jsx-runtime";
|
|
14397
|
+
function ProductsAdminContainer() {
|
|
14398
|
+
const { hasRole } = useCurrentUserContext();
|
|
14399
|
+
const [products, setProducts] = useState67([]);
|
|
14400
|
+
const [loading, setLoading] = useState67(true);
|
|
14401
|
+
const [showCreateProduct, setShowCreateProduct] = useState67(false);
|
|
14402
|
+
if (!hasRole(getRoleId().Administrator)) {
|
|
14403
|
+
return /* @__PURE__ */ jsx178("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx178("p", { className: "text-red-600 font-semibold", children: "Permission denied. Administrator access required." }) });
|
|
14404
|
+
}
|
|
14405
|
+
const loadProducts = /* @__PURE__ */ __name(async () => {
|
|
14406
|
+
setLoading(true);
|
|
14407
|
+
try {
|
|
14408
|
+
const fetchedProducts = await StripeProductService.listProducts();
|
|
14409
|
+
setProducts(fetchedProducts);
|
|
14410
|
+
} catch (error) {
|
|
14411
|
+
console.error("[ProductsAdminContainer] Failed to load products:", error);
|
|
14412
|
+
} finally {
|
|
14413
|
+
setLoading(false);
|
|
14414
|
+
}
|
|
14415
|
+
}, "loadProducts");
|
|
14416
|
+
useEffect49(() => {
|
|
14417
|
+
loadProducts();
|
|
14418
|
+
}, []);
|
|
14419
|
+
if (loading) {
|
|
14420
|
+
return /* @__PURE__ */ jsx178("div", { className: "flex h-64 items-center justify-center", children: /* @__PURE__ */ jsx178("p", { className: "text-muted-foreground", children: "Loading products..." }) });
|
|
14421
|
+
}
|
|
14422
|
+
return /* @__PURE__ */ jsxs115("div", { className: "flex w-full flex-col gap-y-6", children: [
|
|
14423
|
+
/* @__PURE__ */ jsxs115("div", { className: "flex items-center justify-between", children: [
|
|
14424
|
+
/* @__PURE__ */ jsxs115("div", { className: "flex items-center gap-x-3", children: [
|
|
14425
|
+
/* @__PURE__ */ jsx178(Package2, { className: "h-8 w-8" }),
|
|
14426
|
+
/* @__PURE__ */ jsx178("h1", { className: "text-3xl font-bold", children: "Product & Price Management" })
|
|
14427
|
+
] }),
|
|
14428
|
+
/* @__PURE__ */ jsx178(Button, { onClick: () => setShowCreateProduct(true), children: "Create Product" })
|
|
14429
|
+
] }),
|
|
14430
|
+
products.length === 0 && /* @__PURE__ */ jsxs115("div", { className: "bg-muted/50 flex flex-col items-center justify-center gap-y-4 rounded-lg border-2 border-dashed p-12", children: [
|
|
14431
|
+
/* @__PURE__ */ jsx178(Package2, { className: "text-muted-foreground h-16 w-16" }),
|
|
14432
|
+
/* @__PURE__ */ jsxs115("div", { className: "text-center", children: [
|
|
14433
|
+
/* @__PURE__ */ jsx178("h3", { className: "mb-2 text-xl font-semibold", children: "No products yet" }),
|
|
14434
|
+
/* @__PURE__ */ jsx178("p", { className: "text-muted-foreground mb-4", children: "Create your first product to start offering subscriptions to your customers." }),
|
|
14435
|
+
/* @__PURE__ */ jsx178(Button, { onClick: () => setShowCreateProduct(true), children: "Create Your First Product" })
|
|
14436
|
+
] })
|
|
14437
|
+
] }),
|
|
14438
|
+
products.length > 0 && /* @__PURE__ */ jsx178(ProductsList, { products, onProductsChange: loadProducts }),
|
|
14439
|
+
showCreateProduct && /* @__PURE__ */ jsx178(ProductEditor, { open: showCreateProduct, onOpenChange: setShowCreateProduct, onSuccess: loadProducts })
|
|
14440
|
+
] });
|
|
14441
|
+
}
|
|
14442
|
+
__name(ProductsAdminContainer, "ProductsAdminContainer");
|
|
14443
|
+
|
|
14444
|
+
// src/features/content/components/lists/ContentsList.tsx
|
|
14445
|
+
import { useTranslations as useTranslations53 } from "next-intl";
|
|
14446
|
+
import { jsx as jsx179, jsxs as jsxs116 } from "react/jsx-runtime";
|
|
14447
|
+
function ContentsList({ contentList }) {
|
|
14448
|
+
const t = useTranslations53();
|
|
14449
|
+
return /* @__PURE__ */ jsxs116("div", { className: "flex min-h-0 w-full flex-col overflow-y-auto", children: [
|
|
14450
|
+
/* @__PURE__ */ jsx179("h2", { className: "text-xl font-semibold", children: t(`foundations.content.news`) }),
|
|
14451
|
+
/* @__PURE__ */ jsx179("div", { className: "flex flex-col", children: contentList.map((content) => /* @__PURE__ */ jsx179(ContentsListElement, { content }, content.id)) })
|
|
14452
|
+
] });
|
|
14453
|
+
}
|
|
14454
|
+
__name(ContentsList, "ContentsList");
|
|
14455
|
+
function ContentsListElement({ content }) {
|
|
14456
|
+
const generateUrl = usePageUrlGenerator();
|
|
14457
|
+
const contentModule = content.contentType ? Modules.findByModelName(content.contentType) : void 0;
|
|
14458
|
+
const link = contentModule ? generateUrl({ page: contentModule, id: content.id }) : "#";
|
|
14459
|
+
return /* @__PURE__ */ jsx179("div", { className: "hover:bg-muted flex w-full flex-col gap-y-2 border-b p-2 py-4", children: /* @__PURE__ */ jsxs116("div", { className: "flex w-full justify-between gap-x-2", children: [
|
|
14460
|
+
/* @__PURE__ */ jsxs116(HoverCard, { children: [
|
|
14461
|
+
/* @__PURE__ */ jsx179(HoverCardTrigger, { asChild: true, children: /* @__PURE__ */ jsxs116(Link2, { href: link, className: "flex w-full items-center justify-start gap-2 font-semibold", children: [
|
|
14462
|
+
contentModule && getIconByModule({ module: contentModule, className: "h-4 w-4" }),
|
|
14463
|
+
content.name
|
|
14464
|
+
] }) }),
|
|
14465
|
+
/* @__PURE__ */ jsxs116(HoverCardContent, { className: "flex max-h-96 w-96 flex-col gap-y-4 overflow-y-auto", children: [
|
|
14466
|
+
/* @__PURE__ */ jsx179(Link2, { href: link, className: "font-semibold", children: content.name }),
|
|
14467
|
+
/* @__PURE__ */ jsx179("div", { className: "text-xs", children: content.abstract })
|
|
14468
|
+
] })
|
|
14469
|
+
] }),
|
|
14470
|
+
/* @__PURE__ */ jsx179(ContributorsList, { content })
|
|
14471
|
+
] }) });
|
|
14472
|
+
}
|
|
14473
|
+
__name(ContentsListElement, "ContentsListElement");
|
|
14474
|
+
|
|
14475
|
+
// src/features/content/components/lists/ContentsListById.tsx
|
|
14476
|
+
import { useTranslations as useTranslations54 } from "next-intl";
|
|
14477
|
+
import { jsx as jsx180 } from "react/jsx-runtime";
|
|
14478
|
+
function ContentsListById({ contentIds }) {
|
|
14479
|
+
const t = useTranslations54();
|
|
14480
|
+
const data = useDataListRetriever({
|
|
14481
|
+
module: Modules.Content,
|
|
14482
|
+
retriever: /* @__PURE__ */ __name((params) => ContentService.findMany(params), "retriever"),
|
|
14483
|
+
retrieverParams: { contentIds }
|
|
14484
|
+
});
|
|
14485
|
+
return /* @__PURE__ */ jsx180(
|
|
14486
|
+
ContentListTable,
|
|
14487
|
+
{
|
|
14488
|
+
data,
|
|
14489
|
+
fields: ["name" /* name */, "authors" /* authors */, "updatedAt" /* updatedAt */],
|
|
14490
|
+
tableGeneratorType: Modules.Content,
|
|
14491
|
+
title: t(`generic.relevant`)
|
|
14492
|
+
}
|
|
14493
|
+
);
|
|
14494
|
+
}
|
|
14495
|
+
__name(ContentsListById, "ContentsListById");
|
|
14496
|
+
|
|
14497
|
+
// src/features/content/components/lists/RelevantContentsList.tsx
|
|
14498
|
+
import { useTranslations as useTranslations55 } from "next-intl";
|
|
14499
|
+
import { jsx as jsx181 } from "react/jsx-runtime";
|
|
14500
|
+
function RelevantContentsList({ id }) {
|
|
14501
|
+
const t = useTranslations55();
|
|
14502
|
+
const data = useDataListRetriever({
|
|
14503
|
+
module: Modules.Content,
|
|
14504
|
+
retriever: /* @__PURE__ */ __name((params) => ContentService.findRelevant(params), "retriever"),
|
|
14505
|
+
retrieverParams: { id }
|
|
14506
|
+
});
|
|
14507
|
+
return /* @__PURE__ */ jsx181(
|
|
14508
|
+
ContentListTable,
|
|
14509
|
+
{
|
|
14510
|
+
data,
|
|
14511
|
+
fields: ["name" /* name */, "authors" /* authors */, "relevance" /* relevance */, "updatedAt" /* updatedAt */],
|
|
14512
|
+
tableGeneratorType: Modules.Content,
|
|
14513
|
+
title: t(`generic.relevant`)
|
|
14514
|
+
}
|
|
14515
|
+
);
|
|
14516
|
+
}
|
|
14517
|
+
__name(RelevantContentsList, "RelevantContentsList");
|
|
14518
|
+
|
|
14519
|
+
// src/features/notification/components/common/NotificationErrorBoundary.tsx
|
|
14520
|
+
import { Component } from "react";
|
|
14521
|
+
import { jsx as jsx182, jsxs as jsxs117 } from "react/jsx-runtime";
|
|
14522
|
+
var NotificationErrorBoundary = class extends Component {
|
|
14523
|
+
static {
|
|
14524
|
+
__name(this, "NotificationErrorBoundary");
|
|
14525
|
+
}
|
|
14526
|
+
constructor(props) {
|
|
14527
|
+
super(props);
|
|
14528
|
+
this.state = { hasError: false };
|
|
14529
|
+
}
|
|
14530
|
+
static getDerivedStateFromError(error) {
|
|
14531
|
+
return { hasError: true, error };
|
|
14532
|
+
}
|
|
14533
|
+
componentDidCatch(error, errorInfo) {
|
|
14534
|
+
console.error("\u{1F6A8} [NotificationErrorBoundary] Caught error:", error, errorInfo);
|
|
14535
|
+
}
|
|
14536
|
+
render() {
|
|
14537
|
+
if (this.state.hasError) {
|
|
14538
|
+
return this.props.fallback || /* @__PURE__ */ jsx182("div", { className: "flex items-center justify-center p-4 text-center", children: /* @__PURE__ */ jsxs117("div", { className: "text-muted-foreground text-sm", children: [
|
|
14539
|
+
/* @__PURE__ */ jsx182("p", { children: "Something went wrong with notifications." }),
|
|
14540
|
+
/* @__PURE__ */ jsx182(
|
|
14541
|
+
"button",
|
|
14542
|
+
{
|
|
14543
|
+
onClick: () => this.setState({ hasError: false }),
|
|
14544
|
+
className: "text-primary mt-2 underline hover:no-underline",
|
|
14545
|
+
children: "Try again"
|
|
14546
|
+
}
|
|
14547
|
+
)
|
|
14548
|
+
] }) });
|
|
14549
|
+
}
|
|
14550
|
+
return this.props.children;
|
|
14551
|
+
}
|
|
14552
|
+
};
|
|
14553
|
+
|
|
14554
|
+
// src/features/notification/components/containers/NotificationsListContainer.tsx
|
|
14555
|
+
import { useTranslations as useTranslations57 } from "next-intl";
|
|
14556
|
+
|
|
14557
|
+
// src/features/notification/components/lists/NotificationsList.tsx
|
|
14558
|
+
import { ArchiveIcon } from "lucide-react";
|
|
14559
|
+
import { useTranslations as useTranslations56 } from "next-intl";
|
|
14560
|
+
import { Fragment as Fragment35, jsx as jsx183, jsxs as jsxs118 } from "react/jsx-runtime";
|
|
14561
|
+
function NotificationsList({ archived }) {
|
|
14562
|
+
const t = useTranslations56();
|
|
14563
|
+
const generateUrl = usePageUrlGenerator();
|
|
14564
|
+
const data = useDataListRetriever({
|
|
14565
|
+
retriever: /* @__PURE__ */ __name((params) => NotificationService.findMany(params), "retriever"),
|
|
14566
|
+
retrieverParams: { isArchived: archived },
|
|
14567
|
+
module: Modules.Notification
|
|
14568
|
+
});
|
|
14569
|
+
const archiveNotification = /* @__PURE__ */ __name(async (notification) => {
|
|
14570
|
+
await NotificationService.archive({ id: notification.id });
|
|
14571
|
+
data.removeElement(notification);
|
|
14572
|
+
}, "archiveNotification");
|
|
14573
|
+
const LoadingSkeleton = /* @__PURE__ */ __name(() => /* @__PURE__ */ jsx183("div", { className: "space-y-4", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsx183(Card, { children: /* @__PURE__ */ jsx183(CardContent, { className: "p-2", children: /* @__PURE__ */ jsxs118("div", { className: "flex w-full flex-row items-center", children: [
|
|
14574
|
+
/* @__PURE__ */ jsx183(Skeleton, { className: "mr-4 h-8 w-8 rounded-full" }),
|
|
14575
|
+
/* @__PURE__ */ jsxs118("div", { className: "flex-1 space-y-2", children: [
|
|
14576
|
+
/* @__PURE__ */ jsx183(Skeleton, { className: "h-4 w-3/4" }),
|
|
14577
|
+
/* @__PURE__ */ jsx183(Skeleton, { className: "h-3 w-1/2" })
|
|
14578
|
+
] }),
|
|
14579
|
+
/* @__PURE__ */ jsx183(Skeleton, { className: "h-8 w-20" })
|
|
14580
|
+
] }) }) }, i)) }), "LoadingSkeleton");
|
|
14581
|
+
return /* @__PURE__ */ jsx183("div", { className: "space-y-4", children: data.isLoaded ? data.data?.map((notification) => {
|
|
14582
|
+
const notificationData = generateNotificationData({ notification, generateUrl });
|
|
14583
|
+
return /* @__PURE__ */ jsx183(Card, { children: /* @__PURE__ */ jsx183(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxs118("div", { className: `flex w-full flex-row items-center p-2`, children: [
|
|
14584
|
+
notificationData.actor ? /* @__PURE__ */ jsx183("div", { className: "flex w-12 max-w-12 px-2", children: /* @__PURE__ */ jsx183(Link2, { href: generateUrl({ page: Modules.User, id: notificationData.actor.id }), children: /* @__PURE__ */ jsx183(UserAvatar, { user: notificationData.actor, className: "h-8 w-8" }) }) }) : /* @__PURE__ */ jsx183("div", { className: "flex w-14 max-w-14 px-2" }),
|
|
14585
|
+
/* @__PURE__ */ jsxs118("div", { className: "flex w-full flex-col", children: [
|
|
14586
|
+
/* @__PURE__ */ jsx183("p", { className: "text-sm", children: t.rich(`foundations.notification.${notification.notificationType}.description`, {
|
|
14587
|
+
strong: /* @__PURE__ */ __name((chunks) => /* @__PURE__ */ jsx183("strong", { children: chunks }), "strong"),
|
|
14588
|
+
actor: notificationData.actor?.name ?? "",
|
|
14589
|
+
title: notificationData.title
|
|
14590
|
+
}) }),
|
|
14591
|
+
/* @__PURE__ */ jsx183("div", { className: "text-muted-foreground mt-1 w-full text-xs", children: new Date(notification.createdAt).toLocaleString() })
|
|
14592
|
+
] }),
|
|
14593
|
+
/* @__PURE__ */ jsxs118("div", { className: "flex flex-row items-center", children: [
|
|
14594
|
+
notificationData.url ? /* @__PURE__ */ jsx183(Link2, { href: notificationData.url, children: /* @__PURE__ */ jsx183(Button, { variant: `outline`, size: `sm`, onClick: (e) => e.stopPropagation(), children: t(`foundations.notification.${notification.notificationType}.buttons.action`) }) }) : /* @__PURE__ */ jsx183(Fragment35, {}),
|
|
14595
|
+
!archived && /* @__PURE__ */ jsxs118(Tooltip2, { children: [
|
|
14596
|
+
/* @__PURE__ */ jsx183(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx183(
|
|
14597
|
+
Button,
|
|
14598
|
+
{
|
|
14599
|
+
variant: `link`,
|
|
14600
|
+
onClick: (e) => {
|
|
14601
|
+
e.preventDefault();
|
|
14602
|
+
e.stopPropagation();
|
|
14603
|
+
archiveNotification(notification);
|
|
14604
|
+
},
|
|
14605
|
+
className: "text-muted-foreground hover:text-destructive ml-2",
|
|
14606
|
+
children: /* @__PURE__ */ jsx183(ArchiveIcon, { className: "h-4 w-4 cursor-pointer" })
|
|
14607
|
+
}
|
|
14608
|
+
) }),
|
|
14609
|
+
/* @__PURE__ */ jsx183(TooltipContent, { children: t(`foundations.notification.buttons.archive`) })
|
|
14610
|
+
] })
|
|
14611
|
+
] })
|
|
14612
|
+
] }) }) }, notification.id);
|
|
14613
|
+
}) : /* @__PURE__ */ jsx183(LoadingSkeleton, {}) });
|
|
14614
|
+
}
|
|
14615
|
+
__name(NotificationsList, "NotificationsList");
|
|
14616
|
+
|
|
14617
|
+
// src/features/notification/components/containers/NotificationsListContainer.tsx
|
|
14618
|
+
import { jsx as jsx184, jsxs as jsxs119 } from "react/jsx-runtime";
|
|
14619
|
+
function NotificationsListContainerContent() {
|
|
14620
|
+
const t = useTranslations57();
|
|
14621
|
+
const { notifications, isLoading, error } = useNotificationContext();
|
|
14622
|
+
if (error) {
|
|
14623
|
+
return /* @__PURE__ */ jsx184("div", { className: "flex items-center justify-center p-8 text-center", children: /* @__PURE__ */ jsxs119("div", { className: "text-destructive text-sm", children: [
|
|
14624
|
+
/* @__PURE__ */ jsxs119("p", { children: [
|
|
14625
|
+
"Error loading notifications: ",
|
|
14626
|
+
error
|
|
14627
|
+
] }),
|
|
14628
|
+
/* @__PURE__ */ jsx184("p", { className: "text-muted-foreground mt-2", children: "Please try refreshing the page." })
|
|
14629
|
+
] }) });
|
|
14630
|
+
}
|
|
14631
|
+
const tabs = [
|
|
14632
|
+
{
|
|
14633
|
+
label: t(`foundations.notification.inbox`),
|
|
14634
|
+
content: /* @__PURE__ */ jsx184(NotificationsList, { archived: false })
|
|
14635
|
+
},
|
|
14636
|
+
{
|
|
14637
|
+
label: t(`foundations.notification.archived`),
|
|
14638
|
+
content: /* @__PURE__ */ jsx184(NotificationsList, { archived: true })
|
|
14639
|
+
}
|
|
14640
|
+
];
|
|
14641
|
+
return /* @__PURE__ */ jsx184(TabsContainer, { tabs });
|
|
14642
|
+
}
|
|
14643
|
+
__name(NotificationsListContainerContent, "NotificationsListContainerContent");
|
|
14644
|
+
function NotificationsListContainer() {
|
|
14645
|
+
return /* @__PURE__ */ jsx184(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx184(NotificationsListContainerContent, {}) });
|
|
11359
14646
|
}
|
|
11360
14647
|
__name(NotificationsListContainer, "NotificationsListContainer");
|
|
11361
14648
|
|
|
11362
14649
|
// src/features/notification/components/modals/NotificationModal.tsx
|
|
11363
14650
|
import { BellIcon } from "lucide-react";
|
|
11364
14651
|
import { useTranslations as useTranslations58 } from "next-intl";
|
|
11365
|
-
import { Fragment as
|
|
14652
|
+
import { Fragment as Fragment36, useCallback as useCallback19, useEffect as useEffect50, useMemo as useMemo19, useRef as useRef16, useState as useState68 } from "react";
|
|
11366
14653
|
import { toast as toast10 } from "sonner";
|
|
11367
|
-
import { jsx as
|
|
14654
|
+
import { jsx as jsx185, jsxs as jsxs120 } from "react/jsx-runtime";
|
|
11368
14655
|
function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
11369
14656
|
const instanceId = useRef16(Math.random().toString(36).substr(2, 9));
|
|
11370
14657
|
const {
|
|
@@ -11382,14 +14669,14 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
|
11382
14669
|
const { socketNotifications, removeSocketNotification, clearSocketNotifications } = useSocketContext();
|
|
11383
14670
|
const t = useTranslations58();
|
|
11384
14671
|
const generateUrl = usePageUrlGenerator();
|
|
11385
|
-
const [newNotifications, setNewNotifications] =
|
|
14672
|
+
const [newNotifications, setNewNotifications] = useState68(false);
|
|
11386
14673
|
const preventAutoClose = useRef16(false);
|
|
11387
14674
|
const circuitBreakerRef = useRef16({
|
|
11388
14675
|
count: 0,
|
|
11389
14676
|
resetTime: 0,
|
|
11390
14677
|
isOpen: false
|
|
11391
14678
|
});
|
|
11392
|
-
const checkCircuitBreaker =
|
|
14679
|
+
const checkCircuitBreaker = useCallback19(() => {
|
|
11393
14680
|
const now = Date.now();
|
|
11394
14681
|
const breaker = circuitBreakerRef.current;
|
|
11395
14682
|
if (now > breaker.resetTime) {
|
|
@@ -11404,21 +14691,21 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
|
11404
14691
|
}
|
|
11405
14692
|
return !breaker.isOpen;
|
|
11406
14693
|
}, []);
|
|
11407
|
-
const { unreadCount, unreadIds } =
|
|
14694
|
+
const { unreadCount, unreadIds } = useMemo19(() => {
|
|
11408
14695
|
const unreadNotifications2 = notifications.filter((notif) => !notif.isRead);
|
|
11409
14696
|
return {
|
|
11410
14697
|
unreadCount: unreadNotifications2.length,
|
|
11411
14698
|
unreadIds: unreadNotifications2.map((notif) => notif.id)
|
|
11412
14699
|
};
|
|
11413
14700
|
}, [notifications]);
|
|
11414
|
-
|
|
14701
|
+
useEffect50(() => {
|
|
11415
14702
|
setNewNotifications(unreadCount > 0);
|
|
11416
14703
|
}, [unreadCount]);
|
|
11417
|
-
|
|
14704
|
+
useEffect50(() => {
|
|
11418
14705
|
if (lastLoaded === 0) loadNotifications();
|
|
11419
14706
|
}, [lastLoaded, loadNotifications]);
|
|
11420
14707
|
const processSocketNotificationsRef = useRef16(null);
|
|
11421
|
-
const processSocketNotifications =
|
|
14708
|
+
const processSocketNotifications = useCallback19(() => {
|
|
11422
14709
|
if (socketNotifications.length === 0) {
|
|
11423
14710
|
return;
|
|
11424
14711
|
}
|
|
@@ -11457,7 +14744,7 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
|
11457
14744
|
generateUrl,
|
|
11458
14745
|
checkCircuitBreaker
|
|
11459
14746
|
]);
|
|
11460
|
-
|
|
14747
|
+
useEffect50(() => {
|
|
11461
14748
|
if (processSocketNotificationsRef.current) {
|
|
11462
14749
|
clearTimeout(processSocketNotificationsRef.current);
|
|
11463
14750
|
}
|
|
@@ -11494,9 +14781,9 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
|
11494
14781
|
}
|
|
11495
14782
|
}, "handleOpenChange");
|
|
11496
14783
|
const unreadNotifications = newNotifications && unreadCount > 0;
|
|
11497
|
-
return /* @__PURE__ */
|
|
11498
|
-
/* @__PURE__ */
|
|
11499
|
-
/* @__PURE__ */
|
|
14784
|
+
return /* @__PURE__ */ jsxs120(Popover, { open: isOpen, onOpenChange: handleOpenChange, "data-testid": `sidebar-notification button`, children: [
|
|
14785
|
+
/* @__PURE__ */ jsx185(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs120(SidebarMenuButton, { className: "text-muted-foreground h-6", disabled: isLoading, children: [
|
|
14786
|
+
/* @__PURE__ */ jsx185(
|
|
11500
14787
|
BellIcon,
|
|
11501
14788
|
{
|
|
11502
14789
|
className: `h-5 w-5 cursor-pointer ${unreadNotifications ? "text-destructive" : ""} ${isLoading ? "animate-pulse" : ""}`
|
|
@@ -11504,75 +14791,75 @@ function NotificationModalContent({ isOpen, setIsOpen }) {
|
|
|
11504
14791
|
),
|
|
11505
14792
|
t(`types.notifications`, { count: 2 })
|
|
11506
14793
|
] }) }),
|
|
11507
|
-
/* @__PURE__ */
|
|
11508
|
-
/* @__PURE__ */
|
|
11509
|
-
/* @__PURE__ */
|
|
11510
|
-
isLoading && /* @__PURE__ */
|
|
11511
|
-
error && /* @__PURE__ */
|
|
14794
|
+
/* @__PURE__ */ jsx185(PopoverContent, { className: "relative left-10 w-80 border-0 p-0 shadow-none", children: /* @__PURE__ */ jsxs120(Card, { children: [
|
|
14795
|
+
/* @__PURE__ */ jsxs120(CardHeader, { className: "p-4", children: [
|
|
14796
|
+
/* @__PURE__ */ jsx185(CardTitle, { children: t(`types.notifications`, { count: 2 }) }),
|
|
14797
|
+
isLoading && /* @__PURE__ */ jsx185("div", { className: "text-muted-foreground text-xs", children: "Loading..." }),
|
|
14798
|
+
error && /* @__PURE__ */ jsxs120("div", { className: "text-destructive text-xs", children: [
|
|
11512
14799
|
"Error: ",
|
|
11513
14800
|
error
|
|
11514
14801
|
] })
|
|
11515
14802
|
] }),
|
|
11516
|
-
/* @__PURE__ */
|
|
11517
|
-
/* @__PURE__ */
|
|
14803
|
+
/* @__PURE__ */ jsx185(Separator4, {}),
|
|
14804
|
+
/* @__PURE__ */ jsx185(ScrollArea, { className: "h-96", children: notifications.length > 0 ? notifications.map((notification) => /* @__PURE__ */ jsx185(Fragment36, { children: generateNotification(notification, () => setIsOpen(false)) }, notification.id)) : /* @__PURE__ */ jsx185("div", { className: "p-4 text-center text-sm text-gray-500", children: t(`foundations.notification.empty`, { count: 2 }) }) })
|
|
11518
14805
|
] }) })
|
|
11519
14806
|
] });
|
|
11520
14807
|
}
|
|
11521
14808
|
__name(NotificationModalContent, "NotificationModalContent");
|
|
11522
14809
|
function NotificationModal(props) {
|
|
11523
|
-
return /* @__PURE__ */
|
|
14810
|
+
return /* @__PURE__ */ jsx185(NotificationErrorBoundary, { children: /* @__PURE__ */ jsx185(NotificationModalContent, { ...props }) });
|
|
11524
14811
|
}
|
|
11525
14812
|
__name(NotificationModal, "NotificationModal");
|
|
11526
14813
|
|
|
11527
14814
|
// src/features/notification/components/notifications/PushNotificationProvider.tsx
|
|
11528
|
-
import { Fragment as
|
|
14815
|
+
import { Fragment as Fragment37, jsx as jsx186 } from "react/jsx-runtime";
|
|
11529
14816
|
function PushNotificationProvider({ children }) {
|
|
11530
14817
|
usePushNotifications();
|
|
11531
|
-
return /* @__PURE__ */
|
|
14818
|
+
return /* @__PURE__ */ jsx186(Fragment37, { children });
|
|
11532
14819
|
}
|
|
11533
14820
|
__name(PushNotificationProvider, "PushNotificationProvider");
|
|
11534
14821
|
|
|
11535
14822
|
// src/features/role/components/details/RoleDetails.tsx
|
|
11536
14823
|
import { useTranslations as useTranslations59 } from "next-intl";
|
|
11537
|
-
import { jsx as
|
|
14824
|
+
import { jsx as jsx187 } from "react/jsx-runtime";
|
|
11538
14825
|
function RoleDetails() {
|
|
11539
14826
|
const { role } = useRoleContext();
|
|
11540
14827
|
const t = useTranslations59();
|
|
11541
14828
|
if (!role) return null;
|
|
11542
|
-
return /* @__PURE__ */
|
|
14829
|
+
return /* @__PURE__ */ jsx187(Card, { className: "w-full", children: /* @__PURE__ */ jsx187(CardContent, { className: "p-4", children: /* @__PURE__ */ jsx187(AttributeElement, { title: t(`foundations.role.fields.description.label`), value: role.description }) }) });
|
|
11543
14830
|
}
|
|
11544
14831
|
__name(RoleDetails, "RoleDetails");
|
|
11545
14832
|
|
|
11546
14833
|
// src/features/role/components/containers/RoleContainer.tsx
|
|
11547
|
-
import { Fragment as
|
|
14834
|
+
import { Fragment as Fragment38, jsx as jsx188, jsxs as jsxs121 } from "react/jsx-runtime";
|
|
11548
14835
|
function RoleContainer() {
|
|
11549
14836
|
const { role } = useRoleContext();
|
|
11550
14837
|
if (!role) return null;
|
|
11551
|
-
return /* @__PURE__ */
|
|
11552
|
-
/* @__PURE__ */
|
|
11553
|
-
/* @__PURE__ */
|
|
14838
|
+
return /* @__PURE__ */ jsxs121(Fragment38, { children: [
|
|
14839
|
+
/* @__PURE__ */ jsx188(RoleDetails, {}),
|
|
14840
|
+
/* @__PURE__ */ jsx188(RoleUsersList, { role })
|
|
11554
14841
|
] });
|
|
11555
14842
|
}
|
|
11556
14843
|
__name(RoleContainer, "RoleContainer");
|
|
11557
14844
|
|
|
11558
14845
|
// src/features/role/components/forms/FormRoles.tsx
|
|
11559
14846
|
import { useTranslations as useTranslations60 } from "next-intl";
|
|
11560
|
-
import { jsx as
|
|
14847
|
+
import { jsx as jsx189, jsxs as jsxs122 } from "react/jsx-runtime";
|
|
11561
14848
|
function FormRoles({ form, id, name, roles }) {
|
|
11562
14849
|
const t = useTranslations60();
|
|
11563
14850
|
const { hasAccesToFeature } = useCurrentUserContext();
|
|
11564
|
-
return /* @__PURE__ */
|
|
14851
|
+
return /* @__PURE__ */ jsx189("div", { className: "flex w-full flex-col", children: /* @__PURE__ */ jsx189(
|
|
11565
14852
|
FormField,
|
|
11566
14853
|
{
|
|
11567
14854
|
control: form.control,
|
|
11568
14855
|
name: id,
|
|
11569
|
-
render: ({ field }) => /* @__PURE__ */
|
|
11570
|
-
/* @__PURE__ */
|
|
11571
|
-
/* @__PURE__ */
|
|
14856
|
+
render: ({ field }) => /* @__PURE__ */ jsxs122(FormItem, { className: `${name ? "mb-5" : "mb-1"}`, children: [
|
|
14857
|
+
/* @__PURE__ */ jsx189(FormControl, { children: /* @__PURE__ */ jsxs122("div", { children: [
|
|
14858
|
+
/* @__PURE__ */ jsx189("div", { className: "text-sm font-semibold", children: name }),
|
|
11572
14859
|
roles.filter((role) => role.isSelectable).sort((a, b) => a.name.localeCompare(b.name)).map((role) => {
|
|
11573
14860
|
if (role.requiredFeature && !hasAccesToFeature(role.requiredFeature.id)) return null;
|
|
11574
|
-
return /* @__PURE__ */
|
|
11575
|
-
/* @__PURE__ */
|
|
14861
|
+
return /* @__PURE__ */ jsxs122("div", { children: [
|
|
14862
|
+
/* @__PURE__ */ jsx189(
|
|
11576
14863
|
Checkbox,
|
|
11577
14864
|
{
|
|
11578
14865
|
defaultChecked: field.value.some((roleId) => roleId === role.id),
|
|
@@ -11588,14 +14875,14 @@ function FormRoles({ form, id, name, roles }) {
|
|
|
11588
14875
|
}
|
|
11589
14876
|
}
|
|
11590
14877
|
),
|
|
11591
|
-
/* @__PURE__ */
|
|
11592
|
-
/* @__PURE__ */
|
|
11593
|
-
/* @__PURE__ */
|
|
14878
|
+
/* @__PURE__ */ jsxs122(Tooltip2, { children: [
|
|
14879
|
+
/* @__PURE__ */ jsx189(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx189(FormLabel, { className: "ml-3 font-normal", children: t(`foundations.role.roles`, { role: role.id.replaceAll(`-`, ``) }) }) }),
|
|
14880
|
+
/* @__PURE__ */ jsx189(TooltipContent, { children: t(`foundations.role.roles_descriptions`, { role: role.id.replaceAll(`-`, ``) }) })
|
|
11594
14881
|
] })
|
|
11595
14882
|
] }, role.id);
|
|
11596
14883
|
})
|
|
11597
14884
|
] }) }),
|
|
11598
|
-
/* @__PURE__ */
|
|
14885
|
+
/* @__PURE__ */ jsx189(FormMessage, {})
|
|
11599
14886
|
] })
|
|
11600
14887
|
}
|
|
11601
14888
|
) });
|
|
@@ -11604,13 +14891,13 @@ __name(FormRoles, "FormRoles");
|
|
|
11604
14891
|
|
|
11605
14892
|
// src/features/role/components/forms/RemoveUserFromRole.tsx
|
|
11606
14893
|
import { useTranslations as useTranslations61 } from "next-intl";
|
|
11607
|
-
import { useEffect as
|
|
11608
|
-
import { Fragment as
|
|
14894
|
+
import { useEffect as useEffect51, useState as useState69 } from "react";
|
|
14895
|
+
import { Fragment as Fragment39, jsx as jsx190, jsxs as jsxs123 } from "react/jsx-runtime";
|
|
11609
14896
|
function RemoveUserFromRole({ role, user, refresh }) {
|
|
11610
|
-
const [open, setOpen] =
|
|
11611
|
-
const [canRemove, setCanRemove] =
|
|
14897
|
+
const [open, setOpen] = useState69(false);
|
|
14898
|
+
const [canRemove, setCanRemove] = useState69(false);
|
|
11612
14899
|
const t = useTranslations61();
|
|
11613
|
-
|
|
14900
|
+
useEffect51(() => {
|
|
11614
14901
|
async function checkCompanyAdminDeletability() {
|
|
11615
14902
|
const roleUsers = await UserService.findAllUsersByRole({
|
|
11616
14903
|
roleId: role.id
|
|
@@ -11637,8 +14924,8 @@ function RemoveUserFromRole({ role, user, refresh }) {
|
|
|
11637
14924
|
}
|
|
11638
14925
|
}, "remove");
|
|
11639
14926
|
const roleName = t(`foundations.role.roles`, { role: role.id.replaceAll(`-`, ``) });
|
|
11640
|
-
return /* @__PURE__ */
|
|
11641
|
-
/* @__PURE__ */
|
|
14927
|
+
return /* @__PURE__ */ jsxs123(Dialog, { open, onOpenChange: setOpen, children: [
|
|
14928
|
+
/* @__PURE__ */ jsx190(
|
|
11642
14929
|
DialogTrigger,
|
|
11643
14930
|
{
|
|
11644
14931
|
onClick: (e) => {
|
|
@@ -11646,19 +14933,19 @@ function RemoveUserFromRole({ role, user, refresh }) {
|
|
|
11646
14933
|
e.preventDefault();
|
|
11647
14934
|
setOpen(true);
|
|
11648
14935
|
},
|
|
11649
|
-
children: /* @__PURE__ */
|
|
14936
|
+
children: /* @__PURE__ */ jsx190("span", { className: "hover:text-destructive cursor-pointer", children: t(`foundations.role.remove_user.title`) })
|
|
11650
14937
|
}
|
|
11651
14938
|
),
|
|
11652
|
-
/* @__PURE__ */
|
|
11653
|
-
/* @__PURE__ */
|
|
11654
|
-
/* @__PURE__ */
|
|
11655
|
-
/* @__PURE__ */
|
|
14939
|
+
/* @__PURE__ */ jsxs123(DialogContent, { className: `flex max-h-[70vh] max-w-3xl flex-col overflow-y-auto`, children: [
|
|
14940
|
+
/* @__PURE__ */ jsxs123(DialogHeader, { children: [
|
|
14941
|
+
/* @__PURE__ */ jsx190(DialogTitle, { children: t(`foundations.role.remove_user.title`) }),
|
|
14942
|
+
/* @__PURE__ */ jsx190(DialogDescription, { children: canRemove ? t(`foundations.role.remove_user.subtitle_allowed`) : t(`foundations.role.remove_user.subtitle_not_allowed`) })
|
|
11656
14943
|
] }),
|
|
11657
|
-
canRemove ? /* @__PURE__ */
|
|
14944
|
+
canRemove ? /* @__PURE__ */ jsxs123(Fragment39, { children: [
|
|
11658
14945
|
t(`foundations.role.remove_user.description_allowed`, { role: roleName, user: user.name }),
|
|
11659
|
-
/* @__PURE__ */
|
|
11660
|
-
/* @__PURE__ */
|
|
11661
|
-
/* @__PURE__ */
|
|
14946
|
+
/* @__PURE__ */ jsxs123("div", { className: "flex justify-end", children: [
|
|
14947
|
+
/* @__PURE__ */ jsx190(Button, { className: "mr-2", variant: "outline", type: `button`, onClick: () => setOpen(false), children: t(`generic.buttons.cancel`) }),
|
|
14948
|
+
/* @__PURE__ */ jsx190(
|
|
11662
14949
|
Button,
|
|
11663
14950
|
{
|
|
11664
14951
|
type: "submit",
|
|
@@ -11671,7 +14958,7 @@ function RemoveUserFromRole({ role, user, refresh }) {
|
|
|
11671
14958
|
}
|
|
11672
14959
|
)
|
|
11673
14960
|
] })
|
|
11674
|
-
] }) : /* @__PURE__ */
|
|
14961
|
+
] }) : /* @__PURE__ */ jsx190(Fragment39, { children: t(`foundations.role.remove_user.description_not_allowed`, { role: roleName, user: user.name }) })
|
|
11675
14962
|
] })
|
|
11676
14963
|
] });
|
|
11677
14964
|
}
|
|
@@ -11680,14 +14967,14 @@ __name(RemoveUserFromRole, "RemoveUserFromRole");
|
|
|
11680
14967
|
// src/features/role/components/forms/UserRoleAdd.tsx
|
|
11681
14968
|
import { PlusCircle } from "lucide-react";
|
|
11682
14969
|
import { useTranslations as useTranslations62 } from "next-intl";
|
|
11683
|
-
import { useCallback as
|
|
14970
|
+
import { useCallback as useCallback20, useEffect as useEffect52, useRef as useRef17, useState as useState70 } from "react";
|
|
11684
14971
|
import { toast as toast11 } from "sonner";
|
|
11685
|
-
import { Fragment as
|
|
14972
|
+
import { Fragment as Fragment40, jsx as jsx191, jsxs as jsxs124 } from "react/jsx-runtime";
|
|
11686
14973
|
function UserRoleAdd({ user, refresh }) {
|
|
11687
|
-
const [open, setOpen] =
|
|
14974
|
+
const [open, setOpen] = useState70(false);
|
|
11688
14975
|
const inputRef = useRef17(null);
|
|
11689
|
-
const [searchTerm, setSearchTerm] =
|
|
11690
|
-
const [roles, setRoles] =
|
|
14976
|
+
const [searchTerm, setSearchTerm] = useState70("");
|
|
14977
|
+
const [roles, setRoles] = useState70([]);
|
|
11691
14978
|
const t = useTranslations62();
|
|
11692
14979
|
const addUserToRole = /* @__PURE__ */ __name(async (role) => {
|
|
11693
14980
|
await RoleService.addUserToRole({
|
|
@@ -11711,7 +14998,7 @@ function UserRoleAdd({ user, refresh }) {
|
|
|
11711
14998
|
);
|
|
11712
14999
|
refresh();
|
|
11713
15000
|
}, "addUserToRole");
|
|
11714
|
-
const searchRoles =
|
|
15001
|
+
const searchRoles = useCallback20(
|
|
11715
15002
|
async (term) => {
|
|
11716
15003
|
setRoles(
|
|
11717
15004
|
await RoleService.findAllRolesUserNotIn({
|
|
@@ -11723,32 +15010,32 @@ function UserRoleAdd({ user, refresh }) {
|
|
|
11723
15010
|
[searchTerm, user]
|
|
11724
15011
|
);
|
|
11725
15012
|
const updateSearchTerm = useDebounce(searchRoles, 500);
|
|
11726
|
-
|
|
15013
|
+
useEffect52(() => {
|
|
11727
15014
|
if (open) updateSearchTerm(searchTerm);
|
|
11728
15015
|
}, [open, searchTerm]);
|
|
11729
|
-
|
|
15016
|
+
useEffect52(() => {
|
|
11730
15017
|
if (open) searchRoles("");
|
|
11731
15018
|
}, [open]);
|
|
11732
|
-
return /* @__PURE__ */
|
|
11733
|
-
/* @__PURE__ */
|
|
11734
|
-
/* @__PURE__ */
|
|
15019
|
+
return /* @__PURE__ */ jsxs124(Fragment40, { children: [
|
|
15020
|
+
/* @__PURE__ */ jsxs124(Button, { size: "sm", onClick: () => setOpen(true), children: [
|
|
15021
|
+
/* @__PURE__ */ jsx191(PlusCircle, { className: "mr-3 h-3.5 w-3.5" }),
|
|
11735
15022
|
t(`generic.association.label`, {
|
|
11736
15023
|
source: t(`types.roles`, { count: 1 }),
|
|
11737
15024
|
destination: t(`types.users`, { count: 1 })
|
|
11738
15025
|
})
|
|
11739
15026
|
] }),
|
|
11740
|
-
/* @__PURE__ */
|
|
11741
|
-
/* @__PURE__ */
|
|
15027
|
+
/* @__PURE__ */ jsxs124(CommandDialog, { open, onOpenChange: setOpen, children: [
|
|
15028
|
+
/* @__PURE__ */ jsx191(DialogTitle, { children: t(`generic.association.label`, {
|
|
11742
15029
|
source: t(`types.roles`, { count: 1 }),
|
|
11743
15030
|
destination: t(`types.users`, { count: 1 })
|
|
11744
15031
|
}) }),
|
|
11745
|
-
/* @__PURE__ */
|
|
15032
|
+
/* @__PURE__ */ jsx191(DialogDescription, { children: t(`generic.association.description`, {
|
|
11746
15033
|
source: t(`types.roles`, { count: 1 }),
|
|
11747
15034
|
destination: t(`types.users`, { count: 1 }),
|
|
11748
15035
|
destination_name: user.name
|
|
11749
15036
|
}) }),
|
|
11750
|
-
/* @__PURE__ */
|
|
11751
|
-
/* @__PURE__ */
|
|
15037
|
+
/* @__PURE__ */ jsxs124(Command, { shouldFilter: false, children: [
|
|
15038
|
+
/* @__PURE__ */ jsx191(
|
|
11752
15039
|
CommandInput,
|
|
11753
15040
|
{
|
|
11754
15041
|
placeholder: t(`generic.search.placeholder`, { type: t(`types.roles`, { count: 1 }) }),
|
|
@@ -11757,9 +15044,9 @@ function UserRoleAdd({ user, refresh }) {
|
|
|
11757
15044
|
ref: inputRef
|
|
11758
15045
|
}
|
|
11759
15046
|
),
|
|
11760
|
-
/* @__PURE__ */
|
|
11761
|
-
/* @__PURE__ */
|
|
11762
|
-
roles.map((role) => /* @__PURE__ */
|
|
15047
|
+
/* @__PURE__ */ jsxs124(CommandList, { className: "mt-3 h-auto max-h-96 min-h-96 max-w-full overflow-x-hidden overflow-y-auto", children: [
|
|
15048
|
+
/* @__PURE__ */ jsx191(CommandEmpty, { children: t(`generic.search.no_results`, { type: t(`types.roles`, { count: 1 }) }) }),
|
|
15049
|
+
roles.map((role) => /* @__PURE__ */ jsx191(
|
|
11763
15050
|
CommandItem,
|
|
11764
15051
|
{
|
|
11765
15052
|
className: "cursor-pointer",
|
|
@@ -11778,7 +15065,7 @@ __name(UserRoleAdd, "UserRoleAdd");
|
|
|
11778
15065
|
|
|
11779
15066
|
// src/features/role/components/lists/RolesList.tsx
|
|
11780
15067
|
import { useTranslations as useTranslations63 } from "next-intl";
|
|
11781
|
-
import { jsx as
|
|
15068
|
+
import { jsx as jsx192 } from "react/jsx-runtime";
|
|
11782
15069
|
function RolesList() {
|
|
11783
15070
|
const t = useTranslations63();
|
|
11784
15071
|
const data = useDataListRetriever({
|
|
@@ -11786,7 +15073,7 @@ function RolesList() {
|
|
|
11786
15073
|
retrieverParams: {},
|
|
11787
15074
|
module: Modules.Role
|
|
11788
15075
|
});
|
|
11789
|
-
return /* @__PURE__ */
|
|
15076
|
+
return /* @__PURE__ */ jsx192(
|
|
11790
15077
|
ContentListTable,
|
|
11791
15078
|
{
|
|
11792
15079
|
data,
|
|
@@ -11800,7 +15087,7 @@ __name(RolesList, "RolesList");
|
|
|
11800
15087
|
|
|
11801
15088
|
// src/features/role/components/lists/UserRolesList.tsx
|
|
11802
15089
|
import { useTranslations as useTranslations64 } from "next-intl";
|
|
11803
|
-
import { jsx as
|
|
15090
|
+
import { jsx as jsx193 } from "react/jsx-runtime";
|
|
11804
15091
|
function UserRolesList({ user }) {
|
|
11805
15092
|
const t = useTranslations64();
|
|
11806
15093
|
const data = useDataListRetriever({
|
|
@@ -11808,7 +15095,7 @@ function UserRolesList({ user }) {
|
|
|
11808
15095
|
retrieverParams: { userId: user.id },
|
|
11809
15096
|
module: Modules.Role
|
|
11810
15097
|
});
|
|
11811
|
-
return /* @__PURE__ */
|
|
15098
|
+
return /* @__PURE__ */ jsx193(
|
|
11812
15099
|
ContentListTable,
|
|
11813
15100
|
{
|
|
11814
15101
|
data,
|
|
@@ -12146,6 +15433,45 @@ export {
|
|
|
12146
15433
|
Logout,
|
|
12147
15434
|
RefreshUser,
|
|
12148
15435
|
ResetPassword,
|
|
15436
|
+
SubscriptionSummaryCard,
|
|
15437
|
+
PaymentMethodSummaryCard,
|
|
15438
|
+
CustomerInfoCard,
|
|
15439
|
+
InvoicesSummaryCard,
|
|
15440
|
+
BillingUsageSummaryCard,
|
|
15441
|
+
PaymentMethodEditor,
|
|
15442
|
+
PaymentMethodCard,
|
|
15443
|
+
PaymentMethodsList,
|
|
15444
|
+
PaymentMethodsContainer,
|
|
15445
|
+
formatInterval,
|
|
15446
|
+
formatCurrency,
|
|
15447
|
+
formatDate3 as formatDate,
|
|
15448
|
+
InvoiceStatusBadge,
|
|
15449
|
+
InvoiceDetails,
|
|
15450
|
+
InvoicesList,
|
|
15451
|
+
InvoicesContainer,
|
|
15452
|
+
CancelSubscriptionDialog,
|
|
15453
|
+
PricingCard,
|
|
15454
|
+
PricingCardsGrid,
|
|
15455
|
+
ProrationPreview,
|
|
15456
|
+
SubscriptionEditor,
|
|
15457
|
+
SubscriptionStatusBadge,
|
|
15458
|
+
SubscriptionDetails,
|
|
15459
|
+
SubscriptionsList,
|
|
15460
|
+
SubscriptionsContainer,
|
|
15461
|
+
UsageSummaryCard,
|
|
15462
|
+
UsageSummaryCards,
|
|
15463
|
+
UsageContainer,
|
|
15464
|
+
UsageHistoryTable,
|
|
15465
|
+
BillingDetailModal,
|
|
15466
|
+
BillingAlertBanner,
|
|
15467
|
+
BillingDashboardContainer,
|
|
15468
|
+
StripeProvider,
|
|
15469
|
+
isStripeConfigured,
|
|
15470
|
+
PriceEditor,
|
|
15471
|
+
PricesList,
|
|
15472
|
+
ProductEditor,
|
|
15473
|
+
ProductsList,
|
|
15474
|
+
ProductsAdminContainer,
|
|
12149
15475
|
CompanyDetails,
|
|
12150
15476
|
AdminCompanyContainer,
|
|
12151
15477
|
CompanyContainer,
|
|
@@ -12201,4 +15527,4 @@ export {
|
|
|
12201
15527
|
useUserTableStructure,
|
|
12202
15528
|
useContentTableStructure
|
|
12203
15529
|
};
|
|
12204
|
-
//# sourceMappingURL=chunk-
|
|
15530
|
+
//# sourceMappingURL=chunk-5RAUCUAA.mjs.map
|