@burdenoff/microfe-billing 2026.526.1 → 2026.527.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/BillingAdminRoutes.js +1 -1
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js +15 -8
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +13 -6
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +8 -4
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +3 -2
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +44 -23
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +60 -31
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +9 -9
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +8 -8
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +16 -10
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +24 -16
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +5 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +46 -29
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js +34 -22
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +10 -10
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js +3 -3
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js +7 -0
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js +13 -13
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js +5 -5
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +4 -4
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js +11 -11
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +3 -3
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +8 -8
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +61 -52
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +22 -15
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +30 -21
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +9 -8
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +11 -8
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +22 -17
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +15 -8
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +17 -11
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +15 -11
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +21 -17
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +14 -11
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +32 -26
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +14 -10
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +18 -11
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +44 -32
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +35 -26
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +15 -15
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +11 -11
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +5 -5
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +9 -4
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +13 -8
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +3 -2
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +14 -7
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +23 -9
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaPage.js +11 -7
- package/dist/billing/modules/quota/pages/QuotaPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +3 -3
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +6 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +5 -4
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +26 -12
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js +19 -13
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +13 -8
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +15 -7
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +30 -20
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +25 -16
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +50 -34
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js +2 -2
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js +6 -2
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js +1 -1
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js +5 -4
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/package.json +1 -1
|
@@ -161,14 +161,15 @@ var se = () => {
|
|
|
161
161
|
R.length > 1 && /* @__PURE__ */ f("div", {
|
|
162
162
|
className: "relative",
|
|
163
163
|
children: [/* @__PURE__ */ f("button", {
|
|
164
|
+
type: "button",
|
|
164
165
|
onClick: () => C(!S),
|
|
165
166
|
className: "w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors",
|
|
166
167
|
children: [/* @__PURE__ */ f("div", {
|
|
167
168
|
className: "flex items-center gap-3",
|
|
168
169
|
children: [/* @__PURE__ */ d("div", {
|
|
169
|
-
className: "
|
|
170
|
+
className: "size-8 rounded-lg bg-primary/10 flex items-center justify-center",
|
|
170
171
|
children: /* @__PURE__ */ d("svg", {
|
|
171
|
-
className: "
|
|
172
|
+
className: "size-4 text-primary",
|
|
172
173
|
fill: "none",
|
|
173
174
|
viewBox: "0 0 24 24",
|
|
174
175
|
stroke: "currentColor",
|
|
@@ -190,7 +191,7 @@ var se = () => {
|
|
|
190
191
|
})]
|
|
191
192
|
})]
|
|
192
193
|
}), /* @__PURE__ */ d("svg", {
|
|
193
|
-
className: `
|
|
194
|
+
className: `size-4 text-muted-foreground transition-transform ${S ? "rotate-180" : ""}`,
|
|
194
195
|
fill: "none",
|
|
195
196
|
viewBox: "0 0 24 24",
|
|
196
197
|
stroke: "currentColor",
|
|
@@ -207,14 +208,15 @@ var se = () => {
|
|
|
207
208
|
}), /* @__PURE__ */ d("div", {
|
|
208
209
|
className: "absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto",
|
|
209
210
|
children: R.map((e) => /* @__PURE__ */ f("button", {
|
|
211
|
+
type: "button",
|
|
210
212
|
onClick: () => pe(e),
|
|
211
213
|
className: "w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors",
|
|
212
214
|
children: [/* @__PURE__ */ f("div", {
|
|
213
215
|
className: "flex items-center gap-3 min-w-0",
|
|
214
216
|
children: [/* @__PURE__ */ d("div", {
|
|
215
|
-
className: "
|
|
217
|
+
className: "size-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0",
|
|
216
218
|
children: /* @__PURE__ */ d("svg", {
|
|
217
|
-
className: "
|
|
219
|
+
className: "size-4 text-muted-foreground",
|
|
218
220
|
fill: "none",
|
|
219
221
|
viewBox: "0 0 24 24",
|
|
220
222
|
stroke: "currentColor",
|
|
@@ -236,7 +238,7 @@ var se = () => {
|
|
|
236
238
|
})]
|
|
237
239
|
})]
|
|
238
240
|
}), J?.id === e.id && /* @__PURE__ */ d("svg", {
|
|
239
|
-
className: "
|
|
241
|
+
className: "size-4 text-primary flex-shrink-0",
|
|
240
242
|
fill: "none",
|
|
241
243
|
viewBox: "0 0 24 24",
|
|
242
244
|
stroke: "currentColor",
|
|
@@ -265,7 +267,7 @@ var se = () => {
|
|
|
265
267
|
})] }), J?.isDefault && /* @__PURE__ */ f("span", {
|
|
266
268
|
className: "inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium bg-primary/10 text-primary rounded-full",
|
|
267
269
|
children: [/* @__PURE__ */ d("svg", {
|
|
268
|
-
className: "
|
|
270
|
+
className: "size-3",
|
|
269
271
|
fill: "currentColor",
|
|
270
272
|
viewBox: "0 0 20 20",
|
|
271
273
|
children: /* @__PURE__ */ d("path", {
|
|
@@ -447,7 +449,7 @@ var se = () => {
|
|
|
447
449
|
isDefault: e.target.checked
|
|
448
450
|
})),
|
|
449
451
|
disabled: J?.isDefault,
|
|
450
|
-
className: "
|
|
452
|
+
className: "size-4 rounded border-border text-primary focus:ring-primary focus:ring-offset-0 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
451
453
|
})
|
|
452
454
|
}), /* @__PURE__ */ f("div", {
|
|
453
455
|
className: "flex-1",
|
|
@@ -469,7 +471,7 @@ var se = () => {
|
|
|
469
471
|
children: [A && /* @__PURE__ */ f("div", {
|
|
470
472
|
className: "flex items-center gap-2 text-sm text-status-success-text",
|
|
471
473
|
children: [/* @__PURE__ */ d("svg", {
|
|
472
|
-
className: "
|
|
474
|
+
className: "size-4",
|
|
473
475
|
fill: "none",
|
|
474
476
|
viewBox: "0 0 24 24",
|
|
475
477
|
stroke: "currentColor",
|
|
@@ -483,7 +485,7 @@ var se = () => {
|
|
|
483
485
|
}), O && /* @__PURE__ */ f("div", {
|
|
484
486
|
className: "flex items-center gap-2 text-sm text-destructive",
|
|
485
487
|
children: [/* @__PURE__ */ d("svg", {
|
|
486
|
-
className: "
|
|
488
|
+
className: "size-4",
|
|
487
489
|
fill: "none",
|
|
488
490
|
viewBox: "0 0 24 24",
|
|
489
491
|
stroke: "currentColor",
|
|
@@ -498,16 +500,18 @@ var se = () => {
|
|
|
498
500
|
}), /* @__PURE__ */ f("div", {
|
|
499
501
|
className: "flex items-center gap-3",
|
|
500
502
|
children: [h.canArchiveBillingAccount && J?.isActive ? /* @__PURE__ */ d("button", {
|
|
503
|
+
type: "button",
|
|
501
504
|
onClick: ge,
|
|
502
505
|
disabled: w || E,
|
|
503
506
|
className: "px-4 py-2 text-sm font-medium border border-border text-status-error-text rounded-md hover:bg-status-error-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
504
507
|
children: E ? "Archiving..." : "Archive Account"
|
|
505
508
|
}) : null, /* @__PURE__ */ f("button", {
|
|
509
|
+
type: "button",
|
|
506
510
|
onClick: he,
|
|
507
511
|
disabled: !me || w || E || !P.name || !P.email,
|
|
508
512
|
className: "px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2",
|
|
509
513
|
children: [w && /* @__PURE__ */ f("svg", {
|
|
510
|
-
className: "
|
|
514
|
+
className: "size-4 animate-spin",
|
|
511
515
|
fill: "none",
|
|
512
516
|
viewBox: "0 0 24 24",
|
|
513
517
|
children: [/* @__PURE__ */ d("circle", {
|
|
@@ -563,7 +567,7 @@ var se = () => {
|
|
|
563
567
|
children: /* @__PURE__ */ f("div", {
|
|
564
568
|
className: "flex items-start gap-2",
|
|
565
569
|
children: [/* @__PURE__ */ d("svg", {
|
|
566
|
-
className: "
|
|
570
|
+
className: "size-5 text-status-warning-text flex-shrink-0 mt-0.5",
|
|
567
571
|
fill: "none",
|
|
568
572
|
viewBox: "0 0 24 24",
|
|
569
573
|
stroke: "currentColor",
|
|
@@ -588,6 +592,7 @@ var se = () => {
|
|
|
588
592
|
/* @__PURE__ */ f("div", {
|
|
589
593
|
className: "flex justify-end gap-3",
|
|
590
594
|
children: [/* @__PURE__ */ d("button", {
|
|
595
|
+
type: "button",
|
|
591
596
|
onClick: () => {
|
|
592
597
|
M(!1), N(!1), F((e) => ({
|
|
593
598
|
...e,
|
|
@@ -598,11 +603,12 @@ var se = () => {
|
|
|
598
603
|
className: "px-4 py-2 text-sm font-medium text-foreground border border-border rounded-md hover:bg-muted transition-colors disabled:opacity-50",
|
|
599
604
|
children: "Cancel"
|
|
600
605
|
}), /* @__PURE__ */ f("button", {
|
|
606
|
+
type: "button",
|
|
601
607
|
onClick: $,
|
|
602
608
|
disabled: w,
|
|
603
609
|
className: "px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 transition-colors flex items-center gap-2",
|
|
604
610
|
children: [w && /* @__PURE__ */ f("svg", {
|
|
605
|
-
className: "
|
|
611
|
+
className: "size-4 animate-spin",
|
|
606
612
|
fill: "none",
|
|
607
613
|
viewBox: "0 0 24 24",
|
|
608
614
|
children: [/* @__PURE__ */ d("circle", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../../../src/billing/modules/settings/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * Settings Module - Settings Page\n * Billing account settings and configuration\n */\n\nimport { useState, useMemo, useEffect, useCallback, type FC } from 'react';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { directBillingGraphqlRequest } from '../../../shared/utils';\nimport {\n useGetBillingAccountSettingsQuery,\n useGetBillingAccountsSettingsQuery,\n useGetDefaultBillingAccountSettingsQuery,\n useUpdateBillingAccountSettingsMutation,\n useSetDefaultBillingAccountSettingsMutation,\n ArchiveBillingAccountSettingsDocument,\n} from '../../../../generated/global-operations';\nimport type { BillingAccount } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// Helper to get billing account ID from URL (for navigation from Overview page)\nconst getInitialBillingAccountId = (): string | undefined => {\n if (typeof window === 'undefined') return undefined;\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.get('billingAccountId') || undefined;\n};\n\nexport const SettingsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const { emit } = useBillingEventEmitter();\n\n // State - initialize with URL param if present\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<string | undefined>(\n getInitialBillingAccountId\n );\n const [isAccountSelectorOpen, setIsAccountSelectorOpen] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [isArchiving, setIsArchiving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n // Set default confirmation modal state\n const [isSetDefaultModalOpen, setIsSetDefaultModalOpen] = useState(false);\n const [pendingSave, setPendingSave] = useState(false);\n\n // Form state - includes isDefault toggle\n const [formData, setFormData] = useState({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n isDefault: false,\n });\n\n // Fetch all billing accounts for the selector (lightweight query without subscriptions)\n const {\n data: accountsData,\n loading: isLoadingAccounts,\n refetch: refetchAccounts,\n } = useGetBillingAccountsSettingsQuery({});\n const billingAccounts = useMemo<BillingAccount[]>(\n () => accountsData?.getBillingAccountsByOrg || [],\n [accountsData?.getBillingAccountsByOrg]\n );\n\n // Fetch default billing account (without subscriptions)\n const {\n data: defaultData,\n loading: isLoadingDefault,\n refetch: refetchDefault,\n } = useGetDefaultBillingAccountSettingsQuery({});\n const defaultBillingAccount: BillingAccount | null =\n defaultData?.getDefaultBillingAccount || null;\n\n // Always fetch selected billing account if we have an ID from URL (without subscriptions)\n const {\n data: selectedData,\n loading: isLoadingSelected,\n refetch: refetchSelected,\n } = useGetBillingAccountSettingsQuery({\n variables: { id: selectedBillingAccountId! },\n skip: !selectedBillingAccountId,\n });\n const selectedAccountData: BillingAccount | null = selectedData?.getBillingAccount || null;\n\n // Mutation for updating billing account\n const [updateBillingAccountMutation] = useUpdateBillingAccountSettingsMutation();\n\n // Mutation for setting default billing account\n const [setDefaultBillingAccountMutation] = useSetDefaultBillingAccountSettingsMutation();\n\n // Determine which account to use - prioritize URL param\n const billingAccount = useMemo(() => {\n // If we have a selected account ID from URL\n if (selectedBillingAccountId) {\n // First try to use the fetched selected account data\n if (selectedAccountData) {\n return selectedAccountData;\n }\n // While loading, try to find from the accounts list\n const fromList = billingAccounts.find((a) => a.id === selectedBillingAccountId);\n if (fromList) {\n return fromList;\n }\n // If still loading and not in list, return null to show loading state\n if (isLoadingSelected) {\n return null;\n }\n }\n // No URL param - use default account\n return defaultBillingAccount;\n }, [\n selectedBillingAccountId,\n selectedAccountData,\n billingAccounts,\n isLoadingSelected,\n defaultBillingAccount,\n ]);\n\n const isLoading =\n isLoadingAccounts || isLoadingDefault || (selectedBillingAccountId && isLoadingSelected);\n\n // Update form when billing account changes\n useEffect(() => {\n if (billingAccount) {\n setFormData({\n name: billingAccount.name || '',\n email: billingAccount.email || '',\n billingEmail: billingAccount.billingEmail || '',\n currency: billingAccount.currency || 'USD',\n taxId: billingAccount.taxId || '',\n isDefault: billingAccount.isDefault || false,\n });\n }\n }, [billingAccount]);\n\n // Handle account selection\n const handleSelectAccount = (account: BillingAccount) => {\n setSelectedBillingAccountId(account.id);\n setIsAccountSelectorOpen(false);\n setSaveSuccess(false);\n setSaveError(null);\n };\n\n // Handle form input changes\n const handleInputChange = (field: keyof typeof formData, value: string) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n setSaveSuccess(false);\n setSaveError(null);\n };\n\n // Find the current default account\n const currentDefaultAccount = useMemo(() => {\n return billingAccounts.find((a) => a.isDefault) || null;\n }, [billingAccounts]);\n\n // Check if form has changes\n const hasChanges = useMemo(() => {\n if (!billingAccount) return false;\n return (\n formData.name !== (billingAccount.name || '') ||\n formData.email !== (billingAccount.email || '') ||\n formData.billingEmail !== (billingAccount.billingEmail || '') ||\n formData.currency !== (billingAccount.currency || 'USD') ||\n formData.taxId !== (billingAccount.taxId || '') ||\n formData.isDefault !== (billingAccount.isDefault || false)\n );\n }, [formData, billingAccount]);\n\n // Check if trying to change default status to another account\n const isChangingDefault = formData.isDefault && !billingAccount?.isDefault;\n const needsDefaultConfirmation =\n isChangingDefault && currentDefaultAccount && currentDefaultAccount.id !== billingAccount?.id;\n\n // Perform the actual save operation\n const performSave = useCallback(async () => {\n if (!billingAccount?.id) return;\n\n setIsSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n\n try {\n // Update billing account details\n await updateBillingAccountMutation({\n variables: {\n input: {\n id: billingAccount.id,\n name: formData.name,\n email: formData.email,\n billingEmail: formData.billingEmail || null,\n currency: formData.currency,\n taxId: formData.taxId || null,\n },\n },\n });\n emit('billing.billing_account.updated', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings',\n });\n\n // If setting as default, call the separate mutation\n if (isChangingDefault) {\n await setDefaultBillingAccountMutation({\n variables: { id: billingAccount.id },\n refetchQueries: ['GetBillingAccountsByTenant', 'GetDefaultBillingAccount'],\n });\n emit('billing.billing_account.updated', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings.default',\n });\n }\n\n // Refetch to update cache\n if (selectedBillingAccountId) {\n await refetchSelected();\n } else {\n await refetchDefault();\n }\n\n setSaveSuccess(true);\n // Clear success message after 3 seconds\n setTimeout(() => setSaveSuccess(false), 3000);\n } catch (error) {\n setSaveError(error instanceof Error ? error.message : 'Failed to save changes');\n } finally {\n setIsSaving(false);\n }\n }, [\n billingAccount?.id,\n formData,\n isChangingDefault,\n updateBillingAccountMutation,\n setDefaultBillingAccountMutation,\n selectedBillingAccountId,\n refetchSelected,\n refetchDefault,\n emit,\n ]);\n\n // Handle save button click\n const handleSave = useCallback(() => {\n if (!billingAccount?.id) return;\n\n // If changing default and there's an existing default, show confirmation\n if (needsDefaultConfirmation) {\n setPendingSave(true);\n setIsSetDefaultModalOpen(true);\n } else {\n performSave();\n }\n }, [billingAccount?.id, needsDefaultConfirmation, performSave]);\n\n const handleArchiveAccount = useCallback(async () => {\n if (!billingAccount?.id || !billingAccount.isActive) {\n return;\n }\n\n const replacementDefaultAccount = billingAccounts.find(\n (account) => account.id !== billingAccount.id && account.isActive\n );\n\n const confirmed = window.confirm(\n billingAccount.isDefault\n ? `Archive ${billingAccount.name}? ${replacementDefaultAccount ? `${replacementDefaultAccount.name} will become the default account.` : 'No replacement default account is available.'}`\n : `Archive ${billingAccount.name}?`\n );\n\n if (!confirmed) {\n return;\n }\n\n setIsArchiving(true);\n setSaveError(null);\n setSaveSuccess(false);\n\n try {\n await directBillingGraphqlRequest<\n { archiveBillingAccount: { id: string; isActive: boolean; isDefault: boolean } },\n { id: string; reason: string; replacementDefaultBillingAccountId: string | null }\n >({\n apiGatewayUrl,\n authToken,\n orgId,\n query: ArchiveBillingAccountSettingsDocument,\n variables: {\n id: billingAccount.id,\n reason: 'Archived from billing settings',\n replacementDefaultBillingAccountId: billingAccount.isDefault\n ? (replacementDefaultAccount?.id ?? null)\n : null,\n },\n });\n emit('billing.billing_account.archived', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings',\n });\n\n await Promise.all([refetchAccounts(), refetchDefault()]);\n setSelectedBillingAccountId(replacementDefaultAccount?.id);\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 3000);\n } catch (error) {\n setSaveError(error instanceof Error ? error.message : 'Failed to archive billing account');\n } finally {\n setIsArchiving(false);\n }\n }, [\n apiGatewayUrl,\n authToken,\n billingAccount,\n billingAccounts,\n orgId,\n refetchAccounts,\n refetchDefault,\n emit,\n ]);\n\n if (!permissions.canManageBillingAccount) {\n return <AccessDenied message=\"You don't have permission to manage billing settings.\" />;\n }\n\n if (isLoading && !billingAccount) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-10 bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.settings.billingSettings', 'Billing Settings')}\n description={tr(\n 'billing.settings.description',\n 'Manage your billing account configuration'\n )}\n />\n\n {/* Account Selector (if multiple accounts) */}\n {billingAccounts.length > 1 && (\n <div className=\"relative\">\n <button\n onClick={() => setIsAccountSelectorOpen(!isAccountSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"w-8 h-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <svg\n className=\"w-4 h-4 text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {billingAccount?.name || tr('billing.settings.selectAccount', 'Select Account')}\n </p>\n <p className=\"text-xs text-muted-foreground\">{billingAccount?.email}</p>\n </div>\n </div>\n <svg\n className={`w-4 h-4 text-muted-foreground transition-transform ${isAccountSelectorOpen ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n\n {isAccountSelectorOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsAccountSelectorOpen(false)} />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {billingAccounts.map((account) => (\n <button\n key={account.id}\n onClick={() => handleSelectAccount(account)}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"w-8 h-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <svg\n className=\"w-4 h-4 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {account.name}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">{account.email}</p>\n </div>\n </div>\n {billingAccount?.id === account.id && (\n <svg\n className=\"w-4 h-4 text-primary flex-shrink-0\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Account Settings */}\n <div className=\"border border-border rounded-lg bg-card\">\n <div className=\"p-6 border-b border-border\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.settings.accountInfo', 'Account Information')}\n </h2>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.accountInfoDescription',\n 'Update your billing contact details and tax information'\n )}\n </p>\n </div>\n {billingAccount?.isDefault && (\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium bg-primary/10 text-primary rounded-full\">\n <svg className=\"w-3 h-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n {tr('billing.settings.defaultAccount', 'Default Account')}\n </span>\n )}\n </div>\n </div>\n <div className=\"p-6 space-y-6\">\n {/* Account Status Summary */}\n {billingAccount && (\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4 text-sm pb-4 border-b border-border\">\n <div>\n <p className=\"text-muted-foreground\">{tr('billing.settings.status', 'Status')}</p>\n <p\n className={`font-medium ${billingAccount.isActive ? 'text-status-success-text' : 'text-destructive'}`}\n >\n {billingAccount.isActive\n ? tr('billing.settings.active', 'Active')\n : tr('billing.settings.inactive', 'Inactive')}\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">\n {tr('billing.settings.creditBalance', 'Credit Balance')}\n </p>\n <p className=\"font-medium text-foreground\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">\n {tr('billing.settings.accountId', 'Account ID')}\n </p>\n <p className=\"font-mono text-xs text-foreground truncate\" title={billingAccount.id}>\n {billingAccount.id}\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">{tr('billing.settings.created', 'Created')}</p>\n <p className=\"font-medium text-foreground\">\n {billingAccount.createdAt\n ? new Date(billingAccount.createdAt).toLocaleDateString()\n : tr('billing.settings.notAvailable', 'N/A')}\n </p>\n </div>\n </div>\n )}\n\n {/* Contact Details Section */}\n <div>\n <h3 className=\"text-sm font-medium text-foreground mb-4\">\n {tr('billing.settings.contactDetails', 'Contact Details')}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"billing-account-name\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.accountName', 'Account Name')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"billing-account-name\"\n type=\"text\"\n value={formData.name}\n onChange={(e) => handleInputChange('name', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"billing-account-email\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.email', 'Email')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"billing-account-email\"\n type=\"email\"\n value={formData.email}\n onChange={(e) => handleInputChange('email', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"billing-account-billing-email\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.billingEmail', 'Billing Email')}\n </label>\n <input\n id=\"billing-account-billing-email\"\n type=\"email\"\n value={formData.billingEmail}\n onChange={(e) => handleInputChange('billingEmail', e.target.value)}\n placeholder={tr(\n 'billing.settings.billingEmailPlaceholder',\n 'Optional - defaults to account email'\n )}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.billingEmailHelp',\n 'Invoices will be sent to this email if provided'\n )}\n </p>\n </div>\n <div>\n <label\n htmlFor=\"billing-account-currency\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.currency', 'Currency')}\n </label>\n <select\n id=\"billing-account-currency\"\n value={formData.currency}\n onChange={(e) => handleInputChange('currency', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"USD\">USD - US Dollar</option>\n <option value=\"EUR\">EUR - Euro</option>\n <option value=\"GBP\">GBP - British Pound</option>\n <option value=\"INR\">INR - Indian Rupee</option>\n </select>\n </div>\n </div>\n </div>\n\n {/* Tax Information Section */}\n <div className=\"pt-4 border-t border-border\">\n <h3 className=\"text-sm font-medium text-foreground mb-4\">\n {tr('billing.settings.taxInformation', 'Tax Information')}\n </h3>\n <div className=\"max-w-md\">\n <label\n htmlFor=\"billing-account-tax-id\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.taxId', 'Tax ID / VAT Number')}\n </label>\n <input\n id=\"billing-account-tax-id\"\n type=\"text\"\n value={formData.taxId}\n onChange={(e) => handleInputChange('taxId', e.target.value)}\n placeholder={tr(\n 'billing.settings.taxIdPlaceholder',\n 'Enter your tax identification number'\n )}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.taxIdHelp',\n 'Used for invoices and tax compliance (e.g., GST, VAT number)'\n )}\n </p>\n </div>\n </div>\n\n {/* Default Account Setting */}\n {billingAccount?.isActive && billingAccounts.length > 1 && (\n <div className=\"pt-4 border-t border-border\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex items-center h-6\">\n <input\n type=\"checkbox\"\n id=\"isDefault\"\n checked={formData.isDefault}\n onChange={(e) =>\n setFormData((prev) => ({ ...prev, isDefault: e.target.checked }))\n }\n disabled={billingAccount?.isDefault}\n className=\"w-4 h-4 rounded border-border text-primary focus:ring-primary focus:ring-offset-0 disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n </div>\n <div className=\"flex-1\">\n <label\n htmlFor=\"isDefault\"\n className=\"text-sm font-medium text-foreground cursor-pointer\"\n >\n {tr('billing.settings.setDefault', 'Set as default billing account')}\n </label>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {billingAccount?.isDefault\n ? tr(\n 'billing.settings.currentDefaultDescription',\n 'This is currently your default billing account'\n )\n : tr(\n 'billing.settings.makePrimaryDescription',\n 'Make this your primary billing account for new subscriptions'\n )}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Save Button and Status */}\n <div className=\"pt-4 border-t border-border flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {saveSuccess && (\n <div className=\"flex items-center gap-2 text-sm text-status-success-text\">\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n {tr('billing.settings.saveSuccess', 'Changes saved successfully')}\n </div>\n )}\n {saveError && (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n {saveError}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-3\">\n {permissions.canArchiveBillingAccount && billingAccount?.isActive ? (\n <button\n onClick={handleArchiveAccount}\n disabled={isSaving || isArchiving}\n className=\"px-4 py-2 text-sm font-medium border border-border text-status-error-text rounded-md hover:bg-status-error-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {isArchiving ? 'Archiving...' : 'Archive Account'}\n </button>\n ) : null}\n <button\n onClick={handleSave}\n disabled={\n !hasChanges || isSaving || isArchiving || !formData.name || !formData.email\n }\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2\"\n >\n {isSaving && (\n <svg className=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {isSaving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Set as Default Confirmation Modal */}\n {isSetDefaultModalOpen && pendingSave && (\n <>\n <div\n className=\"fixed inset-0 bg-overlay-scrim z-40\"\n onClick={() => {\n if (!isSaving) {\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n // Reset the checkbox if cancelled\n setFormData((prev) => ({ ...prev, isDefault: billingAccount?.isDefault || false }));\n }\n }}\n />\n <div className=\"fixed inset-0 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-card border border-border rounded-lg shadow-xl max-w-md w-full p-6\">\n <h3 className=\"text-lg font-semibold text-foreground mb-2\">\n Confirm Default Account Change\n </h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n You are about to set{' '}\n <strong className=\"text-foreground\">{billingAccount?.name}</strong> as your default\n billing account and save your changes.\n </p>\n\n {currentDefaultAccount && currentDefaultAccount.id !== billingAccount?.id && (\n <div className=\"mb-4 p-3 bg-status-warning-bg-subtle border border-border-subtle rounded-md\">\n <div className=\"flex items-start gap-2\">\n <svg\n className=\"w-5 h-5 text-status-warning-text flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <div className=\"text-sm\">\n <p className=\"font-medium text-status-warning-text\">\n Current default will change\n </p>\n <p className=\"text-status-warning-text mt-0.5\">\n <strong>{currentDefaultAccount.name}</strong> will no longer be the default\n account.\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex justify-end gap-3\">\n <button\n onClick={() => {\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n // Reset the checkbox if cancelled\n setFormData((prev) => ({\n ...prev,\n isDefault: billingAccount?.isDefault || false,\n }));\n }}\n disabled={isSaving}\n className=\"px-4 py-2 text-sm font-medium text-foreground border border-border rounded-md hover:bg-muted transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n onClick={performSave}\n disabled={isSaving}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 transition-colors flex items-center gap-2\"\n >\n {isSaving && (\n <svg className=\"w-4 h-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {isSaving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SettingsPage.js","names":[],"sources":["../../../../../src/billing/modules/settings/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * Settings Module - Settings Page\n * Billing account settings and configuration\n */\n\nimport { useState, useMemo, useEffect, useCallback, type FC } from 'react';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { directBillingGraphqlRequest } from '../../../shared/utils';\nimport {\n useGetBillingAccountSettingsQuery,\n useGetBillingAccountsSettingsQuery,\n useGetDefaultBillingAccountSettingsQuery,\n useUpdateBillingAccountSettingsMutation,\n useSetDefaultBillingAccountSettingsMutation,\n ArchiveBillingAccountSettingsDocument,\n} from '../../../../generated/global-operations';\nimport type { BillingAccount } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n// Helper to get billing account ID from URL (for navigation from Overview page)\nconst getInitialBillingAccountId = (): string | undefined => {\n if (typeof window === 'undefined') return undefined;\n const urlParams = new URLSearchParams(window.location.search);\n return urlParams.get('billingAccountId') || undefined;\n};\n\nexport const SettingsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const { emit } = useBillingEventEmitter();\n\n // State - initialize with URL param if present\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<string | undefined>(\n getInitialBillingAccountId\n );\n const [isAccountSelectorOpen, setIsAccountSelectorOpen] = useState(false);\n const [isSaving, setIsSaving] = useState(false);\n const [isArchiving, setIsArchiving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n // Set default confirmation modal state\n const [isSetDefaultModalOpen, setIsSetDefaultModalOpen] = useState(false);\n const [pendingSave, setPendingSave] = useState(false);\n\n // Form state - includes isDefault toggle\n const [formData, setFormData] = useState({\n name: '',\n email: '',\n billingEmail: '',\n currency: 'USD',\n taxId: '',\n isDefault: false,\n });\n\n // Fetch all billing accounts for the selector (lightweight query without subscriptions)\n const {\n data: accountsData,\n loading: isLoadingAccounts,\n refetch: refetchAccounts,\n } = useGetBillingAccountsSettingsQuery({});\n const billingAccounts = useMemo<BillingAccount[]>(\n () => accountsData?.getBillingAccountsByOrg || [],\n [accountsData?.getBillingAccountsByOrg]\n );\n\n // Fetch default billing account (without subscriptions)\n const {\n data: defaultData,\n loading: isLoadingDefault,\n refetch: refetchDefault,\n } = useGetDefaultBillingAccountSettingsQuery({});\n const defaultBillingAccount: BillingAccount | null =\n defaultData?.getDefaultBillingAccount || null;\n\n // Always fetch selected billing account if we have an ID from URL (without subscriptions)\n const {\n data: selectedData,\n loading: isLoadingSelected,\n refetch: refetchSelected,\n } = useGetBillingAccountSettingsQuery({\n variables: { id: selectedBillingAccountId! },\n skip: !selectedBillingAccountId,\n });\n const selectedAccountData: BillingAccount | null = selectedData?.getBillingAccount || null;\n\n // Mutation for updating billing account\n const [updateBillingAccountMutation] = useUpdateBillingAccountSettingsMutation();\n\n // Mutation for setting default billing account\n const [setDefaultBillingAccountMutation] = useSetDefaultBillingAccountSettingsMutation();\n\n // Determine which account to use - prioritize URL param\n const billingAccount = useMemo(() => {\n // If we have a selected account ID from URL\n if (selectedBillingAccountId) {\n // First try to use the fetched selected account data\n if (selectedAccountData) {\n return selectedAccountData;\n }\n // While loading, try to find from the accounts list\n const fromList = billingAccounts.find((a) => a.id === selectedBillingAccountId);\n if (fromList) {\n return fromList;\n }\n // If still loading and not in list, return null to show loading state\n if (isLoadingSelected) {\n return null;\n }\n }\n // No URL param - use default account\n return defaultBillingAccount;\n }, [\n selectedBillingAccountId,\n selectedAccountData,\n billingAccounts,\n isLoadingSelected,\n defaultBillingAccount,\n ]);\n\n const isLoading =\n isLoadingAccounts || isLoadingDefault || (selectedBillingAccountId && isLoadingSelected);\n\n // Update form when billing account changes\n useEffect(() => {\n if (billingAccount) {\n setFormData({\n name: billingAccount.name || '',\n email: billingAccount.email || '',\n billingEmail: billingAccount.billingEmail || '',\n currency: billingAccount.currency || 'USD',\n taxId: billingAccount.taxId || '',\n isDefault: billingAccount.isDefault || false,\n });\n }\n }, [billingAccount]);\n\n // Handle account selection\n const handleSelectAccount = (account: BillingAccount) => {\n setSelectedBillingAccountId(account.id);\n setIsAccountSelectorOpen(false);\n setSaveSuccess(false);\n setSaveError(null);\n };\n\n // Handle form input changes\n const handleInputChange = (field: keyof typeof formData, value: string) => {\n setFormData((prev) => ({ ...prev, [field]: value }));\n setSaveSuccess(false);\n setSaveError(null);\n };\n\n // Find the current default account\n const currentDefaultAccount = useMemo(() => {\n return billingAccounts.find((a) => a.isDefault) || null;\n }, [billingAccounts]);\n\n // Check if form has changes\n const hasChanges = useMemo(() => {\n if (!billingAccount) return false;\n return (\n formData.name !== (billingAccount.name || '') ||\n formData.email !== (billingAccount.email || '') ||\n formData.billingEmail !== (billingAccount.billingEmail || '') ||\n formData.currency !== (billingAccount.currency || 'USD') ||\n formData.taxId !== (billingAccount.taxId || '') ||\n formData.isDefault !== (billingAccount.isDefault || false)\n );\n }, [formData, billingAccount]);\n\n // Check if trying to change default status to another account\n const isChangingDefault = formData.isDefault && !billingAccount?.isDefault;\n const needsDefaultConfirmation =\n isChangingDefault && currentDefaultAccount && currentDefaultAccount.id !== billingAccount?.id;\n\n // Perform the actual save operation\n const performSave = useCallback(async () => {\n if (!billingAccount?.id) return;\n\n setIsSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n\n try {\n // Update billing account details\n await updateBillingAccountMutation({\n variables: {\n input: {\n id: billingAccount.id,\n name: formData.name,\n email: formData.email,\n billingEmail: formData.billingEmail || null,\n currency: formData.currency,\n taxId: formData.taxId || null,\n },\n },\n });\n emit('billing.billing_account.updated', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings',\n });\n\n // If setting as default, call the separate mutation\n if (isChangingDefault) {\n await setDefaultBillingAccountMutation({\n variables: { id: billingAccount.id },\n refetchQueries: ['GetBillingAccountsByTenant', 'GetDefaultBillingAccount'],\n });\n emit('billing.billing_account.updated', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings.default',\n });\n }\n\n // Refetch to update cache\n if (selectedBillingAccountId) {\n await refetchSelected();\n } else {\n await refetchDefault();\n }\n\n setSaveSuccess(true);\n // Clear success message after 3 seconds\n setTimeout(() => setSaveSuccess(false), 3000);\n } catch (error) {\n setSaveError(error instanceof Error ? error.message : 'Failed to save changes');\n } finally {\n setIsSaving(false);\n }\n }, [\n billingAccount?.id,\n formData,\n isChangingDefault,\n updateBillingAccountMutation,\n setDefaultBillingAccountMutation,\n selectedBillingAccountId,\n refetchSelected,\n refetchDefault,\n emit,\n ]);\n\n // Handle save button click\n const handleSave = useCallback(() => {\n if (!billingAccount?.id) return;\n\n // If changing default and there's an existing default, show confirmation\n if (needsDefaultConfirmation) {\n setPendingSave(true);\n setIsSetDefaultModalOpen(true);\n } else {\n performSave();\n }\n }, [billingAccount?.id, needsDefaultConfirmation, performSave]);\n\n const handleArchiveAccount = useCallback(async () => {\n if (!billingAccount?.id || !billingAccount.isActive) {\n return;\n }\n\n const replacementDefaultAccount = billingAccounts.find(\n (account) => account.id !== billingAccount.id && account.isActive\n );\n\n const confirmed = window.confirm(\n billingAccount.isDefault\n ? `Archive ${billingAccount.name}? ${replacementDefaultAccount ? `${replacementDefaultAccount.name} will become the default account.` : 'No replacement default account is available.'}`\n : `Archive ${billingAccount.name}?`\n );\n\n if (!confirmed) {\n return;\n }\n\n setIsArchiving(true);\n setSaveError(null);\n setSaveSuccess(false);\n\n try {\n await directBillingGraphqlRequest<\n { archiveBillingAccount: { id: string; isActive: boolean; isDefault: boolean } },\n { id: string; reason: string; replacementDefaultBillingAccountId: string | null }\n >({\n apiGatewayUrl,\n authToken,\n orgId,\n query: ArchiveBillingAccountSettingsDocument,\n variables: {\n id: billingAccount.id,\n reason: 'Archived from billing settings',\n replacementDefaultBillingAccountId: billingAccount.isDefault\n ? (replacementDefaultAccount?.id ?? null)\n : null,\n },\n });\n emit('billing.billing_account.archived', {\n route: '/billing/settings',\n entityId: billingAccount.id,\n source: 'settings',\n });\n\n await Promise.all([refetchAccounts(), refetchDefault()]);\n setSelectedBillingAccountId(replacementDefaultAccount?.id);\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 3000);\n } catch (error) {\n setSaveError(error instanceof Error ? error.message : 'Failed to archive billing account');\n } finally {\n setIsArchiving(false);\n }\n }, [\n apiGatewayUrl,\n authToken,\n billingAccount,\n billingAccounts,\n orgId,\n refetchAccounts,\n refetchDefault,\n emit,\n ]);\n\n if (!permissions.canManageBillingAccount) {\n return <AccessDenied message=\"You don't have permission to manage billing settings.\" />;\n }\n\n if (isLoading && !billingAccount) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"border border-border rounded-lg p-6 space-y-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-10 bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.settings.billingSettings', 'Billing Settings')}\n description={tr(\n 'billing.settings.description',\n 'Manage your billing account configuration'\n )}\n />\n\n {/* Account Selector (if multiple accounts) */}\n {billingAccounts.length > 1 && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setIsAccountSelectorOpen(!isAccountSelectorOpen)}\n className=\"w-full sm:w-auto flex items-center justify-between gap-3 px-4 py-3 border border-border rounded-lg bg-card hover:bg-muted/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"size-8 rounded-lg bg-primary/10 flex items-center justify-center\">\n <svg\n className=\"size-4 text-primary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n </div>\n <div className=\"text-left\">\n <p className=\"text-sm font-medium text-foreground\">\n {billingAccount?.name || tr('billing.settings.selectAccount', 'Select Account')}\n </p>\n <p className=\"text-xs text-muted-foreground\">{billingAccount?.email}</p>\n </div>\n </div>\n <svg\n className={`size-4 text-muted-foreground transition-transform ${isAccountSelectorOpen ? 'rotate-180' : ''}`}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 9l-7 7-7-7\"\n />\n </svg>\n </button>\n\n {isAccountSelectorOpen && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setIsAccountSelectorOpen(false)} />\n <div className=\"absolute top-full left-0 right-0 sm:right-auto mt-1 w-full sm:w-80 bg-popover border border-border rounded-lg shadow-lg z-20 py-1 max-h-60 overflow-y-auto\">\n {billingAccounts.map((account) => (\n <button\n type=\"button\"\n key={account.id}\n onClick={() => handleSelectAccount(account)}\n className=\"w-full flex items-center justify-between gap-3 px-4 py-3 hover:bg-muted transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div className=\"size-8 rounded-lg bg-muted flex items-center justify-center flex-shrink-0\">\n <svg\n className=\"size-4 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4\"\n />\n </svg>\n </div>\n <div className=\"text-left min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {account.name}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">{account.email}</p>\n </div>\n </div>\n {billingAccount?.id === account.id && (\n <svg\n className=\"size-4 text-primary flex-shrink-0\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n )}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n )}\n\n {/* Account Settings */}\n <div className=\"border border-border rounded-lg bg-card\">\n <div className=\"p-6 border-b border-border\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-foreground\">\n {tr('billing.settings.accountInfo', 'Account Information')}\n </h2>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.accountInfoDescription',\n 'Update your billing contact details and tax information'\n )}\n </p>\n </div>\n {billingAccount?.isDefault && (\n <span className=\"inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium bg-primary/10 text-primary rounded-full\">\n <svg className=\"size-3\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path\n fillRule=\"evenodd\"\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n clipRule=\"evenodd\"\n />\n </svg>\n {tr('billing.settings.defaultAccount', 'Default Account')}\n </span>\n )}\n </div>\n </div>\n <div className=\"p-6 space-y-6\">\n {/* Account Status Summary */}\n {billingAccount && (\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4 text-sm pb-4 border-b border-border\">\n <div>\n <p className=\"text-muted-foreground\">{tr('billing.settings.status', 'Status')}</p>\n <p\n className={`font-medium ${billingAccount.isActive ? 'text-status-success-text' : 'text-destructive'}`}\n >\n {billingAccount.isActive\n ? tr('billing.settings.active', 'Active')\n : tr('billing.settings.inactive', 'Inactive')}\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">\n {tr('billing.settings.creditBalance', 'Credit Balance')}\n </p>\n <p className=\"font-medium text-foreground\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">\n {tr('billing.settings.accountId', 'Account ID')}\n </p>\n <p className=\"font-mono text-xs text-foreground truncate\" title={billingAccount.id}>\n {billingAccount.id}\n </p>\n </div>\n <div>\n <p className=\"text-muted-foreground\">{tr('billing.settings.created', 'Created')}</p>\n <p className=\"font-medium text-foreground\">\n {billingAccount.createdAt\n ? new Date(billingAccount.createdAt).toLocaleDateString()\n : tr('billing.settings.notAvailable', 'N/A')}\n </p>\n </div>\n </div>\n )}\n\n {/* Contact Details Section */}\n <div>\n <h3 className=\"text-sm font-medium text-foreground mb-4\">\n {tr('billing.settings.contactDetails', 'Contact Details')}\n </h3>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"billing-account-name\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.accountName', 'Account Name')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"billing-account-name\"\n type=\"text\"\n value={formData.name}\n onChange={(e) => handleInputChange('name', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"billing-account-email\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.email', 'Email')}{' '}\n <span className=\"text-destructive\">*</span>\n </label>\n <input\n id=\"billing-account-email\"\n type=\"email\"\n value={formData.email}\n onChange={(e) => handleInputChange('email', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n </div>\n <div>\n <label\n htmlFor=\"billing-account-billing-email\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.billingEmail', 'Billing Email')}\n </label>\n <input\n id=\"billing-account-billing-email\"\n type=\"email\"\n value={formData.billingEmail}\n onChange={(e) => handleInputChange('billingEmail', e.target.value)}\n placeholder={tr(\n 'billing.settings.billingEmailPlaceholder',\n 'Optional - defaults to account email'\n )}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.billingEmailHelp',\n 'Invoices will be sent to this email if provided'\n )}\n </p>\n </div>\n <div>\n <label\n htmlFor=\"billing-account-currency\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.currency', 'Currency')}\n </label>\n <select\n id=\"billing-account-currency\"\n value={formData.currency}\n onChange={(e) => handleInputChange('currency', e.target.value)}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n >\n <option value=\"USD\">USD - US Dollar</option>\n <option value=\"EUR\">EUR - Euro</option>\n <option value=\"GBP\">GBP - British Pound</option>\n <option value=\"INR\">INR - Indian Rupee</option>\n </select>\n </div>\n </div>\n </div>\n\n {/* Tax Information Section */}\n <div className=\"pt-4 border-t border-border\">\n <h3 className=\"text-sm font-medium text-foreground mb-4\">\n {tr('billing.settings.taxInformation', 'Tax Information')}\n </h3>\n <div className=\"max-w-md\">\n <label\n htmlFor=\"billing-account-tax-id\"\n className=\"block text-sm font-medium text-foreground mb-1\"\n >\n {tr('billing.settings.taxId', 'Tax ID / VAT Number')}\n </label>\n <input\n id=\"billing-account-tax-id\"\n type=\"text\"\n value={formData.taxId}\n onChange={(e) => handleInputChange('taxId', e.target.value)}\n placeholder={tr(\n 'billing.settings.taxIdPlaceholder',\n 'Enter your tax identification number'\n )}\n className=\"w-full px-3 py-2 text-sm border border-border rounded-md bg-background text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent\"\n />\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.settings.taxIdHelp',\n 'Used for invoices and tax compliance (e.g., GST, VAT number)'\n )}\n </p>\n </div>\n </div>\n\n {/* Default Account Setting */}\n {billingAccount?.isActive && billingAccounts.length > 1 && (\n <div className=\"pt-4 border-t border-border\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex items-center h-6\">\n <input\n type=\"checkbox\"\n id=\"isDefault\"\n checked={formData.isDefault}\n onChange={(e) =>\n setFormData((prev) => ({ ...prev, isDefault: e.target.checked }))\n }\n disabled={billingAccount?.isDefault}\n className=\"size-4 rounded border-border text-primary focus:ring-primary focus:ring-offset-0 disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n </div>\n <div className=\"flex-1\">\n <label\n htmlFor=\"isDefault\"\n className=\"text-sm font-medium text-foreground cursor-pointer\"\n >\n {tr('billing.settings.setDefault', 'Set as default billing account')}\n </label>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {billingAccount?.isDefault\n ? tr(\n 'billing.settings.currentDefaultDescription',\n 'This is currently your default billing account'\n )\n : tr(\n 'billing.settings.makePrimaryDescription',\n 'Make this your primary billing account for new subscriptions'\n )}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Save Button and Status */}\n <div className=\"pt-4 border-t border-border flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {saveSuccess && (\n <div className=\"flex items-center gap-2 text-sm text-status-success-text\">\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n {tr('billing.settings.saveSuccess', 'Changes saved successfully')}\n </div>\n )}\n {saveError && (\n <div className=\"flex items-center gap-2 text-sm text-destructive\">\n <svg className=\"size-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n {saveError}\n </div>\n )}\n </div>\n <div className=\"flex items-center gap-3\">\n {permissions.canArchiveBillingAccount && billingAccount?.isActive ? (\n <button\n type=\"button\"\n onClick={handleArchiveAccount}\n disabled={isSaving || isArchiving}\n className=\"px-4 py-2 text-sm font-medium border border-border text-status-error-text rounded-md hover:bg-status-error-bg-subtle disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {isArchiving ? 'Archiving...' : 'Archive Account'}\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={\n !hasChanges || isSaving || isArchiving || !formData.name || !formData.email\n }\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2\"\n >\n {isSaving && (\n <svg className=\"size-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {isSaving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n </div>\n </div>\n\n {/* Set as Default Confirmation Modal */}\n {isSetDefaultModalOpen && pendingSave && (\n <>\n <div\n className=\"fixed inset-0 bg-overlay-scrim z-40\"\n onClick={() => {\n if (!isSaving) {\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n // Reset the checkbox if cancelled\n setFormData((prev) => ({ ...prev, isDefault: billingAccount?.isDefault || false }));\n }\n }}\n />\n <div className=\"fixed inset-0 flex items-center justify-center z-50 p-4\">\n <div className=\"bg-card border border-border rounded-lg shadow-xl max-w-md w-full p-6\">\n <h3 className=\"text-lg font-semibold text-foreground mb-2\">\n Confirm Default Account Change\n </h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n You are about to set{' '}\n <strong className=\"text-foreground\">{billingAccount?.name}</strong> as your default\n billing account and save your changes.\n </p>\n\n {currentDefaultAccount && currentDefaultAccount.id !== billingAccount?.id && (\n <div className=\"mb-4 p-3 bg-status-warning-bg-subtle border border-border-subtle rounded-md\">\n <div className=\"flex items-start gap-2\">\n <svg\n className=\"size-5 text-status-warning-text flex-shrink-0 mt-0.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <div className=\"text-sm\">\n <p className=\"font-medium text-status-warning-text\">\n Current default will change\n </p>\n <p className=\"text-status-warning-text mt-0.5\">\n <strong>{currentDefaultAccount.name}</strong> will no longer be the default\n account.\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={() => {\n setIsSetDefaultModalOpen(false);\n setPendingSave(false);\n // Reset the checkbox if cancelled\n setFormData((prev) => ({\n ...prev,\n isDefault: billingAccount?.isDefault || false,\n }));\n }}\n disabled={isSaving}\n className=\"px-4 py-2 text-sm font-medium text-foreground border border-border rounded-md hover:bg-muted transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={performSave}\n disabled={isSaving}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 transition-colors flex items-center gap-2\"\n >\n {isSaving && (\n <svg className=\"size-4 animate-spin\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n )}\n {isSaving ? 'Saving...' : 'Save Changes'}\n </button>\n </div>\n </div>\n </div>\n </>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -49,12 +49,13 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
49
49
|
className: "flex items-center justify-between p-6 border-b border-border",
|
|
50
50
|
children: [/* @__PURE__ */ l("div", {
|
|
51
51
|
className: "flex items-center gap-2",
|
|
52
|
-
children: [/* @__PURE__ */ c(s, { className: "
|
|
52
|
+
children: [/* @__PURE__ */ c(s, { className: "size-5 text-primary" }), /* @__PURE__ */ c("h2", {
|
|
53
53
|
id: "manage-seats-title",
|
|
54
54
|
className: "text-lg font-semibold text-foreground",
|
|
55
55
|
children: g("billing.subscriptions.manageSeats", "Manage Seats")
|
|
56
56
|
})]
|
|
57
57
|
}), /* @__PURE__ */ c("button", {
|
|
58
|
+
type: "button",
|
|
58
59
|
onClick: f,
|
|
59
60
|
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
60
61
|
"aria-label": "Close manage seats dialog",
|
|
@@ -80,11 +81,12 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
80
81
|
className: "flex items-center gap-3",
|
|
81
82
|
children: [
|
|
82
83
|
/* @__PURE__ */ c("button", {
|
|
84
|
+
type: "button",
|
|
83
85
|
onClick: j,
|
|
84
86
|
disabled: C <= v || m,
|
|
85
|
-
className: "
|
|
87
|
+
className: "size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
86
88
|
"aria-label": "Decrease seat count",
|
|
87
|
-
children: /* @__PURE__ */ c(a, { className: "
|
|
89
|
+
children: /* @__PURE__ */ c(a, { className: "size-4" })
|
|
88
90
|
}),
|
|
89
91
|
/* @__PURE__ */ c("input", {
|
|
90
92
|
type: "number",
|
|
@@ -96,11 +98,12 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
96
98
|
className: "w-20 h-9 text-center border border-border rounded-md bg-background text-foreground text-sm focus:outline-none focus:ring-2 focus:ring-primary disabled:opacity-50"
|
|
97
99
|
}),
|
|
98
100
|
/* @__PURE__ */ c("button", {
|
|
101
|
+
type: "button",
|
|
99
102
|
onClick: M,
|
|
100
103
|
disabled: C >= y || m,
|
|
101
|
-
className: "
|
|
104
|
+
className: "size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
102
105
|
"aria-label": "Increase seat count",
|
|
103
|
-
children: /* @__PURE__ */ c(o, { className: "
|
|
106
|
+
children: /* @__PURE__ */ c(o, { className: "size-4" })
|
|
104
107
|
}),
|
|
105
108
|
/* @__PURE__ */ c("span", {
|
|
106
109
|
className: "text-sm text-muted-foreground",
|
|
@@ -135,26 +138,28 @@ var d = ({ subscription: d, onClose: f, onConfirm: p, isLoading: m = !1 }) => {
|
|
|
135
138
|
}),
|
|
136
139
|
A && D > 0 && /* @__PURE__ */ l("div", {
|
|
137
140
|
className: "flex gap-2 p-3 rounded-md bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text",
|
|
138
|
-
children: [/* @__PURE__ */ c(r, { className: "
|
|
141
|
+
children: [/* @__PURE__ */ c(r, { className: "size-4 mt-0.5 shrink-0" }), /* @__PURE__ */ c("span", { children: "Seat additions apply from the next billing cycle. A separate prorated charge will be raised for the remaining days in the current cycle." })]
|
|
139
142
|
}),
|
|
140
143
|
T && /* @__PURE__ */ l("div", {
|
|
141
144
|
className: "flex gap-2 p-3 rounded-md bg-destructive/10 border border-destructive/30 text-sm text-destructive",
|
|
142
|
-
children: [/* @__PURE__ */ c(r, { className: "
|
|
145
|
+
children: [/* @__PURE__ */ c(r, { className: "size-4 mt-0.5 shrink-0" }), /* @__PURE__ */ c("span", { children: T })]
|
|
143
146
|
})
|
|
144
147
|
]
|
|
145
148
|
}),
|
|
146
149
|
/* @__PURE__ */ l("div", {
|
|
147
150
|
className: "flex items-center justify-end gap-3 p-6 border-t border-border",
|
|
148
151
|
children: [/* @__PURE__ */ c("button", {
|
|
152
|
+
type: "button",
|
|
149
153
|
onClick: f,
|
|
150
154
|
disabled: m,
|
|
151
155
|
className: "px-4 py-2 text-sm rounded-md border border-border hover:bg-accent text-foreground transition-colors disabled:opacity-50",
|
|
152
156
|
children: "Cancel"
|
|
153
157
|
}), /* @__PURE__ */ l("button", {
|
|
158
|
+
type: "button",
|
|
154
159
|
onClick: P,
|
|
155
160
|
disabled: m || C === S || C < v || C > y,
|
|
156
161
|
className: "px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
157
|
-
children: [m && /* @__PURE__ */ c(i, { className: "
|
|
162
|
+
children: [m && /* @__PURE__ */ c(i, { className: "size-4 animate-spin" }), C === S ? "No change" : D > 0 ? `Add ${D} seat${D === 1 ? "" : "s"}` : `Remove ${Math.abs(D)} seat${Math.abs(D) === 1 ? "" : "s"}`]
|
|
158
163
|
})]
|
|
159
164
|
})
|
|
160
165
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ManageSeatsModal.js","names":[],"sources":["../../../../../src/billing/modules/subscriptions/components/ManageSeatsModal.tsx"],"sourcesContent":["/**\n * ManageSeatsModal\n * Lets users update the seat count on a PER_SEAT subscription.\n * Shows current seats, min/max bounds, and a proration notice for Razorpay.\n */\n\nimport { type FC, useState, useEffect } from 'react';\nimport { Minus, Plus, Users, AlertCircle, Loader2 } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport type { BillingSubscription } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface ManageSeatsModalProps {\n subscription: BillingSubscription;\n onClose: () => void;\n onConfirm: (seatCount: number) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const ManageSeatsModal: FC<ManageSeatsModalProps> = ({\n subscription,\n onClose,\n onConfirm,\n isLoading = false,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const plan = subscription.plan;\n const minSeats = plan?.minSeats ?? 1;\n const maxSeats = plan?.maxSeats ?? 999;\n const pricePerSeat = plan?.pricePerSeat ?? 0;\n const currency = plan?.currency ?? 'USD';\n const currentSeats = subscription.seatCount ?? minSeats;\n\n const [newSeatCount, setNewSeatCount] = useState(currentSeats);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n setNewSeatCount(currentSeats);\n }, [currentSeats]);\n\n const seatDelta = newSeatCount - currentSeats;\n const newMonthlyTotal = newSeatCount * pricePerSeat;\n const currentMonthlyTotal = currentSeats * pricePerSeat;\n const isRazorpay = subscription.paymentGateway === 'razorpay';\n\n function decrement() {\n setNewSeatCount((n) => Math.max(minSeats, n - 1));\n setError(null);\n }\n\n function increment() {\n setNewSeatCount((n) => Math.min(maxSeats, n + 1));\n setError(null);\n }\n\n function handleInputChange(value: string) {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed)) return;\n if (parsed < minSeats) {\n setError(`Minimum ${minSeats} seat${minSeats !== 1 ? 's' : ''} required for this plan.`);\n setNewSeatCount(parsed);\n } else if (parsed > maxSeats) {\n setError(`Maximum ${maxSeats} seats allowed.`);\n setNewSeatCount(parsed);\n } else {\n setError(null);\n setNewSeatCount(parsed);\n }\n }\n\n async function handleConfirm() {\n if (newSeatCount < minSeats || newSeatCount > maxSeats) return;\n if (newSeatCount === currentSeats) {\n onClose();\n return;\n }\n setError(null);\n try {\n await onConfirm(newSeatCount);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update seats.');\n }\n }\n\n return (\n <div className=\"fixed inset-0 bg-overlay-scrim flex items-center justify-center z-50 p-4\">\n <div\n className=\"bg-background border border-border rounded-lg shadow-lg w-full max-w-md\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"manage-seats-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"w-5 h-5 text-primary\" />\n <h2 id=\"manage-seats-title\" className=\"text-lg font-semibold text-foreground\">\n {tr('billing.subscriptions.manageSeats', 'Manage Seats')}\n </h2>\n </div>\n <button\n onClick={onClose}\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\n aria-label=\"Close manage seats dialog\"\n >\n ✕\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-6 space-y-6\">\n {/* Current vs new */}\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <span>Current seats</span>\n <span className=\"font-medium text-foreground\">{currentSeats}</span>\n </div>\n\n {/* Seat selector */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium text-foreground\">New seat count</label>\n <div className=\"flex items-center gap-3\">\n <button\n onClick={decrement}\n disabled={newSeatCount <= minSeats || isLoading}\n className=\"w-9 h-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Decrease seat count\"\n >\n <Minus className=\"w-4 h-4\" />\n </button>\n <input\n type=\"number\"\n value={newSeatCount}\n min={minSeats}\n max={maxSeats}\n onChange={(e) => handleInputChange(e.target.value)}\n disabled={isLoading}\n className=\"w-20 h-9 text-center border border-border rounded-md bg-background text-foreground text-sm focus:outline-none focus:ring-2 focus:ring-primary disabled:opacity-50\"\n />\n <button\n onClick={increment}\n disabled={newSeatCount >= maxSeats || isLoading}\n className=\"w-9 h-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Increase seat count\"\n >\n <Plus className=\"w-4 h-4\" />\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {minSeats === maxSeats\n ? `(${minSeats} fixed)`\n : `(min ${minSeats}${maxSeats < 999 ? `, max ${maxSeats}` : ''})`}\n </span>\n </div>\n </div>\n\n {/* Pricing breakdown */}\n {pricePerSeat > 0 && (\n <div className=\"rounded-lg bg-muted/50 border border-border p-4 space-y-2 text-sm\">\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Per seat</span>\n <span>{formatCurrency(pricePerSeat, currency)} / month</span>\n </div>\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Current total</span>\n <span>{formatCurrency(currentMonthlyTotal, currency)} / month</span>\n </div>\n <div className=\"border-t border-border pt-2 flex justify-between font-medium text-foreground\">\n <span>New total</span>\n <span\n className={\n seatDelta > 0\n ? 'text-destructive'\n : seatDelta < 0\n ? 'text-status-success-text'\n : ''\n }\n >\n {formatCurrency(newMonthlyTotal, currency)} / month\n </span>\n </div>\n {seatDelta !== 0 && (\n <div className=\"text-xs text-muted-foreground\">\n {seatDelta > 0\n ? `+${seatDelta} seat${seatDelta !== 1 ? 's' : ''} — +${formatCurrency(seatDelta * pricePerSeat, currency)}/month`\n : `${seatDelta} seat${Math.abs(seatDelta) !== 1 ? 's' : ''} — ${formatCurrency(seatDelta * pricePerSeat, currency)}/month`}\n </div>\n )}\n </div>\n )}\n\n {/* Razorpay proration notice */}\n {isRazorpay && seatDelta > 0 && (\n <div className=\"flex gap-2 p-3 rounded-md bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text\">\n <AlertCircle className=\"w-4 h-4 mt-0.5 shrink-0\" />\n <span>\n Seat additions apply from the next billing cycle. A separate prorated charge will be\n raised for the remaining days in the current cycle.\n </span>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"flex gap-2 p-3 rounded-md bg-destructive/10 border border-destructive/30 text-sm text-destructive\">\n <AlertCircle className=\"w-4 h-4 mt-0.5 shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-border\">\n <button\n onClick={onClose}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm rounded-md border border-border hover:bg-accent text-foreground transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n onClick={handleConfirm}\n disabled={\n isLoading ||\n newSeatCount === currentSeats ||\n newSeatCount < minSeats ||\n newSeatCount > maxSeats\n }\n className=\"px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {isLoading && <Loader2 className=\"w-4 h-4 animate-spin\" />}\n {newSeatCount === currentSeats\n ? 'No change'\n : seatDelta > 0\n ? `Add ${seatDelta} seat${seatDelta !== 1 ? 's' : ''}`\n : `Remove ${Math.abs(seatDelta)} seat${Math.abs(seatDelta) !== 1 ? 's' : ''}`}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ManageSeatsModal.js","names":[],"sources":["../../../../../src/billing/modules/subscriptions/components/ManageSeatsModal.tsx"],"sourcesContent":["/**\n * ManageSeatsModal\n * Lets users update the seat count on a PER_SEAT subscription.\n * Shows current seats, min/max bounds, and a proration notice for Razorpay.\n */\n\nimport { type FC, useState, useEffect } from 'react';\nimport { Minus, Plus, Users, AlertCircle, Loader2 } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport type { BillingSubscription } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface ManageSeatsModalProps {\n subscription: BillingSubscription;\n onClose: () => void;\n onConfirm: (seatCount: number) => Promise<void>;\n isLoading?: boolean;\n}\n\nexport const ManageSeatsModal: FC<ManageSeatsModalProps> = ({\n subscription,\n onClose,\n onConfirm,\n isLoading = false,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const plan = subscription.plan;\n const minSeats = plan?.minSeats ?? 1;\n const maxSeats = plan?.maxSeats ?? 999;\n const pricePerSeat = plan?.pricePerSeat ?? 0;\n const currency = plan?.currency ?? 'USD';\n const currentSeats = subscription.seatCount ?? minSeats;\n\n const [newSeatCount, setNewSeatCount] = useState(currentSeats);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n setNewSeatCount(currentSeats);\n }, [currentSeats]);\n\n const seatDelta = newSeatCount - currentSeats;\n const newMonthlyTotal = newSeatCount * pricePerSeat;\n const currentMonthlyTotal = currentSeats * pricePerSeat;\n const isRazorpay = subscription.paymentGateway === 'razorpay';\n\n function decrement() {\n setNewSeatCount((n) => Math.max(minSeats, n - 1));\n setError(null);\n }\n\n function increment() {\n setNewSeatCount((n) => Math.min(maxSeats, n + 1));\n setError(null);\n }\n\n function handleInputChange(value: string) {\n const parsed = parseInt(value, 10);\n if (isNaN(parsed)) return;\n if (parsed < minSeats) {\n setError(`Minimum ${minSeats} seat${minSeats !== 1 ? 's' : ''} required for this plan.`);\n setNewSeatCount(parsed);\n } else if (parsed > maxSeats) {\n setError(`Maximum ${maxSeats} seats allowed.`);\n setNewSeatCount(parsed);\n } else {\n setError(null);\n setNewSeatCount(parsed);\n }\n }\n\n async function handleConfirm() {\n if (newSeatCount < minSeats || newSeatCount > maxSeats) return;\n if (newSeatCount === currentSeats) {\n onClose();\n return;\n }\n setError(null);\n try {\n await onConfirm(newSeatCount);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update seats.');\n }\n }\n\n return (\n <div className=\"fixed inset-0 bg-overlay-scrim flex items-center justify-center z-50 p-4\">\n <div\n className=\"bg-background border border-border rounded-lg shadow-lg w-full max-w-md\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"manage-seats-title\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 border-b border-border\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"size-5 text-primary\" />\n <h2 id=\"manage-seats-title\" className=\"text-lg font-semibold text-foreground\">\n {tr('billing.subscriptions.manageSeats', 'Manage Seats')}\n </h2>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-muted-foreground hover:text-foreground transition-colors\"\n aria-label=\"Close manage seats dialog\"\n >\n ✕\n </button>\n </div>\n\n {/* Body */}\n <div className=\"p-6 space-y-6\">\n {/* Current vs new */}\n <div className=\"flex items-center justify-between text-sm text-muted-foreground\">\n <span>Current seats</span>\n <span className=\"font-medium text-foreground\">{currentSeats}</span>\n </div>\n\n {/* Seat selector */}\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium text-foreground\">New seat count</label>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={decrement}\n disabled={newSeatCount <= minSeats || isLoading}\n className=\"size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Decrease seat count\"\n >\n <Minus className=\"size-4\" />\n </button>\n <input\n type=\"number\"\n value={newSeatCount}\n min={minSeats}\n max={maxSeats}\n onChange={(e) => handleInputChange(e.target.value)}\n disabled={isLoading}\n className=\"w-20 h-9 text-center border border-border rounded-md bg-background text-foreground text-sm focus:outline-none focus:ring-2 focus:ring-primary disabled:opacity-50\"\n />\n <button\n type=\"button\"\n onClick={increment}\n disabled={newSeatCount >= maxSeats || isLoading}\n className=\"size-9 rounded-md border border-border flex items-center justify-center hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n aria-label=\"Increase seat count\"\n >\n <Plus className=\"size-4\" />\n </button>\n <span className=\"text-sm text-muted-foreground\">\n {minSeats === maxSeats\n ? `(${minSeats} fixed)`\n : `(min ${minSeats}${maxSeats < 999 ? `, max ${maxSeats}` : ''})`}\n </span>\n </div>\n </div>\n\n {/* Pricing breakdown */}\n {pricePerSeat > 0 && (\n <div className=\"rounded-lg bg-muted/50 border border-border p-4 space-y-2 text-sm\">\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Per seat</span>\n <span>{formatCurrency(pricePerSeat, currency)} / month</span>\n </div>\n <div className=\"flex justify-between text-muted-foreground\">\n <span>Current total</span>\n <span>{formatCurrency(currentMonthlyTotal, currency)} / month</span>\n </div>\n <div className=\"border-t border-border pt-2 flex justify-between font-medium text-foreground\">\n <span>New total</span>\n <span\n className={\n seatDelta > 0\n ? 'text-destructive'\n : seatDelta < 0\n ? 'text-status-success-text'\n : ''\n }\n >\n {formatCurrency(newMonthlyTotal, currency)} / month\n </span>\n </div>\n {seatDelta !== 0 && (\n <div className=\"text-xs text-muted-foreground\">\n {seatDelta > 0\n ? `+${seatDelta} seat${seatDelta !== 1 ? 's' : ''} — +${formatCurrency(seatDelta * pricePerSeat, currency)}/month`\n : `${seatDelta} seat${Math.abs(seatDelta) !== 1 ? 's' : ''} — ${formatCurrency(seatDelta * pricePerSeat, currency)}/month`}\n </div>\n )}\n </div>\n )}\n\n {/* Razorpay proration notice */}\n {isRazorpay && seatDelta > 0 && (\n <div className=\"flex gap-2 p-3 rounded-md bg-status-warning-bg-subtle border border-status-warning-border text-sm text-status-warning-text\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>\n Seat additions apply from the next billing cycle. A separate prorated charge will be\n raised for the remaining days in the current cycle.\n </span>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"flex gap-2 p-3 rounded-md bg-destructive/10 border border-destructive/30 text-sm text-destructive\">\n <AlertCircle className=\"size-4 mt-0.5 shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 p-6 border-t border-border\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"px-4 py-2 text-sm rounded-md border border-border hover:bg-accent text-foreground transition-colors disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleConfirm}\n disabled={\n isLoading ||\n newSeatCount === currentSeats ||\n newSeatCount < minSeats ||\n newSeatCount > maxSeats\n }\n className=\"px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {isLoading && <Loader2 className=\"size-4 animate-spin\" />}\n {newSeatCount === currentSeats\n ? 'No change'\n : seatDelta > 0\n ? `Add ${seatDelta} seat${seatDelta !== 1 ? 's' : ''}`\n : `Remove ${Math.abs(seatDelta)} seat${Math.abs(seatDelta) !== 1 ? 's' : ''}`}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|