@burdenoff/microfe-billing 2026.526.1 → 2026.528.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/billing/BillingAdminRoutes.js +1 -1
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js +15 -8
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +13 -6
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js +8 -4
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js +3 -2
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +44 -23
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js +60 -31
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +9 -9
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +8 -8
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +16 -10
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +24 -16
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +5 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js +46 -29
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js +34 -22
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js +10 -10
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js +3 -3
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js +7 -0
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js +13 -13
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js +5 -5
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js +5 -5
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js +4 -4
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js +11 -11
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js +3 -3
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js +8 -8
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +61 -52
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js +22 -15
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js +30 -21
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js +9 -8
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js +11 -8
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +22 -17
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +15 -8
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js +17 -11
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +15 -11
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +21 -17
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js +14 -11
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +32 -26
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +14 -10
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +18 -11
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js +44 -32
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js +35 -26
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +15 -15
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +11 -11
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +5 -5
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +9 -4
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js +13 -8
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js +3 -2
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js +14 -7
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js +23 -9
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaPage.js +11 -7
- package/dist/billing/modules/quota/pages/QuotaPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +3 -3
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +6 -2
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +5 -4
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +26 -12
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js +356 -349
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +157 -123
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +13 -8
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +15 -7
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +30 -20
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +25 -16
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +50 -34
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js +2 -2
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/ActorIdentity.js +67 -0
- package/dist/billing/shared/components/ActorIdentity.js.map +1 -0
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js +6 -2
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js +7 -21
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/PageHeader.js +7 -19
- package/dist/billing/shared/components/PageHeader.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js +5 -4
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/index.js +1 -0
- package/dist/billing/shared/hooks/index.js +1 -0
- package/dist/billing/shared/hooks/useActorProfiles.js +113 -0
- package/dist/billing/shared/hooks/useActorProfiles.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/TransactionsPage.tsx"],"sourcesContent":["/**\n * Billing Module - Transactions Page\n * Displays all billing transactions for a specific billing account\n */\n\nimport { useState, useRef, useEffect, type FC } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n MoreHorizontal,\n Eye,\n FileText,\n X,\n CreditCard,\n Mail,\n Wallet,\n ChevronLeft,\n ChevronRight,\n Calendar,\n CheckCircle,\n XCircle,\n} from 'lucide-react';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useTransactions } from '../hooks';\nimport { nativeImpact, nativeOpenUrl } from '../../../../utils/nativeBridge';\nimport { AccessDenied, PageHeader, EmptyState, ServerError } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { getTransactionStatusColor, getStatusBadgeClasses } from '../../../shared/utils/status';\nimport type { Transaction, TransactionType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype FilterType = 'all' | TransactionType;\n\nconst TYPE_LABELS: Record<TransactionType, string> = {\n payment: 'Payment',\n refund: 'Refund',\n adjustment: 'Adjustment',\n};\n\n// Helper to get label for transaction type (case-insensitive)\nconst getTypeLabel = (type: string): string => {\n const normalized = type.toLowerCase() as TransactionType;\n return TYPE_LABELS[normalized] ?? type;\n};\n\n// Transaction Actions Dropdown Component\ninterface TransactionActionsDropdownProps {\n transaction: Transaction;\n onViewDetails: () => void;\n onViewInvoice: () => void;\n hasInvoiceUrl: boolean;\n}\n\nconst TransactionActionsDropdown: FC<TransactionActionsDropdownProps> = ({\n transaction,\n onViewDetails,\n onViewInvoice,\n hasInvoiceUrl,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n return (\n <div className=\"relative overflow-visible\" ref={dropdownRef}>\n <button\n onClick={() => setIsOpen(!isOpen)}\n className=\"p-1.5 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Transaction actions\"\n >\n <MoreHorizontal className=\"w-4 h-4 text-muted-foreground\" />\n </button>\n\n {isOpen && (\n <div className=\"absolute right-0 top-full mt-1 z-50 min-w-[160px] bg-popover border border-border rounded-md shadow-lg py-1\">\n <button\n onClick={() => {\n onViewDetails();\n setIsOpen(false);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted/50 transition-colors whitespace-nowrap\"\n >\n <Eye className=\"w-4 h-4\" />\n View Details\n </button>\n {transaction.type === 'payment' && hasInvoiceUrl && (\n <button\n onClick={() => {\n onViewInvoice();\n setIsOpen(false);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted/50 transition-colors whitespace-nowrap\"\n >\n <FileText className=\"w-4 h-4\" />\n View Invoice\n </button>\n )}\n </div>\n )}\n </div>\n );\n};\n\n// Transaction Details Modal Component\ninterface TransactionDetailsModalProps {\n transaction: Transaction | null;\n onClose: () => void;\n onViewInvoice?: (transaction: Transaction) => void;\n invoiceUrl?: string | null;\n invoiceProvider?: string | null;\n}\n\nconst TransactionDetailsModal: FC<TransactionDetailsModalProps> = ({\n transaction,\n onClose,\n onViewInvoice,\n invoiceUrl,\n invoiceProvider,\n}) => {\n if (!transaction) return null;\n\n // Extract tax information from metadata\n const metadata = transaction.metadata as Record<string, unknown> | null;\n const subtotal = metadata?.subtotal as number | undefined;\n const taxAmount = metadata?.taxAmount as number | undefined;\n const taxRate = metadata?.taxRate as number | undefined;\n const taxType = metadata?.taxType as string | undefined;\n const total = metadata?.total as number | undefined;\n const invoiceNumber = metadata?.invoiceNumber as string | undefined;\n const invoiceStatus = metadata?.invoiceStatus as string | undefined;\n\n // Extract refund-specific information\n const isRefund = transaction.type === 'refund';\n const refundRecordId = metadata?.refundRecordId as string | undefined;\n const originalTransactionId = metadata?.originalTransactionId as string | undefined;\n const creditNoteId = metadata?.creditNoteId as string | undefined;\n const creditNoteNumber = metadata?.creditNoteNumber as string | undefined;\n const creditNotePdfUrl = metadata?.creditNotePdfUrl as string | undefined;\n const refundReason = metadata?.reason as string | undefined;\n const purchaseType = metadata?.purchaseType as string | undefined;\n const purchaseDetail = metadata?.purchaseDetail as string | undefined;\n\n // Determine if we should show tax breakdown\n const showTaxBreakdown = total && taxAmount !== undefined && taxAmount > 0;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={onClose} />\n <div\n className=\"relative bg-background border border-border rounded-lg shadow-xl max-w-md w-full mx-4 max-h-[90vh] overflow-auto\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"transaction-details-title\"\n >\n <div className=\"flex items-center justify-between p-4 border-b border-border\">\n <h2 id=\"transaction-details-title\" className=\"text-lg font-semibold\">\n Transaction Details\n </h2>\n <button\n onClick={onClose}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close transaction details\"\n >\n <X className=\"w-5 h-5\" />\n </button>\n </div>\n\n <div className=\"p-4 space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Transaction ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.id}</p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Type</p>\n <p className=\"text-sm capitalize\">{getTypeLabel(transaction.type)}</p>\n </div>\n </div>\n\n {/* Amount Section with Tax Breakdown */}\n <div className=\"space-y-2\">\n {showTaxBreakdown ? (\n <>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-muted-foreground\">Subtotal</span>\n <span>\n {formatCurrency(subtotal || transaction.amount, transaction.currency)}\n </span>\n </div>\n {taxAmount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-muted-foreground\">\n {taxType || 'Tax'} {taxRate ? `(${(taxRate * 100).toFixed(0)}%)` : ''}\n </span>\n <span>{formatCurrency(taxAmount, transaction.currency)}</span>\n </div>\n )}\n <div className=\"flex justify-between text-sm font-semibold border-t border-border pt-2\">\n <span>Total</span>\n <span className={transaction.type === 'refund' ? 'text-status-error-text' : ''}>\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(total, transaction.currency)}\n </span>\n </div>\n </>\n ) : (\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Amount</p>\n <p\n className={`text-sm font-medium ${transaction.type === 'refund' ? 'text-status-error-text' : ''}`}\n >\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(total || transaction.amount, transaction.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Status</p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </div>\n </div>\n )}\n </div>\n\n {/* Status (if tax breakdown shown) */}\n {showTaxBreakdown && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Status</p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </div>\n )}\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Date & Time</p>\n <p className=\"text-sm\">{formatDateTime(transaction.createdAt)}</p>\n </div>\n\n {transaction.description && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Description</p>\n <p className=\"text-sm\">{transaction.description}</p>\n </div>\n )}\n\n {/* Invoice Information */}\n {invoiceNumber && (\n <div className=\"p-3 bg-muted/50 rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Invoice</p>\n <p className=\"text-sm font-mono\">{invoiceNumber}</p>\n </div>\n {invoiceStatus && (\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n invoiceStatus === 'PAID'\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-status-warning-bg-subtle text-status-warning-text'\n }`}\n >\n {invoiceStatus}\n </span>\n )}\n </div>\n {invoiceProvider && (\n <p className=\"text-xs text-muted-foreground\">Provider: {invoiceProvider}</p>\n )}\n {invoiceUrl && onViewInvoice && (\n <button\n onClick={() => onViewInvoice(transaction)}\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <FileText className=\"w-4 h-4\" />\n View Invoice\n </button>\n )}\n </div>\n )}\n\n {/* Fallback invoice button if no invoice number but URL exists */}\n {!invoiceNumber && invoiceUrl && onViewInvoice && (\n <div className=\"p-3 bg-muted/50 rounded-lg\">\n <button\n onClick={() => onViewInvoice(transaction)}\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <FileText className=\"w-4 h-4\" />\n View Invoice {invoiceProvider && `(${invoiceProvider})`}\n </button>\n </div>\n )}\n\n {/* Refund-Specific Information */}\n {isRefund && (creditNoteId || refundReason || purchaseType) && (\n <div className=\"p-3 bg-status-error-bg-subtle/20 border border-border-subtle rounded-lg space-y-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-1.5 h-1.5 rounded-full bg-status-error-bg\" />\n <p className=\"text-sm font-semibold text-status-error-text\">Refund Information</p>\n </div>\n\n {/* Credit Note Section */}\n {creditNoteNumber && (\n <div className=\"space-y-2\">\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Credit Note</p>\n <p className=\"text-sm font-mono text-status-error-text\">{creditNoteNumber}</p>\n </div>\n {creditNotePdfUrl && (\n <button\n onClick={() => {\n void nativeImpact('light');\n void nativeOpenUrl(creditNotePdfUrl);\n }}\n className=\"flex items-center gap-2 text-sm text-status-error-text hover:underline\"\n >\n <FileText className=\"w-4 h-4\" />\n Download Credit Note PDF\n </button>\n )}\n </div>\n )}\n\n {/* Purchase Type & Detail */}\n {purchaseType && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Purchase Type</p>\n <p className=\"text-sm text-status-error-text\">\n {purchaseType}\n {purchaseDetail && ` - ${purchaseDetail}`}\n </p>\n </div>\n )}\n\n {/* Refund Reason */}\n {refundReason && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Reason</p>\n <p className=\"text-sm text-status-error-text\">{refundReason}</p>\n </div>\n )}\n\n {/* Original Transaction Reference */}\n {originalTransactionId && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Original Transaction</p>\n <p className=\"text-sm font-mono text-status-error-text break-all\">\n {originalTransactionId}\n </p>\n </div>\n )}\n\n {/* Refund Record ID */}\n {refundRecordId && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Refund Record ID</p>\n <p className=\"text-sm font-mono text-status-error-text break-all\">\n {refundRecordId}\n </p>\n </div>\n )}\n </div>\n )}\n\n {transaction.stripePaymentId && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Stripe Payment ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.stripePaymentId}</p>\n </div>\n )}\n\n {transaction.razorpayPaymentId && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Razorpay Payment ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.razorpayPaymentId}</p>\n </div>\n )}\n </div>\n\n <div className=\"p-4 border-t border-border\">\n <button\n onClick={onClose}\n className=\"w-full py-2 px-4 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n};\n\nexport const TransactionsPage: 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 { billingAccountId } = useParams<{ billingAccountId: string }>();\n const permissions = useBillingPermissions();\n const navigateTo = useBillingNavigate();\n const {\n billingAccount,\n transactions,\n pagination,\n isLoading,\n error,\n refetch,\n goToNextPage,\n goToPreviousPage,\n } = useTransactions(billingAccountId);\n const [filterType, setFilterType] = useState<FilterType>('all');\n const [selectedTransaction, setSelectedTransaction] = useState<Transaction | null>(null);\n\n // Get invoice URL from transaction metadata (supports both Zoho and Stripe)\n const getInvoiceUrl = (transaction: Transaction): string | null => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n // Check for Zoho Books invoice first (INR payments)\n if (metadata?.zohoBooksInvoiceUrl) {\n return metadata.zohoBooksInvoiceUrl as string;\n }\n // Check for Stripe invoice (international payments)\n if (metadata?.invoiceUrl) {\n return metadata.invoiceUrl as string;\n }\n // Check for Stripe PDF (fallback)\n if (metadata?.invoicePdf) {\n return metadata.invoicePdf as string;\n }\n return null;\n };\n\n // Get total amount (with tax) from metadata if available\n const getTotalAmount = (transaction: Transaction): number => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n // Check for total in metadata (includes tax)\n if (metadata?.total && typeof metadata.total === 'number') {\n return metadata.total;\n }\n // Fallback to transaction amount\n return transaction.amount;\n };\n\n // Get invoice provider name for display\n const getInvoiceProvider = (transaction: Transaction): string | null => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n if (metadata?.zohoBooksInvoiceUrl) return 'Zoho Books';\n if (metadata?.invoiceUrl || metadata?.invoicePdf) return 'Stripe';\n return null;\n };\n\n const handleViewInvoice = (transaction: Transaction) => {\n const invoiceUrl = getInvoiceUrl(transaction);\n if (invoiceUrl) {\n void nativeImpact('light');\n void nativeOpenUrl(invoiceUrl);\n } else {\n // Fallback to invoices page if no invoice URL\n navigateTo('/invoices');\n }\n };\n\n if (!permissions.canViewPayments) {\n return (\n <AccessDenied\n message={tr(\n 'billing.transactions.noPermission',\n \"You don't have permission to view transaction history.\"\n )}\n />\n );\n }\n\n // Show error if no billing account ID provided\n if (!billingAccountId) {\n return (\n <div className=\"p-6\">\n <EmptyState\n icon={\n <svg\n className=\"w-6 h-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n title={tr('billing.transactions.noAccountSelected', 'No billing account selected')}\n description={tr(\n 'billing.transactions.noAccountSelectedDesc',\n 'Please select a billing account from the overview page to view transactions.'\n )}\n />\n </div>\n );\n }\n\n // Show server error if backend is down\n if (error && isServerError(error)) {\n return (\n <div className=\"p-6\">\n <ServerError\n title={tr('billing.transactions.serverUnavailable', 'Server Unavailable')}\n message={tr(\n 'billing.transactions.serverUnavailableMessage',\n 'Unable to load transactions. The server might be down or experiencing issues.'\n )}\n onRetry={() => refetch()}\n showRetry\n />\n </div>\n );\n }\n const filteredTransactions =\n filterType === 'all' ? transactions : transactions.filter((t) => t.type === filterType);\n\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Back Button */}\n <button\n onClick={() => navigateTo('/overview')}\n className=\"inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n Back to Overview\n </button>\n\n <PageHeader\n title={tr('billing.transactions.title', 'Transaction History')}\n description={\n billingAccount\n ? `Transactions for ${billingAccount.name}`\n : 'View all your billing transactions'\n }\n />\n\n {/* Billing Account Info Card */}\n {billingAccount && (\n <div className=\"border border-border rounded-lg p-4 bg-card\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4\">\n {/* Account Name & Status */}\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"w-4 h-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Account</p>\n <p className=\"text-sm font-medium\">{billingAccount.name}</p>\n {billingAccount.isActive ? (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"w-3 h-3\" />\n Active\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-error-bg-subtle text-status-error-text\">\n <XCircle className=\"w-3 h-3\" />\n Inactive\n </span>\n )}\n </div>\n </div>\n\n {/* Email */}\n <div className=\"flex items-start gap-2\">\n <Mail className=\"w-4 h-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Email</p>\n <p className=\"text-sm font-medium break-all\">\n {billingAccount.billingEmail || billingAccount.email}\n </p>\n </div>\n </div>\n\n {/* Credit Balance */}\n <div className=\"flex items-start gap-2\">\n <Wallet className=\"w-4 h-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Credits Balance</p>\n <p className=\"text-sm font-semibold text-foreground\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"flex items-start gap-2\">\n <FileText className=\"w-4 h-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Tax ID</p>\n <p className=\"text-sm font-medium\">{billingAccount.taxId || '-'}</p>\n </div>\n </div>\n\n {/* Account Created */}\n <div className=\"flex items-start gap-2\">\n <Calendar className=\"w-4 h-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Member Since</p>\n <p className=\"text-sm font-medium\">\n {billingAccount.createdAt ? formatDateTime(billingAccount.createdAt) : '-'}\n </p>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"flex items-center gap-4\">\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n {(['all', 'payment', 'refund', 'adjustment'] as FilterType[]).map((type) => (\n <button\n key={type}\n onClick={() => setFilterType(type)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n filterType === type\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n {type === 'all' ? 'All' : TYPE_LABELS[type as TransactionType]}\n </button>\n ))}\n </div>\n </div>\n\n {/* Transactions List */}\n {filteredTransactions.length === 0 ? (\n <EmptyState\n icon={\n <svg\n className=\"w-6 h-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n }\n title={tr('billing.transactions.noTransactionsFound', 'No transactions found')}\n description={\n filterType !== 'all'\n ? tr(\n 'billing.transactions.noTransactionsFiltered',\n 'No transactions match your filter.'\n )\n : tr(\n 'billing.transactions.noTransactionsYet',\n 'Your transaction history will appear here.'\n )\n }\n />\n ) : (\n <div className=\"border border-border rounded-lg overflow-visible\">\n <table className=\"w-full\">\n <thead className=\"bg-muted/50\">\n <tr>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Date\n </th>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Type\n </th>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Description\n </th>\n <th className=\"text-right text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Amount\n </th>\n <th className=\"text-center text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Status\n </th>\n <th className=\"px-2 py-2 w-10\"></th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {filteredTransactions.map((transaction) => (\n <tr key={transaction.id} className=\"hover:bg-muted/30 transition-colors\">\n <td className=\"px-3 py-2 text-sm text-foreground whitespace-nowrap\">\n {formatDateTime(transaction.createdAt)}\n </td>\n <td className=\"px-3 py-2 text-sm text-foreground capitalize whitespace-nowrap\">\n {getTypeLabel(transaction.type)}\n </td>\n <td className=\"px-3 py-2 text-sm text-muted-foreground\">\n {transaction.description ?? '-'}\n </td>\n <td\n className={`px-3 py-2 text-sm text-right font-medium whitespace-nowrap ${\n transaction.type === 'refund' ? 'text-status-error-text' : 'text-foreground'\n }`}\n >\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(getTotalAmount(transaction), transaction.currency)}\n </td>\n <td className=\"px-3 py-2 text-center whitespace-nowrap\">\n <span\n className={`px-1.5 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </td>\n <td className=\"px-2 py-2 text-center\">\n <TransactionActionsDropdown\n transaction={transaction}\n onViewDetails={() => setSelectedTransaction(transaction)}\n onViewInvoice={() => handleViewInvoice(transaction)}\n hasInvoiceUrl={!!getInvoiceUrl(transaction)}\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {/* Pagination Controls */}\n {pagination.totalCount > 0 && (\n <div className=\"flex items-center justify-between border-t border-border pt-4\">\n <p className=\"text-sm text-muted-foreground\">\n Showing {pagination.page * pagination.pageSize + 1} to{' '}\n {Math.min((pagination.page + 1) * pagination.pageSize, pagination.totalCount)} of{' '}\n {pagination.totalCount} transactions\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={goToPreviousPage}\n disabled={!pagination.hasPrevious}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <ChevronLeft className=\"w-4 h-4\" />\n Previous\n </button>\n <span className=\"text-sm text-muted-foreground px-2\">\n Page {pagination.page + 1} of {Math.ceil(pagination.totalCount / pagination.pageSize)}\n </span>\n <button\n onClick={goToNextPage}\n disabled={!pagination.hasMore}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n <ChevronRight className=\"w-4 h-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Transaction Details Modal */}\n <TransactionDetailsModal\n transaction={selectedTransaction}\n onClose={() => setSelectedTransaction(null)}\n onViewInvoice={handleViewInvoice}\n invoiceUrl={selectedTransaction ? getInvoiceUrl(selectedTransaction) : null}\n invoiceProvider={selectedTransaction ? getInvoiceProvider(selectedTransaction) : null}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TransactionsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/TransactionsPage.tsx"],"sourcesContent":["/**\n * Billing Module - Transactions Page\n * Displays all billing transactions for a specific billing account\n */\n\nimport { useState, useRef, useEffect, type FC } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n MoreHorizontal,\n Eye,\n FileText,\n X,\n CreditCard,\n Mail,\n Wallet,\n ChevronLeft,\n ChevronRight,\n Calendar,\n CheckCircle,\n XCircle,\n} from 'lucide-react';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useTransactions } from '../hooks';\nimport { nativeImpact, nativeOpenUrl } from '../../../../utils/nativeBridge';\nimport { AccessDenied, PageHeader, EmptyState, ServerError } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { getTransactionStatusColor, getStatusBadgeClasses } from '../../../shared/utils/status';\nimport type { Transaction, TransactionType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype FilterType = 'all' | TransactionType;\n\nconst TYPE_LABELS: Record<TransactionType, string> = {\n payment: 'Payment',\n refund: 'Refund',\n adjustment: 'Adjustment',\n};\n\n// Helper to get label for transaction type (case-insensitive)\nconst getTypeLabel = (type: string): string => {\n const normalized = type.toLowerCase() as TransactionType;\n return TYPE_LABELS[normalized] ?? type;\n};\n\n// Transaction Actions Dropdown Component\ninterface TransactionActionsDropdownProps {\n transaction: Transaction;\n onViewDetails: () => void;\n onViewInvoice: () => void;\n hasInvoiceUrl: boolean;\n}\n\nconst TransactionActionsDropdown: FC<TransactionActionsDropdownProps> = ({\n transaction,\n onViewDetails,\n onViewInvoice,\n hasInvoiceUrl,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n return (\n <div className=\"relative overflow-visible\" ref={dropdownRef}>\n <button\n type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"p-1.5 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Transaction actions\"\n >\n <MoreHorizontal className=\"size-4 text-muted-foreground\" />\n </button>\n\n {isOpen && (\n <div className=\"absolute right-0 top-full mt-1 z-50 min-w-[160px] bg-popover border border-border rounded-md shadow-lg py-1\">\n <button\n type=\"button\"\n onClick={() => {\n onViewDetails();\n setIsOpen(false);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted/50 transition-colors whitespace-nowrap\"\n >\n <Eye className=\"size-4\" />\n View Details\n </button>\n {transaction.type === 'payment' && hasInvoiceUrl && (\n <button\n type=\"button\"\n onClick={() => {\n onViewInvoice();\n setIsOpen(false);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-foreground hover:bg-muted/50 transition-colors whitespace-nowrap\"\n >\n <FileText className=\"size-4\" />\n View Invoice\n </button>\n )}\n </div>\n )}\n </div>\n );\n};\n\n// Transaction Details Modal Component\ninterface TransactionDetailsModalProps {\n transaction: Transaction | null;\n onClose: () => void;\n onViewInvoice?: (transaction: Transaction) => void;\n invoiceUrl?: string | null;\n invoiceProvider?: string | null;\n}\n\nconst TransactionDetailsModal: FC<TransactionDetailsModalProps> = ({\n transaction,\n onClose,\n onViewInvoice,\n invoiceUrl,\n invoiceProvider,\n}) => {\n if (!transaction) return null;\n\n // Extract tax information from metadata\n const metadata = transaction.metadata as Record<string, unknown> | null;\n const subtotal = metadata?.subtotal as number | undefined;\n const taxAmount = metadata?.taxAmount as number | undefined;\n const taxRate = metadata?.taxRate as number | undefined;\n const taxType = metadata?.taxType as string | undefined;\n const total = metadata?.total as number | undefined;\n const invoiceNumber = metadata?.invoiceNumber as string | undefined;\n const invoiceStatus = metadata?.invoiceStatus as string | undefined;\n\n // Extract refund-specific information\n const isRefund = transaction.type === 'refund';\n const refundRecordId = metadata?.refundRecordId as string | undefined;\n const originalTransactionId = metadata?.originalTransactionId as string | undefined;\n const creditNoteId = metadata?.creditNoteId as string | undefined;\n const creditNoteNumber = metadata?.creditNoteNumber as string | undefined;\n const creditNotePdfUrl = metadata?.creditNotePdfUrl as string | undefined;\n const refundReason = metadata?.reason as string | undefined;\n const purchaseType = metadata?.purchaseType as string | undefined;\n const purchaseDetail = metadata?.purchaseDetail as string | undefined;\n\n // Determine if we should show tax breakdown\n const showTaxBreakdown = total && taxAmount !== undefined && taxAmount > 0;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <div className=\"absolute inset-0 bg-overlay-scrim\" onClick={onClose} />\n <div\n className=\"relative bg-background border border-border rounded-lg shadow-xl max-w-md w-full mx-4 max-h-[90vh] overflow-auto\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"transaction-details-title\"\n >\n <div className=\"flex items-center justify-between p-4 border-b border-border\">\n <h2 id=\"transaction-details-title\" className=\"text-lg font-semibold\">\n Transaction Details\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded-md hover:bg-muted/50 transition-colors\"\n aria-label=\"Close transaction details\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"p-4 space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Transaction ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.id}</p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Type</p>\n <p className=\"text-sm capitalize\">{getTypeLabel(transaction.type)}</p>\n </div>\n </div>\n\n {/* Amount Section with Tax Breakdown */}\n <div className=\"space-y-2\">\n {showTaxBreakdown ? (\n <>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-muted-foreground\">Subtotal</span>\n <span>\n {formatCurrency(subtotal || transaction.amount, transaction.currency)}\n </span>\n </div>\n {taxAmount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-muted-foreground\">\n {taxType || 'Tax'} {taxRate ? `(${(taxRate * 100).toFixed(0)}%)` : ''}\n </span>\n <span>{formatCurrency(taxAmount, transaction.currency)}</span>\n </div>\n )}\n <div className=\"flex justify-between text-sm font-semibold border-t border-border pt-2\">\n <span>Total</span>\n <span className={transaction.type === 'refund' ? 'text-status-error-text' : ''}>\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(total, transaction.currency)}\n </span>\n </div>\n </>\n ) : (\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Amount</p>\n <p\n className={`text-sm font-medium ${transaction.type === 'refund' ? 'text-status-error-text' : ''}`}\n >\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(total || transaction.amount, transaction.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Status</p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </div>\n </div>\n )}\n </div>\n\n {/* Status (if tax breakdown shown) */}\n {showTaxBreakdown && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Status</p>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </div>\n )}\n\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Date & Time</p>\n <p className=\"text-sm\">{formatDateTime(transaction.createdAt)}</p>\n </div>\n\n {transaction.description && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Description</p>\n <p className=\"text-sm\">{transaction.description}</p>\n </div>\n )}\n\n {/* Invoice Information */}\n {invoiceNumber && (\n <div className=\"p-3 bg-muted/50 rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Invoice</p>\n <p className=\"text-sm font-mono\">{invoiceNumber}</p>\n </div>\n {invoiceStatus && (\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded ${\n invoiceStatus === 'PAID'\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : 'bg-status-warning-bg-subtle text-status-warning-text'\n }`}\n >\n {invoiceStatus}\n </span>\n )}\n </div>\n {invoiceProvider && (\n <p className=\"text-xs text-muted-foreground\">Provider: {invoiceProvider}</p>\n )}\n {invoiceUrl && onViewInvoice && (\n <button\n type=\"button\"\n onClick={() => onViewInvoice(transaction)}\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <FileText className=\"size-4\" />\n View Invoice\n </button>\n )}\n </div>\n )}\n\n {/* Fallback invoice button if no invoice number but URL exists */}\n {!invoiceNumber && invoiceUrl && onViewInvoice && (\n <div className=\"p-3 bg-muted/50 rounded-lg\">\n <button\n type=\"button\"\n onClick={() => onViewInvoice(transaction)}\n className=\"flex items-center gap-2 text-sm text-primary hover:underline\"\n >\n <FileText className=\"size-4\" />\n View Invoice {invoiceProvider && `(${invoiceProvider})`}\n </button>\n </div>\n )}\n\n {/* Refund-Specific Information */}\n {isRefund && (creditNoteId || refundReason || purchaseType) && (\n <div className=\"p-3 bg-status-error-bg-subtle/20 border border-border-subtle rounded-lg space-y-3\">\n <div className=\"flex items-center gap-2\">\n <div className=\"size-1.5 rounded-full bg-status-error-bg\" />\n <p className=\"text-sm font-semibold text-status-error-text\">Refund Information</p>\n </div>\n\n {/* Credit Note Section */}\n {creditNoteNumber && (\n <div className=\"space-y-2\">\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Credit Note</p>\n <p className=\"text-sm font-mono text-status-error-text\">{creditNoteNumber}</p>\n </div>\n {creditNotePdfUrl && (\n <button\n type=\"button\"\n onClick={() => {\n void nativeImpact('light');\n void nativeOpenUrl(creditNotePdfUrl);\n }}\n className=\"flex items-center gap-2 text-sm text-status-error-text hover:underline\"\n >\n <FileText className=\"size-4\" />\n Download Credit Note PDF\n </button>\n )}\n </div>\n )}\n\n {/* Purchase Type & Detail */}\n {purchaseType && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Purchase Type</p>\n <p className=\"text-sm text-status-error-text\">\n {purchaseType}\n {purchaseDetail && ` - ${purchaseDetail}`}\n </p>\n </div>\n )}\n\n {/* Refund Reason */}\n {refundReason && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Reason</p>\n <p className=\"text-sm text-status-error-text\">{refundReason}</p>\n </div>\n )}\n\n {/* Original Transaction Reference */}\n {originalTransactionId && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Original Transaction</p>\n <p className=\"text-sm font-mono text-status-error-text break-all\">\n {originalTransactionId}\n </p>\n </div>\n )}\n\n {/* Refund Record ID */}\n {refundRecordId && (\n <div>\n <p className=\"text-xs text-status-error-text mb-1\">Refund Record ID</p>\n <p className=\"text-sm font-mono text-status-error-text break-all\">\n {refundRecordId}\n </p>\n </div>\n )}\n </div>\n )}\n\n {transaction.stripePaymentId && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Stripe Payment ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.stripePaymentId}</p>\n </div>\n )}\n\n {transaction.razorpayPaymentId && (\n <div>\n <p className=\"text-xs text-muted-foreground mb-1\">Razorpay Payment ID</p>\n <p className=\"text-sm font-mono break-all\">{transaction.razorpayPaymentId}</p>\n </div>\n )}\n </div>\n\n <div className=\"p-4 border-t border-border\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"w-full py-2 px-4 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n Close\n </button>\n </div>\n </div>\n </div>\n );\n};\n\nexport const TransactionsPage: 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 { billingAccountId } = useParams<{ billingAccountId: string }>();\n const permissions = useBillingPermissions();\n const navigateTo = useBillingNavigate();\n const {\n billingAccount,\n transactions,\n pagination,\n isLoading,\n error,\n refetch,\n goToNextPage,\n goToPreviousPage,\n } = useTransactions(billingAccountId);\n const [filterType, setFilterType] = useState<FilterType>('all');\n const [selectedTransaction, setSelectedTransaction] = useState<Transaction | null>(null);\n\n // Get invoice URL from transaction metadata (supports both Zoho and Stripe)\n const getInvoiceUrl = (transaction: Transaction): string | null => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n // Check for Zoho Books invoice first (INR payments)\n if (metadata?.zohoBooksInvoiceUrl) {\n return metadata.zohoBooksInvoiceUrl as string;\n }\n // Check for Stripe invoice (international payments)\n if (metadata?.invoiceUrl) {\n return metadata.invoiceUrl as string;\n }\n // Check for Stripe PDF (fallback)\n if (metadata?.invoicePdf) {\n return metadata.invoicePdf as string;\n }\n return null;\n };\n\n // Get total amount (with tax) from metadata if available\n const getTotalAmount = (transaction: Transaction): number => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n // Check for total in metadata (includes tax)\n if (metadata?.total && typeof metadata.total === 'number') {\n return metadata.total;\n }\n // Fallback to transaction amount\n return transaction.amount;\n };\n\n // Get invoice provider name for display\n const getInvoiceProvider = (transaction: Transaction): string | null => {\n const metadata = transaction.metadata as Record<string, unknown> | null;\n if (metadata?.zohoBooksInvoiceUrl) return 'Zoho Books';\n if (metadata?.invoiceUrl || metadata?.invoicePdf) return 'Stripe';\n return null;\n };\n\n const handleViewInvoice = (transaction: Transaction) => {\n const invoiceUrl = getInvoiceUrl(transaction);\n if (invoiceUrl) {\n void nativeImpact('light');\n void nativeOpenUrl(invoiceUrl);\n } else {\n // Fallback to invoices page if no invoice URL\n navigateTo('/invoices');\n }\n };\n\n if (!permissions.canViewPayments) {\n return (\n <AccessDenied\n message={tr(\n 'billing.transactions.noPermission',\n \"You don't have permission to view transaction history.\"\n )}\n />\n );\n }\n\n // Show error if no billing account ID provided\n if (!billingAccountId) {\n return (\n <div className=\"p-6\">\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n }\n title={tr('billing.transactions.noAccountSelected', 'No billing account selected')}\n description={tr(\n 'billing.transactions.noAccountSelectedDesc',\n 'Please select a billing account from the overview page to view transactions.'\n )}\n />\n </div>\n );\n }\n\n // Show server error if backend is down\n if (error && isServerError(error)) {\n return (\n <div className=\"p-6\">\n <ServerError\n title={tr('billing.transactions.serverUnavailable', 'Server Unavailable')}\n message={tr(\n 'billing.transactions.serverUnavailableMessage',\n 'Unable to load transactions. The server might be down or experiencing issues.'\n )}\n onRetry={() => refetch()}\n showRetry\n />\n </div>\n );\n }\n const filteredTransactions =\n filterType === 'all' ? transactions : transactions.filter((t) => t.type === filterType);\n\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"space-y-2\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-muted animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={() => navigateTo('/overview')}\n className=\"inline-flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n Back to Overview\n </button>\n\n <PageHeader\n title={tr('billing.transactions.title', 'Transaction History')}\n description={\n billingAccount\n ? `Transactions for ${billingAccount.name}`\n : 'View all your billing transactions'\n }\n />\n\n {/* Billing Account Info Card */}\n {billingAccount && (\n <div className=\"border border-border rounded-lg p-4 bg-card\">\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4\">\n {/* Account Name & Status */}\n <div className=\"flex items-start gap-2\">\n <CreditCard className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Account</p>\n <p className=\"text-sm font-medium\">{billingAccount.name}</p>\n {billingAccount.isActive ? (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-3\" />\n Active\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 mt-1 px-1.5 py-0.5 text-xs font-medium rounded bg-status-error-bg-subtle text-status-error-text\">\n <XCircle className=\"size-3\" />\n Inactive\n </span>\n )}\n </div>\n </div>\n\n {/* Email */}\n <div className=\"flex items-start gap-2\">\n <Mail className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Email</p>\n <p className=\"text-sm font-medium break-all\">\n {billingAccount.billingEmail || billingAccount.email}\n </p>\n </div>\n </div>\n\n {/* Credit Balance */}\n <div className=\"flex items-start gap-2\">\n <Wallet className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Credits Balance</p>\n <p className=\"text-sm font-semibold text-foreground\">\n {(billingAccount.creditAmount || 0).toLocaleString()} Credits\n </p>\n </div>\n </div>\n\n {/* Tax ID */}\n <div className=\"flex items-start gap-2\">\n <FileText className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Tax ID</p>\n <p className=\"text-sm font-medium\">{billingAccount.taxId || '-'}</p>\n </div>\n </div>\n\n {/* Account Created */}\n <div className=\"flex items-start gap-2\">\n <Calendar className=\"size-4 text-muted-foreground mt-0.5\" />\n <div>\n <p className=\"text-xs text-muted-foreground mb-0.5\">Member Since</p>\n <p className=\"text-sm font-medium\">\n {billingAccount.createdAt ? formatDateTime(billingAccount.createdAt) : '-'}\n </p>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Filters */}\n <div className=\"flex items-center gap-4\">\n <div className=\"inline-flex rounded-lg border border-border p-1 bg-muted/50\">\n {(['all', 'payment', 'refund', 'adjustment'] as FilterType[]).map((type) => (\n <button\n type=\"button\"\n key={type}\n onClick={() => setFilterType(type)}\n className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${\n filterType === type\n ? 'bg-background text-foreground shadow-sm'\n : 'text-muted-foreground hover:text-foreground'\n }`}\n >\n {type === 'all' ? 'All' : TYPE_LABELS[type as TransactionType]}\n </button>\n ))}\n </div>\n </div>\n\n {/* Transactions List */}\n {filteredTransactions.length === 0 ? (\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"\n />\n </svg>\n }\n title={tr('billing.transactions.noTransactionsFound', 'No transactions found')}\n description={\n filterType !== 'all'\n ? tr(\n 'billing.transactions.noTransactionsFiltered',\n 'No transactions match your filter.'\n )\n : tr(\n 'billing.transactions.noTransactionsYet',\n 'Your transaction history will appear here.'\n )\n }\n />\n ) : (\n <div className=\"border border-border rounded-lg overflow-visible\">\n <table className=\"w-full\">\n <thead className=\"bg-muted/50\">\n <tr>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Date\n </th>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Type\n </th>\n <th className=\"text-left text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Description\n </th>\n <th className=\"text-right text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Amount\n </th>\n <th className=\"text-center text-sm font-medium text-muted-foreground px-3 py-2 whitespace-nowrap\">\n Status\n </th>\n <th className=\"p-2 w-10\"></th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {filteredTransactions.map((transaction) => (\n <tr key={transaction.id} className=\"hover:bg-muted/30 transition-colors\">\n <td className=\"px-3 py-2 text-sm text-foreground whitespace-nowrap\">\n {formatDateTime(transaction.createdAt)}\n </td>\n <td className=\"px-3 py-2 text-sm text-foreground capitalize whitespace-nowrap\">\n {getTypeLabel(transaction.type)}\n </td>\n <td className=\"px-3 py-2 text-sm text-muted-foreground\">\n {transaction.description ?? '-'}\n </td>\n <td\n className={`px-3 py-2 text-sm text-right font-medium whitespace-nowrap ${\n transaction.type === 'refund' ? 'text-status-error-text' : 'text-foreground'\n }`}\n >\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(getTotalAmount(transaction), transaction.currency)}\n </td>\n <td className=\"px-3 py-2 text-center whitespace-nowrap\">\n <span\n className={`px-1.5 py-0.5 text-xs font-medium rounded ${getStatusBadgeClasses(\n getTransactionStatusColor(transaction.status)\n )}`}\n >\n {transaction.status}\n </span>\n </td>\n <td className=\"p-2 text-center\">\n <TransactionActionsDropdown\n transaction={transaction}\n onViewDetails={() => setSelectedTransaction(transaction)}\n onViewInvoice={() => handleViewInvoice(transaction)}\n hasInvoiceUrl={!!getInvoiceUrl(transaction)}\n />\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {/* Pagination Controls */}\n {pagination.totalCount > 0 && (\n <div className=\"flex items-center justify-between border-t border-border pt-4\">\n <p className=\"text-sm text-muted-foreground\">\n Showing {pagination.page * pagination.pageSize + 1} to{' '}\n {Math.min((pagination.page + 1) * pagination.pageSize, pagination.totalCount)} of{' '}\n {pagination.totalCount} transactions\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={goToPreviousPage}\n disabled={!pagination.hasPrevious}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n <ChevronLeft className=\"size-4\" />\n Previous\n </button>\n <span className=\"text-sm text-muted-foreground px-2\">\n Page {pagination.page + 1} of {Math.ceil(pagination.totalCount / pagination.pageSize)}\n </span>\n <button\n type=\"button\"\n onClick={goToNextPage}\n disabled={!pagination.hasMore}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm font-medium rounded-md border border-border bg-background hover:bg-muted/50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n <ChevronRight className=\"size-4\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Transaction Details Modal */}\n <TransactionDetailsModal\n transaction={selectedTransaction}\n onClose={() => setSelectedTransaction(null)}\n onViewInvoice={handleViewInvoice}\n invoiceUrl={selectedTransaction ? getInvoiceUrl(selectedTransaction) : null}\n invoiceProvider={selectedTransaction ? getInvoiceProvider(selectedTransaction) : null}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -26,7 +26,7 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
26
26
|
children: [/* @__PURE__ */ l("div", { className: "h-4 w-28 bg-muted animate-pulse rounded" }), /* @__PURE__ */ l("div", { className: "h-12 bg-muted animate-pulse rounded-lg" })]
|
|
27
27
|
}) : f.length === 0 ? /* @__PURE__ */ u("div", {
|
|
28
28
|
className: "rounded-lg border border-dashed border-border p-4 text-center",
|
|
29
|
-
children: [/* @__PURE__ */ l(i, { className: "mx-auto
|
|
29
|
+
children: [/* @__PURE__ */ l(i, { className: "mx-auto size-6 text-muted-foreground" }), /* @__PURE__ */ l("p", {
|
|
30
30
|
className: "mt-2 text-sm text-muted-foreground",
|
|
31
31
|
children: "No billing accounts found"
|
|
32
32
|
})]
|
|
@@ -41,7 +41,7 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
41
41
|
children: y("billing.checkout.billingAccount", "Billing Account")
|
|
42
42
|
}), g && /* @__PURE__ */ u("span", {
|
|
43
43
|
className: "flex items-center gap-1 text-xs text-muted-foreground",
|
|
44
|
-
children: [/* @__PURE__ */ l(c, { className: "
|
|
44
|
+
children: [/* @__PURE__ */ l(c, { className: "size-3" }), "Locked"]
|
|
45
45
|
})]
|
|
46
46
|
}),
|
|
47
47
|
/* @__PURE__ */ u("button", {
|
|
@@ -57,8 +57,8 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
57
57
|
className: "flex items-center gap-3 min-w-0 flex-1",
|
|
58
58
|
children: [
|
|
59
59
|
/* @__PURE__ */ l("div", {
|
|
60
|
-
className: `flex
|
|
61
|
-
children: /* @__PURE__ */ l(i, { className: "
|
|
60
|
+
className: `flex size-8 shrink-0 items-center justify-center rounded-full ${g ? "bg-muted text-muted-foreground" : "bg-primary/10 text-primary"}`,
|
|
61
|
+
children: /* @__PURE__ */ l(i, { className: "size-4" })
|
|
62
62
|
}),
|
|
63
63
|
/* @__PURE__ */ u("div", {
|
|
64
64
|
className: "min-w-0 flex-1",
|
|
@@ -80,14 +80,14 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
80
80
|
className: "shrink-0 text-right",
|
|
81
81
|
children: /* @__PURE__ */ u("div", {
|
|
82
82
|
className: "flex items-center gap-1 text-sm font-medium text-foreground",
|
|
83
|
-
children: [/* @__PURE__ */ l(s, { className: "
|
|
83
|
+
children: [/* @__PURE__ */ l(s, { className: "size-3.5 text-muted-foreground" }), e(C.creditAmount, "CREDITS")]
|
|
84
84
|
})
|
|
85
85
|
})
|
|
86
86
|
]
|
|
87
87
|
}) : /* @__PURE__ */ l("span", {
|
|
88
88
|
className: "text-muted-foreground",
|
|
89
89
|
children: "Select billing account"
|
|
90
|
-
}), g ? /* @__PURE__ */ l(c, { className: "
|
|
90
|
+
}), g ? /* @__PURE__ */ l(c, { className: "size-4 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ l(o, { className: `size-4 shrink-0 text-muted-foreground transition-transform ${b ? "rotate-180" : ""}` })]
|
|
91
91
|
}),
|
|
92
92
|
g && _ && /* @__PURE__ */ l("p", {
|
|
93
93
|
className: "text-xs text-muted-foreground",
|
|
@@ -109,8 +109,8 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
109
109
|
`,
|
|
110
110
|
children: [
|
|
111
111
|
/* @__PURE__ */ l("div", {
|
|
112
|
-
className: "flex
|
|
113
|
-
children: /* @__PURE__ */ l(i, { className: "
|
|
112
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary",
|
|
113
|
+
children: /* @__PURE__ */ l(i, { className: "size-4" })
|
|
114
114
|
}),
|
|
115
115
|
/* @__PURE__ */ u("div", {
|
|
116
116
|
className: "min-w-0 flex-1",
|
|
@@ -134,9 +134,9 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
|
|
|
134
134
|
className: "text-right",
|
|
135
135
|
children: /* @__PURE__ */ u("div", {
|
|
136
136
|
className: "flex items-center gap-1 text-sm font-medium text-foreground",
|
|
137
|
-
children: [/* @__PURE__ */ l(s, { className: "
|
|
137
|
+
children: [/* @__PURE__ */ l(s, { className: "size-3.5 text-muted-foreground" }), e(t.creditAmount, "CREDITS")]
|
|
138
138
|
})
|
|
139
|
-
}), n && /* @__PURE__ */ l(a, { className: "
|
|
139
|
+
}), n && /* @__PURE__ */ l(a, { className: "size-4 text-primary" })]
|
|
140
140
|
})
|
|
141
141
|
]
|
|
142
142
|
}, t.id);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BillingAccountSelector.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/BillingAccountSelector.tsx"],"sourcesContent":["/**\n * Billing Account Selector Component\n * Dropdown selector for choosing billing account in checkout\n */\n\nimport { type FC, useState, useRef, useEffect } from 'react';\nimport { Building2, CreditCard, ChevronDown, Check, Lock } from 'lucide-react';\nimport type { CheckoutBillingAccount } from '../types';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface BillingAccountSelectorProps {\n accounts: CheckoutBillingAccount[];\n selectedAccountId: string | null;\n onSelect: (account: CheckoutBillingAccount) => void;\n isLoading?: boolean;\n disabled?: boolean;\n disabledMessage?: string;\n}\n\nexport const BillingAccountSelector: FC<BillingAccountSelectorProps> = ({\n accounts,\n selectedAccountId,\n onSelect,\n isLoading = false,\n disabled = false,\n disabledMessage,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Close on escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n const selectedAccount = accounts.find((a) => a.id === selectedAccountId);\n\n if (isLoading) {\n return (\n <div className=\"space-y-2\">\n <div className=\"h-4 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-12 bg-muted animate-pulse rounded-lg\" />\n </div>\n );\n }\n\n if (accounts.length === 0) {\n return (\n <div className=\"rounded-lg border border-dashed border-border p-4 text-center\">\n <Building2 className=\"mx-auto h-6 w-6 text-muted-foreground\" />\n <p className=\"mt-2 text-sm text-muted-foreground\">No billing accounts found</p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2 relative\" ref={dropdownRef}>\n <div className=\"flex items-center justify-between\">\n <label className=\"text-sm font-medium text-foreground\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </label>\n {disabled && (\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Lock className=\"h-3 w-3\" />\n Locked\n </span>\n )}\n </div>\n\n {/* Dropdown trigger */}\n <button\n type=\"button\"\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n className={`\n w-full flex items-center justify-between gap-3 p-3 rounded-lg border\n transition-colors text-left\n ${\n disabled\n ? 'border-border bg-muted/30 cursor-not-allowed opacity-80'\n : isOpen\n ? 'border-primary ring-1 ring-primary'\n : 'border-border hover:border-primary/50'\n }\n `}\n >\n {selectedAccount ? (\n <div className=\"flex items-center gap-3 min-w-0 flex-1\">\n <div\n className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-full ${\n disabled ? 'bg-muted text-muted-foreground' : 'bg-primary/10 text-primary'\n }`}\n >\n <Building2 className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-foreground truncate\">{selectedAccount.name}</span>\n {!selectedAccount.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-destructive/10 text-destructive shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground truncate\">{selectedAccount.email}</p>\n </div>\n <div className=\"shrink-0 text-right\">\n <div className=\"flex items-center gap-1 text-sm font-medium text-foreground\">\n <CreditCard className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {formatCurrency(selectedAccount.creditAmount, 'CREDITS')}\n </div>\n </div>\n </div>\n ) : (\n <span className=\"text-muted-foreground\">Select billing account</span>\n )}\n {disabled ? (\n <Lock className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n ) : (\n <ChevronDown\n className={`h-4 w-4 shrink-0 text-muted-foreground transition-transform ${\n isOpen ? 'rotate-180' : ''\n }`}\n />\n )}\n </button>\n\n {/* Disabled message */}\n {disabled && disabledMessage && (\n <p className=\"text-xs text-muted-foreground\">{disabledMessage}</p>\n )}\n\n {/* Dropdown menu */}\n {isOpen && !disabled && (\n <div className=\"absolute left-0 right-0 z-50 mt-1 max-h-64 overflow-auto rounded-lg border border-border bg-popover shadow-lg\">\n {accounts.map((account) => {\n const isSelected = account.id === selectedAccountId;\n return (\n <button\n key={account.id}\n type=\"button\"\n onClick={() => {\n onSelect(account);\n setIsOpen(false);\n }}\n className={`\n w-full flex items-center gap-3 p-3 text-left\n transition-colors\n ${isSelected ? 'bg-primary/5' : 'hover:bg-muted/50'}\n `}\n >\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Building2 className=\"h-4 w-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-foreground truncate\">{account.name}</span>\n {!account.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-destructive/10 text-destructive shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground truncate\">{account.email}</p>\n </div>\n <div className=\"shrink-0 flex items-center gap-2\">\n <div className=\"text-right\">\n <div className=\"flex items-center gap-1 text-sm font-medium text-foreground\">\n <CreditCard className=\"h-3.5 w-3.5 text-muted-foreground\" />\n {formatCurrency(account.creditAmount, 'CREDITS')}\n </div>\n </div>\n {isSelected && <Check className=\"h-4 w-4 text-primary\" />}\n </div>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BillingAccountSelector.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/BillingAccountSelector.tsx"],"sourcesContent":["/**\n * Billing Account Selector Component\n * Dropdown selector for choosing billing account in checkout\n */\n\nimport { type FC, useState, useRef, useEffect } from 'react';\nimport { Building2, CreditCard, ChevronDown, Check, Lock } from 'lucide-react';\nimport type { CheckoutBillingAccount } from '../types';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface BillingAccountSelectorProps {\n accounts: CheckoutBillingAccount[];\n selectedAccountId: string | null;\n onSelect: (account: CheckoutBillingAccount) => void;\n isLoading?: boolean;\n disabled?: boolean;\n disabledMessage?: string;\n}\n\nexport const BillingAccountSelector: FC<BillingAccountSelectorProps> = ({\n accounts,\n selectedAccountId,\n onSelect,\n isLoading = false,\n disabled = false,\n disabledMessage,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [isOpen, setIsOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Close on escape key\n useEffect(() => {\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }\n }, [isOpen]);\n\n const selectedAccount = accounts.find((a) => a.id === selectedAccountId);\n\n if (isLoading) {\n return (\n <div className=\"space-y-2\">\n <div className=\"h-4 w-28 bg-muted animate-pulse rounded\" />\n <div className=\"h-12 bg-muted animate-pulse rounded-lg\" />\n </div>\n );\n }\n\n if (accounts.length === 0) {\n return (\n <div className=\"rounded-lg border border-dashed border-border p-4 text-center\">\n <Building2 className=\"mx-auto size-6 text-muted-foreground\" />\n <p className=\"mt-2 text-sm text-muted-foreground\">No billing accounts found</p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2 relative\" ref={dropdownRef}>\n <div className=\"flex items-center justify-between\">\n <label className=\"text-sm font-medium text-foreground\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </label>\n {disabled && (\n <span className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <Lock className=\"size-3\" />\n Locked\n </span>\n )}\n </div>\n\n {/* Dropdown trigger */}\n <button\n type=\"button\"\n onClick={() => !disabled && setIsOpen(!isOpen)}\n disabled={disabled}\n className={`\n w-full flex items-center justify-between gap-3 p-3 rounded-lg border\n transition-colors text-left\n ${\n disabled\n ? 'border-border bg-muted/30 cursor-not-allowed opacity-80'\n : isOpen\n ? 'border-primary ring-1 ring-primary'\n : 'border-border hover:border-primary/50'\n }\n `}\n >\n {selectedAccount ? (\n <div className=\"flex items-center gap-3 min-w-0 flex-1\">\n <div\n className={`flex size-8 shrink-0 items-center justify-center rounded-full ${\n disabled ? 'bg-muted text-muted-foreground' : 'bg-primary/10 text-primary'\n }`}\n >\n <Building2 className=\"size-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-foreground truncate\">{selectedAccount.name}</span>\n {!selectedAccount.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-destructive/10 text-destructive shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground truncate\">{selectedAccount.email}</p>\n </div>\n <div className=\"shrink-0 text-right\">\n <div className=\"flex items-center gap-1 text-sm font-medium text-foreground\">\n <CreditCard className=\"size-3.5 text-muted-foreground\" />\n {formatCurrency(selectedAccount.creditAmount, 'CREDITS')}\n </div>\n </div>\n </div>\n ) : (\n <span className=\"text-muted-foreground\">Select billing account</span>\n )}\n {disabled ? (\n <Lock className=\"size-4 shrink-0 text-muted-foreground\" />\n ) : (\n <ChevronDown\n className={`size-4 shrink-0 text-muted-foreground transition-transform ${\n isOpen ? 'rotate-180' : ''\n }`}\n />\n )}\n </button>\n\n {/* Disabled message */}\n {disabled && disabledMessage && (\n <p className=\"text-xs text-muted-foreground\">{disabledMessage}</p>\n )}\n\n {/* Dropdown menu */}\n {isOpen && !disabled && (\n <div className=\"absolute left-0 right-0 z-50 mt-1 max-h-64 overflow-auto rounded-lg border border-border bg-popover shadow-lg\">\n {accounts.map((account) => {\n const isSelected = account.id === selectedAccountId;\n return (\n <button\n key={account.id}\n type=\"button\"\n onClick={() => {\n onSelect(account);\n setIsOpen(false);\n }}\n className={`\n w-full flex items-center gap-3 p-3 text-left\n transition-colors\n ${isSelected ? 'bg-primary/5' : 'hover:bg-muted/50'}\n `}\n >\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Building2 className=\"size-4\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium text-foreground truncate\">{account.name}</span>\n {!account.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-destructive/10 text-destructive shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground truncate\">{account.email}</p>\n </div>\n <div className=\"shrink-0 flex items-center gap-2\">\n <div className=\"text-right\">\n <div className=\"flex items-center gap-1 text-sm font-medium text-foreground\">\n <CreditCard className=\"size-3.5 text-muted-foreground\" />\n {formatCurrency(account.creditAmount, 'CREDITS')}\n </div>\n </div>\n {isSelected && <Check className=\"size-4 text-primary\" />}\n </div>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -54,7 +54,7 @@ var l = [
|
|
|
54
54
|
className: "flex items-center justify-between",
|
|
55
55
|
children: [/* @__PURE__ */ s("div", {
|
|
56
56
|
className: "flex items-center gap-2",
|
|
57
|
-
children: [/* @__PURE__ */ o(r, { className: "
|
|
57
|
+
children: [/* @__PURE__ */ o(r, { className: "size-4 text-status-warning-text" }), /* @__PURE__ */ o("span", {
|
|
58
58
|
className: "font-medium text-foreground",
|
|
59
59
|
children: v("billing.checkout.creditAmount", "Credit Amount")
|
|
60
60
|
})]
|
|
@@ -72,7 +72,7 @@ var l = [
|
|
|
72
72
|
disabled: g || u <= f,
|
|
73
73
|
className: "p-2 rounded-md border border-border hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed",
|
|
74
74
|
"aria-label": "Decrease by 100",
|
|
75
|
-
children: /* @__PURE__ */ o(i, { className: "
|
|
75
|
+
children: /* @__PURE__ */ o(i, { className: "size-4" })
|
|
76
76
|
}),
|
|
77
77
|
/* @__PURE__ */ o("div", {
|
|
78
78
|
className: "relative flex-1",
|
|
@@ -93,7 +93,7 @@ var l = [
|
|
|
93
93
|
disabled: g || u >= p,
|
|
94
94
|
className: "p-2 rounded-md border border-border hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed",
|
|
95
95
|
"aria-label": "Increase by 100",
|
|
96
|
-
children: /* @__PURE__ */ o(a, { className: "
|
|
96
|
+
children: /* @__PURE__ */ o(a, { className: "size-4" })
|
|
97
97
|
})
|
|
98
98
|
]
|
|
99
99
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreditsAmountInput.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/CreditsAmountInput.tsx"],"sourcesContent":["/**\n * Credits Amount Input Component\n * Compact input for specifying how many credits to purchase\n */\n\nimport { type FC, useState, useCallback } from 'react';\nimport { Coins, Minus, Plus } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface CreditsAmountInputProps {\n value: number;\n onChange: (value: number) => void;\n minAmount?: number;\n maxAmount?: number;\n costPerCredit?: number;\n currency?: string;\n disabled?: boolean;\n}\n\nconst QUICK_AMOUNTS = [100, 500, 1000, 5000];\n\nexport const CreditsAmountInput: FC<CreditsAmountInputProps> = ({\n value,\n onChange,\n minAmount = 1,\n maxAmount = 100000,\n costPerCredit = 0.01,\n currency = 'USD',\n disabled = false,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [inputValue, setInputValue] = useState(value.toString());\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.replace(/[^0-9]/g, '');\n setInputValue(raw);\n\n const parsed = parseInt(raw, 10);\n if (!isNaN(parsed) && parsed >= minAmount && parsed <= maxAmount) {\n onChange(parsed);\n }\n },\n [onChange, minAmount, maxAmount]\n );\n\n const handleBlur = useCallback(() => {\n let parsed = parseInt(inputValue, 10);\n if (isNaN(parsed) || parsed < minAmount) {\n parsed = minAmount;\n } else if (parsed > maxAmount) {\n parsed = maxAmount;\n }\n setInputValue(parsed.toString());\n onChange(parsed);\n }, [inputValue, onChange, minAmount, maxAmount]);\n\n const handleIncrement = useCallback(\n (amount: number) => {\n const newValue = Math.min(value + amount, maxAmount);\n setInputValue(newValue.toString());\n onChange(newValue);\n },\n [value, onChange, maxAmount]\n );\n\n const handleDecrement = useCallback(\n (amount: number) => {\n const newValue = Math.max(value - amount, minAmount);\n setInputValue(newValue.toString());\n onChange(newValue);\n },\n [value, onChange, minAmount]\n );\n\n const handleQuickAmount = useCallback(\n (amount: number) => {\n setInputValue(amount.toString());\n onChange(amount);\n },\n [onChange]\n );\n\n const totalCost = value * costPerCredit;\n\n return (\n <div className=\"space-y-3\">\n {/* Header - compact */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Coins className=\"
|
|
1
|
+
{"version":3,"file":"CreditsAmountInput.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/CreditsAmountInput.tsx"],"sourcesContent":["/**\n * Credits Amount Input Component\n * Compact input for specifying how many credits to purchase\n */\n\nimport { type FC, useState, useCallback } from 'react';\nimport { Coins, Minus, Plus } from 'lucide-react';\nimport { formatCurrency } from '../../../shared/utils/format';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface CreditsAmountInputProps {\n value: number;\n onChange: (value: number) => void;\n minAmount?: number;\n maxAmount?: number;\n costPerCredit?: number;\n currency?: string;\n disabled?: boolean;\n}\n\nconst QUICK_AMOUNTS = [100, 500, 1000, 5000];\n\nexport const CreditsAmountInput: FC<CreditsAmountInputProps> = ({\n value,\n onChange,\n minAmount = 1,\n maxAmount = 100000,\n costPerCredit = 0.01,\n currency = 'USD',\n disabled = false,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n const [inputValue, setInputValue] = useState(value.toString());\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const raw = e.target.value.replace(/[^0-9]/g, '');\n setInputValue(raw);\n\n const parsed = parseInt(raw, 10);\n if (!isNaN(parsed) && parsed >= minAmount && parsed <= maxAmount) {\n onChange(parsed);\n }\n },\n [onChange, minAmount, maxAmount]\n );\n\n const handleBlur = useCallback(() => {\n let parsed = parseInt(inputValue, 10);\n if (isNaN(parsed) || parsed < minAmount) {\n parsed = minAmount;\n } else if (parsed > maxAmount) {\n parsed = maxAmount;\n }\n setInputValue(parsed.toString());\n onChange(parsed);\n }, [inputValue, onChange, minAmount, maxAmount]);\n\n const handleIncrement = useCallback(\n (amount: number) => {\n const newValue = Math.min(value + amount, maxAmount);\n setInputValue(newValue.toString());\n onChange(newValue);\n },\n [value, onChange, maxAmount]\n );\n\n const handleDecrement = useCallback(\n (amount: number) => {\n const newValue = Math.max(value - amount, minAmount);\n setInputValue(newValue.toString());\n onChange(newValue);\n },\n [value, onChange, minAmount]\n );\n\n const handleQuickAmount = useCallback(\n (amount: number) => {\n setInputValue(amount.toString());\n onChange(amount);\n },\n [onChange]\n );\n\n const totalCost = value * costPerCredit;\n\n return (\n <div className=\"space-y-3\">\n {/* Header - compact */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Coins className=\"size-4 text-status-warning-text\" />\n <span className=\"font-medium text-foreground\">\n {tr('billing.checkout.creditAmount', 'Credit Amount')}\n </span>\n </div>\n <span className=\"text-sm text-muted-foreground\">\n {formatCurrency(costPerCredit, currency)}/credit\n </span>\n </div>\n\n {/* Input row - compact */}\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => handleDecrement(100)}\n disabled={disabled || value <= minAmount}\n className=\"p-2 rounded-md border border-border hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label=\"Decrease by 100\"\n >\n <Minus className=\"size-4\" />\n </button>\n\n <div className=\"relative flex-1\">\n <input\n type=\"text\"\n inputMode=\"numeric\"\n aria-label={tr('billing.checkout.creditAmountInput', 'Credit amount')}\n value={inputValue}\n onChange={handleInputChange}\n onBlur={handleBlur}\n disabled={disabled}\n className=\"w-full px-4 py-2 text-center text-lg font-semibold\n rounded-md border border-border bg-background text-foreground\n focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary\n disabled:opacity-50 disabled:cursor-not-allowed\"\n />\n </div>\n\n <button\n type=\"button\"\n onClick={() => handleIncrement(100)}\n disabled={disabled || value >= maxAmount}\n className=\"p-2 rounded-md border border-border hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label=\"Increase by 100\"\n >\n <Plus className=\"size-4\" />\n </button>\n </div>\n\n {/* Quick amount buttons - compact row */}\n <div className=\"flex gap-2\">\n {QUICK_AMOUNTS.map((amount) => (\n <button\n key={amount}\n type=\"button\"\n onClick={() => handleQuickAmount(amount)}\n disabled={disabled}\n className={`\n flex-1 px-2 py-1.5 rounded-md border text-sm font-medium transition-colors\n ${\n value === amount\n ? 'border-primary bg-primary/10 text-primary'\n : 'border-border hover:border-primary/50 hover:bg-muted text-foreground'\n }\n disabled:opacity-50 disabled:cursor-not-allowed\n `}\n >\n {amount.toLocaleString()}\n </button>\n ))}\n </div>\n\n {/* Cost summary - compact inline */}\n <div className=\"flex items-center justify-between p-3 rounded-md bg-status-warning-bg-subtle border border-border-subtle\">\n <span className=\"text-sm text-status-warning-text\">{value.toLocaleString()} credits</span>\n <span className=\"font-semibold text-foreground\">{formatCurrency(totalCost, currency)}</span>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -107,6 +107,7 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
107
107
|
})]
|
|
108
108
|
}),
|
|
109
109
|
/* @__PURE__ */ g("button", {
|
|
110
|
+
type: "button",
|
|
110
111
|
disabled: r,
|
|
111
112
|
onClick: n,
|
|
112
113
|
className: "flex w-full items-center justify-center gap-2 rounded-xl bg-[--color-primary] px-6 py-4 text-sm font-semibold text-[--color-primary-foreground] transition-opacity disabled:opacity-60 active:opacity-80",
|
|
@@ -137,6 +138,7 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
137
138
|
}), e.map((e) => {
|
|
138
139
|
let i = x(e.subscriptionPeriod);
|
|
139
140
|
return /* @__PURE__ */ _("button", {
|
|
141
|
+
type: "button",
|
|
140
142
|
disabled: r,
|
|
141
143
|
onClick: () => n(e),
|
|
142
144
|
className: "flex items-center justify-between rounded-xl border border-[--color-border] bg-[--color-surface] p-4 text-left transition-colors hover:border-[--color-primary] hover:bg-[--color-surface-hover] disabled:opacity-60",
|
|
@@ -183,6 +185,7 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
183
185
|
children: S(r)
|
|
184
186
|
})] }),
|
|
185
187
|
/* @__PURE__ */ g("button", {
|
|
188
|
+
type: "button",
|
|
186
189
|
onClick: s,
|
|
187
190
|
className: "rounded-xl bg-[--color-primary] px-8 py-3 text-sm font-semibold text-[--color-primary-foreground]",
|
|
188
191
|
children: "Done"
|
|
@@ -203,10 +206,12 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
203
206
|
/* @__PURE__ */ _("div", {
|
|
204
207
|
className: "flex gap-3",
|
|
205
208
|
children: [/* @__PURE__ */ g("button", {
|
|
209
|
+
type: "button",
|
|
206
210
|
onClick: () => void b(i ? [i] : void 0),
|
|
207
211
|
className: "rounded-xl border border-[--color-border] px-6 py-3 text-sm font-medium text-[--color-text-primary]",
|
|
208
212
|
children: "Try Again"
|
|
209
213
|
}), /* @__PURE__ */ g("button", {
|
|
214
|
+
type: "button",
|
|
210
215
|
onClick: s,
|
|
211
216
|
className: "rounded-xl bg-[--color-primary] px-6 py-3 text-sm font-medium text-[--color-primary-foreground]",
|
|
212
217
|
children: "Cancel"
|
|
@@ -221,6 +226,7 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
221
226
|
/* @__PURE__ */ _("div", {
|
|
222
227
|
className: "flex items-center gap-3 border-b border-[--color-border] px-4 py-3",
|
|
223
228
|
children: [/* @__PURE__ */ g("button", {
|
|
229
|
+
type: "button",
|
|
224
230
|
onClick: s,
|
|
225
231
|
className: "rounded-lg p-2 text-[--color-text-secondary] hover:bg-[--color-surface-hover]",
|
|
226
232
|
children: /* @__PURE__ */ g(n, { className: "size-5" })
|
|
@@ -259,6 +265,7 @@ var C = ({ product: e, purchaseType: t, onPay: n, isProcessing: r }) => {
|
|
|
259
265
|
!k && /* @__PURE__ */ g("div", {
|
|
260
266
|
className: "px-4 pb-6 pt-2",
|
|
261
267
|
children: /* @__PURE__ */ _("button", {
|
|
268
|
+
type: "button",
|
|
262
269
|
onClick: () => void T(),
|
|
263
270
|
className: "flex w-full items-center justify-center gap-1.5 text-xs text-[--color-text-tertiary] underline-offset-2 hover:underline",
|
|
264
271
|
children: [/* @__PURE__ */ g(d, { className: "size-3" }), "Restore previous purchases"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeCheckoutView.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/NativeCheckoutView.tsx"],"sourcesContent":["/**\n * Native IAP Checkout View\n *\n * Replaces the Stripe/Razorpay checkout UI when running inside a Capacitor\n * native app (iOS / Android). Shows an order summary then triggers the native\n * payment sheet on confirmation.\n *\n * After a successful purchase the backend validates the receipt/token with\n * Apple/Google servers and activates the subscription, credits, or add-on.\n */\n\nimport { type FC, useEffect, useState } from 'react';\nimport {\n ArrowLeft,\n Loader2,\n CheckCircle,\n XCircle,\n RotateCcw,\n Smartphone,\n Package,\n Coins,\n Blocks,\n ShoppingBag,\n CalendarDays,\n Info,\n ChevronRight,\n} from 'lucide-react';\nimport type { useNativeCheckout } from '../hooks/useNativeCheckout';\nimport type { Product } from '@capgo/native-purchases';\nimport type { PurchaseType } from '../types';\n\ninterface NativeCheckoutViewProps {\n purchaseType: PurchaseType;\n productId?: string;\n billingAccountId?: string;\n nativeCheckout: ReturnType<typeof useNativeCheckout>;\n onBack: () => void;\n}\n\nconst isIOS =\n typeof navigator !== 'undefined' &&\n (/iPad|iPhone|iPod/.test(navigator.userAgent) ||\n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));\n\nconst storeName = isIOS ? 'App Store' : 'Google Play';\n\nfunction purchaseTypeLabel(type: PurchaseType): string {\n switch (type) {\n case 'CREDITS':\n return 'Credits';\n case 'ADDON':\n return 'Add-on';\n case 'ORDER':\n return 'Order';\n default:\n return 'Subscription';\n }\n}\n\nfunction purchaseTypeIcon(type: PurchaseType) {\n switch (type) {\n case 'CREDITS':\n return <Coins className=\"size-6 text-[--color-primary]\" />;\n case 'ADDON':\n return <Blocks className=\"size-6 text-[--color-primary]\" />;\n case 'ORDER':\n return <ShoppingBag className=\"size-6 text-[--color-primary]\" />;\n default:\n return <Package className=\"size-6 text-[--color-primary]\" />;\n }\n}\n\ninterface SubscriptionPeriod {\n numberOfUnits: number;\n unit: number;\n}\n\n// unit: 0=day, 1=week, 2=month, 3=year (Apple/Google convention)\nfunction billingPeriodLabel(period: SubscriptionPeriod | null | undefined): string | null {\n if (!period) return null;\n switch (period.unit) {\n case 0:\n return period.numberOfUnits === 1\n ? 'Billed daily'\n : `Billed every ${period.numberOfUnits} days`;\n case 1:\n return period.numberOfUnits === 1\n ? 'Billed weekly'\n : `Billed every ${period.numberOfUnits} weeks`;\n case 2:\n return period.numberOfUnits === 1\n ? 'Billed monthly'\n : `Billed every ${period.numberOfUnits} months`;\n case 3:\n return period.numberOfUnits === 1\n ? 'Billed yearly'\n : `Billed every ${period.numberOfUnits} years`;\n default:\n return null;\n }\n}\n\nfunction successLabel(type: PurchaseType): string {\n switch (type) {\n case 'CREDITS':\n return 'Your credits will be added shortly. It may take a few seconds to reflect.';\n case 'ADDON':\n return 'Your add-on will be activated shortly. It may take a few seconds to reflect.';\n case 'ORDER':\n return 'Your order has been placed. It may take a few seconds to reflect.';\n default:\n return 'Your subscription will be activated shortly. It may take a few seconds to reflect.';\n }\n}\n\n// ─── Single-product summary card ──────────────────────────────────────────────\n\ninterface ProductSummaryProps {\n product: Product;\n purchaseType: PurchaseType;\n onPay: () => void;\n isProcessing: boolean;\n}\n\nconst ProductSummary: FC<ProductSummaryProps> = ({\n product,\n purchaseType,\n onPay,\n isProcessing,\n}) => {\n const period = billingPeriodLabel(\n product.subscriptionPeriod as SubscriptionPeriod | null | undefined\n );\n const hasIntro = !!product.introductoryPrice;\n\n return (\n <div className=\"flex flex-col gap-4 p-4\">\n {/* What you're getting */}\n <div className=\"rounded-2xl border border-[--color-border] bg-[--color-surface] overflow-hidden\">\n {/* Item row */}\n <div className=\"flex items-start gap-4 p-4\">\n <div className=\"flex size-11 shrink-0 items-center justify-center rounded-xl bg-[--color-primary-subtle]\">\n {purchaseTypeIcon(purchaseType)}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-semibold text-[--color-text-primary] leading-snug\">\n {product.title}\n </p>\n {product.description ? (\n <p className=\"mt-1 text-xs text-[--color-text-secondary] leading-relaxed\">\n {product.description}\n </p>\n ) : null}\n </div>\n </div>\n\n {/* Divider */}\n <div className=\"h-px bg-[--color-border]\" />\n\n {/* Pricing row */}\n <div className=\"flex items-center justify-between px-4 py-3\">\n <div className=\"flex flex-col\">\n {hasIntro && product.introductoryPrice ? (\n <>\n <span className=\"text-xs text-[--color-text-secondary] line-through\">\n {product.priceString}\n </span>\n <span className=\"text-lg font-bold text-[--color-primary]\">\n {product.introductoryPrice.priceString}\n <span className=\"ml-1 text-xs font-normal text-[--color-text-secondary]\">\n intro offer\n </span>\n </span>\n </>\n ) : (\n <span className=\"text-lg font-bold text-[--color-primary]\">\n {product.priceString}\n </span>\n )}\n {period ? (\n <div className=\"mt-0.5 flex items-center gap-1\">\n <CalendarDays className=\"size-3 text-[--color-text-tertiary]\" />\n <span className=\"text-xs text-[--color-text-secondary]\">{period}</span>\n </div>\n ) : null}\n </div>\n <div className=\"flex items-center gap-1 rounded-full bg-[--color-surface-subtle] px-2.5 py-1\">\n <span className=\"text-xs font-medium text-[--color-text-secondary]\">\n {purchaseTypeLabel(purchaseType)}\n </span>\n </div>\n </div>\n </div>\n\n {/* Tax note */}\n <div className=\"flex items-start gap-2 rounded-xl bg-[--color-surface-subtle] px-3 py-2.5\">\n <Info className=\"mt-0.5 size-3.5 shrink-0 text-[--color-text-tertiary]\" />\n <p className=\"text-xs text-[--color-text-secondary] leading-relaxed\">\n Price includes all applicable taxes as determined by {storeName}. No additional charges.\n </p>\n </div>\n\n {/* Pay CTA */}\n <button\n disabled={isProcessing}\n onClick={onPay}\n className=\"flex w-full items-center justify-center gap-2 rounded-xl bg-[--color-primary] px-6 py-4 text-sm font-semibold text-[--color-primary-foreground] transition-opacity disabled:opacity-60 active:opacity-80\"\n >\n {isProcessing ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Processing…\n </>\n ) : (\n <>\n <Smartphone className=\"size-4\" />\n Pay with {storeName}\n <ChevronRight className=\"size-4 opacity-70\" />\n </>\n )}\n </button>\n\n {/* Legal note */}\n <p className=\"text-center text-[10px] leading-relaxed text-[--color-text-tertiary]\">\n By continuing, you agree to the {storeName} terms.{' '}\n {purchaseType === 'PLAN'\n ? 'Subscription renews automatically. Cancel anytime.'\n : 'This is a one-time purchase.'}\n </p>\n </div>\n );\n};\n\n// ─── Multi-product list ───────────────────────────────────────────────────────\n\ninterface ProductListProps {\n products: Product[];\n purchaseType: PurchaseType;\n onSelect: (product: Product) => void;\n isProcessing: boolean;\n}\n\nconst ProductList: FC<ProductListProps> = ({ products, purchaseType, onSelect, isProcessing }) => (\n <div className=\"flex flex-col gap-3 p-4\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-[--color-text-tertiary]\">\n Select a {purchaseTypeLabel(purchaseType)}\n </p>\n {products.map((product) => {\n const period = billingPeriodLabel(\n product.subscriptionPeriod as SubscriptionPeriod | null | undefined\n );\n return (\n <button\n key={product.identifier}\n disabled={isProcessing}\n onClick={() => onSelect(product)}\n className=\"flex items-center justify-between rounded-xl border border-[--color-border] bg-[--color-surface] p-4 text-left transition-colors hover:border-[--color-primary] hover:bg-[--color-surface-hover] disabled:opacity-60\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-9 shrink-0 items-center justify-center rounded-lg bg-[--color-primary-subtle]\">\n {purchaseTypeIcon(purchaseType)}\n </div>\n <div>\n <p className=\"text-sm font-semibold text-[--color-text-primary]\">{product.title}</p>\n {period ? (\n <p className=\"mt-0.5 text-xs text-[--color-text-secondary]\">{period}</p>\n ) : null}\n </div>\n </div>\n <div className=\"ml-4 shrink-0 text-right\">\n <p className=\"text-base font-bold text-[--color-primary]\">{product.priceString}</p>\n {isProcessing && (\n <Loader2 className=\"ml-auto mt-1 size-4 animate-spin text-[--color-text-tertiary]\" />\n )}\n </div>\n </button>\n );\n })}\n </div>\n);\n\n// ─── Main component ───────────────────────────────────────────────────────────\n\nexport const NativeCheckoutView: FC<NativeCheckoutViewProps> = ({\n purchaseType,\n productId,\n nativeCheckout,\n onBack,\n}) => {\n const {\n products,\n checkoutState,\n error,\n isLoading,\n loadProducts,\n purchaseProduct,\n restorePurchases,\n } = nativeCheckout;\n\n // When user already selected a specific product, track it for the summary view\n const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);\n\n useEffect(() => {\n void loadProducts(productId ? [productId] : undefined);\n }, [loadProducts, productId]);\n\n // Auto-select when only one product loaded (specific product was pre-selected)\n useEffect(() => {\n if (products.length === 1 && products[0] && !selectedProduct) {\n setSelectedProduct(products[0]);\n }\n }, [products, selectedProduct]);\n\n const handlePay = (product: Product) => {\n setSelectedProduct(product);\n void purchaseProduct(product);\n };\n\n // ── Success ────────────────────────────────────────────────────────────────\n if (checkoutState === 'success') {\n return (\n <div className=\"flex flex-col items-center justify-center gap-6 py-16 px-6 text-center\">\n <CheckCircle className=\"size-16 text-[--color-success]\" />\n <div>\n <p className=\"text-xl font-semibold text-[--color-text-primary]\">Purchase Successful</p>\n <p className=\"mt-2 text-sm text-[--color-text-secondary]\">{successLabel(purchaseType)}</p>\n </div>\n <button\n onClick={onBack}\n className=\"rounded-xl bg-[--color-primary] px-8 py-3 text-sm font-semibold text-[--color-primary-foreground]\"\n >\n Done\n </button>\n </div>\n );\n }\n\n // ── Error ──────────────────────────────────────────────────────────────────\n if (checkoutState === 'error') {\n return (\n <div className=\"flex flex-col items-center justify-center gap-6 py-16 px-6 text-center\">\n <XCircle className=\"size-16 text-[--color-destructive]\" />\n <div>\n <p className=\"text-xl font-semibold text-[--color-text-primary]\">Purchase Failed</p>\n <p className=\"mt-2 text-sm text-[--color-text-secondary]\">{error}</p>\n </div>\n <div className=\"flex gap-3\">\n <button\n onClick={() => void loadProducts(productId ? [productId] : undefined)}\n className=\"rounded-xl border border-[--color-border] px-6 py-3 text-sm font-medium text-[--color-text-primary]\"\n >\n Try Again\n </button>\n <button\n onClick={onBack}\n className=\"rounded-xl bg-[--color-primary] px-6 py-3 text-sm font-medium text-[--color-primary-foreground]\"\n >\n Cancel\n </button>\n </div>\n </div>\n );\n }\n\n const isProcessing = checkoutState === 'processing';\n\n return (\n <div className=\"flex flex-col gap-0\">\n {/* Header */}\n <div className=\"flex items-center gap-3 border-b border-[--color-border] px-4 py-3\">\n <button\n onClick={onBack}\n className=\"rounded-lg p-2 text-[--color-text-secondary] hover:bg-[--color-surface-hover]\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div>\n <p className=\"text-base font-semibold text-[--color-text-primary]\">\n {(selectedProduct ?? products.length === 1)\n ? 'Order Summary'\n : `Choose a ${purchaseTypeLabel(purchaseType)}`}\n </p>\n </div>\n </div>\n\n {/* Store badge */}\n <div className=\"flex items-center gap-2 border-b border-[--color-border] bg-[--color-surface-subtle] px-4 py-2\">\n <Smartphone className=\"size-3.5 text-[--color-text-tertiary]\" />\n <span className=\"text-xs text-[--color-text-secondary]\">\n Payments processed securely by <span className=\"font-medium\">{storeName}</span>\n </span>\n </div>\n\n {/* Content */}\n {isLoading && products.length === 0 ? (\n <div className=\"flex items-center justify-center py-20\">\n <Loader2 className=\"size-6 animate-spin text-[--color-text-tertiary]\" />\n </div>\n ) : products.length === 0 ? (\n <div className=\"py-16 text-center text-sm text-[--color-text-secondary] px-6\">\n No products available for this platform. Please try again later.\n </div>\n ) : (selectedProduct ?? products.length === 1) ? (\n // Single product — show order summary + pay CTA\n <ProductSummary\n product={(selectedProduct ?? products[0])!}\n purchaseType={purchaseType}\n onPay={() => handlePay((selectedProduct ?? products[0])!)}\n isProcessing={isProcessing}\n />\n ) : (\n // Multiple products — show list to pick from\n <ProductList\n products={products}\n purchaseType={purchaseType}\n onSelect={(p) => handlePay(p)}\n isProcessing={isProcessing}\n />\n )}\n\n {/* Restore purchases */}\n {!isProcessing && (\n <div className=\"px-4 pb-6 pt-2\">\n <button\n onClick={() => void restorePurchases()}\n className=\"flex w-full items-center justify-center gap-1.5 text-xs text-[--color-text-tertiary] underline-offset-2 hover:underline\"\n >\n <RotateCcw className=\"size-3\" />\n Restore previous purchases\n </button>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NativeCheckoutView.js","names":[],"sources":["../../../../../src/billing/modules/checkout/components/NativeCheckoutView.tsx"],"sourcesContent":["/**\n * Native IAP Checkout View\n *\n * Replaces the Stripe/Razorpay checkout UI when running inside a Capacitor\n * native app (iOS / Android). Shows an order summary then triggers the native\n * payment sheet on confirmation.\n *\n * After a successful purchase the backend validates the receipt/token with\n * Apple/Google servers and activates the subscription, credits, or add-on.\n */\n\nimport { type FC, useEffect, useState } from 'react';\nimport {\n ArrowLeft,\n Loader2,\n CheckCircle,\n XCircle,\n RotateCcw,\n Smartphone,\n Package,\n Coins,\n Blocks,\n ShoppingBag,\n CalendarDays,\n Info,\n ChevronRight,\n} from 'lucide-react';\nimport type { useNativeCheckout } from '../hooks/useNativeCheckout';\nimport type { Product } from '@capgo/native-purchases';\nimport type { PurchaseType } from '../types';\n\ninterface NativeCheckoutViewProps {\n purchaseType: PurchaseType;\n productId?: string;\n billingAccountId?: string;\n nativeCheckout: ReturnType<typeof useNativeCheckout>;\n onBack: () => void;\n}\n\nconst isIOS =\n typeof navigator !== 'undefined' &&\n (/iPad|iPhone|iPod/.test(navigator.userAgent) ||\n (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));\n\nconst storeName = isIOS ? 'App Store' : 'Google Play';\n\nfunction purchaseTypeLabel(type: PurchaseType): string {\n switch (type) {\n case 'CREDITS':\n return 'Credits';\n case 'ADDON':\n return 'Add-on';\n case 'ORDER':\n return 'Order';\n default:\n return 'Subscription';\n }\n}\n\nfunction purchaseTypeIcon(type: PurchaseType) {\n switch (type) {\n case 'CREDITS':\n return <Coins className=\"size-6 text-[--color-primary]\" />;\n case 'ADDON':\n return <Blocks className=\"size-6 text-[--color-primary]\" />;\n case 'ORDER':\n return <ShoppingBag className=\"size-6 text-[--color-primary]\" />;\n default:\n return <Package className=\"size-6 text-[--color-primary]\" />;\n }\n}\n\ninterface SubscriptionPeriod {\n numberOfUnits: number;\n unit: number;\n}\n\n// unit: 0=day, 1=week, 2=month, 3=year (Apple/Google convention)\nfunction billingPeriodLabel(period: SubscriptionPeriod | null | undefined): string | null {\n if (!period) return null;\n switch (period.unit) {\n case 0:\n return period.numberOfUnits === 1\n ? 'Billed daily'\n : `Billed every ${period.numberOfUnits} days`;\n case 1:\n return period.numberOfUnits === 1\n ? 'Billed weekly'\n : `Billed every ${period.numberOfUnits} weeks`;\n case 2:\n return period.numberOfUnits === 1\n ? 'Billed monthly'\n : `Billed every ${period.numberOfUnits} months`;\n case 3:\n return period.numberOfUnits === 1\n ? 'Billed yearly'\n : `Billed every ${period.numberOfUnits} years`;\n default:\n return null;\n }\n}\n\nfunction successLabel(type: PurchaseType): string {\n switch (type) {\n case 'CREDITS':\n return 'Your credits will be added shortly. It may take a few seconds to reflect.';\n case 'ADDON':\n return 'Your add-on will be activated shortly. It may take a few seconds to reflect.';\n case 'ORDER':\n return 'Your order has been placed. It may take a few seconds to reflect.';\n default:\n return 'Your subscription will be activated shortly. It may take a few seconds to reflect.';\n }\n}\n\n// ─── Single-product summary card ──────────────────────────────────────────────\n\ninterface ProductSummaryProps {\n product: Product;\n purchaseType: PurchaseType;\n onPay: () => void;\n isProcessing: boolean;\n}\n\nconst ProductSummary: FC<ProductSummaryProps> = ({\n product,\n purchaseType,\n onPay,\n isProcessing,\n}) => {\n const period = billingPeriodLabel(\n product.subscriptionPeriod as SubscriptionPeriod | null | undefined\n );\n const hasIntro = !!product.introductoryPrice;\n\n return (\n <div className=\"flex flex-col gap-4 p-4\">\n {/* What you're getting */}\n <div className=\"rounded-2xl border border-[--color-border] bg-[--color-surface] overflow-hidden\">\n {/* Item row */}\n <div className=\"flex items-start gap-4 p-4\">\n <div className=\"flex size-11 shrink-0 items-center justify-center rounded-xl bg-[--color-primary-subtle]\">\n {purchaseTypeIcon(purchaseType)}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-semibold text-[--color-text-primary] leading-snug\">\n {product.title}\n </p>\n {product.description ? (\n <p className=\"mt-1 text-xs text-[--color-text-secondary] leading-relaxed\">\n {product.description}\n </p>\n ) : null}\n </div>\n </div>\n\n {/* Divider */}\n <div className=\"h-px bg-[--color-border]\" />\n\n {/* Pricing row */}\n <div className=\"flex items-center justify-between px-4 py-3\">\n <div className=\"flex flex-col\">\n {hasIntro && product.introductoryPrice ? (\n <>\n <span className=\"text-xs text-[--color-text-secondary] line-through\">\n {product.priceString}\n </span>\n <span className=\"text-lg font-bold text-[--color-primary]\">\n {product.introductoryPrice.priceString}\n <span className=\"ml-1 text-xs font-normal text-[--color-text-secondary]\">\n intro offer\n </span>\n </span>\n </>\n ) : (\n <span className=\"text-lg font-bold text-[--color-primary]\">\n {product.priceString}\n </span>\n )}\n {period ? (\n <div className=\"mt-0.5 flex items-center gap-1\">\n <CalendarDays className=\"size-3 text-[--color-text-tertiary]\" />\n <span className=\"text-xs text-[--color-text-secondary]\">{period}</span>\n </div>\n ) : null}\n </div>\n <div className=\"flex items-center gap-1 rounded-full bg-[--color-surface-subtle] px-2.5 py-1\">\n <span className=\"text-xs font-medium text-[--color-text-secondary]\">\n {purchaseTypeLabel(purchaseType)}\n </span>\n </div>\n </div>\n </div>\n\n {/* Tax note */}\n <div className=\"flex items-start gap-2 rounded-xl bg-[--color-surface-subtle] px-3 py-2.5\">\n <Info className=\"mt-0.5 size-3.5 shrink-0 text-[--color-text-tertiary]\" />\n <p className=\"text-xs text-[--color-text-secondary] leading-relaxed\">\n Price includes all applicable taxes as determined by {storeName}. No additional charges.\n </p>\n </div>\n\n {/* Pay CTA */}\n <button\n type=\"button\"\n disabled={isProcessing}\n onClick={onPay}\n className=\"flex w-full items-center justify-center gap-2 rounded-xl bg-[--color-primary] px-6 py-4 text-sm font-semibold text-[--color-primary-foreground] transition-opacity disabled:opacity-60 active:opacity-80\"\n >\n {isProcessing ? (\n <>\n <Loader2 className=\"size-4 animate-spin\" />\n Processing…\n </>\n ) : (\n <>\n <Smartphone className=\"size-4\" />\n Pay with {storeName}\n <ChevronRight className=\"size-4 opacity-70\" />\n </>\n )}\n </button>\n\n {/* Legal note */}\n <p className=\"text-center text-[10px] leading-relaxed text-[--color-text-tertiary]\">\n By continuing, you agree to the {storeName} terms.{' '}\n {purchaseType === 'PLAN'\n ? 'Subscription renews automatically. Cancel anytime.'\n : 'This is a one-time purchase.'}\n </p>\n </div>\n );\n};\n\n// ─── Multi-product list ───────────────────────────────────────────────────────\n\ninterface ProductListProps {\n products: Product[];\n purchaseType: PurchaseType;\n onSelect: (product: Product) => void;\n isProcessing: boolean;\n}\n\nconst ProductList: FC<ProductListProps> = ({ products, purchaseType, onSelect, isProcessing }) => (\n <div className=\"flex flex-col gap-3 p-4\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-[--color-text-tertiary]\">\n Select a {purchaseTypeLabel(purchaseType)}\n </p>\n {products.map((product) => {\n const period = billingPeriodLabel(\n product.subscriptionPeriod as SubscriptionPeriod | null | undefined\n );\n return (\n <button\n type=\"button\"\n key={product.identifier}\n disabled={isProcessing}\n onClick={() => onSelect(product)}\n className=\"flex items-center justify-between rounded-xl border border-[--color-border] bg-[--color-surface] p-4 text-left transition-colors hover:border-[--color-primary] hover:bg-[--color-surface-hover] disabled:opacity-60\"\n >\n <div className=\"flex items-center gap-3\">\n <div className=\"flex size-9 shrink-0 items-center justify-center rounded-lg bg-[--color-primary-subtle]\">\n {purchaseTypeIcon(purchaseType)}\n </div>\n <div>\n <p className=\"text-sm font-semibold text-[--color-text-primary]\">{product.title}</p>\n {period ? (\n <p className=\"mt-0.5 text-xs text-[--color-text-secondary]\">{period}</p>\n ) : null}\n </div>\n </div>\n <div className=\"ml-4 shrink-0 text-right\">\n <p className=\"text-base font-bold text-[--color-primary]\">{product.priceString}</p>\n {isProcessing && (\n <Loader2 className=\"ml-auto mt-1 size-4 animate-spin text-[--color-text-tertiary]\" />\n )}\n </div>\n </button>\n );\n })}\n </div>\n);\n\n// ─── Main component ───────────────────────────────────────────────────────────\n\nexport const NativeCheckoutView: FC<NativeCheckoutViewProps> = ({\n purchaseType,\n productId,\n nativeCheckout,\n onBack,\n}) => {\n const {\n products,\n checkoutState,\n error,\n isLoading,\n loadProducts,\n purchaseProduct,\n restorePurchases,\n } = nativeCheckout;\n\n // When user already selected a specific product, track it for the summary view\n const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);\n\n useEffect(() => {\n void loadProducts(productId ? [productId] : undefined);\n }, [loadProducts, productId]);\n\n // Auto-select when only one product loaded (specific product was pre-selected)\n useEffect(() => {\n if (products.length === 1 && products[0] && !selectedProduct) {\n setSelectedProduct(products[0]);\n }\n }, [products, selectedProduct]);\n\n const handlePay = (product: Product) => {\n setSelectedProduct(product);\n void purchaseProduct(product);\n };\n\n // ── Success ────────────────────────────────────────────────────────────────\n if (checkoutState === 'success') {\n return (\n <div className=\"flex flex-col items-center justify-center gap-6 py-16 px-6 text-center\">\n <CheckCircle className=\"size-16 text-[--color-success]\" />\n <div>\n <p className=\"text-xl font-semibold text-[--color-text-primary]\">Purchase Successful</p>\n <p className=\"mt-2 text-sm text-[--color-text-secondary]\">{successLabel(purchaseType)}</p>\n </div>\n <button\n type=\"button\"\n onClick={onBack}\n className=\"rounded-xl bg-[--color-primary] px-8 py-3 text-sm font-semibold text-[--color-primary-foreground]\"\n >\n Done\n </button>\n </div>\n );\n }\n\n // ── Error ──────────────────────────────────────────────────────────────────\n if (checkoutState === 'error') {\n return (\n <div className=\"flex flex-col items-center justify-center gap-6 py-16 px-6 text-center\">\n <XCircle className=\"size-16 text-[--color-destructive]\" />\n <div>\n <p className=\"text-xl font-semibold text-[--color-text-primary]\">Purchase Failed</p>\n <p className=\"mt-2 text-sm text-[--color-text-secondary]\">{error}</p>\n </div>\n <div className=\"flex gap-3\">\n <button\n type=\"button\"\n onClick={() => void loadProducts(productId ? [productId] : undefined)}\n className=\"rounded-xl border border-[--color-border] px-6 py-3 text-sm font-medium text-[--color-text-primary]\"\n >\n Try Again\n </button>\n <button\n type=\"button\"\n onClick={onBack}\n className=\"rounded-xl bg-[--color-primary] px-6 py-3 text-sm font-medium text-[--color-primary-foreground]\"\n >\n Cancel\n </button>\n </div>\n </div>\n );\n }\n\n const isProcessing = checkoutState === 'processing';\n\n return (\n <div className=\"flex flex-col gap-0\">\n {/* Header */}\n <div className=\"flex items-center gap-3 border-b border-[--color-border] px-4 py-3\">\n <button\n type=\"button\"\n onClick={onBack}\n className=\"rounded-lg p-2 text-[--color-text-secondary] hover:bg-[--color-surface-hover]\"\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <div>\n <p className=\"text-base font-semibold text-[--color-text-primary]\">\n {(selectedProduct ?? products.length === 1)\n ? 'Order Summary'\n : `Choose a ${purchaseTypeLabel(purchaseType)}`}\n </p>\n </div>\n </div>\n\n {/* Store badge */}\n <div className=\"flex items-center gap-2 border-b border-[--color-border] bg-[--color-surface-subtle] px-4 py-2\">\n <Smartphone className=\"size-3.5 text-[--color-text-tertiary]\" />\n <span className=\"text-xs text-[--color-text-secondary]\">\n Payments processed securely by <span className=\"font-medium\">{storeName}</span>\n </span>\n </div>\n\n {/* Content */}\n {isLoading && products.length === 0 ? (\n <div className=\"flex items-center justify-center py-20\">\n <Loader2 className=\"size-6 animate-spin text-[--color-text-tertiary]\" />\n </div>\n ) : products.length === 0 ? (\n <div className=\"py-16 text-center text-sm text-[--color-text-secondary] px-6\">\n No products available for this platform. Please try again later.\n </div>\n ) : (selectedProduct ?? products.length === 1) ? (\n // Single product — show order summary + pay CTA\n <ProductSummary\n product={(selectedProduct ?? products[0])!}\n purchaseType={purchaseType}\n onPay={() => handlePay((selectedProduct ?? products[0])!)}\n isProcessing={isProcessing}\n />\n ) : (\n // Multiple products — show list to pick from\n <ProductList\n products={products}\n purchaseType={purchaseType}\n onSelect={(p) => handlePay(p)}\n isProcessing={isProcessing}\n />\n )}\n\n {/* Restore purchases */}\n {!isProcessing && (\n <div className=\"px-4 pb-6 pt-2\">\n <button\n type=\"button\"\n onClick={() => void restorePurchases()}\n className=\"flex w-full items-center justify-center gap-1.5 text-xs text-[--color-text-tertiary] underline-offset-2 hover:underline\"\n >\n <RotateCcw className=\"size-3\" />\n Restore previous purchases\n </button>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|