@burdenoff/microfe-billing 2026.601.2 → 2026.601.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +388 -384
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +5 -2
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckoutPage.js","names":[],"sources":["../../../../../src/billing/modules/checkout/pages/CheckoutPage.tsx"],"sourcesContent":["/**\n * Checkout Page Component\n * Main checkout flow for purchasing credits, plans, and add-ons\n * Supports single item checkout and multi-addon cart checkout\n */\n\nimport { type FC, useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport {\n ArrowLeft,\n ShoppingCart,\n Loader2,\n CheckCircle,\n XCircle,\n Coins,\n Package,\n Blocks,\n Wallet,\n CreditCard,\n ArrowRight,\n Receipt,\n RefreshCw,\n} from 'lucide-react';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { useAddonCartStore } from '../../addons/store/addonCartStore';\n\nimport {\n useCheckout,\n useNativeCheckout,\n usePaymentProviders,\n usePaymentStatusPolling,\n} from '../hooks';\nimport { isNativeIAPAvailable } from '../../../lib/native-purchases';\nimport { NativeCheckoutView } from '../components/NativeCheckoutView';\nimport { getStoredBillingAccountId } from '../../../hooks/useBillingAccountSelection';\nimport {\n useGetBillingAccountsCheckoutQuery,\n useGetPlanCheckoutQuery,\n useGetSelectedAddonCheckoutQuery,\n useGetPaymentMethodsCheckoutQuery,\n useGetActiveSubscriptionsCheckoutQuery,\n useGetCostOfCreditsCheckoutQuery,\n useGetStoreOrderCheckoutQuery,\n} from '../../../../generated/global-operations';\nimport {\n BillingAccountSelector,\n OrderSummary,\n CreditsAmountInput,\n StripePaymentForm,\n RazorpayPaymentButton,\n SubscriptionSelector,\n SimpleAutoPayToggle,\n UnifiedPaymentMethodSelector,\n PromoCodeInput,\n CompleteBillingAccountModal,\n isBillingAccountComplete,\n} from '../components';\nimport { buildStoreOrderCheckoutItems, normalizeStoreOrderCurrency } from '../utils/storeOrder';\nimport type { SavedPaymentMethod } from '../types';\n\nimport type { CheckoutItem, CheckoutBillingAccount, PurchaseType } from '../types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAppShell } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { recordAffiliateEvent } from '../../affiliate/api';\n\ntype CheckoutMode = 'select' | 'payment' | 'processing' | 'success' | 'error';\n\ninterface LocationState {\n purchaseType?: PurchaseType;\n itemId?: string;\n quantity?: number;\n upgradeFromSubscriptionId?: string;\n downgradeFromSubscriptionId?: string;\n currentPlanName?: string;\n billingAccountId?: string;\n}\n\nexport const CheckoutPage: 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 { planId, addonId, storeOrderId } = useParams<{\n planId?: string;\n addonId?: string;\n storeOrderId?: string;\n }>();\n const navigateTo = useBillingNavigate();\n const location = useLocation();\n const locationState = location.state as LocationState | undefined;\n\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { orgId, stripePublishableKey, razorpayKey, apiGatewayUrl, authToken, currentUser } =\n useBilling();\n const { productSlug } = useAppShell();\n const referralEventReportedRef = useRef<string | null>(null);\n\n // Addon cart store for multi-addon checkout\n const { items: cartItems, clearCart, _hasHydrated: cartHydrated } = useAddonCartStore();\n\n // Check if this is a cart-based checkout (route: /checkout/addons)\n const isCartCheckout = location.pathname.includes('/checkout/addons') && !addonId;\n\n // Check if this is a store order checkout (route: /checkout/store/:storeOrderId)\n const isStoreCheckout = location.pathname.includes('/checkout/store') && !!storeOrderId;\n\n // Determine what we're purchasing\n const purchaseType: PurchaseType = isCartCheckout\n ? 'ADDON'\n : isStoreCheckout\n ? 'ORDER' // Store orders use ORDER purchase type\n : (locationState?.purchaseType ?? (planId ? 'PLAN' : addonId ? 'ADDON' : 'CREDITS'));\n const itemId = locationState?.itemId ?? planId ?? addonId ?? storeOrderId;\n\n // Billing account completion gate\n const [showCompleteAccountModal, setShowCompleteAccountModal] = useState(false);\n\n // Checkout state\n const [mode, setMode] = useState<CheckoutMode>('select');\n const [paymentResponse, setPaymentResponse] = useState<{\n clientSecret?: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n paymentId?: string;\n paymentComplete?: boolean;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n total?: number; // Total in target currency from backend (e.g., INR)\n currency?: string;\n } | null>(null);\n const [paymentErrorMessage, setPaymentErrorMessage] = useState<string | null>(null);\n\n // Store purchase details for success page (captured before clearing)\n const [purchaseDetails, setPurchaseDetails] = useState<{\n items: typeof checkout.items;\n total: number;\n billingAccountName: string;\n billingAccountId: string;\n previousBalance: number;\n newBalance: number;\n paymentMethod: 'credits' | 'card';\n currency: string;\n transactionId?: string;\n } | null>(null);\n\n // Track payment type for polling (card vs credits)\n const [pollingPaymentType, setPollingPaymentType] = useState<'card' | 'credits'>('card');\n\n useEffect(() => {\n if (mode !== 'success' || !purchaseDetails) {\n return;\n }\n\n const rawAttribution =\n typeof window !== 'undefined'\n ? window.localStorage.getItem(getProfileScopedKey('boff-referral-attribution'))\n : null;\n if (!rawAttribution) {\n return;\n }\n\n let attribution: { journeyId?: string; codeId?: string };\n try {\n attribution = JSON.parse(rawAttribution) as { journeyId?: string; codeId?: string };\n } catch {\n return;\n }\n if (!attribution.journeyId && !attribution.codeId) {\n return;\n }\n\n const uniqueReference =\n purchaseDetails.transactionId ||\n paymentResponse?.paymentId ||\n paymentResponse?.orderId ||\n storeOrderId ||\n itemId ||\n purchaseType;\n\n const signature = `${attribution.journeyId ?? 'journey'}:${uniqueReference}`;\n if (referralEventReportedRef.current === signature) {\n return;\n }\n referralEventReportedRef.current = signature;\n\n void recordAffiliateEvent(\n {\n journeyId: attribution.journeyId,\n codeId: attribution.codeId,\n eventType: purchaseType === 'ORDER' ? 'STORE_PURCHASE' : 'PAID_CONVERSION',\n productSlug,\n actorUserId: currentUser?.id,\n orderId:\n purchaseDetails.transactionId || paymentResponse?.paymentId || paymentResponse?.orderId,\n billingAccountId: purchaseDetails.billingAccountId,\n storeOrderId: purchaseType === 'ORDER' ? storeOrderId : undefined,\n valueAmount: purchaseDetails.total,\n currency: purchaseDetails.currency,\n mode: 'billing-checkout',\n metadata: {\n purchaseType,\n billingAccountName: purchaseDetails.billingAccountName,\n },\n },\n { apiGatewayUrl, authToken, orgId }\n ).catch(() => {\n referralEventReportedRef.current = null;\n });\n }, [\n apiGatewayUrl,\n authToken,\n currentUser?.id,\n itemId,\n mode,\n orgId,\n paymentResponse?.orderId,\n paymentResponse?.paymentId,\n productSlug,\n purchaseDetails,\n purchaseType,\n storeOrderId,\n ]);\n\n // Per-seat plan seat count\n const [seatCount, setSeatCount] = useState<number>(1);\n\n // Use checkout hook - pass upgrade/downgrade context if this is a plan change\n const checkout = useCheckout({\n defaultCurrency: 'USD',\n upgradeFromSubscriptionId: locationState?.upgradeFromSubscriptionId,\n downgradeFromSubscriptionId: locationState?.downgradeFromSubscriptionId,\n });\n const { config: providerConfig, stripeEnabled, razorpayEnabled } = usePaymentProviders();\n\n // Payment status polling for both card and credit payments\n const {\n // isPolling - available but UI relies on mode state instead\n elapsedTime,\n error: pollingError,\n // paymentResult - available but not directly used (callbacks handle results)\n } = usePaymentStatusPolling({\n paymentId: mode === 'processing' ? (paymentResponse?.paymentId ?? null) : null,\n billingAccountId: checkout.billingAccount?.id ?? purchaseDetails?.billingAccountId ?? null,\n paymentType: pollingPaymentType, // 'card' or 'credits' based on selected provider\n pollingInterval: 5000, // Poll every 5 seconds\n maxPollingTime: 300000, // 5 minutes timeout\n onSuccess: (result) => {\n // Update transaction ID if available from polling result\n if (result.transactionId) {\n setPurchaseDetails((prev) =>\n prev ? { ...prev, transactionId: result.transactionId } : prev\n );\n }\n setMode('success');\n if (isCartCheckout) {\n clearCart();\n }\n // Auto-redirect is handled by useEffect\n },\n onFailure: (result) => {\n setPaymentErrorMessage(result.failureReason || 'Payment failed');\n setMode('error');\n },\n onTimeout: () => {\n setPaymentErrorMessage(\n 'Payment verification timed out. Please check your billing history for the payment status.'\n );\n setMode('error');\n },\n });\n\n // Fetch billing accounts\n const { data: accountsData, loading: accountsLoading } = useGetBillingAccountsCheckoutQuery({});\n\n // Fetch plan if purchasing a plan\n const {\n data: planData,\n loading: planLoading,\n // error: planError - available but not displayed (loading/empty states suffice)\n } = useGetPlanCheckoutQuery({\n variables: { id: itemId! },\n skip: purchaseType !== 'PLAN' || !itemId,\n });\n\n // Fetch addon if purchasing an addon\n const { data: addonData, loading: addonLoading } = useGetSelectedAddonCheckoutQuery({\n variables: { addonIDs: itemId ? [itemId] : [] },\n skip: purchaseType !== 'ADDON' || !itemId || isStoreCheckout, // Skip for store checkout\n });\n\n // Fetch store order (for store checkout)\n const { data: storeOrderData } = useGetStoreOrderCheckoutQuery({\n variables: { id: storeOrderId! },\n skip: !isStoreCheckout || !storeOrderId,\n });\n\n // Fetch saved payment methods for selected billing account\n const { data: paymentMethodsData, loading: paymentMethodsLoading } =\n useGetPaymentMethodsCheckoutQuery({\n variables: { billingAccountId: checkout.billingAccount?.id! },\n skip: !checkout.billingAccount?.id,\n });\n\n // Fetch active subscriptions for addon purchases (needed to select which subscription to attach addon to)\n // Skip for store checkout - store items don't require an active subscription\n const { data: subscriptionsData, loading: subscriptionsLoading } =\n useGetActiveSubscriptionsCheckoutQuery({\n variables: { billingAccountId: checkout.billingAccount?.id! },\n skip: !checkout.billingAccount?.id || purchaseType !== 'ADDON' || isStoreCheckout,\n });\n\n // Memoized subscriptions list\n const activeSubscriptions = useMemo(() => {\n return subscriptionsData?.getActiveSubscriptions ?? [];\n }, [subscriptionsData]);\n\n // Selected subscription for addon purchases\n const selectedSubscription = useMemo(() => {\n if (!checkout.selectedSubscriptionId || activeSubscriptions.length === 0) return null;\n return (\n activeSubscriptions.find((s: { id: string }) => s.id === checkout.selectedSubscriptionId) ??\n null\n );\n }, [checkout.selectedSubscriptionId, activeSubscriptions]);\n\n // Fetch credit cost from backend (for credits purchase)\n // Use current quantity from items, or default to 100 for initial query\n // Query in selected currency to get correct pricing\n const creditQuantity = checkout.items[0]?.type === 'CREDITS' ? checkout.items[0].quantity : 100;\n const { data: creditCostData, loading: creditCostLoading } = useGetCostOfCreditsCheckoutQuery({\n variables: { creditAmount: creditQuantity, currency: checkout.selectedCurrency || 'USD' },\n skip: purchaseType !== 'CREDITS',\n });\n\n // Calculate cost per credit from backend response\n const costPerCredit = useMemo(() => {\n if (creditCostData?.getCostOfCredits?.amount && creditQuantity > 0) {\n return creditCostData.getCostOfCredits.amount / creditQuantity;\n }\n return 0.01; // Default: 100 credits = $1\n }, [creditCostData, creditQuantity]);\n\n // Memoized saved payment methods\n const savedPaymentMethods = useMemo<SavedPaymentMethod[]>(() => {\n return paymentMethodsData?.getPaymentMethods ?? [];\n }, [paymentMethodsData]);\n\n // Memoized billing accounts list\n const billingAccounts = useMemo<CheckoutBillingAccount[]>(() => {\n return accountsData?.getBillingAccountsByOrg ?? [];\n }, [accountsData]);\n\n // Extract billing country from selected billing account's first billing address\n // This is used to restrict currency and payment provider options\n const billingCountry = useMemo<string | undefined>(() => {\n if (!checkout.billingAccount) return undefined;\n\n // Find the full account data with billing addresses\n const fullAccount = billingAccounts.find((acc) => acc.id === checkout.billingAccount?.id);\n const billingAddresses = fullAccount?.billingAddresses;\n\n if (billingAddresses && billingAddresses.length > 0) {\n return billingAddresses[0]?.country || undefined;\n }\n return undefined;\n }, [checkout.billingAccount, billingAccounts]);\n\n // Track if initial provider selection has been done for this billing country\n const [initialProviderSet, setInitialProviderSet] = useState<string | null>(null);\n\n // Auto-select appropriate currency based on billing country and billing account currency\n // - India: INR only (for Zoho Books GST invoice compatibility)\n // - International: Prefer billing account currency, or USD (INR not allowed for Stripe invoice compatibility)\n useEffect(() => {\n if (!billingCountry) return;\n\n if (billingCountry === 'IN') {\n // Indian billing: Force INR currency\n if (checkout.selectedCurrency !== 'INR') {\n checkout.setCurrency('INR');\n }\n // Auto-select Razorpay ONLY on first load for this billing country (don't override user's choice)\n if (\n razorpayEnabled &&\n initialProviderSet !== billingCountry &&\n checkout.selectedProvider !== 'CREDITS'\n ) {\n checkout.setPaymentProvider('RAZORPAY');\n setInitialProviderSet(billingCountry);\n }\n } else {\n // International billing: Force non-INR currency\n if (checkout.selectedCurrency === 'INR') {\n // Prefer billing account's currency if it's not INR, otherwise default to USD\n const accountCurrency = checkout.billingAccount?.currency;\n const preferredCurrency =\n accountCurrency && accountCurrency !== 'INR' ? accountCurrency : 'USD';\n checkout.setCurrency(preferredCurrency);\n }\n // For international, Stripe is the only option (Razorpay is India-only)\n if (checkout.selectedProvider === 'RAZORPAY') {\n checkout.setPaymentProvider('STRIPE');\n setInitialProviderSet(billingCountry);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n billingCountry,\n checkout.selectedCurrency,\n checkout.selectedProvider,\n checkout.setCurrency,\n checkout.setPaymentProvider,\n checkout.billingAccount?.currency,\n razorpayEnabled,\n initialProviderSet,\n ]);\n\n // Auto-select billing account's currency when billing account changes (for international)\n useEffect(() => {\n if (!checkout.billingAccount?.currency || billingCountry === 'IN') return;\n\n const accountCurrency = checkout.billingAccount.currency;\n // Update to billing account's currency if it's different and valid (not INR for international)\n if (accountCurrency !== 'INR' && checkout.selectedCurrency !== accountCurrency) {\n checkout.setCurrency(accountCurrency);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n checkout.billingAccount?.id,\n checkout.billingAccount?.currency,\n billingCountry,\n checkout.selectedCurrency,\n checkout.setCurrency,\n ]);\n\n // Auto-select payment method with priority: Credits > Saved Card > New Card\n useEffect(() => {\n // Skip if already manually selected something (not AUTO or null)\n if (checkout.selectedProvider !== 'AUTO' && checkout.selectedProvider !== null) {\n return; // Already selected, don't override user choice\n }\n\n const hasEnoughCredits = checkout.availableCredits >= checkout.total;\n\n // Priority 1: Credits (if available and sufficient)\n if (checkout.canPayWithCredits && hasEnoughCredits) {\n checkout.setPaymentProvider('CREDITS');\n checkout.setSelectedPaymentMethodId(null);\n return;\n }\n\n // Priority 2: Default saved card\n if (savedPaymentMethods.length > 0 && !checkout.selectedPaymentMethodId) {\n const defaultMethod = savedPaymentMethods.find((pm) => pm.isDefault && pm.isVerified);\n const firstVerified = savedPaymentMethods.find((pm) => pm.isVerified);\n const methodToSelect = defaultMethod || firstVerified;\n\n if (methodToSelect) {\n checkout.setSelectedPaymentMethodId(methodToSelect.id);\n // Auto-set provider based on card type\n if (methodToSelect.razorpayPaymentMethodId) {\n checkout.setPaymentProvider('RAZORPAY');\n } else if (methodToSelect.stripePaymentMethodId) {\n checkout.setPaymentProvider('STRIPE');\n }\n return;\n }\n }\n\n // Priority 3: New card (auto-select provider based on country)\n // This is already handled by the currency auto-selection effect above\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Auto-select on mount with specific dependencies\n }, [\n savedPaymentMethods.length,\n checkout.canPayWithCredits,\n checkout.availableCredits,\n checkout.total,\n ]);\n\n // Track if item was already added to prevent duplicates\n const [itemAdded, setItemAdded] = useState(false);\n\n useEffect(() => {\n if (!isStoreCheckout || itemAdded || !storeOrderData?.getStoreOrder) {\n return;\n }\n\n const orderCurrency = normalizeStoreOrderCurrency(storeOrderData.getStoreOrder.currency);\n if (checkout.selectedCurrency !== orderCurrency) {\n checkout.setCurrency(orderCurrency);\n }\n }, [isStoreCheckout, itemAdded, storeOrderData, checkout.selectedCurrency, checkout.setCurrency]);\n\n // Initialize checkout with items\n // Initialize seat count from plan minSeats when plan data loads\n useEffect(() => {\n if (purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT') {\n const minSeats = planData.getPlan.minSeats ?? 1;\n setSeatCount((prev) => (prev < minSeats ? minSeats : prev));\n }\n }, [planData, purchaseType]);\n\n // Recalculate checkout item when seat count changes for PER_SEAT plans\n useEffect(() => {\n if (purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT' && itemAdded) {\n setItemAdded(false); // triggers re-add with new seatCount\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [seatCount]);\n\n useEffect(() => {\n // Skip if already added items\n if (itemAdded) {\n return;\n }\n\n // Handle cart-based checkout (multiple addons from cart)\n // Wait for cart to hydrate before processing\n if (isCartCheckout && cartHydrated && cartItems.length > 0) {\n // Clear existing items first to prevent duplicates (React strict mode can run effects twice)\n checkout.clearItems();\n\n for (const cartItem of cartItems) {\n const addon = cartItem.addon;\n\n // Extract features from addon (using SubscriptionFeatures type with quota)\n const features =\n addon.features?.map((f) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits as Record<string, number | string | boolean> | undefined,\n })) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = (addon as { currencyPrices?: Record<string, number> })\n .currencyPrices;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n\n const item: CheckoutItem = {\n id: addon.id,\n type: 'ADDON',\n name: addon.name,\n description:\n typeof addon.context === 'object' && addon.context !== null\n ? (addon.context as { description?: string }).description\n : typeof addon.context === 'string'\n ? addon.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD: addon.price,\n currency: selectedCurrency,\n quantity: cartItem.quantity,\n features,\n metadata: { addonId: addon.id },\n };\n checkout.addItem(item);\n }\n setItemAdded(true);\n\n return;\n }\n\n if (purchaseType === 'PLAN' && planData?.getPlan) {\n const plan = planData.getPlan;\n\n // Extract features from plan\n const features =\n plan.features?.map(\n (f: {\n id: string;\n quota?: { id: string; name: string; limits?: Record<string, unknown> };\n }) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits,\n })\n ) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = plan.currencyPrices as Record<\n string,\n number | { perSeat?: number }\n > | null;\n const isPerSeat = plan.pricingModel === 'PER_SEAT';\n\n let priceInSelectedCurrency: number;\n if (isPerSeat && plan.pricePerSeat) {\n // PER_SEAT: per-seat rate × seat count\n const currencyEntry = currencyPrices?.[selectedCurrency];\n const perSeatRate =\n typeof currencyEntry === 'object' && currencyEntry?.perSeat\n ? currencyEntry.perSeat\n : plan.pricePerSeat;\n priceInSelectedCurrency = perSeatRate * seatCount;\n } else {\n const currencyEntry = currencyPrices?.[selectedCurrency];\n priceInSelectedCurrency = typeof currencyEntry === 'number' ? currencyEntry : plan.price;\n }\n\n const resolvedSeatCount = isPerSeat ? seatCount : 1;\n\n const item: CheckoutItem = {\n id: plan.id,\n type: 'PLAN',\n name: plan.name,\n description:\n typeof plan.context === 'object' && plan.context !== null\n ? (plan.context as { description?: string }).description\n : typeof plan.context === 'string'\n ? plan.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD:\n isPerSeat && plan.pricePerSeat ? plan.pricePerSeat * resolvedSeatCount : plan.price,\n currency: selectedCurrency,\n quantity: resolvedSeatCount,\n features,\n metadata: {\n planId: plan.id,\n duration: plan.duration,\n seatCount: isPerSeat ? resolvedSeatCount : undefined,\n },\n };\n\n checkout.addItem(item);\n setItemAdded(true);\n } else if (purchaseType === 'ADDON' && !isCartCheckout && addonData?.getSelectedAddons?.[0]) {\n const addon = addonData.getSelectedAddons[0];\n\n // Extract features from addon\n const features =\n addon.features?.map(\n (f: {\n id: string;\n quota?: { id: string; name: string; limits?: Record<string, unknown> };\n }) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits,\n })\n ) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = addon.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n\n const item: CheckoutItem = {\n id: addon.id,\n type: 'ADDON',\n name: addon.name,\n description:\n typeof addon.context === 'object' && addon.context !== null\n ? (addon.context as { description?: string }).description\n : typeof addon.context === 'string'\n ? addon.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD: addon.price,\n currency: selectedCurrency,\n quantity: locationState?.quantity ?? 1,\n features,\n metadata: { addonId: addon.id },\n };\n checkout.addItem(item);\n setItemAdded(true);\n } else if (isStoreCheckout && storeOrderData?.getStoreOrder) {\n // Load store order items into checkout\n const storeOrder = storeOrderData.getStoreOrder;\n const items = buildStoreOrderCheckoutItems(storeOrder);\n\n for (const item of items) {\n checkout.addItem(item);\n }\n setItemAdded(true);\n } else if (purchaseType === 'CREDITS') {\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const item: CheckoutItem = {\n id: 'credits-purchase',\n type: 'CREDITS',\n name: 'Credits',\n description: 'Purchase credits for your account',\n price: costPerCredit, // Use actual cost per credit from backend (in selected currency)\n currency: selectedCurrency,\n quantity: 100, // Default amount\n };\n checkout.addItem(item);\n setItemAdded(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n purchaseType,\n planData,\n addonData,\n storeOrderData,\n checkout.addItem,\n checkout.clearItems,\n locationState?.quantity,\n itemAdded,\n isCartCheckout,\n isStoreCheckout,\n cartItems,\n cartHydrated,\n costPerCredit,\n checkout.selectedCurrency, // Re-add items when currency changes to use correct prices\n ]);\n\n // Update store-order item prices when a payment currency change requires conversion.\n // If the persisted order currency already matches the selected currency this is a no-op.\n useEffect(() => {\n if (!isStoreCheckout || !itemAdded || checkout.conversionRate <= 1) return;\n\n for (const item of checkout.items) {\n if (item.type === 'ORDER' && item.currency !== checkout.selectedCurrency) {\n const convertedPrice = item.price * checkout.conversionRate;\n checkout.updateItemPrice(item.id, convertedPrice, checkout.selectedCurrency);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- checkout.items intentionally excluded to avoid infinite loop\n }, [\n isStoreCheckout,\n itemAdded,\n checkout.conversionRate,\n checkout.selectedCurrency,\n checkout.updateItemPrice,\n ]);\n\n // Update item price when backend credit cost changes (after item is already added)\n // This handles cases where the rate might differ based on quantity or currency\n useEffect(() => {\n if (purchaseType === 'CREDITS' && itemAdded && costPerCredit > 0) {\n const currentItem = checkout.items.find((i) => i.id === 'credits-purchase');\n // Only update if price actually changed\n if (currentItem && currentItem.price !== costPerCredit) {\n checkout.updateItemPrice('credits-purchase', costPerCredit);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [purchaseType, itemAdded, costPerCredit, checkout.items, checkout.updateItemPrice]);\n\n // Update item prices when currency changes (for plans and addons with fixed currencyPrices)\n // This handles mid-checkout currency changes by updating prices from stored currencyPrices\n useEffect(() => {\n if (!itemAdded || checkout.items.length === 0) return;\n\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n\n for (const item of checkout.items) {\n if (item.type === 'PLAN' && planData?.getPlan) {\n const currencyPrices = planData.getPlan.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency =\n currencyPrices?.[selectedCurrency] ?? planData.getPlan.price;\n // Update both price AND currency so conversion check works correctly\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n } else if (item.type === 'ADDON') {\n // For single addon checkout\n if (!isCartCheckout && addonData?.getSelectedAddons?.[0]) {\n const addon = addonData.getSelectedAddons[0];\n const currencyPrices = addon.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n }\n // For cart checkout, find the addon in cartItems\n if (isCartCheckout) {\n const cartItem = cartItems.find((ci) => ci.addon.id === item.id);\n if (cartItem) {\n const currencyPrices = (cartItem.addon as { currencyPrices?: Record<string, number> })\n .currencyPrices;\n const priceInSelectedCurrency =\n currencyPrices?.[selectedCurrency] ?? cartItem.addon.price;\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n }\n }\n }\n // CREDITS are handled by the credit cost effect above\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n checkout.selectedCurrency,\n itemAdded,\n checkout.items,\n checkout.updateItemPrice,\n planData,\n addonData,\n cartItems,\n isCartCheckout,\n ]);\n\n // Set default billing account\n // Priority: 1. Location state (for upgrade flows), 2. localStorage (user's last selection), 3. First account\n useEffect(() => {\n if (billingAccounts.length > 0 && !checkout.billingAccount) {\n // 1. If this is an upgrade, find and select the specific billing account from location state\n if (locationState?.billingAccountId) {\n const targetAccount = billingAccounts.find(\n (acc) => acc.id === locationState.billingAccountId\n );\n if (targetAccount) {\n checkout.setBillingAccount(targetAccount);\n return;\n }\n }\n\n // 2. Check localStorage for previously selected billing account (set from /overview page)\n if (orgId) {\n const storedAccountId = getStoredBillingAccountId(orgId);\n if (storedAccountId) {\n const storedAccount = billingAccounts.find((acc) => acc.id === storedAccountId);\n if (storedAccount) {\n checkout.setBillingAccount(storedAccount);\n return;\n }\n }\n }\n\n // 3. Default: select first account\n checkout.setBillingAccount(billingAccounts[0]);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n billingAccounts,\n checkout.billingAccount,\n checkout.setBillingAccount,\n locationState?.billingAccountId,\n orgId,\n ]);\n\n // Determine if billing account selector should be locked (for upgrade/downgrade flows)\n const isBillingAccountLocked = Boolean(\n locationState?.upgradeFromSubscriptionId || locationState?.downgradeFromSubscriptionId\n );\n\n // Redirect to addons page if cart is empty for cart checkout.\n // Navigation must happen after render to avoid React setState-in-render warnings.\n useEffect(() => {\n if (isCartCheckout && cartHydrated && cartItems.length === 0 && !itemAdded) {\n navigateTo('/addons', { replace: true });\n }\n }, [cartHydrated, cartItems.length, isCartCheckout, itemAdded, navigateTo]);\n\n const nativeCheckout = useNativeCheckout({\n billingAccountId: checkout.billingAccount?.id,\n purchaseType,\n productId: itemId,\n });\n\n const handleProceedToPayment = useCallback(async () => {\n if (!checkout.billingAccount) {\n return;\n }\n\n // Gate: require complete billing details before payment\n if (!isBillingAccountComplete(checkout.billingAccount)) {\n setShowCompleteAccountModal(true);\n return;\n }\n\n setPaymentErrorMessage(null);\n\n // Capture purchase details before payment (for success page)\n const previousBalance = checkout.billingAccount.creditAmount ?? 0;\n const purchasedItems = [...checkout.items];\n const purchaseTotal = checkout.total;\n\n const response = await checkout.initiatePayment();\n\n if (response.success) {\n emit('billing.checkout.initiated', {\n route: '/billing/checkout',\n entityId: response.paymentId ?? response.orderId,\n source: 'checkout',\n amount: response.total || purchaseTotal,\n currency: response.currency || checkout.selectedCurrency,\n });\n // For credit payments, go to processing mode and poll for transaction status\n if (checkout.selectedProvider === 'CREDITS') {\n emit('billing.credits.spent', {\n route: '/billing/checkout',\n entityId: response.orderId,\n source: 'checkout',\n amount: purchaseTotal,\n currency: 'CREDITS',\n });\n // Store purchase details for success page\n setPurchaseDetails({\n items: purchasedItems,\n total: purchaseTotal,\n billingAccountName: checkout.billingAccount.name,\n billingAccountId: checkout.billingAccount.id,\n previousBalance,\n newBalance: previousBalance - purchaseTotal,\n paymentMethod: 'credits',\n currency: 'Credits', // Credit payments use credits as currency\n transactionId: response.orderId, // This is creditTransactionID from spendCredits\n });\n\n // Set payment type for polling and start verification\n setPollingPaymentType('credits');\n setPaymentResponse({\n paymentId: response.orderId, // creditTransactionID from spendCredits\n });\n setMode('processing');\n return;\n }\n\n // For card payments, proceed to payment form\n // Store partial details (will be completed after payment confirmation)\n setPurchaseDetails({\n items: purchasedItems,\n total: response.total || purchaseTotal, // Use response total which includes tax\n billingAccountName: checkout.billingAccount.name,\n billingAccountId: checkout.billingAccount.id,\n previousBalance,\n newBalance: previousBalance, // Card payment doesn't affect credits\n paymentMethod: 'card',\n currency: response.currency || checkout.selectedCurrency, // Use actual currency from response\n transactionId: response.paymentId, // Backend payment ID\n });\n\n setPollingPaymentType('card');\n setPaymentResponse({\n clientSecret: response.clientSecret,\n orderId: response.orderId, // Gateway order ID (for Razorpay)\n razorpayKeyId: response.razorpayKeyId,\n razorpayCustomerId: response.razorpayCustomerId, // For Razorpay saved cards\n paymentId: response.paymentId, // Backend payment ID for polling\n paymentComplete: response.paymentComplete, // For saved card one-click payments\n prefillName: response.prefillName,\n prefillEmail: response.prefillEmail,\n prefillContact: response.prefillContact,\n total: response.total, // Total in target currency (from backend, e.g., INR amount)\n currency: response.currency, // Currency code from backend\n });\n\n // If payment completed immediately (saved card), go to processing for verification\n if (response.paymentComplete) {\n setMode('processing');\n } else {\n setMode('payment');\n }\n } else {\n emit('billing.checkout.failed', {\n route: '/billing/checkout',\n source: 'checkout',\n reason: response.error || 'Payment initiation failed',\n });\n setPaymentErrorMessage(response.error || 'Payment initiation failed');\n setMode('error');\n }\n }, [checkout, emit]);\n\n const handlePaymentSuccess = useCallback(\n (_gatewayPaymentId: string) => {\n emit('billing.payment.succeeded', {\n route: '/billing/checkout',\n entityId: paymentResponse?.paymentId ?? paymentResponse?.orderId,\n source: 'checkout',\n });\n // Keep using the backend payment ID (orderId) that was already set\n // The _gatewayPaymentId is for reference only, not for our polling\n setPaymentResponse((prev) => {\n return prev; // Keep existing paymentId (orderId from initiatePayment)\n });\n setMode('processing');\n },\n [emit, paymentResponse?.orderId, paymentResponse?.paymentId]\n );\n\n const handlePaymentError = useCallback(\n (error: string) => {\n emit('billing.payment.failed', {\n route: '/billing/checkout',\n entityId: paymentResponse?.paymentId ?? paymentResponse?.orderId,\n source: 'checkout',\n reason: error,\n });\n setPaymentErrorMessage(error);\n setMode('error');\n },\n [emit, paymentResponse?.orderId, paymentResponse?.paymentId]\n );\n\n const handleCreditsAmountChange = useCallback(\n (amount: number) => {\n checkout.updateItemQuantity('credits-purchase', amount);\n },\n [checkout]\n );\n\n if (!permissions.canProcessPayment) {\n return <AccessDenied message=\"You don't have permission to make purchases.\" />;\n }\n\n if (isNativeIAPAvailable()) {\n return (\n <NativeCheckoutView\n purchaseType={purchaseType}\n productId={itemId}\n billingAccountId={checkout.billingAccount?.id}\n nativeCheckout={nativeCheckout}\n onBack={() => navigateTo('dashboard')}\n />\n );\n }\n\n const isLoading =\n accountsLoading ||\n (planLoading && purchaseType === 'PLAN') ||\n (addonLoading && purchaseType === 'ADDON' && !isCartCheckout) ||\n (isCartCheckout && !cartHydrated);\n\n if (isCartCheckout && cartHydrated && cartItems.length === 0 && !itemAdded) {\n return null;\n }\n\n // Get page title based on purchase type\n const getPageTitle = () => {\n if (isCartCheckout) {\n const addonCount = checkout.items.length;\n return `Purchase ${addonCount} Add-on${addonCount !== 1 ? 's' : ''}`;\n }\n switch (purchaseType) {\n case 'CREDITS':\n return 'Buy Credits';\n case 'PLAN':\n return 'Subscribe to Plan';\n case 'ADDON':\n return 'Purchase Add-on';\n default:\n return 'Checkout';\n }\n };\n\n const getPageIcon = () => {\n switch (purchaseType) {\n case 'CREDITS':\n return <Coins className=\"size-6\" />;\n case 'PLAN':\n return <Package className=\"size-6\" />;\n case 'ADDON':\n return <Blocks className=\"size-6\" />;\n default:\n return <ShoppingCart className=\"size-6\" />;\n }\n };\n\n // Render loading state\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <Loader2 className=\"size-8 animate-spin mx-auto text-primary\" />\n <p className=\"text-muted-foreground\">\n {tr('billing.checkout.loadingCheckout', 'Loading checkout...')}\n </p>\n </div>\n </div>\n );\n }\n\n // Render success state\n if (mode === 'success') {\n // Format amount based on payment method and currency\n const formatAmount = (amount: number) => {\n if (!purchaseDetails) return `${amount.toFixed(2)}`;\n\n const currency = purchaseDetails.currency;\n\n // For credits, show \"X.XX Credits\"\n if (currency === 'Credits') {\n return `${amount.toFixed(2)} Credits`;\n }\n\n // For real currencies, show with symbol\n const currencySymbols: Record<string, string> = {\n INR: '₹',\n USD: '$',\n EUR: '€',\n GBP: '£',\n };\n const symbol = currencySymbols[currency] || currency + ' ';\n return `${symbol}${amount.toFixed(2)}`;\n };\n\n // Keep formatCredits for credit balance section\n const formatCredits = (amount: number) => `${amount.toFixed(2)} Credits`;\n\n return (\n <div className=\"max-w-2xl mx-auto p-6 space-y-6\">\n {/* Success Header */}\n <div className=\"text-center space-y-4\">\n <div className=\"inline-flex p-4 rounded-full bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-12\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.paymentSuccessful', 'Payment Successful!')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {tr(\n 'billing.checkout.purchaseCompleted',\n 'Your purchase has been completed successfully.'\n )}\n </p>\n </div>\n </div>\n\n {/* Purchase Details Card */}\n {purchaseDetails && (\n <div className=\"bg-card border border-border rounded-lg overflow-hidden\">\n {/* Items Purchased */}\n <div className=\"p-4 border-b border-border\">\n <h3 className=\"font-semibold text-foreground mb-3 flex items-center gap-2\">\n <Receipt className=\"size-4\" />\n {tr('billing.checkout.itemsPurchased', 'Items Purchased')}\n </h3>\n <div className=\"space-y-2\">\n {purchaseDetails.items.map((item) => (\n <div key={item.id} className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {item.type === 'PLAN' && <Package className=\"size-4 text-accent-blue\" />}\n {item.type === 'ADDON' && <Blocks className=\"size-4 text-accent-purple\" />}\n {item.type === 'CREDITS' && (\n <Coins className=\"size-4 text-status-warning-text\" />\n )}\n {item.type === 'ORDER' && (\n <ShoppingCart className=\"size-4 text-status-success-text\" />\n )}\n <span className=\"text-foreground\">{item.name}</span>\n {item.quantity > 1 && (\n <span className=\"text-xs text-muted-foreground\">x{item.quantity}</span>\n )}\n </div>\n <span className=\"text-muted-foreground\">\n {formatAmount(item.price * item.quantity)}\n </span>\n </div>\n ))}\n </div>\n </div>\n\n {/* Payment Info */}\n <div className=\"p-4 border-b border-border bg-muted/30\">\n <div className=\"grid grid-cols-2 gap-4\">\n {/* Payment Method */}\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.paymentMethod', 'Payment Method')}\n </p>\n <div className=\"flex items-center gap-2\">\n {purchaseDetails.paymentMethod === 'credits' ? (\n <>\n <Wallet className=\"size-4 text-status-warning-text\" />\n <span className=\"font-medium text-foreground\">\n {tr('billing.checkout.credits', 'Credits')}\n </span>\n </>\n ) : (\n <>\n <CreditCard className=\"size-4 text-accent-blue\" />\n <span className=\"font-medium text-foreground\">\n {tr('billing.checkout.card', 'Card')}\n </span>\n </>\n )}\n </div>\n </div>\n {/* Total */}\n <div className=\"text-right\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.totalPaid', 'Total Paid')}\n </p>\n <p className=\"font-bold text-lg text-foreground\">\n {formatAmount(purchaseDetails.total)}\n </p>\n </div>\n </div>\n </div>\n\n {/* Credit Balance (only for credit payments) */}\n {purchaseDetails.paymentMethod === 'credits' && (\n <div className=\"p-4 border-b border-border\">\n <h3 className=\"font-semibold text-foreground mb-3 flex items-center gap-2\">\n <Wallet className=\"size-4\" />\n {tr('billing.checkout.creditBalance', 'Credit Balance')}\n </h3>\n <div className=\"flex items-center gap-4\">\n <div className=\"flex-1 text-center p-3 rounded-lg bg-muted/50\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.previousBalance', 'Previous Balance')}\n </p>\n <p className=\"font-semibold text-foreground\">\n {formatCredits(purchaseDetails.previousBalance)}\n </p>\n </div>\n <ArrowRight className=\"size-5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 text-center p-3 rounded-lg bg-status-success-bg-subtle\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.newBalance', 'New Balance')}\n </p>\n <p className=\"font-semibold text-status-success-text\">\n {formatCredits(purchaseDetails.newBalance)}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Billing Account Info */}\n <div className=\"p-4 bg-muted/20\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </p>\n <p className=\"font-medium text-foreground\">\n {purchaseDetails.billingAccountName}\n </p>\n </div>\n {purchaseDetails.transactionId && (\n <div className=\"text-right\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.transactionId', 'Transaction ID')}\n </p>\n <p className=\"font-mono text-xs text-muted-foreground\">\n {purchaseDetails.transactionId.slice(0, 8)}...\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Action Buttons */}\n <div className=\"flex flex-col sm:flex-row gap-3 justify-center pt-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/overview')}\n className=\"px-6 py-3 text-sm font-medium bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors\"\n >\n {tr('billing.checkout.backToOverview', 'Back to Overview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/subscriptions')}\n className=\"px-6 py-3 text-sm font-medium border border-border text-foreground rounded-lg hover:bg-muted transition-colors\"\n >\n {tr('billing.checkout.viewSubscriptions', 'View Subscriptions')}\n </button>\n </div>\n </div>\n );\n }\n\n // Render error state\n if (mode === 'error') {\n return (\n <div className=\"max-w-lg mx-auto p-6\">\n <div className=\"text-center space-y-6\">\n <div className=\"inline-flex p-4 rounded-full bg-destructive/10 text-destructive\">\n <XCircle className=\"size-12\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.paymentFailed', 'Payment Failed')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {paymentErrorMessage ||\n pollingError ||\n checkout.error ||\n tr('billing.checkout.genericError', 'Something went wrong. Please try again.')}\n </p>\n </div>\n <div className=\"flex gap-3 justify-center\">\n <button\n type=\"button\"\n onClick={() => navigateTo(-1)}\n className=\"px-4 py-2 rounded-lg border border-border hover:bg-muted\"\n >\n {tr('billing.checkout.goBack', 'Go Back')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setMode('select');\n setPaymentErrorMessage(null);\n checkout.reset();\n }}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('billing.checkout.tryAgain', 'Try Again')}\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n // Render processing state (waiting for payment confirmation)\n if (mode === 'processing') {\n const formatTime = (ms: number) => {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;\n };\n\n return (\n <div className=\"max-w-lg mx-auto p-6\">\n <div className=\"text-center space-y-6\">\n <div className=\"inline-flex p-4 rounded-full bg-primary/10 text-primary\">\n <Loader2 className=\"size-12 animate-spin\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.verifyingPayment', 'Verifying Payment')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {tr(\n 'billing.checkout.verifyingPaymentDescription',\n 'Please wait while we confirm your payment...'\n )}\n </p>\n </div>\n\n {/* Elapsed time */}\n <div className=\"bg-muted/50 rounded-lg p-4\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.checkout.timeElapsed', 'Time elapsed:')}{' '}\n <span className=\"font-mono font-medium text-foreground\">\n {formatTime(elapsedTime)}\n </span>\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.checkout.keepPageOpen',\n \"This may take a few moments. Please don't close this page.\"\n )}\n </p>\n </div>\n\n {/* Progress indicator */}\n <div className=\"w-full bg-muted rounded-full h-2 overflow-hidden\">\n <div\n className=\"bg-primary h-2 rounded-full transition-all duration-1000\"\n style={{ width: `${Math.min((elapsedTime / 300000) * 100, 100)}%` }}\n />\n </div>\n\n {/* Cancel button - only show after 30 seconds */}\n {elapsedTime > 30000 && (\n <button\n type=\"button\"\n onClick={() => {\n setMode('error');\n setPaymentErrorMessage(\n 'Payment verification was cancelled. Please check your billing history.'\n );\n }}\n className=\"text-sm text-muted-foreground hover:text-foreground underline\"\n >\n {tr('billing.checkout.cancelAndCheckHistory', 'Cancel and check billing history')}\n </button>\n )}\n </div>\n </div>\n );\n }\n\n // Render payment form\n if (mode === 'payment' && paymentResponse) {\n // Format currency for display\n const formatDisplayCurrency = (amount: number, currencyCode: string) => {\n const symbols: Record<string, string> = { INR: '₹', USD: '$', EUR: '€', GBP: '£' };\n const symbol = symbols[currencyCode] || currencyCode + ' ';\n return `${symbol}${amount.toFixed(2)}`;\n };\n\n const displayCurrency = paymentResponse.currency || checkout.selectedCurrency;\n const displayTotal = paymentResponse.total ?? checkout.total;\n\n return (\n <div className=\"max-w-2xl mx-auto p-4 sm:p-6 space-y-6\">\n <button\n type=\"button\"\n onClick={() => setMode('select')}\n className=\"flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('billing.checkout.backToCheckout', 'Back to checkout')}\n </button>\n\n <PageHeader\n title={tr('billing.checkout.completePayment', 'Complete Payment')}\n description={tr(\n 'billing.checkout.completePaymentDescription',\n 'Enter your payment details to complete the purchase'\n )}\n />\n\n {/* Payment Summary with correct tax calculation */}\n <div className=\"rounded-lg border border-border bg-card p-4 space-y-4\">\n <h3 className=\"font-semibold text-foreground flex items-center gap-2\">\n <Receipt className=\"size-4\" />\n {tr('billing.checkout.paymentSummary', 'Payment Summary')}\n </h3>\n\n {/* Billing Account Info */}\n {checkout.billingAccount && (\n <div className=\"p-3 bg-muted/30 rounded-lg space-y-1\">\n <div className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </div>\n <div className=\"font-medium text-foreground\">{checkout.billingAccount.name}</div>\n <div className=\"text-sm text-muted-foreground\">{checkout.billingAccount.email}</div>\n </div>\n )}\n\n {/* Subscription Info (for addon purchases) */}\n {purchaseType === 'ADDON' && checkout.selectedSubscriptionId && selectedSubscription && (\n <div className=\"p-3 bg-muted/30 rounded-lg space-y-1\">\n <div className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {tr('billing.checkout.addingToSubscription', 'Adding to Subscription')}\n </div>\n <div className=\"font-medium text-foreground\">\n {selectedSubscription.plan?.name ||\n tr('billing.checkout.subscription', 'Subscription')}\n </div>\n {selectedSubscription.plan?.product?.name && (\n <div className=\"text-sm text-muted-foreground\">\n {selectedSubscription.plan.product.name}\n </div>\n )}\n </div>\n )}\n\n {/* Price Breakdown */}\n <div className=\"space-y-2 text-sm\">\n {/* Calculate display values correctly */}\n {(() => {\n const taxRate = checkout.taxRate;\n // For non-USD: calculate subtotal and tax from the total\n const calcSubtotal = taxRate > 0 ? displayTotal / (1 + taxRate) : displayTotal;\n const calcTax = taxRate > 0 ? displayTotal - calcSubtotal : 0;\n\n return (\n <>\n {/* Subtotal */}\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {tr('billing.checkout.subtotal', 'Subtotal')}\n </span>\n <span className=\"text-foreground\">\n {formatDisplayCurrency(calcSubtotal, displayCurrency)}\n </span>\n </div>\n {/* Discount */}\n {checkout.discountAmount > 0 && (\n <div className=\"flex justify-between text-status-success-text\">\n <span>{tr('billing.checkout.discount', 'Discount')}</span>\n <span>\n -{formatDisplayCurrency(checkout.discountAmount, displayCurrency)}\n </span>\n </div>\n )}\n {/* Tax */}\n {calcTax > 0 && (\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {checkout.taxType || tr('billing.checkout.tax', 'Tax')} (\n {(taxRate * 100).toFixed(0)}%)\n </span>\n <span className=\"text-foreground\">\n {formatDisplayCurrency(calcTax, displayCurrency)}\n </span>\n </div>\n )}\n </>\n );\n })()}\n {/* Divider */}\n <div className=\"border-t border-border my-2\" />\n {/* Total */}\n <div className=\"flex justify-between font-semibold\">\n <span className=\"text-foreground\">{tr('billing.checkout.total', 'Total')}</span>\n <span className=\"text-lg text-foreground\">\n {formatDisplayCurrency(displayTotal, displayCurrency)}\n </span>\n </div>\n </div>\n </div>\n\n {checkout.selectedProvider === 'STRIPE' &&\n paymentResponse.clientSecret &&\n (() => {\n // NOTE: Saved cards for Stripe are temporarily disabled on the backend\n // NOTE: Card saving disabled — re-enable when backend supports setup_future_usage on PaymentIntents\n // const stripeCards = savedPaymentMethods.filter(pm => pm.stripePaymentMethodId && pm.isVerified);\n\n return (\n <div className=\"rounded-lg border border-border bg-card overflow-hidden\">\n {/* Stripe Elements form for new card */}\n <div className=\"p-4 space-y-4\">\n {/* Save card checkbox - disabled until backend supports it */}\n {/* <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checkout.saveCard}\n onChange={(e) => checkout.setSaveCard(e.target.checked)}\n className=\"size-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-sm text-muted-foreground\">\n Save card for future purchases\n </span>\n </label> */}\n\n <StripePaymentForm\n clientSecret={paymentResponse.clientSecret}\n publishableKey={\n stripePublishableKey || providerConfig?.stripePublishableKey || ''\n }\n amount={Math.round((paymentResponse.total ?? checkout.total) * 100)}\n currency={paymentResponse.currency || checkout.selectedCurrency}\n onSuccess={handlePaymentSuccess}\n onError={handlePaymentError}\n onCancel={() => setMode('select')}\n isCompletingExistingPayment={!!checkout.selectedPaymentMethodId}\n />\n </div>\n </div>\n );\n })()}\n\n {checkout.selectedProvider === 'RAZORPAY' && paymentResponse.orderId && (\n <div className=\"rounded-lg border border-border bg-card overflow-hidden\">\n {/* Razorpay Payment Section */}\n <div className=\"p-4 space-y-4\">\n {/* Save card checkbox for new card payments */}\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checkout.saveCard}\n onChange={(e) => checkout.setSaveCard(e.target.checked)}\n className=\"size-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-sm text-muted-foreground\">\n Save card for future purchases\n </span>\n </label>\n\n <RazorpayPaymentButton\n orderId={paymentResponse.orderId}\n keyId={paymentResponse.razorpayKeyId || razorpayKey || ''}\n amount={Math.round((paymentResponse.total ?? checkout.total) * 100)}\n currency={paymentResponse.currency || 'INR'}\n customerId={paymentResponse.razorpayCustomerId}\n prefill={{\n name: paymentResponse.prefillName,\n email: paymentResponse.prefillEmail,\n contact: paymentResponse.prefillContact,\n }}\n onSuccess={(response) => handlePaymentSuccess(response.razorpay_payment_id)}\n onError={handlePaymentError}\n onCancel={() => setMode('select')}\n />\n </div>\n </div>\n )}\n </div>\n );\n }\n\n // Main checkout flow\n return (\n <div className=\"max-w-6xl mx-auto p-4 sm:p-6\">\n {/* Back button */}\n <button\n type=\"button\"\n onClick={() => navigateTo(-1)}\n className=\"flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground mb-4\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-6\">\n <div className=\"p-2 rounded-lg bg-primary/10 text-primary\">{getPageIcon()}</div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">{getPageTitle()}</h1>\n <p className=\"text-sm text-muted-foreground\">Complete your purchase securely</p>\n </div>\n </div>\n\n {/* Upgrade Banner */}\n {locationState?.upgradeFromSubscriptionId && locationState?.currentPlanName && (\n <div className=\"mb-6 p-4 rounded-lg border border-border-subtle bg-status-info-bg-subtle\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-full bg-status-info-bg-subtle\">\n <RefreshCw className=\"size-4 text-accent-blue\" />\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n Upgrading from:{' '}\n <span className=\"font-semibold\">{locationState.currentPlanName}</span>\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n Your current subscription will be marked as upgraded and quotas will transfer to the\n new plan.\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Downgrade Banner */}\n {locationState?.downgradeFromSubscriptionId && locationState?.currentPlanName && (\n <div className=\"mb-6 p-4 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-full bg-status-warning-bg-subtle\">\n <RefreshCw className=\"size-4 text-status-warning-text\" />\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n Downgrading from:{' '}\n <span className=\"font-semibold\">{locationState.currentPlanName}</span>\n </p>\n <p className=\"text-xs text-status-warning-text mt-0.5\">\n Your current plan stays active until it expires, you keep all its features until\n then. After expiry, only the new plan applies.\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Main content - responsive grid. On mobile the order summary appears first\n so users see the total before filling in payment details. */}\n <div className=\"grid gap-6 lg:grid-cols-5\">\n {/* Left column - Configuration (renders second on mobile) */}\n <div className=\"lg:col-span-3 space-y-6 order-2 lg:order-1\">\n {/* Credits amount (for credits purchase) */}\n {purchaseType === 'CREDITS' && checkout.items[0] && (\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6\">\n <CreditsAmountInput\n value={checkout.items[0].quantity}\n onChange={handleCreditsAmountChange}\n costPerCredit={costPerCredit}\n currency={checkout.selectedCurrency}\n disabled={creditCostLoading}\n />\n </div>\n )}\n\n {/* Billing Account Selection */}\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6 space-y-4\">\n <BillingAccountSelector\n accounts={billingAccounts}\n selectedAccountId={checkout.billingAccount?.id ?? null}\n onSelect={checkout.setBillingAccount}\n isLoading={accountsLoading}\n disabled={isBillingAccountLocked}\n disabledMessage={\n isBillingAccountLocked ? 'Billing account is locked for plan changes' : undefined\n }\n />\n\n {/* Subscription Selection - inline for addon purchases (only shows if multiple subs or no subs) */}\n {/* Skip subscription selection for store checkout - store items don't require an active subscription */}\n {purchaseType === 'ADDON' && !isStoreCheckout && checkout.billingAccount && (\n <SubscriptionSelector\n subscriptions={activeSubscriptions}\n selectedSubscriptionId={checkout.selectedSubscriptionId}\n onSelect={checkout.setSelectedSubscriptionId}\n isLoading={subscriptionsLoading}\n />\n )}\n </div>\n\n {/* Unified Payment Method Selection */}\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6 space-y-4\">\n <UnifiedPaymentMethodSelector\n savedPaymentMethods={savedPaymentMethods}\n selectedPaymentMethodId={checkout.selectedPaymentMethodId}\n onSelectSavedCard={checkout.setSelectedPaymentMethodId}\n selectedProvider={checkout.selectedProvider}\n onSelectProvider={checkout.setPaymentProvider}\n stripeEnabled={stripeEnabled}\n razorpayEnabled={razorpayEnabled}\n canPayWithCredits={checkout.canPayWithCredits && checkout.hasEnoughCredits}\n availableCredits={checkout.availableCredits}\n totalAmount={checkout.subtotalUSD}\n billingCountry={billingCountry}\n saveCard={checkout.saveCard}\n onSaveCardChange={checkout.setSaveCard}\n autoRenewEnabled={purchaseType === 'PLAN' && checkout.autoRenew}\n isLoading={paymentMethodsLoading}\n />\n\n {/* Currency Info - Locked to Billing Account */}\n {checkout.selectedProvider !== 'CREDITS' && checkout.selectedProvider !== 'AUTO' && (\n <>\n <div className=\"border-t border-border\" />\n <div className=\"bg-muted/50 p-4 rounded-md\">\n <div className=\"flex items-start gap-3\">\n <svg\n className=\"size-5 text-muted-foreground mt-0.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <div className=\"flex-1 text-sm\">\n <p className=\"font-medium text-foreground mb-1\">\n Currency: {checkout.selectedCurrency}\n </p>\n <p className=\"text-muted-foreground text-xs\">\n All prices are shown in{' '}\n <strong className=\"text-foreground\">{checkout.selectedCurrency}</strong>{' '}\n based on your billing account settings.\n {checkout.selectedCurrency === 'INR' && ' GST will be applied at checkout.'}\n </p>\n </div>\n </div>\n </div>\n </>\n )}\n\n {/* Seat count selector — only for PER_SEAT plans */}\n {purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT' && (\n <div className=\"border-t border-border pt-4\">\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-sm font-medium text-foreground\">Number of seats</label>\n {planData.getPlan.minSeats && (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Minimum {planData.getPlan.minSeats} seat\n {planData.getPlan.minSeats !== 1 ? 's' : ''} required\n </p>\n )}\n </div>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() =>\n setSeatCount((n) => Math.max(planData.getPlan?.minSeats ?? 1, n - 1))\n }\n disabled={seatCount <= (planData.getPlan.minSeats ?? 1)}\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 text-foreground\"\n >\n −\n </button>\n <input\n type=\"number\"\n value={seatCount}\n min={planData.getPlan.minSeats ?? 1}\n max={planData.getPlan.maxSeats ?? 999}\n onChange={(e) => {\n const v = parseInt(e.target.value, 10);\n if (!isNaN(v)) setSeatCount(Math.max(planData.getPlan?.minSeats ?? 1, v));\n }}\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\"\n />\n <button\n type=\"button\"\n onClick={() =>\n setSeatCount((n) => Math.min(planData.getPlan?.maxSeats ?? 999, n + 1))\n }\n disabled={seatCount >= (planData.getPlan.maxSeats ?? 999)}\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 text-foreground\"\n >\n +\n </button>\n {planData.getPlan.pricePerSeat && (\n <span className=\"text-sm text-muted-foreground\">\n ×{' '}\n {planData.getPlan.pricePerSeat.toLocaleString('en', {\n style: 'currency',\n currency: planData.getPlan.currency ?? 'USD',\n })}{' '}\n ={' '}\n {(planData.getPlan.pricePerSeat * seatCount).toLocaleString('en', {\n style: 'currency',\n currency: planData.getPlan.currency ?? 'USD',\n })}\n /mo\n </span>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Right column - Order Summary (sticky on desktop, shown first on mobile) */}\n <div className=\"lg:col-span-2 order-1 lg:order-2\">\n <div className=\"lg:sticky lg:top-6 space-y-4\">\n <div className=\"rounded-lg border border-border bg-card\">\n <div className=\"p-4\">\n <OrderSummary\n items={checkout.items}\n subtotal={checkout.subtotal}\n discountAmount={checkout.discountAmount}\n taxAmount={checkout.taxAmount}\n taxRate={checkout.taxRate}\n taxType={checkout.taxType}\n total={checkout.total}\n currency={checkout.selectedCurrency}\n isCalculatingTax={checkout.isCalculatingTax}\n showInCredits={checkout.selectedProvider === 'CREDITS'}\n onUpdateQuantity={\n purchaseType !== 'PLAN' ? checkout.updateItemQuantity : undefined\n }\n onRemoveItem={checkout.removeItem}\n isEditable={purchaseType !== 'PLAN'}\n />\n </div>\n\n {/* Promo Code Input */}\n <div className=\"px-4 pb-4 border-t border-border pt-4\">\n <PromoCodeInput\n value={checkout.promoCode}\n onChange={checkout.setPromoCode}\n onValidate={async () => {\n const result = await checkout.validatePromoCode();\n return result;\n }}\n onClear={checkout.clearPromoCode}\n isApplied={checkout.promoDiscount > 0}\n discountValue={checkout.promoDiscount}\n discountType={checkout.promoDiscountType}\n isValidating={checkout.isProcessing}\n />\n </div>\n\n {/* Simple Auto-Pay Toggle - only for PLAN purchases */}\n {purchaseType === 'PLAN' &&\n checkout.selectedProvider !== 'CREDITS' &&\n checkout.selectedProvider !== 'AUTO' &&\n (() => {\n // Determine payment method display\n let paymentMethodDisplay = '';\n let hasPaymentMethod = false;\n let isNewCard = false;\n\n if (checkout.selectedPaymentMethodId) {\n // Saved card selected\n const selectedCard = savedPaymentMethods.find(\n (pm) => pm.id === checkout.selectedPaymentMethodId\n );\n if (selectedCard) {\n const type =\n selectedCard.type === 'CREDIT_CARD'\n ? 'Card'\n : selectedCard.type === 'DEBIT_CARD'\n ? 'Card'\n : selectedCard.type;\n const last4 = selectedCard.last4 ? ` •••• ${selectedCard.last4}` : '';\n paymentMethodDisplay = `${type}${last4}`;\n hasPaymentMethod = true;\n isNewCard = false;\n }\n } else if (\n checkout.selectedProvider === 'RAZORPAY' ||\n checkout.selectedProvider === 'STRIPE'\n ) {\n // New card selected\n paymentMethodDisplay =\n checkout.selectedProvider === 'RAZORPAY'\n ? 'new card (Razorpay)'\n : 'new card (Stripe)';\n hasPaymentMethod = true;\n isNewCard = true;\n }\n\n return (\n <div className=\"px-4 pb-4\">\n <SimpleAutoPayToggle\n enabled={checkout.autoRenew}\n onToggle={(enabled) => {\n checkout.setAutoRenew(enabled);\n // When enabling auto-pay with saved card, also set it as auto-renew method\n if (enabled && checkout.selectedPaymentMethodId) {\n checkout.setAutoRenewPaymentMethodId(checkout.selectedPaymentMethodId);\n }\n }}\n hasPaymentMethodSelected={hasPaymentMethod}\n selectedPaymentMethodDisplay={paymentMethodDisplay}\n isNewCard={isNewCard}\n />\n </div>\n );\n })()}\n </div>\n\n {/* Checkout Button */}\n <button\n type=\"button\"\n onClick={handleProceedToPayment}\n disabled={\n checkout.isProcessing ||\n !checkout.billingAccount ||\n checkout.items.length === 0 ||\n // For addon purchases: require active subscription to be selected (skip for store checkout)\n (purchaseType === 'ADDON' && !isStoreCheckout && subscriptionsLoading) ||\n (purchaseType === 'ADDON' &&\n !isStoreCheckout &&\n activeSubscriptions.length === 0) ||\n (purchaseType === 'ADDON' && !isStoreCheckout && !checkout.selectedSubscriptionId)\n }\n className=\"w-full px-6 py-4 rounded-lg bg-primary text-primary-foreground font-semibold\n hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\n transition-colors flex items-center justify-center gap-2\"\n >\n {checkout.isProcessing ? (\n <>\n <Loader2 className=\"size-5 animate-spin\" />\n Processing…\n </>\n ) : checkout.selectedProvider === 'CREDITS' ? (\n 'Pay with Credits'\n ) : (\n 'Proceed to Payment'\n )}\n </button>\n\n {/* Security badge */}\n <p className=\"text-center text-xs text-muted-foreground\">\n 🔒 Secure checkout with 256-bit SSL encryption\n </p>\n </div>\n </div>\n </div>\n\n {/* Billing account completion gate */}\n {showCompleteAccountModal && checkout.billingAccount && (\n <CompleteBillingAccountModal\n billingAccountId={checkout.billingAccount.id}\n hasPhone={Boolean(checkout.billingAccount.contactNumber?.trim())}\n hasAddress={Boolean(\n checkout.billingAccount.billingAddresses?.[0]?.line1?.trim() &&\n checkout.billingAccount.billingAddresses?.[0]?.postalCode?.trim()\n )}\n onCompleted={() => {\n setShowCompleteAccountModal(false);\n // Re-trigger payment now that details are saved\n void handleProceedToPayment();\n }}\n onCancel={() => setShowCompleteAccountModal(false)}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CheckoutPage.js","names":[],"sources":["../../../../../src/billing/modules/checkout/pages/CheckoutPage.tsx"],"sourcesContent":["/**\n * Checkout Page Component\n * Main checkout flow for purchasing credits, plans, and add-ons\n * Supports single item checkout and multi-addon cart checkout\n */\n\nimport { type FC, useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport {\n ArrowLeft,\n ShoppingCart,\n Loader2,\n CheckCircle,\n XCircle,\n Coins,\n Package,\n Blocks,\n Wallet,\n CreditCard,\n ArrowRight,\n Receipt,\n RefreshCw,\n} from 'lucide-react';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader } from '../../../shared/components';\nimport { useAddonCartStore } from '../../addons/store/addonCartStore';\n\nimport {\n useCheckout,\n useNativeCheckout,\n usePaymentProviders,\n usePaymentStatusPolling,\n} from '../hooks';\nimport { isNativeIAPAvailable } from '../../../lib/native-purchases';\nimport { NativeCheckoutView } from '../components/NativeCheckoutView';\nimport { getStoredBillingAccountId } from '../../../hooks/useBillingAccountSelection';\nimport {\n useGetBillingAccountsCheckoutQuery,\n useGetPlanCheckoutQuery,\n useGetSelectedAddonCheckoutQuery,\n useGetPaymentMethodsCheckoutQuery,\n useGetActiveSubscriptionsCheckoutQuery,\n useGetCostOfCreditsCheckoutQuery,\n useGetStoreOrderCheckoutQuery,\n} from '../../../../generated/global-operations';\nimport {\n BillingAccountSelector,\n OrderSummary,\n CreditsAmountInput,\n StripePaymentForm,\n RazorpayPaymentButton,\n SubscriptionSelector,\n SimpleAutoPayToggle,\n UnifiedPaymentMethodSelector,\n PromoCodeInput,\n CompleteBillingAccountModal,\n isBillingAccountComplete,\n} from '../components';\nimport { buildStoreOrderCheckoutItems, normalizeStoreOrderCurrency } from '../utils/storeOrder';\nimport type { SavedPaymentMethod } from '../types';\n\nimport type { CheckoutItem, CheckoutBillingAccount, PurchaseType } from '../types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAppShell } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { recordAffiliateEvent } from '../../affiliate/api';\n\ntype CheckoutMode = 'select' | 'payment' | 'processing' | 'success' | 'error';\n\ninterface LocationState {\n purchaseType?: PurchaseType;\n itemId?: string;\n quantity?: number;\n upgradeFromSubscriptionId?: string;\n downgradeFromSubscriptionId?: string;\n currentPlanName?: string;\n billingAccountId?: string;\n}\n\nexport const CheckoutPage: 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 { planId, addonId, storeOrderId } = useParams<{\n planId?: string;\n addonId?: string;\n storeOrderId?: string;\n }>();\n const navigateTo = useBillingNavigate();\n const location = useLocation();\n const locationState = location.state as LocationState | undefined;\n\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { orgId, stripePublishableKey, razorpayKey, apiGatewayUrl, authToken, currentUser } =\n useBilling();\n const { productSlug } = useAppShell();\n const referralEventReportedRef = useRef<string | null>(null);\n\n // Addon cart store for multi-addon checkout\n const { items: cartItems, clearCart, _hasHydrated: cartHydrated } = useAddonCartStore();\n\n // Check if this is a cart-based checkout (route: /checkout/addons)\n const isCartCheckout = location.pathname.includes('/checkout/addons') && !addonId;\n\n // Check if this is a store order checkout (route: /checkout/store/:storeOrderId)\n const isStoreCheckout = location.pathname.includes('/checkout/store') && !!storeOrderId;\n\n // Determine what we're purchasing\n const purchaseType: PurchaseType = isCartCheckout\n ? 'ADDON'\n : isStoreCheckout\n ? 'ORDER' // Store orders use ORDER purchase type\n : (locationState?.purchaseType ?? (planId ? 'PLAN' : addonId ? 'ADDON' : 'CREDITS'));\n const itemId = locationState?.itemId ?? planId ?? addonId ?? storeOrderId;\n\n // Billing account completion gate\n const [showCompleteAccountModal, setShowCompleteAccountModal] = useState(false);\n // Bypass the isBillingAccountComplete gate for the call that follows modal completion.\n // The gate uses stale Apollo cache (contactNumber/billingAddresses are not returned by\n // updateBillingAccount mutation), so we skip it once immediately after the modal saves.\n const bypassBillingGate = useRef(false);\n\n // Checkout state\n const [mode, setMode] = useState<CheckoutMode>('select');\n const [paymentResponse, setPaymentResponse] = useState<{\n clientSecret?: string;\n orderId?: string;\n razorpayKeyId?: string;\n razorpayCustomerId?: string;\n paymentId?: string;\n paymentComplete?: boolean;\n prefillName?: string;\n prefillEmail?: string;\n prefillContact?: string;\n total?: number; // Total in target currency from backend (e.g., INR)\n currency?: string;\n } | null>(null);\n const [paymentErrorMessage, setPaymentErrorMessage] = useState<string | null>(null);\n\n // Store purchase details for success page (captured before clearing)\n const [purchaseDetails, setPurchaseDetails] = useState<{\n items: typeof checkout.items;\n total: number;\n billingAccountName: string;\n billingAccountId: string;\n previousBalance: number;\n newBalance: number;\n paymentMethod: 'credits' | 'card';\n currency: string;\n transactionId?: string;\n } | null>(null);\n\n // Track payment type for polling (card vs credits)\n const [pollingPaymentType, setPollingPaymentType] = useState<'card' | 'credits'>('card');\n\n useEffect(() => {\n if (mode !== 'success' || !purchaseDetails) {\n return;\n }\n\n const rawAttribution =\n typeof window !== 'undefined'\n ? window.localStorage.getItem(getProfileScopedKey('boff-referral-attribution'))\n : null;\n if (!rawAttribution) {\n return;\n }\n\n let attribution: { journeyId?: string; codeId?: string };\n try {\n attribution = JSON.parse(rawAttribution) as { journeyId?: string; codeId?: string };\n } catch {\n return;\n }\n if (!attribution.journeyId && !attribution.codeId) {\n return;\n }\n\n const uniqueReference =\n purchaseDetails.transactionId ||\n paymentResponse?.paymentId ||\n paymentResponse?.orderId ||\n storeOrderId ||\n itemId ||\n purchaseType;\n\n const signature = `${attribution.journeyId ?? 'journey'}:${uniqueReference}`;\n if (referralEventReportedRef.current === signature) {\n return;\n }\n referralEventReportedRef.current = signature;\n\n void recordAffiliateEvent(\n {\n journeyId: attribution.journeyId,\n codeId: attribution.codeId,\n eventType: purchaseType === 'ORDER' ? 'STORE_PURCHASE' : 'PAID_CONVERSION',\n productSlug,\n actorUserId: currentUser?.id,\n orderId:\n purchaseDetails.transactionId || paymentResponse?.paymentId || paymentResponse?.orderId,\n billingAccountId: purchaseDetails.billingAccountId,\n storeOrderId: purchaseType === 'ORDER' ? storeOrderId : undefined,\n valueAmount: purchaseDetails.total,\n currency: purchaseDetails.currency,\n mode: 'billing-checkout',\n metadata: {\n purchaseType,\n billingAccountName: purchaseDetails.billingAccountName,\n },\n },\n { apiGatewayUrl, authToken, orgId }\n ).catch(() => {\n referralEventReportedRef.current = null;\n });\n }, [\n apiGatewayUrl,\n authToken,\n currentUser?.id,\n itemId,\n mode,\n orgId,\n paymentResponse?.orderId,\n paymentResponse?.paymentId,\n productSlug,\n purchaseDetails,\n purchaseType,\n storeOrderId,\n ]);\n\n // Per-seat plan seat count\n const [seatCount, setSeatCount] = useState<number>(1);\n\n // Use checkout hook - pass upgrade/downgrade context if this is a plan change\n const checkout = useCheckout({\n defaultCurrency: 'USD',\n upgradeFromSubscriptionId: locationState?.upgradeFromSubscriptionId,\n downgradeFromSubscriptionId: locationState?.downgradeFromSubscriptionId,\n });\n const { config: providerConfig, stripeEnabled, razorpayEnabled } = usePaymentProviders();\n\n // Payment status polling for both card and credit payments\n const {\n // isPolling - available but UI relies on mode state instead\n elapsedTime,\n error: pollingError,\n // paymentResult - available but not directly used (callbacks handle results)\n } = usePaymentStatusPolling({\n paymentId: mode === 'processing' ? (paymentResponse?.paymentId ?? null) : null,\n billingAccountId: checkout.billingAccount?.id ?? purchaseDetails?.billingAccountId ?? null,\n paymentType: pollingPaymentType, // 'card' or 'credits' based on selected provider\n pollingInterval: 5000, // Poll every 5 seconds\n maxPollingTime: 300000, // 5 minutes timeout\n onSuccess: (result) => {\n // Update transaction ID if available from polling result\n if (result.transactionId) {\n setPurchaseDetails((prev) =>\n prev ? { ...prev, transactionId: result.transactionId } : prev\n );\n }\n setMode('success');\n if (isCartCheckout) {\n clearCart();\n }\n // Auto-redirect is handled by useEffect\n },\n onFailure: (result) => {\n setPaymentErrorMessage(result.failureReason || 'Payment failed');\n setMode('error');\n },\n onTimeout: () => {\n setPaymentErrorMessage(\n 'Payment verification timed out. Please check your billing history for the payment status.'\n );\n setMode('error');\n },\n });\n\n // Fetch billing accounts\n const {\n data: accountsData,\n loading: accountsLoading,\n refetch: refetchAccounts,\n } = useGetBillingAccountsCheckoutQuery({});\n\n // Fetch plan if purchasing a plan\n const {\n data: planData,\n loading: planLoading,\n // error: planError - available but not displayed (loading/empty states suffice)\n } = useGetPlanCheckoutQuery({\n variables: { id: itemId! },\n skip: purchaseType !== 'PLAN' || !itemId,\n });\n\n // Fetch addon if purchasing an addon\n const { data: addonData, loading: addonLoading } = useGetSelectedAddonCheckoutQuery({\n variables: { addonIDs: itemId ? [itemId] : [] },\n skip: purchaseType !== 'ADDON' || !itemId || isStoreCheckout, // Skip for store checkout\n });\n\n // Fetch store order (for store checkout)\n const { data: storeOrderData } = useGetStoreOrderCheckoutQuery({\n variables: { id: storeOrderId! },\n skip: !isStoreCheckout || !storeOrderId,\n });\n\n // Fetch saved payment methods for selected billing account\n const { data: paymentMethodsData, loading: paymentMethodsLoading } =\n useGetPaymentMethodsCheckoutQuery({\n variables: { billingAccountId: checkout.billingAccount?.id! },\n skip: !checkout.billingAccount?.id,\n });\n\n // Fetch active subscriptions for addon purchases (needed to select which subscription to attach addon to)\n // Skip for store checkout - store items don't require an active subscription\n const { data: subscriptionsData, loading: subscriptionsLoading } =\n useGetActiveSubscriptionsCheckoutQuery({\n variables: { billingAccountId: checkout.billingAccount?.id! },\n skip: !checkout.billingAccount?.id || purchaseType !== 'ADDON' || isStoreCheckout,\n });\n\n // Memoized subscriptions list\n const activeSubscriptions = useMemo(() => {\n return subscriptionsData?.getActiveSubscriptions ?? [];\n }, [subscriptionsData]);\n\n // Selected subscription for addon purchases\n const selectedSubscription = useMemo(() => {\n if (!checkout.selectedSubscriptionId || activeSubscriptions.length === 0) return null;\n return (\n activeSubscriptions.find((s: { id: string }) => s.id === checkout.selectedSubscriptionId) ??\n null\n );\n }, [checkout.selectedSubscriptionId, activeSubscriptions]);\n\n // Fetch credit cost from backend (for credits purchase)\n // Use current quantity from items, or default to 100 for initial query\n // Query in selected currency to get correct pricing\n const creditQuantity = checkout.items[0]?.type === 'CREDITS' ? checkout.items[0].quantity : 100;\n const { data: creditCostData, loading: creditCostLoading } = useGetCostOfCreditsCheckoutQuery({\n variables: { creditAmount: creditQuantity, currency: checkout.selectedCurrency || 'USD' },\n skip: purchaseType !== 'CREDITS',\n });\n\n // Calculate cost per credit from backend response\n const costPerCredit = useMemo(() => {\n if (creditCostData?.getCostOfCredits?.amount && creditQuantity > 0) {\n return creditCostData.getCostOfCredits.amount / creditQuantity;\n }\n return 0.01; // Default: 100 credits = $1\n }, [creditCostData, creditQuantity]);\n\n // Memoized saved payment methods\n const savedPaymentMethods = useMemo<SavedPaymentMethod[]>(() => {\n return paymentMethodsData?.getPaymentMethods ?? [];\n }, [paymentMethodsData]);\n\n // Memoized billing accounts list\n const billingAccounts = useMemo<CheckoutBillingAccount[]>(() => {\n return accountsData?.getBillingAccountsByOrg ?? [];\n }, [accountsData]);\n\n // Extract billing country from selected billing account's first billing address\n // This is used to restrict currency and payment provider options\n const billingCountry = useMemo<string | undefined>(() => {\n if (!checkout.billingAccount) return undefined;\n\n // Find the full account data with billing addresses\n const fullAccount = billingAccounts.find((acc) => acc.id === checkout.billingAccount?.id);\n const billingAddresses = fullAccount?.billingAddresses;\n\n if (billingAddresses && billingAddresses.length > 0) {\n return billingAddresses[0]?.country || undefined;\n }\n return undefined;\n }, [checkout.billingAccount, billingAccounts]);\n\n // Track if initial provider selection has been done for this billing country\n const [initialProviderSet, setInitialProviderSet] = useState<string | null>(null);\n\n // Auto-select appropriate currency based on billing country and billing account currency\n // - India: INR only (for Zoho Books GST invoice compatibility)\n // - International: Prefer billing account currency, or USD (INR not allowed for Stripe invoice compatibility)\n useEffect(() => {\n if (!billingCountry) return;\n\n if (billingCountry === 'IN') {\n // Indian billing: Force INR currency\n if (checkout.selectedCurrency !== 'INR') {\n checkout.setCurrency('INR');\n }\n // Auto-select Razorpay ONLY on first load for this billing country (don't override user's choice)\n if (\n razorpayEnabled &&\n initialProviderSet !== billingCountry &&\n checkout.selectedProvider !== 'CREDITS'\n ) {\n checkout.setPaymentProvider('RAZORPAY');\n setInitialProviderSet(billingCountry);\n }\n } else {\n // International billing: Force non-INR currency\n if (checkout.selectedCurrency === 'INR') {\n // Prefer billing account's currency if it's not INR, otherwise default to USD\n const accountCurrency = checkout.billingAccount?.currency;\n const preferredCurrency =\n accountCurrency && accountCurrency !== 'INR' ? accountCurrency : 'USD';\n checkout.setCurrency(preferredCurrency);\n }\n // For international, Stripe is the only option (Razorpay is India-only)\n if (checkout.selectedProvider === 'RAZORPAY') {\n checkout.setPaymentProvider('STRIPE');\n setInitialProviderSet(billingCountry);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n billingCountry,\n checkout.selectedCurrency,\n checkout.selectedProvider,\n checkout.setCurrency,\n checkout.setPaymentProvider,\n checkout.billingAccount?.currency,\n razorpayEnabled,\n initialProviderSet,\n ]);\n\n // Auto-select billing account's currency when billing account changes (for international)\n useEffect(() => {\n if (!checkout.billingAccount?.currency || billingCountry === 'IN') return;\n\n const accountCurrency = checkout.billingAccount.currency;\n // Update to billing account's currency if it's different and valid (not INR for international)\n if (accountCurrency !== 'INR' && checkout.selectedCurrency !== accountCurrency) {\n checkout.setCurrency(accountCurrency);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n checkout.billingAccount?.id,\n checkout.billingAccount?.currency,\n billingCountry,\n checkout.selectedCurrency,\n checkout.setCurrency,\n ]);\n\n // Auto-select payment method with priority: Credits > Saved Card > New Card\n useEffect(() => {\n // Skip if already manually selected something (not AUTO or null)\n if (checkout.selectedProvider !== 'AUTO' && checkout.selectedProvider !== null) {\n return; // Already selected, don't override user choice\n }\n\n const hasEnoughCredits = checkout.availableCredits >= checkout.total;\n\n // Priority 1: Credits (if available and sufficient)\n if (checkout.canPayWithCredits && hasEnoughCredits) {\n checkout.setPaymentProvider('CREDITS');\n checkout.setSelectedPaymentMethodId(null);\n return;\n }\n\n // Priority 2: Default saved card\n if (savedPaymentMethods.length > 0 && !checkout.selectedPaymentMethodId) {\n const defaultMethod = savedPaymentMethods.find((pm) => pm.isDefault && pm.isVerified);\n const firstVerified = savedPaymentMethods.find((pm) => pm.isVerified);\n const methodToSelect = defaultMethod || firstVerified;\n\n if (methodToSelect) {\n checkout.setSelectedPaymentMethodId(methodToSelect.id);\n // Auto-set provider based on card type\n if (methodToSelect.razorpayPaymentMethodId) {\n checkout.setPaymentProvider('RAZORPAY');\n } else if (methodToSelect.stripePaymentMethodId) {\n checkout.setPaymentProvider('STRIPE');\n }\n return;\n }\n }\n\n // Priority 3: New card (auto-select provider based on country)\n // This is already handled by the currency auto-selection effect above\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Auto-select on mount with specific dependencies\n }, [\n savedPaymentMethods.length,\n checkout.canPayWithCredits,\n checkout.availableCredits,\n checkout.total,\n ]);\n\n // Track if item was already added to prevent duplicates\n const [itemAdded, setItemAdded] = useState(false);\n\n useEffect(() => {\n if (!isStoreCheckout || itemAdded || !storeOrderData?.getStoreOrder) {\n return;\n }\n\n const orderCurrency = normalizeStoreOrderCurrency(storeOrderData.getStoreOrder.currency);\n if (checkout.selectedCurrency !== orderCurrency) {\n checkout.setCurrency(orderCurrency);\n }\n }, [isStoreCheckout, itemAdded, storeOrderData, checkout.selectedCurrency, checkout.setCurrency]);\n\n // Initialize checkout with items\n // Initialize seat count from plan minSeats when plan data loads\n useEffect(() => {\n if (purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT') {\n const minSeats = planData.getPlan.minSeats ?? 1;\n setSeatCount((prev) => (prev < minSeats ? minSeats : prev));\n }\n }, [planData, purchaseType]);\n\n // Recalculate checkout item when seat count changes for PER_SEAT plans\n useEffect(() => {\n if (purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT' && itemAdded) {\n setItemAdded(false); // triggers re-add with new seatCount\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [seatCount]);\n\n useEffect(() => {\n // Skip if already added items\n if (itemAdded) {\n return;\n }\n\n // Handle cart-based checkout (multiple addons from cart)\n // Wait for cart to hydrate before processing\n if (isCartCheckout && cartHydrated && cartItems.length > 0) {\n // Clear existing items first to prevent duplicates (React strict mode can run effects twice)\n checkout.clearItems();\n\n for (const cartItem of cartItems) {\n const addon = cartItem.addon;\n\n // Extract features from addon (using SubscriptionFeatures type with quota)\n const features =\n addon.features?.map((f) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits as Record<string, number | string | boolean> | undefined,\n })) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = (addon as { currencyPrices?: Record<string, number> })\n .currencyPrices;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n\n const item: CheckoutItem = {\n id: addon.id,\n type: 'ADDON',\n name: addon.name,\n description:\n typeof addon.context === 'object' && addon.context !== null\n ? (addon.context as { description?: string }).description\n : typeof addon.context === 'string'\n ? addon.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD: addon.price,\n currency: selectedCurrency,\n quantity: cartItem.quantity,\n features,\n metadata: { addonId: addon.id },\n };\n checkout.addItem(item);\n }\n setItemAdded(true);\n\n return;\n }\n\n if (purchaseType === 'PLAN' && planData?.getPlan) {\n const plan = planData.getPlan;\n\n // Extract features from plan\n const features =\n plan.features?.map(\n (f: {\n id: string;\n quota?: { id: string; name: string; limits?: Record<string, unknown> };\n }) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits,\n })\n ) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = plan.currencyPrices as Record<\n string,\n number | { perSeat?: number }\n > | null;\n const isPerSeat = plan.pricingModel === 'PER_SEAT';\n\n let priceInSelectedCurrency: number;\n if (isPerSeat && plan.pricePerSeat) {\n // PER_SEAT: per-seat rate × seat count\n const currencyEntry = currencyPrices?.[selectedCurrency];\n const perSeatRate =\n typeof currencyEntry === 'object' && currencyEntry?.perSeat\n ? currencyEntry.perSeat\n : plan.pricePerSeat;\n priceInSelectedCurrency = perSeatRate * seatCount;\n } else {\n const currencyEntry = currencyPrices?.[selectedCurrency];\n priceInSelectedCurrency = typeof currencyEntry === 'number' ? currencyEntry : plan.price;\n }\n\n const resolvedSeatCount = isPerSeat ? seatCount : 1;\n\n const item: CheckoutItem = {\n id: plan.id,\n type: 'PLAN',\n name: plan.name,\n description:\n typeof plan.context === 'object' && plan.context !== null\n ? (plan.context as { description?: string }).description\n : typeof plan.context === 'string'\n ? plan.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD:\n isPerSeat && plan.pricePerSeat ? plan.pricePerSeat * resolvedSeatCount : plan.price,\n currency: selectedCurrency,\n quantity: resolvedSeatCount,\n features,\n metadata: {\n planId: plan.id,\n duration: plan.duration,\n seatCount: isPerSeat ? resolvedSeatCount : undefined,\n },\n };\n\n checkout.addItem(item);\n setItemAdded(true);\n } else if (purchaseType === 'ADDON' && !isCartCheckout && addonData?.getSelectedAddons?.[0]) {\n const addon = addonData.getSelectedAddons[0];\n\n // Extract features from addon\n const features =\n addon.features?.map(\n (f: {\n id: string;\n quota?: { id: string; name: string; limits?: Record<string, unknown> };\n }) => ({\n id: f.quota?.id || f.id,\n name: f.quota?.name || 'Feature',\n limits: f.quota?.limits,\n })\n ) || [];\n\n // Use stored currency price if available, otherwise fallback to base USD price\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const currencyPrices = addon.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n\n const item: CheckoutItem = {\n id: addon.id,\n type: 'ADDON',\n name: addon.name,\n description:\n typeof addon.context === 'object' && addon.context !== null\n ? (addon.context as { description?: string }).description\n : typeof addon.context === 'string'\n ? addon.context\n : undefined,\n price: priceInSelectedCurrency,\n priceUSD: addon.price,\n currency: selectedCurrency,\n quantity: locationState?.quantity ?? 1,\n features,\n metadata: { addonId: addon.id },\n };\n checkout.addItem(item);\n setItemAdded(true);\n } else if (isStoreCheckout && storeOrderData?.getStoreOrder) {\n // Load store order items into checkout\n const storeOrder = storeOrderData.getStoreOrder;\n const items = buildStoreOrderCheckoutItems(storeOrder);\n\n for (const item of items) {\n checkout.addItem(item);\n }\n setItemAdded(true);\n } else if (purchaseType === 'CREDITS') {\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n const item: CheckoutItem = {\n id: 'credits-purchase',\n type: 'CREDITS',\n name: 'Credits',\n description: 'Purchase credits for your account',\n price: costPerCredit, // Use actual cost per credit from backend (in selected currency)\n currency: selectedCurrency,\n quantity: 100, // Default amount\n };\n checkout.addItem(item);\n setItemAdded(true);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n purchaseType,\n planData,\n addonData,\n storeOrderData,\n checkout.addItem,\n checkout.clearItems,\n locationState?.quantity,\n itemAdded,\n isCartCheckout,\n isStoreCheckout,\n cartItems,\n cartHydrated,\n costPerCredit,\n checkout.selectedCurrency, // Re-add items when currency changes to use correct prices\n ]);\n\n // Update store-order item prices when a payment currency change requires conversion.\n // If the persisted order currency already matches the selected currency this is a no-op.\n useEffect(() => {\n if (!isStoreCheckout || !itemAdded || checkout.conversionRate <= 1) return;\n\n for (const item of checkout.items) {\n if (item.type === 'ORDER' && item.currency !== checkout.selectedCurrency) {\n const convertedPrice = item.price * checkout.conversionRate;\n checkout.updateItemPrice(item.id, convertedPrice, checkout.selectedCurrency);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- checkout.items intentionally excluded to avoid infinite loop\n }, [\n isStoreCheckout,\n itemAdded,\n checkout.conversionRate,\n checkout.selectedCurrency,\n checkout.updateItemPrice,\n ]);\n\n // Update item price when backend credit cost changes (after item is already added)\n // This handles cases where the rate might differ based on quantity or currency\n useEffect(() => {\n if (purchaseType === 'CREDITS' && itemAdded && costPerCredit > 0) {\n const currentItem = checkout.items.find((i) => i.id === 'credits-purchase');\n // Only update if price actually changed\n if (currentItem && currentItem.price !== costPerCredit) {\n checkout.updateItemPrice('credits-purchase', costPerCredit);\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [purchaseType, itemAdded, costPerCredit, checkout.items, checkout.updateItemPrice]);\n\n // Update item prices when currency changes (for plans and addons with fixed currencyPrices)\n // This handles mid-checkout currency changes by updating prices from stored currencyPrices\n useEffect(() => {\n if (!itemAdded || checkout.items.length === 0) return;\n\n const selectedCurrency = checkout.selectedCurrency || 'USD';\n\n for (const item of checkout.items) {\n if (item.type === 'PLAN' && planData?.getPlan) {\n const currencyPrices = planData.getPlan.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency =\n currencyPrices?.[selectedCurrency] ?? planData.getPlan.price;\n // Update both price AND currency so conversion check works correctly\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n } else if (item.type === 'ADDON') {\n // For single addon checkout\n if (!isCartCheckout && addonData?.getSelectedAddons?.[0]) {\n const addon = addonData.getSelectedAddons[0];\n const currencyPrices = addon.currencyPrices as Record<string, number> | null;\n const priceInSelectedCurrency = currencyPrices?.[selectedCurrency] ?? addon.price;\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n }\n // For cart checkout, find the addon in cartItems\n if (isCartCheckout) {\n const cartItem = cartItems.find((ci) => ci.addon.id === item.id);\n if (cartItem) {\n const currencyPrices = (cartItem.addon as { currencyPrices?: Record<string, number> })\n .currencyPrices;\n const priceInSelectedCurrency =\n currencyPrices?.[selectedCurrency] ?? cartItem.addon.price;\n if (item.price !== priceInSelectedCurrency || item.currency !== selectedCurrency) {\n checkout.updateItemPrice(item.id, priceInSelectedCurrency, selectedCurrency);\n }\n }\n }\n }\n // CREDITS are handled by the credit cost effect above\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n checkout.selectedCurrency,\n itemAdded,\n checkout.items,\n checkout.updateItemPrice,\n planData,\n addonData,\n cartItems,\n isCartCheckout,\n ]);\n\n // Set default billing account\n // Priority: 1. Location state (for upgrade flows), 2. localStorage (user's last selection), 3. First account\n useEffect(() => {\n if (billingAccounts.length > 0 && !checkout.billingAccount) {\n // 1. If this is an upgrade, find and select the specific billing account from location state\n if (locationState?.billingAccountId) {\n const targetAccount = billingAccounts.find(\n (acc) => acc.id === locationState.billingAccountId\n );\n if (targetAccount) {\n checkout.setBillingAccount(targetAccount);\n return;\n }\n }\n\n // 2. Check localStorage for previously selected billing account (set from /overview page)\n if (orgId) {\n const storedAccountId = getStoredBillingAccountId(orgId);\n if (storedAccountId) {\n const storedAccount = billingAccounts.find((acc) => acc.id === storedAccountId);\n if (storedAccount) {\n checkout.setBillingAccount(storedAccount);\n return;\n }\n }\n }\n\n // 3. Default: select first account\n checkout.setBillingAccount(billingAccounts[0]);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Using specific checkout properties is intentional for granular updates\n }, [\n billingAccounts,\n checkout.billingAccount,\n checkout.setBillingAccount,\n locationState?.billingAccountId,\n orgId,\n ]);\n\n // Determine if billing account selector should be locked (for upgrade/downgrade flows)\n const isBillingAccountLocked = Boolean(\n locationState?.upgradeFromSubscriptionId || locationState?.downgradeFromSubscriptionId\n );\n\n // Redirect to addons page if cart is empty for cart checkout.\n // Navigation must happen after render to avoid React setState-in-render warnings.\n useEffect(() => {\n if (isCartCheckout && cartHydrated && cartItems.length === 0 && !itemAdded) {\n navigateTo('/addons', { replace: true });\n }\n }, [cartHydrated, cartItems.length, isCartCheckout, itemAdded, navigateTo]);\n\n const nativeCheckout = useNativeCheckout({\n billingAccountId: checkout.billingAccount?.id,\n purchaseType,\n productId: itemId,\n });\n\n const handleProceedToPayment = useCallback(async () => {\n if (!checkout.billingAccount) {\n return;\n }\n\n // Gate: require complete billing details before payment.\n // Skip once after the CompleteBillingAccountModal saves — Apollo cache still holds stale\n // contactNumber/billingAddresses because the mutation selection doesn't return those fields.\n const skipGate = bypassBillingGate.current;\n bypassBillingGate.current = false;\n if (!skipGate && !isBillingAccountComplete(checkout.billingAccount)) {\n setShowCompleteAccountModal(true);\n return;\n }\n\n setPaymentErrorMessage(null);\n\n // Capture purchase details before payment (for success page)\n const previousBalance = checkout.billingAccount.creditAmount ?? 0;\n const purchasedItems = [...checkout.items];\n const purchaseTotal = checkout.total;\n\n const response = await checkout.initiatePayment();\n\n if (response.success) {\n emit('billing.checkout.initiated', {\n route: '/billing/checkout',\n entityId: response.paymentId ?? response.orderId,\n source: 'checkout',\n amount: response.total || purchaseTotal,\n currency: response.currency || checkout.selectedCurrency,\n });\n // For credit payments, go to processing mode and poll for transaction status\n if (checkout.selectedProvider === 'CREDITS') {\n emit('billing.credits.spent', {\n route: '/billing/checkout',\n entityId: response.orderId,\n source: 'checkout',\n amount: purchaseTotal,\n currency: 'CREDITS',\n });\n // Store purchase details for success page\n setPurchaseDetails({\n items: purchasedItems,\n total: purchaseTotal,\n billingAccountName: checkout.billingAccount.name,\n billingAccountId: checkout.billingAccount.id,\n previousBalance,\n newBalance: previousBalance - purchaseTotal,\n paymentMethod: 'credits',\n currency: 'Credits', // Credit payments use credits as currency\n transactionId: response.orderId, // This is creditTransactionID from spendCredits\n });\n\n // Set payment type for polling and start verification\n setPollingPaymentType('credits');\n setPaymentResponse({\n paymentId: response.orderId, // creditTransactionID from spendCredits\n });\n setMode('processing');\n return;\n }\n\n // For card payments, proceed to payment form\n // Store partial details (will be completed after payment confirmation)\n setPurchaseDetails({\n items: purchasedItems,\n total: response.total || purchaseTotal, // Use response total which includes tax\n billingAccountName: checkout.billingAccount.name,\n billingAccountId: checkout.billingAccount.id,\n previousBalance,\n newBalance: previousBalance, // Card payment doesn't affect credits\n paymentMethod: 'card',\n currency: response.currency || checkout.selectedCurrency, // Use actual currency from response\n transactionId: response.paymentId, // Backend payment ID\n });\n\n setPollingPaymentType('card');\n setPaymentResponse({\n clientSecret: response.clientSecret,\n orderId: response.orderId, // Gateway order ID (for Razorpay)\n razorpayKeyId: response.razorpayKeyId,\n razorpayCustomerId: response.razorpayCustomerId, // For Razorpay saved cards\n paymentId: response.paymentId, // Backend payment ID for polling\n paymentComplete: response.paymentComplete, // For saved card one-click payments\n prefillName: response.prefillName,\n prefillEmail: response.prefillEmail,\n prefillContact: response.prefillContact,\n total: response.total, // Total in target currency (from backend, e.g., INR amount)\n currency: response.currency, // Currency code from backend\n });\n\n // If payment completed immediately (saved card), go to processing for verification\n if (response.paymentComplete) {\n setMode('processing');\n } else {\n setMode('payment');\n }\n } else {\n emit('billing.checkout.failed', {\n route: '/billing/checkout',\n source: 'checkout',\n reason: response.error || 'Payment initiation failed',\n });\n setPaymentErrorMessage(response.error || 'Payment initiation failed');\n setMode('error');\n }\n }, [checkout, emit]);\n\n const handlePaymentSuccess = useCallback(\n (_gatewayPaymentId: string) => {\n emit('billing.payment.succeeded', {\n route: '/billing/checkout',\n entityId: paymentResponse?.paymentId ?? paymentResponse?.orderId,\n source: 'checkout',\n });\n // Keep using the backend payment ID (orderId) that was already set\n // The _gatewayPaymentId is for reference only, not for our polling\n setPaymentResponse((prev) => {\n return prev; // Keep existing paymentId (orderId from initiatePayment)\n });\n setMode('processing');\n },\n [emit, paymentResponse?.orderId, paymentResponse?.paymentId]\n );\n\n const handlePaymentError = useCallback(\n (error: string) => {\n emit('billing.payment.failed', {\n route: '/billing/checkout',\n entityId: paymentResponse?.paymentId ?? paymentResponse?.orderId,\n source: 'checkout',\n reason: error,\n });\n setPaymentErrorMessage(error);\n setMode('error');\n },\n [emit, paymentResponse?.orderId, paymentResponse?.paymentId]\n );\n\n const handleCreditsAmountChange = useCallback(\n (amount: number) => {\n checkout.updateItemQuantity('credits-purchase', amount);\n },\n [checkout]\n );\n\n if (!permissions.canProcessPayment) {\n return <AccessDenied message=\"You don't have permission to make purchases.\" />;\n }\n\n if (isNativeIAPAvailable()) {\n return (\n <NativeCheckoutView\n purchaseType={purchaseType}\n productId={itemId}\n billingAccountId={checkout.billingAccount?.id}\n nativeCheckout={nativeCheckout}\n onBack={() => navigateTo('dashboard')}\n />\n );\n }\n\n const isLoading =\n accountsLoading ||\n (planLoading && purchaseType === 'PLAN') ||\n (addonLoading && purchaseType === 'ADDON' && !isCartCheckout) ||\n (isCartCheckout && !cartHydrated);\n\n if (isCartCheckout && cartHydrated && cartItems.length === 0 && !itemAdded) {\n return null;\n }\n\n // Get page title based on purchase type\n const getPageTitle = () => {\n if (isCartCheckout) {\n const addonCount = checkout.items.length;\n return `Purchase ${addonCount} Add-on${addonCount !== 1 ? 's' : ''}`;\n }\n switch (purchaseType) {\n case 'CREDITS':\n return 'Buy Credits';\n case 'PLAN':\n return 'Subscribe to Plan';\n case 'ADDON':\n return 'Purchase Add-on';\n default:\n return 'Checkout';\n }\n };\n\n const getPageIcon = () => {\n switch (purchaseType) {\n case 'CREDITS':\n return <Coins className=\"size-6\" />;\n case 'PLAN':\n return <Package className=\"size-6\" />;\n case 'ADDON':\n return <Blocks className=\"size-6\" />;\n default:\n return <ShoppingCart className=\"size-6\" />;\n }\n };\n\n // Render loading state\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <Loader2 className=\"size-8 animate-spin mx-auto text-primary\" />\n <p className=\"text-muted-foreground\">\n {tr('billing.checkout.loadingCheckout', 'Loading checkout...')}\n </p>\n </div>\n </div>\n );\n }\n\n // Render success state\n if (mode === 'success') {\n // Format amount based on payment method and currency\n const formatAmount = (amount: number) => {\n if (!purchaseDetails) return `${amount.toFixed(2)}`;\n\n const currency = purchaseDetails.currency;\n\n // For credits, show \"X.XX Credits\"\n if (currency === 'Credits') {\n return `${amount.toFixed(2)} Credits`;\n }\n\n // For real currencies, show with symbol\n const currencySymbols: Record<string, string> = {\n INR: '₹',\n USD: '$',\n EUR: '€',\n GBP: '£',\n };\n const symbol = currencySymbols[currency] || currency + ' ';\n return `${symbol}${amount.toFixed(2)}`;\n };\n\n // Keep formatCredits for credit balance section\n const formatCredits = (amount: number) => `${amount.toFixed(2)} Credits`;\n\n return (\n <div className=\"max-w-2xl mx-auto p-6 space-y-6\">\n {/* Success Header */}\n <div className=\"text-center space-y-4\">\n <div className=\"inline-flex p-4 rounded-full bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-12\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.paymentSuccessful', 'Payment Successful!')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {tr(\n 'billing.checkout.purchaseCompleted',\n 'Your purchase has been completed successfully.'\n )}\n </p>\n </div>\n </div>\n\n {/* Purchase Details Card */}\n {purchaseDetails && (\n <div className=\"bg-card border border-border rounded-lg overflow-hidden\">\n {/* Items Purchased */}\n <div className=\"p-4 border-b border-border\">\n <h3 className=\"font-semibold text-foreground mb-3 flex items-center gap-2\">\n <Receipt className=\"size-4\" />\n {tr('billing.checkout.itemsPurchased', 'Items Purchased')}\n </h3>\n <div className=\"space-y-2\">\n {purchaseDetails.items.map((item) => (\n <div key={item.id} className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n {item.type === 'PLAN' && <Package className=\"size-4 text-accent-blue\" />}\n {item.type === 'ADDON' && <Blocks className=\"size-4 text-accent-purple\" />}\n {item.type === 'CREDITS' && (\n <Coins className=\"size-4 text-status-warning-text\" />\n )}\n {item.type === 'ORDER' && (\n <ShoppingCart className=\"size-4 text-status-success-text\" />\n )}\n <span className=\"text-foreground\">{item.name}</span>\n {item.quantity > 1 && (\n <span className=\"text-xs text-muted-foreground\">x{item.quantity}</span>\n )}\n </div>\n <span className=\"text-muted-foreground\">\n {formatAmount(item.price * item.quantity)}\n </span>\n </div>\n ))}\n </div>\n </div>\n\n {/* Payment Info */}\n <div className=\"p-4 border-b border-border bg-muted/30\">\n <div className=\"grid grid-cols-2 gap-4\">\n {/* Payment Method */}\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.paymentMethod', 'Payment Method')}\n </p>\n <div className=\"flex items-center gap-2\">\n {purchaseDetails.paymentMethod === 'credits' ? (\n <>\n <Wallet className=\"size-4 text-status-warning-text\" />\n <span className=\"font-medium text-foreground\">\n {tr('billing.checkout.credits', 'Credits')}\n </span>\n </>\n ) : (\n <>\n <CreditCard className=\"size-4 text-accent-blue\" />\n <span className=\"font-medium text-foreground\">\n {tr('billing.checkout.card', 'Card')}\n </span>\n </>\n )}\n </div>\n </div>\n {/* Total */}\n <div className=\"text-right\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.totalPaid', 'Total Paid')}\n </p>\n <p className=\"font-bold text-lg text-foreground\">\n {formatAmount(purchaseDetails.total)}\n </p>\n </div>\n </div>\n </div>\n\n {/* Credit Balance (only for credit payments) */}\n {purchaseDetails.paymentMethod === 'credits' && (\n <div className=\"p-4 border-b border-border\">\n <h3 className=\"font-semibold text-foreground mb-3 flex items-center gap-2\">\n <Wallet className=\"size-4\" />\n {tr('billing.checkout.creditBalance', 'Credit Balance')}\n </h3>\n <div className=\"flex items-center gap-4\">\n <div className=\"flex-1 text-center p-3 rounded-lg bg-muted/50\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.previousBalance', 'Previous Balance')}\n </p>\n <p className=\"font-semibold text-foreground\">\n {formatCredits(purchaseDetails.previousBalance)}\n </p>\n </div>\n <ArrowRight className=\"size-5 text-muted-foreground shrink-0\" />\n <div className=\"flex-1 text-center p-3 rounded-lg bg-status-success-bg-subtle\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.newBalance', 'New Balance')}\n </p>\n <p className=\"font-semibold text-status-success-text\">\n {formatCredits(purchaseDetails.newBalance)}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Billing Account Info */}\n <div className=\"p-4 bg-muted/20\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </p>\n <p className=\"font-medium text-foreground\">\n {purchaseDetails.billingAccountName}\n </p>\n </div>\n {purchaseDetails.transactionId && (\n <div className=\"text-right\">\n <p className=\"text-xs text-muted-foreground mb-1\">\n {tr('billing.checkout.transactionId', 'Transaction ID')}\n </p>\n <p className=\"font-mono text-xs text-muted-foreground\">\n {purchaseDetails.transactionId.slice(0, 8)}...\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Action Buttons */}\n <div className=\"flex flex-col sm:flex-row gap-3 justify-center pt-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/overview')}\n className=\"px-6 py-3 text-sm font-medium bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors\"\n >\n {tr('billing.checkout.backToOverview', 'Back to Overview')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/subscriptions')}\n className=\"px-6 py-3 text-sm font-medium border border-border text-foreground rounded-lg hover:bg-muted transition-colors\"\n >\n {tr('billing.checkout.viewSubscriptions', 'View Subscriptions')}\n </button>\n </div>\n </div>\n );\n }\n\n // Render error state\n if (mode === 'error') {\n return (\n <div className=\"max-w-lg mx-auto p-6\">\n <div className=\"text-center space-y-6\">\n <div className=\"inline-flex p-4 rounded-full bg-destructive/10 text-destructive\">\n <XCircle className=\"size-12\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.paymentFailed', 'Payment Failed')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {paymentErrorMessage ||\n pollingError ||\n checkout.error ||\n tr('billing.checkout.genericError', 'Something went wrong. Please try again.')}\n </p>\n </div>\n <div className=\"flex gap-3 justify-center\">\n <button\n type=\"button\"\n onClick={() => navigateTo(-1)}\n className=\"px-4 py-2 rounded-lg border border-border hover:bg-muted\"\n >\n {tr('billing.checkout.goBack', 'Go Back')}\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setMode('select');\n setPaymentErrorMessage(null);\n checkout.reset();\n }}\n className=\"px-4 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90\"\n >\n {tr('billing.checkout.tryAgain', 'Try Again')}\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n // Render processing state (waiting for payment confirmation)\n if (mode === 'processing') {\n const formatTime = (ms: number) => {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;\n };\n\n return (\n <div className=\"max-w-lg mx-auto p-6\">\n <div className=\"text-center space-y-6\">\n <div className=\"inline-flex p-4 rounded-full bg-primary/10 text-primary\">\n <Loader2 className=\"size-12 animate-spin\" />\n </div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">\n {tr('billing.checkout.verifyingPayment', 'Verifying Payment')}\n </h1>\n <p className=\"text-muted-foreground mt-2\">\n {tr(\n 'billing.checkout.verifyingPaymentDescription',\n 'Please wait while we confirm your payment...'\n )}\n </p>\n </div>\n\n {/* Elapsed time */}\n <div className=\"bg-muted/50 rounded-lg p-4\">\n <p className=\"text-sm text-muted-foreground\">\n {tr('billing.checkout.timeElapsed', 'Time elapsed:')}{' '}\n <span className=\"font-mono font-medium text-foreground\">\n {formatTime(elapsedTime)}\n </span>\n </p>\n <p className=\"text-xs text-muted-foreground mt-1\">\n {tr(\n 'billing.checkout.keepPageOpen',\n \"This may take a few moments. Please don't close this page.\"\n )}\n </p>\n </div>\n\n {/* Progress indicator */}\n <div className=\"w-full bg-muted rounded-full h-2 overflow-hidden\">\n <div\n className=\"bg-primary h-2 rounded-full transition-all duration-1000\"\n style={{ width: `${Math.min((elapsedTime / 300000) * 100, 100)}%` }}\n />\n </div>\n\n {/* Cancel button - only show after 30 seconds */}\n {elapsedTime > 30000 && (\n <button\n type=\"button\"\n onClick={() => {\n setMode('error');\n setPaymentErrorMessage(\n 'Payment verification was cancelled. Please check your billing history.'\n );\n }}\n className=\"text-sm text-muted-foreground hover:text-foreground underline\"\n >\n {tr('billing.checkout.cancelAndCheckHistory', 'Cancel and check billing history')}\n </button>\n )}\n </div>\n </div>\n );\n }\n\n // Render payment form\n if (mode === 'payment' && paymentResponse) {\n // Format currency for display\n const formatDisplayCurrency = (amount: number, currencyCode: string) => {\n const symbols: Record<string, string> = { INR: '₹', USD: '$', EUR: '€', GBP: '£' };\n const symbol = symbols[currencyCode] || currencyCode + ' ';\n return `${symbol}${amount.toFixed(2)}`;\n };\n\n const displayCurrency = paymentResponse.currency || checkout.selectedCurrency;\n const displayTotal = paymentResponse.total ?? checkout.total;\n\n return (\n <div className=\"max-w-2xl mx-auto p-4 sm:p-6 space-y-6\">\n <button\n type=\"button\"\n onClick={() => setMode('select')}\n className=\"flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('billing.checkout.backToCheckout', 'Back to checkout')}\n </button>\n\n <PageHeader\n title={tr('billing.checkout.completePayment', 'Complete Payment')}\n description={tr(\n 'billing.checkout.completePaymentDescription',\n 'Enter your payment details to complete the purchase'\n )}\n />\n\n {/* Payment Summary with correct tax calculation */}\n <div className=\"rounded-lg border border-border bg-card p-4 space-y-4\">\n <h3 className=\"font-semibold text-foreground flex items-center gap-2\">\n <Receipt className=\"size-4\" />\n {tr('billing.checkout.paymentSummary', 'Payment Summary')}\n </h3>\n\n {/* Billing Account Info */}\n {checkout.billingAccount && (\n <div className=\"p-3 bg-muted/30 rounded-lg space-y-1\">\n <div className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </div>\n <div className=\"font-medium text-foreground\">{checkout.billingAccount.name}</div>\n <div className=\"text-sm text-muted-foreground\">{checkout.billingAccount.email}</div>\n </div>\n )}\n\n {/* Subscription Info (for addon purchases) */}\n {purchaseType === 'ADDON' && checkout.selectedSubscriptionId && selectedSubscription && (\n <div className=\"p-3 bg-muted/30 rounded-lg space-y-1\">\n <div className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {tr('billing.checkout.addingToSubscription', 'Adding to Subscription')}\n </div>\n <div className=\"font-medium text-foreground\">\n {selectedSubscription.plan?.name ||\n tr('billing.checkout.subscription', 'Subscription')}\n </div>\n {selectedSubscription.plan?.product?.name && (\n <div className=\"text-sm text-muted-foreground\">\n {selectedSubscription.plan.product.name}\n </div>\n )}\n </div>\n )}\n\n {/* Price Breakdown */}\n <div className=\"space-y-2 text-sm\">\n {/* Calculate display values correctly */}\n {(() => {\n const taxRate = checkout.taxRate;\n // For non-USD: calculate subtotal and tax from the total\n const calcSubtotal = taxRate > 0 ? displayTotal / (1 + taxRate) : displayTotal;\n const calcTax = taxRate > 0 ? displayTotal - calcSubtotal : 0;\n\n return (\n <>\n {/* Subtotal */}\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {tr('billing.checkout.subtotal', 'Subtotal')}\n </span>\n <span className=\"text-foreground\">\n {formatDisplayCurrency(calcSubtotal, displayCurrency)}\n </span>\n </div>\n {/* Discount */}\n {checkout.discountAmount > 0 && (\n <div className=\"flex justify-between text-status-success-text\">\n <span>{tr('billing.checkout.discount', 'Discount')}</span>\n <span>\n -{formatDisplayCurrency(checkout.discountAmount, displayCurrency)}\n </span>\n </div>\n )}\n {/* Tax */}\n {calcTax > 0 && (\n <div className=\"flex justify-between\">\n <span className=\"text-muted-foreground\">\n {checkout.taxType || tr('billing.checkout.tax', 'Tax')} (\n {(taxRate * 100).toFixed(0)}%)\n </span>\n <span className=\"text-foreground\">\n {formatDisplayCurrency(calcTax, displayCurrency)}\n </span>\n </div>\n )}\n </>\n );\n })()}\n {/* Divider */}\n <div className=\"border-t border-border my-2\" />\n {/* Total */}\n <div className=\"flex justify-between font-semibold\">\n <span className=\"text-foreground\">{tr('billing.checkout.total', 'Total')}</span>\n <span className=\"text-lg text-foreground\">\n {formatDisplayCurrency(displayTotal, displayCurrency)}\n </span>\n </div>\n </div>\n </div>\n\n {checkout.selectedProvider === 'STRIPE' &&\n paymentResponse.clientSecret &&\n (() => {\n // NOTE: Saved cards for Stripe are temporarily disabled on the backend\n // NOTE: Card saving disabled — re-enable when backend supports setup_future_usage on PaymentIntents\n // const stripeCards = savedPaymentMethods.filter(pm => pm.stripePaymentMethodId && pm.isVerified);\n\n return (\n <div className=\"rounded-lg border border-border bg-card overflow-hidden\">\n {/* Stripe Elements form for new card */}\n <div className=\"p-4 space-y-4\">\n {/* Save card checkbox - disabled until backend supports it */}\n {/* <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checkout.saveCard}\n onChange={(e) => checkout.setSaveCard(e.target.checked)}\n className=\"size-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-sm text-muted-foreground\">\n Save card for future purchases\n </span>\n </label> */}\n\n <StripePaymentForm\n clientSecret={paymentResponse.clientSecret}\n publishableKey={\n stripePublishableKey || providerConfig?.stripePublishableKey || ''\n }\n amount={Math.round((paymentResponse.total ?? checkout.total) * 100)}\n currency={paymentResponse.currency || checkout.selectedCurrency}\n onSuccess={handlePaymentSuccess}\n onError={handlePaymentError}\n onCancel={() => setMode('select')}\n isCompletingExistingPayment={!!checkout.selectedPaymentMethodId}\n />\n </div>\n </div>\n );\n })()}\n\n {checkout.selectedProvider === 'RAZORPAY' && paymentResponse.orderId && (\n <div className=\"rounded-lg border border-border bg-card overflow-hidden\">\n {/* Razorpay Payment Section */}\n <div className=\"p-4 space-y-4\">\n {/* Save card checkbox for new card payments */}\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={checkout.saveCard}\n onChange={(e) => checkout.setSaveCard(e.target.checked)}\n className=\"size-4 rounded border-border text-primary focus:ring-primary\"\n />\n <span className=\"text-sm text-muted-foreground\">\n Save card for future purchases\n </span>\n </label>\n\n <RazorpayPaymentButton\n orderId={paymentResponse.orderId}\n keyId={paymentResponse.razorpayKeyId || razorpayKey || ''}\n amount={Math.round((paymentResponse.total ?? checkout.total) * 100)}\n currency={paymentResponse.currency || 'INR'}\n customerId={paymentResponse.razorpayCustomerId}\n prefill={{\n name: paymentResponse.prefillName,\n email: paymentResponse.prefillEmail,\n contact: paymentResponse.prefillContact,\n }}\n onSuccess={(response) => handlePaymentSuccess(response.razorpay_payment_id)}\n onError={handlePaymentError}\n onCancel={() => setMode('select')}\n />\n </div>\n </div>\n )}\n </div>\n );\n }\n\n // Main checkout flow\n return (\n <div className=\"max-w-6xl mx-auto p-4 sm:p-6\">\n {/* Back button */}\n <button\n type=\"button\"\n onClick={() => navigateTo(-1)}\n className=\"flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground mb-4\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-6\">\n <div className=\"p-2 rounded-lg bg-primary/10 text-primary\">{getPageIcon()}</div>\n <div>\n <h1 className=\"text-2xl font-bold text-foreground\">{getPageTitle()}</h1>\n <p className=\"text-sm text-muted-foreground\">Complete your purchase securely</p>\n </div>\n </div>\n\n {/* Upgrade Banner */}\n {locationState?.upgradeFromSubscriptionId && locationState?.currentPlanName && (\n <div className=\"mb-6 p-4 rounded-lg border border-border-subtle bg-status-info-bg-subtle\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-full bg-status-info-bg-subtle\">\n <RefreshCw className=\"size-4 text-accent-blue\" />\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n Upgrading from:{' '}\n <span className=\"font-semibold\">{locationState.currentPlanName}</span>\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n Your current subscription will be marked as upgraded and quotas will transfer to the\n new plan.\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Downgrade Banner */}\n {locationState?.downgradeFromSubscriptionId && locationState?.currentPlanName && (\n <div className=\"mb-6 p-4 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle\">\n <div className=\"flex items-center gap-3\">\n <div className=\"p-2 rounded-full bg-status-warning-bg-subtle\">\n <RefreshCw className=\"size-4 text-status-warning-text\" />\n </div>\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-warning-text\">\n Downgrading from:{' '}\n <span className=\"font-semibold\">{locationState.currentPlanName}</span>\n </p>\n <p className=\"text-xs text-status-warning-text mt-0.5\">\n Your current plan stays active until it expires, you keep all its features until\n then. After expiry, only the new plan applies.\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Main content - responsive grid. On mobile the order summary appears first\n so users see the total before filling in payment details. */}\n <div className=\"grid gap-6 lg:grid-cols-5\">\n {/* Left column - Configuration (renders second on mobile) */}\n <div className=\"lg:col-span-3 space-y-6 order-2 lg:order-1\">\n {/* Credits amount (for credits purchase) */}\n {purchaseType === 'CREDITS' && checkout.items[0] && (\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6\">\n <CreditsAmountInput\n value={checkout.items[0].quantity}\n onChange={handleCreditsAmountChange}\n costPerCredit={costPerCredit}\n currency={checkout.selectedCurrency}\n disabled={creditCostLoading}\n />\n </div>\n )}\n\n {/* Billing Account Selection */}\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6 space-y-4\">\n <BillingAccountSelector\n accounts={billingAccounts}\n selectedAccountId={checkout.billingAccount?.id ?? null}\n onSelect={checkout.setBillingAccount}\n isLoading={accountsLoading}\n disabled={isBillingAccountLocked}\n disabledMessage={\n isBillingAccountLocked ? 'Billing account is locked for plan changes' : undefined\n }\n />\n\n {/* Subscription Selection - inline for addon purchases (only shows if multiple subs or no subs) */}\n {/* Skip subscription selection for store checkout - store items don't require an active subscription */}\n {purchaseType === 'ADDON' && !isStoreCheckout && checkout.billingAccount && (\n <SubscriptionSelector\n subscriptions={activeSubscriptions}\n selectedSubscriptionId={checkout.selectedSubscriptionId}\n onSelect={checkout.setSelectedSubscriptionId}\n isLoading={subscriptionsLoading}\n />\n )}\n </div>\n\n {/* Unified Payment Method Selection */}\n <div className=\"rounded-lg border border-border bg-card p-4 sm:p-6 space-y-4\">\n <UnifiedPaymentMethodSelector\n savedPaymentMethods={savedPaymentMethods}\n selectedPaymentMethodId={checkout.selectedPaymentMethodId}\n onSelectSavedCard={checkout.setSelectedPaymentMethodId}\n selectedProvider={checkout.selectedProvider}\n onSelectProvider={checkout.setPaymentProvider}\n stripeEnabled={stripeEnabled}\n razorpayEnabled={razorpayEnabled}\n canPayWithCredits={checkout.canPayWithCredits && checkout.hasEnoughCredits}\n availableCredits={checkout.availableCredits}\n totalAmount={checkout.subtotalUSD}\n billingCountry={billingCountry}\n saveCard={checkout.saveCard}\n onSaveCardChange={checkout.setSaveCard}\n autoRenewEnabled={purchaseType === 'PLAN' && checkout.autoRenew}\n isLoading={paymentMethodsLoading}\n />\n\n {/* Currency Info - Locked to Billing Account */}\n {checkout.selectedProvider !== 'CREDITS' && checkout.selectedProvider !== 'AUTO' && (\n <>\n <div className=\"border-t border-border\" />\n <div className=\"bg-muted/50 p-4 rounded-md\">\n <div className=\"flex items-start gap-3\">\n <svg\n className=\"size-5 text-muted-foreground mt-0.5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n />\n </svg>\n <div className=\"flex-1 text-sm\">\n <p className=\"font-medium text-foreground mb-1\">\n Currency: {checkout.selectedCurrency}\n </p>\n <p className=\"text-muted-foreground text-xs\">\n All prices are shown in{' '}\n <strong className=\"text-foreground\">{checkout.selectedCurrency}</strong>{' '}\n based on your billing account settings.\n {checkout.selectedCurrency === 'INR' && ' GST will be applied at checkout.'}\n </p>\n </div>\n </div>\n </div>\n </>\n )}\n\n {/* Seat count selector — only for PER_SEAT plans */}\n {purchaseType === 'PLAN' && planData?.getPlan?.pricingModel === 'PER_SEAT' && (\n <div className=\"border-t border-border pt-4\">\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-sm font-medium text-foreground\">Number of seats</label>\n {planData.getPlan.minSeats && (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Minimum {planData.getPlan.minSeats} seat\n {planData.getPlan.minSeats !== 1 ? 's' : ''} required\n </p>\n )}\n </div>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() =>\n setSeatCount((n) => Math.max(planData.getPlan?.minSeats ?? 1, n - 1))\n }\n disabled={seatCount <= (planData.getPlan.minSeats ?? 1)}\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 text-foreground\"\n >\n −\n </button>\n <input\n type=\"number\"\n value={seatCount}\n min={planData.getPlan.minSeats ?? 1}\n max={planData.getPlan.maxSeats ?? 999}\n onChange={(e) => {\n const v = parseInt(e.target.value, 10);\n if (!isNaN(v)) setSeatCount(Math.max(planData.getPlan?.minSeats ?? 1, v));\n }}\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\"\n />\n <button\n type=\"button\"\n onClick={() =>\n setSeatCount((n) => Math.min(planData.getPlan?.maxSeats ?? 999, n + 1))\n }\n disabled={seatCount >= (planData.getPlan.maxSeats ?? 999)}\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 text-foreground\"\n >\n +\n </button>\n {planData.getPlan.pricePerSeat && (\n <span className=\"text-sm text-muted-foreground\">\n ×{' '}\n {planData.getPlan.pricePerSeat.toLocaleString('en', {\n style: 'currency',\n currency: planData.getPlan.currency ?? 'USD',\n })}{' '}\n ={' '}\n {(planData.getPlan.pricePerSeat * seatCount).toLocaleString('en', {\n style: 'currency',\n currency: planData.getPlan.currency ?? 'USD',\n })}\n /mo\n </span>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Right column - Order Summary (sticky on desktop, shown first on mobile) */}\n <div className=\"lg:col-span-2 order-1 lg:order-2\">\n <div className=\"lg:sticky lg:top-6 space-y-4\">\n <div className=\"rounded-lg border border-border bg-card\">\n <div className=\"p-4\">\n <OrderSummary\n items={checkout.items}\n subtotal={checkout.subtotal}\n discountAmount={checkout.discountAmount}\n taxAmount={checkout.taxAmount}\n taxRate={checkout.taxRate}\n taxType={checkout.taxType}\n total={checkout.total}\n currency={checkout.selectedCurrency}\n isCalculatingTax={checkout.isCalculatingTax}\n showInCredits={checkout.selectedProvider === 'CREDITS'}\n onUpdateQuantity={\n purchaseType !== 'PLAN' ? checkout.updateItemQuantity : undefined\n }\n onRemoveItem={checkout.removeItem}\n isEditable={purchaseType !== 'PLAN'}\n />\n </div>\n\n {/* Promo Code Input */}\n <div className=\"px-4 pb-4 border-t border-border pt-4\">\n <PromoCodeInput\n value={checkout.promoCode}\n onChange={checkout.setPromoCode}\n onValidate={async () => {\n const result = await checkout.validatePromoCode();\n return result;\n }}\n onClear={checkout.clearPromoCode}\n isApplied={checkout.promoDiscount > 0}\n discountValue={checkout.promoDiscount}\n discountType={checkout.promoDiscountType}\n isValidating={checkout.isProcessing}\n />\n </div>\n\n {/* Simple Auto-Pay Toggle - only for PLAN purchases */}\n {purchaseType === 'PLAN' &&\n checkout.selectedProvider !== 'CREDITS' &&\n checkout.selectedProvider !== 'AUTO' &&\n (() => {\n // Determine payment method display\n let paymentMethodDisplay = '';\n let hasPaymentMethod = false;\n let isNewCard = false;\n\n if (checkout.selectedPaymentMethodId) {\n // Saved card selected\n const selectedCard = savedPaymentMethods.find(\n (pm) => pm.id === checkout.selectedPaymentMethodId\n );\n if (selectedCard) {\n const type =\n selectedCard.type === 'CREDIT_CARD'\n ? 'Card'\n : selectedCard.type === 'DEBIT_CARD'\n ? 'Card'\n : selectedCard.type;\n const last4 = selectedCard.last4 ? ` •••• ${selectedCard.last4}` : '';\n paymentMethodDisplay = `${type}${last4}`;\n hasPaymentMethod = true;\n isNewCard = false;\n }\n } else if (\n checkout.selectedProvider === 'RAZORPAY' ||\n checkout.selectedProvider === 'STRIPE'\n ) {\n // New card selected\n paymentMethodDisplay =\n checkout.selectedProvider === 'RAZORPAY'\n ? 'new card (Razorpay)'\n : 'new card (Stripe)';\n hasPaymentMethod = true;\n isNewCard = true;\n }\n\n return (\n <div className=\"px-4 pb-4\">\n <SimpleAutoPayToggle\n enabled={checkout.autoRenew}\n onToggle={(enabled) => {\n checkout.setAutoRenew(enabled);\n // When enabling auto-pay with saved card, also set it as auto-renew method\n if (enabled && checkout.selectedPaymentMethodId) {\n checkout.setAutoRenewPaymentMethodId(checkout.selectedPaymentMethodId);\n }\n }}\n hasPaymentMethodSelected={hasPaymentMethod}\n selectedPaymentMethodDisplay={paymentMethodDisplay}\n isNewCard={isNewCard}\n />\n </div>\n );\n })()}\n </div>\n\n {/* Checkout Button */}\n <button\n type=\"button\"\n onClick={handleProceedToPayment}\n disabled={\n checkout.isProcessing ||\n !checkout.billingAccount ||\n checkout.items.length === 0 ||\n // For addon purchases: require active subscription to be selected (skip for store checkout)\n (purchaseType === 'ADDON' && !isStoreCheckout && subscriptionsLoading) ||\n (purchaseType === 'ADDON' &&\n !isStoreCheckout &&\n activeSubscriptions.length === 0) ||\n (purchaseType === 'ADDON' && !isStoreCheckout && !checkout.selectedSubscriptionId)\n }\n className=\"w-full px-6 py-4 rounded-lg bg-primary text-primary-foreground font-semibold\n hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\n transition-colors flex items-center justify-center gap-2\"\n >\n {checkout.isProcessing ? (\n <>\n <Loader2 className=\"size-5 animate-spin\" />\n Processing…\n </>\n ) : checkout.selectedProvider === 'CREDITS' ? (\n 'Pay with Credits'\n ) : (\n 'Proceed to Payment'\n )}\n </button>\n\n {/* Security badge */}\n <p className=\"text-center text-xs text-muted-foreground\">\n 🔒 Secure checkout with 256-bit SSL encryption\n </p>\n </div>\n </div>\n </div>\n\n {/* Billing account completion gate */}\n {showCompleteAccountModal && checkout.billingAccount && (\n <CompleteBillingAccountModal\n billingAccountId={checkout.billingAccount.id}\n hasPhone={Boolean(checkout.billingAccount.contactNumber?.trim())}\n hasAddress={Boolean(\n checkout.billingAccount.billingAddresses?.[0]?.line1?.trim() &&\n checkout.billingAccount.billingAddresses?.[0]?.postalCode?.trim()\n )}\n onCompleted={() => {\n // Set bypass BEFORE closing modal so the re-triggered payment skips the stale check\n bypassBillingGate.current = true;\n setShowCompleteAccountModal(false);\n void handleProceedToPayment();\n // Refetch accounts in background so future gate checks use fresh contactNumber/address\n void refetchAccounts().then((result) => {\n const freshAccounts = result.data?.getBillingAccountsByOrg ?? [];\n const freshAccount = freshAccounts.find(\n (a: CheckoutBillingAccount) => a.id === checkout.billingAccount?.id\n );\n if (freshAccount) checkout.setBillingAccount(freshAccount);\n });\n }}\n onCancel={() => setShowCompleteAccountModal(false)}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -107,7 +107,7 @@ var v = [
|
|
|
107
107
|
applicableProducts: [],
|
|
108
108
|
applicableServices: [],
|
|
109
109
|
campaignName: ""
|
|
110
|
-
}), [O, k] = o({}), [A, j] = o(!1), M = v.find((e) => e.code === E.currency)?.symbol ?? E.currency, [N] = r();
|
|
110
|
+
}), [O, k] = o({}), [A, j] = o(!1), M = v.find((e) => e.code === E.currency)?.symbol ?? E.currency, [N] = r({ refetchQueries: ["ListCoupons"] });
|
|
111
111
|
if (!S.canManageDiscounts) return /* @__PURE__ */ h(e, { message: "You don't have permission to create coupons." });
|
|
112
112
|
let P = (e, t) => {
|
|
113
113
|
D((n) => ({
|