@burdenoff/microfe-billing 2026.624.2 → 2026.625.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.
Files changed (97) hide show
  1. package/dist/billing/BillingAdminRoutes.js +1 -1
  2. package/dist/billing/BillingAdminRoutes.js.map +1 -1
  3. package/dist/billing/modules/addons/pages/AddonCreatePage.js +2 -2
  4. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  5. package/dist/billing/modules/addons/pages/AddonDetailPage.js +4 -4
  6. package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
  7. package/dist/billing/modules/addons/pages/AddonEditPage.js +2 -2
  8. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  9. package/dist/billing/modules/addons/pages/AddonsListPage.js +1 -1
  10. package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
  11. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +98 -99
  12. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  13. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +88 -85
  14. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  15. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +6 -6
  16. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  17. package/dist/billing/modules/billing/pages/InvoicesListPage.js +2 -2
  18. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  19. package/dist/billing/modules/billing/pages/RefundsPage.js +383 -399
  20. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  21. package/dist/billing/modules/billing/pages/TransactionsPage.js +232 -252
  22. package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
  23. package/dist/billing/modules/billing/pages/UserRefundsPage.js +2 -2
  24. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  25. package/dist/billing/modules/checkout/components/BillingAccountSelector.js +1 -1
  26. package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
  27. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +1 -1
  28. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
  29. package/dist/billing/modules/checkout/components/SubscriptionSelector.js +1 -1
  30. package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
  31. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +2 -2
  32. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
  33. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +102 -104
  34. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  35. package/dist/billing/modules/coupons/pages/CouponsListPage.js +211 -249
  36. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  37. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
  38. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  39. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +1 -1
  40. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
  41. package/dist/billing/modules/credits/pages/CreditsPage.js +29 -28
  42. package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
  43. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js +2 -2
  44. package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
  45. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +1 -1
  46. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
  47. package/dist/billing/modules/dashboard/components/BillingAccountCard.js +3 -3
  48. package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
  49. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +2 -2
  50. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
  51. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js +1 -1
  52. package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
  53. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js +1 -1
  54. package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
  55. package/dist/billing/modules/dashboard/pages/OverviewPage.js +139 -142
  56. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  57. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +6 -6
  58. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  59. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +4 -4
  60. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  61. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +1 -1
  62. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  63. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +142 -133
  64. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  65. package/dist/billing/modules/plans/pages/PlanCreatePage.js +2 -2
  66. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  67. package/dist/billing/modules/plans/pages/PlanDetailPage.js +4 -4
  68. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  69. package/dist/billing/modules/plans/pages/PlanEditPage.js +2 -2
  70. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  71. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +3 -3
  72. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  73. package/dist/billing/modules/plans/pages/PlansListPage.js +2 -2
  74. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  75. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +4 -4
  76. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  77. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +2 -2
  78. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
  79. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +2 -2
  80. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  81. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +5 -5
  82. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
  83. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +2 -2
  84. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  85. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +1 -1
  86. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
  87. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +259 -265
  88. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  89. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +7 -7
  90. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  91. package/dist/billing/modules/usage/pages/UsagePage.js +13 -13
  92. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  93. package/dist/billing/shared/ui/Card.js +1 -1
  94. package/dist/billing/shared/ui/Card.js.map +1 -1
  95. package/dist/billing/shared/ui/MetricCard.js +28 -21
  96. package/dist/billing/shared/ui/MetricCard.js.map +1 -1
  97. 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 type=\"button\"\n onClick={() => setIsOpen(!isOpen)}\n className=\"p-1.5 rounded-md hover:bg-bg-sunken/50 transition-colors\"\n aria-label=\"Transaction actions\"\n >\n <MoreHorizontal className=\"size-4 text-text-secondary\" />\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-subtle 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-text-primary hover:bg-bg-sunken/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-text-primary hover:bg-bg-sunken/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-bg-surface border border-border-subtle 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-subtle\">\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-bg-sunken/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-text-secondary 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-text-secondary 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-text-secondary\">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-text-secondary\">\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-subtle 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-text-secondary 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-text-secondary 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-text-secondary 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-text-secondary 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-text-secondary 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-bg-sunken/50 rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary\">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-bg-sunken/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-text-secondary 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-text-secondary 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-subtle\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"w-full py-2 px-4 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/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 }\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-text-secondary\"\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-bg-sunken 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-bg-sunken 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-text-secondary hover:text-text-primary 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-subtle rounded-lg p-4 bg-bg-surface\">\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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Credits Balance</p>\n <p className=\"text-sm font-semibold text-text-primary\">\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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-subtle p-1 bg-bg-sunken/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-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\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-text-secondary\"\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-subtle rounded-lg overflow-visible\">\n <table className=\"w-full\">\n <thead className=\"bg-bg-sunken/50\">\n <tr>\n <th className=\"text-left text-sm font-medium text-text-secondary px-3 py-2 whitespace-nowrap\">\n Date\n </th>\n <th className=\"text-left text-sm font-medium text-text-secondary px-3 py-2 whitespace-nowrap\">\n Type\n </th>\n <th className=\"text-left text-sm font-medium text-text-secondary px-3 py-2 whitespace-nowrap\">\n Description\n </th>\n <th className=\"text-right text-sm font-medium text-text-secondary px-3 py-2 whitespace-nowrap\">\n Amount\n </th>\n <th className=\"text-center text-sm font-medium text-text-secondary 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-bg-sunken/30 transition-colors\">\n <td className=\"px-3 py-2 text-sm text-text-primary whitespace-nowrap\">\n {formatDateTime(transaction.createdAt)}\n </td>\n <td className=\"px-3 py-2 text-sm text-text-primary capitalize whitespace-nowrap\">\n {getTypeLabel(transaction.type)}\n </td>\n <td className=\"px-3 py-2 text-sm text-text-secondary\">\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-text-primary'\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-subtle pt-4\">\n <p className=\"text-sm text-text-secondary\">\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-subtle bg-bg-surface hover:bg-bg-sunken/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-text-secondary 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-subtle bg-bg-surface hover:bg-bg-sunken/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":";;;;;;;;;;;;;;;;;;;;AAkCA,IAAM,IAA+C;CACnD,SAAS;CACT,QAAQ;CACR,YAAY;CACb,EAGK,KAAgB,MAEb,EADY,EAAK,aAAa,KACH,GAW9B,KAAmE,EACvE,gBACA,kBACA,kBACA,uBACI;CACJ,IAAM,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,IAAc,EAAuB,KAAK;AAYhD,QAVA,QAAgB;EACd,IAAM,KAAsB,MAAsB;AAChD,GAAI,EAAY,WAAW,CAAC,EAAY,QAAQ,SAAS,EAAM,OAAe,IAC5E,EAAU,GAAM;;AAIpB,SADA,SAAS,iBAAiB,aAAa,EAAmB,QAC7C,SAAS,oBAAoB,aAAa,EAAmB;IACzE,EAAE,CAAC,EAGJ,kBAAC,OAAD;EAAK,WAAU;EAA4B,KAAK;YAAhD,CACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAU,CAAC,EAAO;GACjC,WAAU;GACV,cAAW;aAEX,kBAAC,GAAD,EAAgB,WAAU,8BAA+B,CAAA;GAClD,CAAA,EAER,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe;AAEb,KADA,GAAe,EACf,EAAU,GAAM;;IAElB,WAAU;cANZ,CAQE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA,EAAA,eAEnB;OACR,EAAY,SAAS,aAAa,KACjC,kBAAC,UAAD;IACE,MAAK;IACL,eAAe;AAEb,KADA,GAAe,EACf,EAAU,GAAM;;IAElB,WAAU;cANZ,CAQE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA,EAAA,eAExB;MAEP;KAEJ;;GAaJ,KAA6D,EACjE,gBACA,YACA,kBACA,eACA,yBACI;AACJ,KAAI,CAAC,EAAa,QAAO;CAGzB,IAAM,IAAW,EAAY,UACvB,IAAW,GAAU,UACrB,IAAY,GAAU,WACtB,IAAU,GAAU,SACpB,IAAU,GAAU,SACpB,IAAQ,GAAU,OAClB,IAAgB,GAAU,eAC1B,IAAgB,GAAU,eAG1B,IAAW,EAAY,SAAS,UAChC,IAAiB,GAAU,gBAC3B,IAAwB,GAAU,uBAClC,IAAe,GAAU,cACzB,IAAmB,GAAU,kBAC7B,IAAmB,GAAU,kBAC7B,IAAe,GAAU,QACzB,IAAe,GAAU,cACzB,IAAiB,GAAU,gBAG3B,IAAmB,KAAS,MAAc,KAAA,KAAa,IAAY;AAEzE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;GAAoC,SAAS;GAAW,CAAA,EACvE,kBAAC,OAAD;GACE,WAAU;GACV,MAAK;GACL,cAAW;GACX,mBAAgB;aAJlB;IAME,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,IAAG;MAA4B,WAAU;gBAAwB;MAEhE,CAAA,EACL,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;MACjB,CAAA,CACL;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAmC;QAAkB,CAAA,EAClE,kBAAC,KAAD;QAAG,WAAU;kBAA+B,EAAY;QAAO,CAAA,CAC3D,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAmC;QAAQ,CAAA,EACxD,kBAAC,KAAD;QAAG,WAAU;kBAAsB,EAAa,EAAY,KAAK;QAAK,CAAA,CAClE,EAAA,CAAA,CACF;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBACZ,IACC,kBAAA,GAAA,EAAA,UAAA;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAsB;UAAe,CAAA,EACrD,kBAAC,QAAD,EAAA,UACG,EAAe,KAAY,EAAY,QAAQ,EAAY,SAAS,EAChE,CAAA,CACH;;QACL,IAAY,KACX,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACG,KAAW;WAAM;WAAE,IAAU,KAAK,IAAU,KAAK,QAAQ,EAAE,CAAC,MAAM;WAC9D;aACP,kBAAC,QAAD,EAAA,UAAO,EAAe,GAAW,EAAY,SAAS,EAAQ,CAAA,CAC1D;;QAER,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD,EAAA,UAAM,SAAY,CAAA,EAClB,kBAAC,QAAD;UAAM,WAAW,EAAY,SAAS,WAAW,2BAA2B;oBAA5E,CACG,EAAY,SAAS,WAAW,MAAM,IACtC,EAAe,GAAO,EAAY,SAAS,CACvC;YACH;;QACL,EAAA,CAAA,GAEH,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAmC;SAAU,CAAA,EAC1D,kBAAC,KAAD;SACE,WAAW,uBAAuB,EAAY,SAAS,WAAW,2BAA2B;mBAD/F,CAGG,EAAY,SAAS,WAAW,MAAM,IACtC,EAAe,KAAS,EAAY,QAAQ,EAAY,SAAS,CAChE;WACA,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAmC;SAAU,CAAA,EAC1D,kBAAC,QAAD;SACE,WAAW,2CAA2C,EACpD,EAA0B,EAAY,OAAO,CAC9C;mBAEA,EAAY;SACR,CAAA,CACH,EAAA,CAAA,CACF;;OAEJ,CAAA;MAGL,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAU,CAAA,EAC1D,kBAAC,QAAD;OACE,WAAW,2CAA2C,EACpD,EAA0B,EAAY,OAAO,CAC9C;iBAEA,EAAY;OACR,CAAA,CACH,EAAA,CAAA;MAGR,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAe,CAAA,EAC/D,kBAAC,KAAD;OAAG,WAAU;iBAAW,EAAe,EAAY,UAAU;OAAK,CAAA,CAC9D,EAAA,CAAA;MAEL,EAAY,eACX,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAe,CAAA,EAC/D,kBAAC,KAAD;OAAG,WAAU;iBAAW,EAAY;OAAgB,CAAA,CAChD,EAAA,CAAA;MAIP,KACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAmC;UAAW,CAAA,EAC3D,kBAAC,KAAD;UAAG,WAAU;oBAAqB;UAAkB,CAAA,CAChD,EAAA,CAAA,EACL,KACC,kBAAC,QAAD;UACE,WAAW,2CACT,MAAkB,SACd,yDACA;oBAGL;UACI,CAAA,CAEL;;QACL,KACC,kBAAC,KAAD;SAAG,WAAU;mBAAb,CAA2C,cAAW,EAAoB;;QAE3E,KAAc,KACb,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAc,EAAY;SACzC,WAAU;mBAHZ,CAKE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA,EAAA,eAExB;;QAEP;;MAIP,CAAC,KAAiB,KAAc,KAC/B,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAc,EAAY;QACzC,WAAU;kBAHZ;SAKE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;;SACjB,KAAmB,IAAI,EAAgB;SAC9C;;OACL,CAAA;MAIP,MAAa,KAAgB,KAAgB,MAC5C,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAK,WAAU,4CAA6C,CAAA,EAC5D,kBAAC,KAAD;UAAG,WAAU;oBAA+C;UAAsB,CAAA,CAC9E;;QAGL,KACC,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAsC;UAAe,CAAA,EAClE,kBAAC,KAAD;UAAG,WAAU;oBAA4C;UAAqB,CAAA,CAC1E,EAAA,CAAA,EACL,KACC,kBAAC,UAAD;UACE,MAAK;UACL,eAAe;AAER,WADA,EAAa,QAAQ,EACrB,EAAc,EAAiB;;UAEtC,WAAU;oBANZ,CAQE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA,EAAA,2BAExB;YAEP;;QAIP,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAsC;SAAiB,CAAA,EACpE,kBAAC,KAAD;SAAG,WAAU;mBAAb,CACG,GACA,KAAkB,MAAM,IACvB;WACA,EAAA,CAAA;QAIP,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAsC;SAAU,CAAA,EAC7D,kBAAC,KAAD;SAAG,WAAU;mBAAkC;SAAiB,CAAA,CAC5D,EAAA,CAAA;QAIP,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAsC;SAAwB,CAAA,EAC3E,kBAAC,KAAD;SAAG,WAAU;mBACV;SACC,CAAA,CACA,EAAA,CAAA;QAIP,KACC,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAsC;SAAoB,CAAA,EACvE,kBAAC,KAAD;SAAG,WAAU;mBACV;SACC,CAAA,CACA,EAAA,CAAA;QAEJ;;MAGP,EAAY,mBACX,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAqB,CAAA,EACrE,kBAAC,KAAD;OAAG,WAAU;iBAA+B,EAAY;OAAoB,CAAA,CACxE,EAAA,CAAA;MAGP,EAAY,qBACX,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAmC;OAAuB,CAAA,EACvE,kBAAC,KAAD;OAAG,WAAU;iBAA+B,EAAY;OAAsB,CAAA,CAC1E,EAAA,CAAA;MAEJ;;IAEN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBACX;MAEQ,CAAA;KACL,CAAA;IACF;KACF;;GAIG,UAA6B;CACxC,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAEnC,EAAE,wBAAqB,GAAyC,EAChE,IAAc,GAAuB,EACrC,IAAa,GAAoB,EACjC,EACJ,mBACA,iBACA,eACA,cACA,UACA,YACA,iBACA,wBACE,EAAgB,EAAiB,EAC/B,CAAC,GAAY,KAAiB,EAAqB,MAAM,EACzD,CAAC,GAAqB,KAA0B,EAA6B,KAAK,EAGlF,KAAiB,MAA4C;EACjE,IAAM,IAAW,EAAY;AAa7B,SAXI,GAAU,sBACL,EAAS,sBAGd,GAAU,aACL,EAAS,aAGd,GAAU,aACL,EAAS,aAEX;IAIH,KAAkB,MAAqC;EAC3D,IAAM,IAAW,EAAY;AAM7B,SAJI,GAAU,SAAS,OAAO,EAAS,SAAU,WACxC,EAAS,QAGX,EAAY;IAIf,MAAsB,MAA4C;EACtE,IAAM,IAAW,EAAY;AAG7B,SAFI,GAAU,sBAA4B,eACtC,GAAU,cAAc,GAAU,aAAmB,WAClD;IAGH,KAAqB,MAA6B;EACtD,IAAM,IAAa,EAAc,EAAY;AAC7C,EAAI,MACG,EAAa,QAAQ,EACrB,EAAc,EAAW;;AAIlC,KAAI,CAAC,EAAY,gBACf,QACE,kBAAC,GAAD,EACE,SAAS,EACP,qCACA,yDACD,EACD,CAAA;AAKN,KAAI,CAAC,EACH,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,MACE,kBAAC,OAAD;IACE,WAAU;IACV,MAAK;IACL,SAAQ;IACR,QAAO;cAEP,kBAAC,QAAD;KACE,eAAc;KACd,gBAAe;KACf,aAAa;KACb,GAAE;KACF,CAAA;IACE,CAAA;GAER,OAAO,EAAG,0CAA0C,8BAA8B;GAClF,aAAa,EACX,8CACA,+EACD;GACD,CAAA;EACE,CAAA;AAKV,KAAI,KAAS,EAAc,EAAM,CAC/B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,OAAO,EAAG,0CAA0C,qBAAqB;GACzE,SAAS,EACP,iDACA,gFACD;GACD,eAAe,GAAS;GACxB,WAAA;GACA,CAAA;EACE,CAAA;CAGV,IAAM,IACJ,MAAe,QAAQ,IAAe,EAAa,QAAQ,MAAM,EAAE,SAAS,EAAW;AAezF,QAbI,IAEA,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD,EAAK,WAAU,+CAAgD,CAAA,EAC/D,kBAAC,OAAD;GAAK,WAAU;aACZ;IAAC;IAAG;IAAG;IAAG;IAAG;IAAE,CAAC,KAAK,MACpB,kBAAC,OAAD,EAAa,WAAU,2CAA4C,EAAzD,EAAyD,CACnE;GACE,CAAA,CACF;MAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,YAAY;IACtC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,EAAA,mBAEzB;;GAET,kBAAC,GAAD;IACE,OAAO,EAAG,8BAA8B,sBAAsB;IAC9D,aACE,IACI,oBAAoB,EAAe,SACnC;IAEN,CAAA;GAGD,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf;MAEE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,qCAAsC,CAAA,EAC5D,kBAAC,OAAD,EAAA,UAAA;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAqC;SAAW,CAAA;QAC7D,kBAAC,KAAD;SAAG,WAAU;mBAAuB,EAAe;SAAS,CAAA;QAC3D,EAAe,WACd,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,GAAD,EAAa,WAAU,UAAW,CAAA,EAAA,SAE7B;aAEP,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,UAAW,CAAA,EAAA,WAEzB;;QAEL,EAAA,CAAA,CACF;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,qCAAsC,CAAA,EACtD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAqC;QAAS,CAAA,EAC3D,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAe,gBAAgB,EAAe;QAC7C,CAAA,CACA,EAAA,CAAA,CACF;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,qCAAsC,CAAA,EACxD,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAqC;QAAmB,CAAA,EACrE,kBAAC,KAAD;QAAG,WAAU;kBAAb,EACI,EAAe,gBAAgB,GAAG,gBAAgB,EAAC,WACnD;UACA,EAAA,CAAA,CACF;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,qCAAsC,CAAA,EAC1D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAqC;QAAU,CAAA,EAC5D,kBAAC,KAAD;QAAG,WAAU;kBAAuB,EAAe,SAAS;QAAQ,CAAA,CAChE,EAAA,CAAA,CACF;;MAGN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAU,WAAU,qCAAsC,CAAA,EAC1D,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAqC;QAAgB,CAAA,EAClE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAe,YAAY,EAAe,EAAe,UAAU,GAAG;QACrE,CAAA,CACA,EAAA,CAAA,CACF;;MACF;;IACF,CAAA;GAIR,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACX;MAAC;MAAO;MAAW;MAAU;MAAa,CAAkB,KAAK,MACjE,kBAAC,UAAD;MACE,MAAK;MAEL,eAAe,EAAc,EAAK;MAClC,WAAW,gEACT,MAAe,IACX,8CACA;gBAGL,MAAS,QAAQ,QAAQ,EAAY;MAC/B,EATF,EASE,CACT;KACE,CAAA;IACF,CAAA;GAGL,EAAqB,WAAW,IAC/B,kBAAC,GAAD;IACE,MACE,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,SAAQ;KACR,QAAO;eAEP,kBAAC,QAAD;MACE,eAAc;MACd,gBAAe;MACf,aAAa;MACb,GAAE;MACF,CAAA;KACE,CAAA;IAER,OAAO,EAAG,4CAA4C,wBAAwB;IAC9E,aACE,MAAe,QAKX,EACE,0CACA,6CACD,GAPD,EACE,+CACA,qCACD;IAMP,CAAA,GAEF,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,SAAD;MAAO,WAAU;gBACf,kBAAC,MAAD,EAAA,UAAA;OACE,kBAAC,MAAD;QAAI,WAAU;kBAAgF;QAEzF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAgF;QAEzF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAgF;QAEzF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAiF;QAE1F,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAkF;QAE3F,CAAA;OACL,kBAAC,MAAD,EAAI,WAAU,YAAgB,CAAA;OAC3B,EAAA,CAAA;MACC,CAAA,EACR,kBAAC,SAAD;MAAO,WAAU;gBACd,EAAqB,KAAK,MACzB,kBAAC,MAAD;OAAyB,WAAU;iBAAnC;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAe,EAAY,UAAU;SACnC,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAa,EAAY,KAAK;SAC5B,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAY,eAAe;SACzB,CAAA;QACL,kBAAC,MAAD;SACE,WAAW,8DACT,EAAY,SAAS,WAAW,2BAA2B;mBAF/D,CAKG,EAAY,SAAS,WAAW,MAAM,IACtC,EAAe,EAAe,EAAY,EAAE,EAAY,SAAS,CAC/D;;QACL,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,QAAD;UACE,WAAW,6CAA6C,EACtD,EAA0B,EAAY,OAAO,CAC9C;oBAEA,EAAY;UACR,CAAA;SACJ,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACZ,kBAAC,GAAD;UACe;UACb,qBAAqB,EAAuB,EAAY;UACxD,qBAAqB,EAAkB,EAAY;UACnD,eAAe,CAAC,CAAC,EAAc,EAAY;UAC3C,CAAA;SACC,CAAA;QACF;SAnCI,EAAY,GAmChB,CACL;MACI,CAAA,CACF;;IACJ,CAAA;GAIP,EAAW,aAAa,KACvB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA2C;MAChC,EAAW,OAAO,EAAW,WAAW;MAAE;MAAI;MACtD,KAAK,KAAK,EAAW,OAAO,KAAK,EAAW,UAAU,EAAW,WAAW;MAAC;MAAI;MACjF,EAAW;MAAW;MACrB;QACJ,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU,CAAC,EAAW;OACtB,WAAU;iBAJZ,CAME,kBAAC,GAAD,EAAa,WAAU,UAAW,CAAA,EAAA,WAE3B;;MACT,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QAAmD;QAC3C,EAAW,OAAO;QAAE;QAAK,KAAK,KAAK,EAAW,aAAa,EAAW,SAAS;QAChF;;MACP,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,UAAU,CAAC,EAAW;OACtB,WAAU;iBAJZ,CAKC,QAEC,kBAAC,GAAD,EAAc,WAAU,UAAW,CAAA,CAC5B;;MACL;OACF;;GAIR,kBAAC,GAAD;IACE,aAAa;IACb,eAAe,EAAuB,KAAK;IAC3C,eAAe;IACf,YAAY,IAAsB,EAAc,EAAoB,GAAG;IACvE,iBAAiB,IAAsB,GAAmB,EAAoB,GAAG;IACjF,CAAA;GACE"}
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 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';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogFooter,\n} from '@burdenoff/fe-libs/ui';\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-bg-sunken/50 transition-colors\"\n aria-label=\"Transaction actions\"\n >\n <MoreHorizontal className=\"size-4 text-text-secondary\" />\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-subtle 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-text-primary hover:bg-bg-sunken/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-text-primary hover:bg-bg-sunken/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 <Dialog open={!!transaction} onOpenChange={(open) => !open && onClose()}>\n <DialogContent className=\"max-w-md max-h-[90vh] overflow-auto p-0\">\n <DialogHeader className=\"p-4 border-b border-border-subtle\">\n <DialogTitle className=\"text-lg font-semibold\">Transaction Details</DialogTitle>\n </DialogHeader>\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-text-secondary 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-text-secondary 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-text-secondary\">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-text-secondary\">\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-subtle 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-text-secondary 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-text-secondary 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-text-secondary 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-text-secondary 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-text-secondary 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-bg-sunken/50 rounded-lg space-y-2\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary\">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-bg-sunken/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-text-secondary 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-text-secondary 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 <DialogFooter className=\"p-4 border-t border-border-subtle\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"w-full py-2 px-4 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 transition-colors\"\n >\n Close\n </button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\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 }\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-text-secondary\"\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-bg-sunken 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-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n const transactionColumns: ResponsiveTableColumn<Transaction>[] = [\n {\n key: 'date',\n header: 'Date',\n priority: 'primary',\n cellClassName: 'whitespace-nowrap',\n cell: (transaction) => (\n <span className=\"text-sm text-text-primary\">{formatDateTime(transaction.createdAt)}</span>\n ),\n },\n {\n key: 'type',\n header: 'Type',\n cellClassName: 'whitespace-nowrap',\n cell: (transaction) => (\n <span className=\"text-sm text-text-primary capitalize\">\n {getTypeLabel(transaction.type)}\n </span>\n ),\n },\n {\n key: 'description',\n header: 'Description',\n cell: (transaction) => (\n <span className=\"text-sm text-text-secondary\">{transaction.description ?? '-'}</span>\n ),\n },\n {\n key: 'amount',\n header: 'Amount',\n headerClassName: 'text-right',\n cellClassName: 'text-right whitespace-nowrap',\n cell: (transaction) => (\n <span\n className={`text-sm font-medium tabular-nums ${\n transaction.type === 'refund' ? 'text-status-error-text' : 'text-text-primary'\n }`}\n >\n {transaction.type === 'refund' ? '-' : ''}\n {formatCurrency(getTotalAmount(transaction), transaction.currency)}\n </span>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n headerClassName: 'text-center',\n cellClassName: 'text-center whitespace-nowrap',\n cell: (transaction) => (\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 ),\n },\n ];\n\n const renderTransactionActions = (transaction: Transaction) => (\n <TransactionActionsDropdown\n transaction={transaction}\n onViewDetails={() => setSelectedTransaction(transaction)}\n onViewInvoice={() => handleViewInvoice(transaction)}\n hasInvoiceUrl={!!getInvoiceUrl(transaction)}\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-text-secondary hover:text-text-primary 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-subtle rounded-lg p-4 bg-bg-surface\">\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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary mb-0.5\">Credits Balance</p>\n <p className=\"text-sm font-semibold text-text-primary\">\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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-text-secondary mt-0.5\" />\n <div>\n <p className=\"text-xs text-text-secondary 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-subtle p-1 bg-bg-sunken/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-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\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-text-secondary\"\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-subtle rounded-lg overflow-visible\">\n <ResponsiveTable<Transaction>\n columns={transactionColumns}\n data={filteredTransactions}\n rowKey={(transaction) => transaction.id}\n rowActions={renderTransactionActions}\n />\n </div>\n )}\n\n {/* Pagination Controls */}\n {pagination.totalCount > 0 && (\n <div className=\"flex items-center justify-between border-t border-border-subtle pt-4\">\n <p className=\"text-sm text-text-secondary\">\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-subtle bg-bg-surface hover:bg-bg-sunken/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-text-secondary 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-subtle bg-bg-surface hover:bg-bg-sunken/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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"}
@@ -185,7 +185,7 @@ var C = () => {
185
185
  })]
186
186
  }),
187
187
  C && /* @__PURE__ */ y("div", {
188
- className: "border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden",
188
+ className: "border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden",
189
189
  children: [/* @__PURE__ */ y("div", {
190
190
  className: "flex items-center justify-between p-4 border-b border-border-subtle bg-bg-sunken",
191
191
  children: [/* @__PURE__ */ v("h2", {
@@ -329,7 +329,7 @@ var C = () => {
329
329
  })]
330
330
  }),
331
331
  /* @__PURE__ */ y("div", {
332
- className: "border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden",
332
+ className: "border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden",
333
333
  children: [/* @__PURE__ */ v("div", {
334
334
  className: "p-4 border-b border-border-subtle bg-bg-sunken",
335
335
  children: /* @__PURE__ */ v("h2", {
@@ -1 +1 @@
1
- {"version":3,"file":"UserRefundsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/UserRefundsPage.tsx"],"sourcesContent":["/**\n * Billing Module - User Refunds Page\n * Shows the user's refund request history and allows submitting new requests.\n */\n\nimport { useState, useEffect, useRef, type FC, type FormEvent } from 'react';\nimport {\n RotateCcw,\n PlusCircle,\n X,\n Clock,\n CheckCircle,\n XCircle,\n Loader2,\n Search,\n CreditCard,\n} from 'lucide-react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { formatCurrency, formatDateTime } from '../../../shared/utils';\nimport { PageHeader } from '../../../shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useGetBillingAccountsCheckoutQuery,\n useGetTransactionLazyQuery,\n useGetRefundRecordsQuery,\n useCreateRefundRecordMutation,\n type GetRefundRecordsQuery,\n type GetTransactionQuery,\n} from '../../../../generated/global-operations';\nimport { RefundRecordStatus } from '../../../../generated/global-types';\n\ntype RefundItem = NonNullable<GetRefundRecordsQuery['getRefundRecords']['records']>[number];\ntype TxnLookup = NonNullable<GetTransactionQuery['getTransaction']>;\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n// ============================================================================\n// Status helpers\n// ============================================================================\n\nconst STATUS_CONFIG: Record<\n RefundRecordStatus,\n { label: string; className: string; icon: FC<{ className?: string }> }\n> = {\n [RefundRecordStatus.Pending]: {\n label: 'In Review',\n className: 'bg-status-warning-bg/20 text-status-warning-text border-status-warning-border',\n icon: ({ className }) => <Clock className={className} />,\n },\n [RefundRecordStatus.Processing]: {\n label: 'Processing',\n className: 'bg-action-primary-bg/15 text-action-primary-bg border-action-primary-bg/30',\n icon: ({ className }) => <Loader2 className={`${className} animate-spin`} />,\n },\n [RefundRecordStatus.Completed]: {\n label: 'Refunded',\n className: 'bg-status-success-bg/20 text-status-success-text border-status-success-border',\n icon: ({ className }) => <CheckCircle className={className} />,\n },\n [RefundRecordStatus.Failed]: {\n label: 'Failed',\n className: 'bg-status-error-bg/20 text-status-error-text border-status-error-border',\n icon: ({ className }) => <XCircle className={className} />,\n },\n [RefundRecordStatus.Skipped]: {\n label: 'Closed',\n className: 'bg-bg-sunken text-text-secondary border-border-subtle',\n icon: ({ className }) => <XCircle className={className} />,\n },\n};\n\nfunction StatusBadge({ status }: { status: string }) {\n const cfg = STATUS_CONFIG[status as RefundRecordStatus] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-secondary border-border-subtle',\n icon: ({ className }: { className?: string }) => <Clock className={className} />,\n };\n const Icon = cfg.icon;\n return (\n <span\n className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full border text-xs font-medium ${cfg.className}`}\n >\n <Icon className=\"size-3\" />\n {cfg.label}\n </span>\n );\n}\n\n// ============================================================================\n// Main page\n// ============================================================================\n\nexport const UserRefundsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const navigateTo = useBillingNavigate();\n\n // Form state\n const [showForm, setShowForm] = useState(false);\n const [txnIdInput, setTxnIdInput] = useState('');\n const [lookedUpTxn, setLookedUpTxn] = useState<TxnLookup | null>(null);\n const [txnNotFound, setTxnNotFound] = useState(false);\n const [reason, setReason] = useState('');\n const [amount, setAmount] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n const [formSuccess, setFormSuccess] = useState(false);\n\n // All billing accounts\n const { data: accountsData, loading: accountsLoading } = useGetBillingAccountsCheckoutQuery({\n fetchPolicy: 'cache-and-network',\n });\n type BillingAccount = NonNullable<typeof accountsData>['getBillingAccountsByOrg'][number];\n const accounts: BillingAccount[] = accountsData?.getBillingAccountsByOrg ?? [];\n\n // Default to the first account; user can switch\n const [selectedAccountId, setSelectedAccountId] = useState<string | undefined>(undefined);\n useEffect(() => {\n if (!selectedAccountId && accounts.length > 0) {\n setSelectedAccountId(accounts[0].id);\n }\n }, [accounts, selectedAccountId]);\n\n const selectedAccount = accounts.find((a) => a.id === selectedAccountId);\n\n // Transaction lookup by ID (lazy — fires when user enters a valid UUID)\n const [fetchTxn, { data: txnLookupData, loading: txnLookupLoading, error: txnLookupError }] =\n useGetTransactionLazyQuery({ fetchPolicy: 'network-only' });\n\n // Track the \"active\" lookup key so we only apply results for the latest request\n const lastLookupKey = useRef('');\n\n useEffect(() => {\n if (txnLookupLoading) return;\n const txn = txnLookupData?.getTransaction;\n if (txn) {\n setLookedUpTxn(txn);\n setTxnNotFound(false);\n setAmount(String(txn.amount));\n } else if (txnLookupData !== undefined || txnLookupError) {\n setLookedUpTxn(null);\n setTxnNotFound(true);\n setAmount('');\n }\n }, [txnLookupData, txnLookupLoading, txnLookupError]);\n\n const triggerLookup = (txnId: string, accountId: string) => {\n const key = `${txnId}::${accountId}`;\n lastLookupKey.current = key;\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n fetchTxn({ variables: { id: txnId, billingAccountId: accountId } });\n };\n\n const handleTxnIdChange = (value: string) => {\n setTxnIdInput(value);\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n if (UUID_RE.test(value.trim()) && selectedAccountId) {\n triggerLookup(value.trim(), selectedAccountId);\n }\n };\n\n // When account changes, re-fetch the transaction if one is entered\n const handleAccountChange = (accountId: string) => {\n setSelectedAccountId(accountId);\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n if (UUID_RE.test(txnIdInput.trim())) {\n triggerLookup(txnIdInput.trim(), accountId);\n }\n };\n\n // Refund history for selected account\n const {\n data: refundsData,\n loading: refundsLoading,\n refetch: refetchRefunds,\n } = useGetRefundRecordsQuery({\n variables: { billingAccountId: selectedAccountId, pageSize: 20, page: 1 },\n skip: !selectedAccountId,\n fetchPolicy: 'cache-and-network',\n });\n const refunds = refundsData?.getRefundRecords.records ?? [];\n\n const [createRefund, { loading: isSubmitting }] = useCreateRefundRecordMutation({\n refetchQueries: ['GetRefundRecords'],\n });\n\n const getGatewayInfo = (txn: TxnLookup | null) => {\n if (!txn) return null;\n if (txn.stripePaymentId) return { provider: 'STRIPE', gatewayPaymentId: txn.stripePaymentId };\n if (txn.razorpayPaymentId)\n return { provider: 'RAZORPAY', gatewayPaymentId: txn.razorpayPaymentId };\n return null;\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setFormError(null);\n\n if (!lookedUpTxn || !reason.trim() || !amount) {\n setFormError('Enter a valid transaction ID, an amount, and a reason.');\n return;\n }\n const gatewayInfo = getGatewayInfo(lookedUpTxn);\n if (!gatewayInfo) {\n setFormError('No payment gateway info found for this transaction. Please contact support.');\n return;\n }\n const parsedAmount = parseFloat(amount);\n if (isNaN(parsedAmount) || parsedAmount <= 0) {\n setFormError('Please enter a valid amount greater than 0.');\n return;\n }\n if (parsedAmount > lookedUpTxn.amount) {\n setFormError(\n `Cannot exceed the original payment amount (${formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}).`\n );\n return;\n }\n\n try {\n await createRefund({\n variables: {\n billingAccountId: selectedAccountId,\n provider: gatewayInfo.provider,\n gatewayPaymentId: gatewayInfo.gatewayPaymentId,\n amount: parsedAmount,\n currency: lookedUpTxn.currency ?? selectedAccount?.currency ?? 'USD',\n transactionId: lookedUpTxn.id,\n reason: reason.trim(),\n notes: `Requested by user via billing portal`,\n },\n });\n setFormSuccess(true);\n setShowForm(false);\n resetFormFields();\n await refetchRefunds();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to submit refund request.');\n }\n };\n\n const resetFormFields = () => {\n setTxnIdInput('');\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setReason('');\n setAmount('');\n setFormError(null);\n };\n\n const resetForm = () => {\n setShowForm(false);\n setFormSuccess(false);\n resetFormFields();\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-3xl\">\n <PageHeader\n title={tr('billing.refunds.title', 'Refunds')}\n description={tr(\n 'billing.refunds.description',\n 'View your refund requests and submit new ones'\n )}\n actions={\n !showForm ? (\n <button\n type=\"button\"\n onClick={() => {\n setShowForm(true);\n setFormSuccess(false);\n }}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n <PlusCircle className=\"size-4\" />\n {tr('billing.refunds.requestRefund', 'Request Refund')}\n </button>\n ) : undefined\n }\n />\n\n {/* Billing account switcher */}\n {!accountsLoading && accounts.length > 1 && (\n <div className=\"flex items-center gap-3\">\n <CreditCard className=\"size-4 text-text-secondary shrink-0\" />\n <label htmlFor=\"accountSwitch\" className=\"text-sm text-text-secondary shrink-0\">\n {tr('billing.refunds.account', 'Billing account')}\n </label>\n <select\n id=\"accountSwitch\"\n value={selectedAccountId ?? ''}\n onChange={(e) => handleAccountChange(e.target.value)}\n className=\"flex-1 px-3 py-1.5 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm\"\n >\n {accounts.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name} ({a.currency}) — {a.email}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Success banner */}\n {formSuccess && (\n <div className=\"flex items-center justify-between p-4 rounded-lg border border-status-success-border bg-status-success-bg/10\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle className=\"size-4 text-status-success-text\" />\n <p className=\"text-sm text-status-success-text font-medium\">\n {tr(\n 'billing.refunds.submitted',\n 'Refund request submitted. Our team will review it shortly.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setFormSuccess(false)}\n className=\"text-status-success-text hover:opacity-70\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* Request Refund Form */}\n {showForm && (\n <div className=\"border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"flex items-center justify-between p-4 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.refunds.newRequest', 'New Refund Request')}\n </h2>\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-4 space-y-4\">\n {formError && (\n <div className=\"p-3 rounded-lg border border-status-error-border bg-status-error-bg/10\">\n <p className=\"text-sm text-status-error-text\">{formError}</p>\n </div>\n )}\n\n {/* Transaction ID lookup */}\n <div>\n <label htmlFor=\"txnId\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.refunds.transactionId', 'Transaction ID')} *\n </label>\n <div className=\"relative\">\n <input\n id=\"txnId\"\n type=\"text\"\n value={txnIdInput}\n onChange={(e) => handleTxnIdChange(e.target.value)}\n placeholder=\"Paste your transaction ID...\"\n className=\"w-full pl-3 pr-9 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm font-mono\"\n />\n <div className=\"absolute right-2.5 top-1/2 -translate-y-1/2 text-text-secondary\">\n {txnLookupLoading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Search className=\"size-4\" />\n )}\n </div>\n </div>\n\n {/* Transaction lookup result */}\n {lookedUpTxn && (\n <div className=\"mt-2 p-3 rounded-button border border-status-success-border bg-status-success-bg/10 text-sm space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle className=\"size-3.5 text-status-success-text shrink-0\" />\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}\n </span>\n <span className=\"text-text-secondary\">·</span>\n <span className=\"text-text-secondary\">\n {formatDateTime(lookedUpTxn.createdAt)}\n </span>\n {lookedUpTxn.stripePaymentId && (\n <span className=\"text-xs text-text-secondary\">Stripe</span>\n )}\n {lookedUpTxn.razorpayPaymentId && (\n <span className=\"text-xs text-text-secondary\">Razorpay</span>\n )}\n </div>\n {lookedUpTxn.description && (\n <p className=\"text-xs text-text-secondary pl-5\">{lookedUpTxn.description}</p>\n )}\n </div>\n )}\n {txnNotFound && txnIdInput.length > 0 && !txnLookupLoading && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {tr(\n 'billing.refunds.txnNotFound',\n 'Transaction not found in this billing account.'\n )}\n </p>\n )}\n {!UUID_RE.test(txnIdInput.trim()) && txnIdInput.length > 4 && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'billing.refunds.txnIdHint',\n 'Transaction IDs look like: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'\n )}\n </p>\n )}\n </div>\n\n {/* Amount — only shown once transaction is found */}\n {lookedUpTxn && (\n <div>\n <label\n htmlFor=\"refundAmount\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.refunds.amount', 'Refund Amount')} *\n </label>\n <div className=\"flex items-center gap-2\">\n <input\n id=\"refundAmount\"\n type=\"number\"\n step=\"0.01\"\n min=\"0.01\"\n max={lookedUpTxn.amount}\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n required\n className=\"w-40 px-3 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm\"\n placeholder=\"0.00\"\n />\n <span className=\"text-sm text-text-secondary\">\n {lookedUpTxn.currency ?? selectedAccount?.currency ?? 'USD'}\n </span>\n <span className=\"text-xs text-text-secondary\">\n max {formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}\n </span>\n </div>\n </div>\n )}\n\n {/* Reason */}\n <div>\n <label htmlFor=\"reason\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.refunds.reason', 'Reason for refund')} *\n </label>\n <textarea\n id=\"reason\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n required\n rows={3}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm resize-none\"\n placeholder={tr(\n 'billing.refunds.reasonPlaceholder',\n 'Describe why you are requesting a refund...'\n )}\n />\n </div>\n\n <div className=\"flex items-center gap-3 pt-1\">\n <button\n type=\"submit\"\n disabled={isSubmitting || !lookedUpTxn || !reason.trim() || !amount}\n className=\"px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isSubmitting\n ? tr('billing.refunds.submitting', 'Submitting...')\n : tr('billing.refunds.submitRequest', 'Submit Request')}\n </button>\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"px-4 py-2 text-sm border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n {tr('billing.common.cancel', 'Cancel')}\n </button>\n </div>\n </form>\n </div>\n )}\n\n {/* Refund history */}\n <div className=\"border border-border-subtle rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.refunds.history', 'Refund History')}\n </h2>\n </div>\n\n {accountsLoading || refundsLoading ? (\n <div className=\"p-8 flex items-center justify-center\">\n <Loader2 className=\"size-5 animate-spin text-text-secondary\" />\n </div>\n ) : refunds.length === 0 ? (\n <div className=\"p-10 flex flex-col items-center text-center gap-3\">\n <RotateCcw className=\"size-8 text-text-secondary\" />\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('billing.refunds.noRefunds', 'No refund requests yet')}\n </p>\n <p className=\"text-xs text-text-secondary max-w-sm\">\n {tr(\n 'billing.refunds.noRefundsHint',\n 'If you have an issue with a payment, click \"Request Refund\" to get started.'\n )}\n </p>\n </div>\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {refunds.map((r: RefundItem) => (\n <li\n key={r.id}\n className=\"flex items-start gap-4 p-4 hover:bg-bg-sunken transition-colors\"\n >\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-medium text-text-primary\">\n {formatCurrency(r.amount, r.currency)}\n </span>\n <StatusBadge status={r.status} />\n {r.purchaseDetail && (\n <span className=\"text-xs text-text-secondary truncate\">\n {r.purchaseDetail}\n </span>\n )}\n </div>\n {r.reason && (\n <p className=\"text-xs text-text-secondary mt-1 line-clamp-2\">{r.reason}</p>\n )}\n {r.errorMessage && r.status === RefundRecordStatus.Failed && (\n <p className=\"text-xs text-status-error-text mt-1\">{r.errorMessage}</p>\n )}\n </div>\n <div className=\"text-right shrink-0\">\n <p className=\"text-xs text-text-secondary\">{formatDateTime(r.createdAt)}</p>\n {r.processedAt && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Processed {formatDateTime(r.processedAt)}\n </p>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'billing.refunds.footer',\n 'Refund requests are reviewed by our team within 3–5 business days. For urgent issues, contact support.'\n )}{' '}\n <button\n type=\"button\"\n onClick={() => navigateTo('/transactions/' + selectedAccountId)}\n className=\"underline hover:no-underline\"\n >\n {tr('billing.refunds.viewTransactions', 'View all transactions')}\n </button>\n </p>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"UserRefundsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/UserRefundsPage.tsx"],"sourcesContent":["/**\n * Billing Module - User Refunds Page\n * Shows the user's refund request history and allows submitting new requests.\n */\n\nimport { useState, useEffect, useRef, type FC, type FormEvent } from 'react';\nimport {\n RotateCcw,\n PlusCircle,\n X,\n Clock,\n CheckCircle,\n XCircle,\n Loader2,\n Search,\n CreditCard,\n} from 'lucide-react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { formatCurrency, formatDateTime } from '../../../shared/utils';\nimport { PageHeader } from '../../../shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useGetBillingAccountsCheckoutQuery,\n useGetTransactionLazyQuery,\n useGetRefundRecordsQuery,\n useCreateRefundRecordMutation,\n type GetRefundRecordsQuery,\n type GetTransactionQuery,\n} from '../../../../generated/global-operations';\nimport { RefundRecordStatus } from '../../../../generated/global-types';\n\ntype RefundItem = NonNullable<GetRefundRecordsQuery['getRefundRecords']['records']>[number];\ntype TxnLookup = NonNullable<GetTransactionQuery['getTransaction']>;\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n// ============================================================================\n// Status helpers\n// ============================================================================\n\nconst STATUS_CONFIG: Record<\n RefundRecordStatus,\n { label: string; className: string; icon: FC<{ className?: string }> }\n> = {\n [RefundRecordStatus.Pending]: {\n label: 'In Review',\n className: 'bg-status-warning-bg/20 text-status-warning-text border-status-warning-border',\n icon: ({ className }) => <Clock className={className} />,\n },\n [RefundRecordStatus.Processing]: {\n label: 'Processing',\n className: 'bg-action-primary-bg/15 text-action-primary-bg border-action-primary-bg/30',\n icon: ({ className }) => <Loader2 className={`${className} animate-spin`} />,\n },\n [RefundRecordStatus.Completed]: {\n label: 'Refunded',\n className: 'bg-status-success-bg/20 text-status-success-text border-status-success-border',\n icon: ({ className }) => <CheckCircle className={className} />,\n },\n [RefundRecordStatus.Failed]: {\n label: 'Failed',\n className: 'bg-status-error-bg/20 text-status-error-text border-status-error-border',\n icon: ({ className }) => <XCircle className={className} />,\n },\n [RefundRecordStatus.Skipped]: {\n label: 'Closed',\n className: 'bg-bg-sunken text-text-secondary border-border-subtle',\n icon: ({ className }) => <XCircle className={className} />,\n },\n};\n\nfunction StatusBadge({ status }: { status: string }) {\n const cfg = STATUS_CONFIG[status as RefundRecordStatus] ?? {\n label: status,\n className: 'bg-bg-sunken text-text-secondary border-border-subtle',\n icon: ({ className }: { className?: string }) => <Clock className={className} />,\n };\n const Icon = cfg.icon;\n return (\n <span\n className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full border text-xs font-medium ${cfg.className}`}\n >\n <Icon className=\"size-3\" />\n {cfg.label}\n </span>\n );\n}\n\n// ============================================================================\n// Main page\n// ============================================================================\n\nexport const UserRefundsPage: FC = () => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const navigateTo = useBillingNavigate();\n\n // Form state\n const [showForm, setShowForm] = useState(false);\n const [txnIdInput, setTxnIdInput] = useState('');\n const [lookedUpTxn, setLookedUpTxn] = useState<TxnLookup | null>(null);\n const [txnNotFound, setTxnNotFound] = useState(false);\n const [reason, setReason] = useState('');\n const [amount, setAmount] = useState('');\n const [formError, setFormError] = useState<string | null>(null);\n const [formSuccess, setFormSuccess] = useState(false);\n\n // All billing accounts\n const { data: accountsData, loading: accountsLoading } = useGetBillingAccountsCheckoutQuery({\n fetchPolicy: 'cache-and-network',\n });\n type BillingAccount = NonNullable<typeof accountsData>['getBillingAccountsByOrg'][number];\n const accounts: BillingAccount[] = accountsData?.getBillingAccountsByOrg ?? [];\n\n // Default to the first account; user can switch\n const [selectedAccountId, setSelectedAccountId] = useState<string | undefined>(undefined);\n useEffect(() => {\n if (!selectedAccountId && accounts.length > 0) {\n setSelectedAccountId(accounts[0].id);\n }\n }, [accounts, selectedAccountId]);\n\n const selectedAccount = accounts.find((a) => a.id === selectedAccountId);\n\n // Transaction lookup by ID (lazy — fires when user enters a valid UUID)\n const [fetchTxn, { data: txnLookupData, loading: txnLookupLoading, error: txnLookupError }] =\n useGetTransactionLazyQuery({ fetchPolicy: 'network-only' });\n\n // Track the \"active\" lookup key so we only apply results for the latest request\n const lastLookupKey = useRef('');\n\n useEffect(() => {\n if (txnLookupLoading) return;\n const txn = txnLookupData?.getTransaction;\n if (txn) {\n setLookedUpTxn(txn);\n setTxnNotFound(false);\n setAmount(String(txn.amount));\n } else if (txnLookupData !== undefined || txnLookupError) {\n setLookedUpTxn(null);\n setTxnNotFound(true);\n setAmount('');\n }\n }, [txnLookupData, txnLookupLoading, txnLookupError]);\n\n const triggerLookup = (txnId: string, accountId: string) => {\n const key = `${txnId}::${accountId}`;\n lastLookupKey.current = key;\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n fetchTxn({ variables: { id: txnId, billingAccountId: accountId } });\n };\n\n const handleTxnIdChange = (value: string) => {\n setTxnIdInput(value);\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n if (UUID_RE.test(value.trim()) && selectedAccountId) {\n triggerLookup(value.trim(), selectedAccountId);\n }\n };\n\n // When account changes, re-fetch the transaction if one is entered\n const handleAccountChange = (accountId: string) => {\n setSelectedAccountId(accountId);\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setAmount('');\n if (UUID_RE.test(txnIdInput.trim())) {\n triggerLookup(txnIdInput.trim(), accountId);\n }\n };\n\n // Refund history for selected account\n const {\n data: refundsData,\n loading: refundsLoading,\n refetch: refetchRefunds,\n } = useGetRefundRecordsQuery({\n variables: { billingAccountId: selectedAccountId, pageSize: 20, page: 1 },\n skip: !selectedAccountId,\n fetchPolicy: 'cache-and-network',\n });\n const refunds = refundsData?.getRefundRecords.records ?? [];\n\n const [createRefund, { loading: isSubmitting }] = useCreateRefundRecordMutation({\n refetchQueries: ['GetRefundRecords'],\n });\n\n const getGatewayInfo = (txn: TxnLookup | null) => {\n if (!txn) return null;\n if (txn.stripePaymentId) return { provider: 'STRIPE', gatewayPaymentId: txn.stripePaymentId };\n if (txn.razorpayPaymentId)\n return { provider: 'RAZORPAY', gatewayPaymentId: txn.razorpayPaymentId };\n return null;\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setFormError(null);\n\n if (!lookedUpTxn || !reason.trim() || !amount) {\n setFormError('Enter a valid transaction ID, an amount, and a reason.');\n return;\n }\n const gatewayInfo = getGatewayInfo(lookedUpTxn);\n if (!gatewayInfo) {\n setFormError('No payment gateway info found for this transaction. Please contact support.');\n return;\n }\n const parsedAmount = parseFloat(amount);\n if (isNaN(parsedAmount) || parsedAmount <= 0) {\n setFormError('Please enter a valid amount greater than 0.');\n return;\n }\n if (parsedAmount > lookedUpTxn.amount) {\n setFormError(\n `Cannot exceed the original payment amount (${formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}).`\n );\n return;\n }\n\n try {\n await createRefund({\n variables: {\n billingAccountId: selectedAccountId,\n provider: gatewayInfo.provider,\n gatewayPaymentId: gatewayInfo.gatewayPaymentId,\n amount: parsedAmount,\n currency: lookedUpTxn.currency ?? selectedAccount?.currency ?? 'USD',\n transactionId: lookedUpTxn.id,\n reason: reason.trim(),\n notes: `Requested by user via billing portal`,\n },\n });\n setFormSuccess(true);\n setShowForm(false);\n resetFormFields();\n await refetchRefunds();\n } catch (err) {\n setFormError(err instanceof Error ? err.message : 'Failed to submit refund request.');\n }\n };\n\n const resetFormFields = () => {\n setTxnIdInput('');\n setLookedUpTxn(null);\n setTxnNotFound(false);\n setReason('');\n setAmount('');\n setFormError(null);\n };\n\n const resetForm = () => {\n setShowForm(false);\n setFormSuccess(false);\n resetFormFields();\n };\n\n return (\n <div className=\"space-y-6 p-6 max-w-3xl\">\n <PageHeader\n title={tr('billing.refunds.title', 'Refunds')}\n description={tr(\n 'billing.refunds.description',\n 'View your refund requests and submit new ones'\n )}\n actions={\n !showForm ? (\n <button\n type=\"button\"\n onClick={() => {\n setShowForm(true);\n setFormSuccess(false);\n }}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors\"\n >\n <PlusCircle className=\"size-4\" />\n {tr('billing.refunds.requestRefund', 'Request Refund')}\n </button>\n ) : undefined\n }\n />\n\n {/* Billing account switcher */}\n {!accountsLoading && accounts.length > 1 && (\n <div className=\"flex items-center gap-3\">\n <CreditCard className=\"size-4 text-text-secondary shrink-0\" />\n <label htmlFor=\"accountSwitch\" className=\"text-sm text-text-secondary shrink-0\">\n {tr('billing.refunds.account', 'Billing account')}\n </label>\n <select\n id=\"accountSwitch\"\n value={selectedAccountId ?? ''}\n onChange={(e) => handleAccountChange(e.target.value)}\n className=\"flex-1 px-3 py-1.5 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm\"\n >\n {accounts.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name} ({a.currency}) — {a.email}\n </option>\n ))}\n </select>\n </div>\n )}\n\n {/* Success banner */}\n {formSuccess && (\n <div className=\"flex items-center justify-between p-4 rounded-lg border border-status-success-border bg-status-success-bg/10\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle className=\"size-4 text-status-success-text\" />\n <p className=\"text-sm text-status-success-text font-medium\">\n {tr(\n 'billing.refunds.submitted',\n 'Refund request submitted. Our team will review it shortly.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => setFormSuccess(false)}\n className=\"text-status-success-text hover:opacity-70\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* Request Refund Form */}\n {showForm && (\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"flex items-center justify-between p-4 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.refunds.newRequest', 'New Refund Request')}\n </h2>\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n\n <form onSubmit={handleSubmit} className=\"p-4 space-y-4\">\n {formError && (\n <div className=\"p-3 rounded-lg border border-status-error-border bg-status-error-bg/10\">\n <p className=\"text-sm text-status-error-text\">{formError}</p>\n </div>\n )}\n\n {/* Transaction ID lookup */}\n <div>\n <label htmlFor=\"txnId\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.refunds.transactionId', 'Transaction ID')} *\n </label>\n <div className=\"relative\">\n <input\n id=\"txnId\"\n type=\"text\"\n value={txnIdInput}\n onChange={(e) => handleTxnIdChange(e.target.value)}\n placeholder=\"Paste your transaction ID...\"\n className=\"w-full pl-3 pr-9 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm font-mono\"\n />\n <div className=\"absolute right-2.5 top-1/2 -translate-y-1/2 text-text-secondary\">\n {txnLookupLoading ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Search className=\"size-4\" />\n )}\n </div>\n </div>\n\n {/* Transaction lookup result */}\n {lookedUpTxn && (\n <div className=\"mt-2 p-3 rounded-button border border-status-success-border bg-status-success-bg/10 text-sm space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <CheckCircle className=\"size-3.5 text-status-success-text shrink-0\" />\n <span className=\"font-medium text-text-primary\">\n {formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}\n </span>\n <span className=\"text-text-secondary\">·</span>\n <span className=\"text-text-secondary\">\n {formatDateTime(lookedUpTxn.createdAt)}\n </span>\n {lookedUpTxn.stripePaymentId && (\n <span className=\"text-xs text-text-secondary\">Stripe</span>\n )}\n {lookedUpTxn.razorpayPaymentId && (\n <span className=\"text-xs text-text-secondary\">Razorpay</span>\n )}\n </div>\n {lookedUpTxn.description && (\n <p className=\"text-xs text-text-secondary pl-5\">{lookedUpTxn.description}</p>\n )}\n </div>\n )}\n {txnNotFound && txnIdInput.length > 0 && !txnLookupLoading && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {tr(\n 'billing.refunds.txnNotFound',\n 'Transaction not found in this billing account.'\n )}\n </p>\n )}\n {!UUID_RE.test(txnIdInput.trim()) && txnIdInput.length > 4 && (\n <p className=\"mt-1 text-xs text-text-secondary\">\n {tr(\n 'billing.refunds.txnIdHint',\n 'Transaction IDs look like: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'\n )}\n </p>\n )}\n </div>\n\n {/* Amount — only shown once transaction is found */}\n {lookedUpTxn && (\n <div>\n <label\n htmlFor=\"refundAmount\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.refunds.amount', 'Refund Amount')} *\n </label>\n <div className=\"flex items-center gap-2\">\n <input\n id=\"refundAmount\"\n type=\"number\"\n step=\"0.01\"\n min=\"0.01\"\n max={lookedUpTxn.amount}\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n required\n className=\"w-40 px-3 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm\"\n placeholder=\"0.00\"\n />\n <span className=\"text-sm text-text-secondary\">\n {lookedUpTxn.currency ?? selectedAccount?.currency ?? 'USD'}\n </span>\n <span className=\"text-xs text-text-secondary\">\n max {formatCurrency(lookedUpTxn.amount, lookedUpTxn.currency)}\n </span>\n </div>\n </div>\n )}\n\n {/* Reason */}\n <div>\n <label htmlFor=\"reason\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.refunds.reason', 'Reason for refund')} *\n </label>\n <textarea\n id=\"reason\"\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n required\n rows={3}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-button bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-sm resize-none\"\n placeholder={tr(\n 'billing.refunds.reasonPlaceholder',\n 'Describe why you are requesting a refund...'\n )}\n />\n </div>\n\n <div className=\"flex items-center gap-3 pt-1\">\n <button\n type=\"submit\"\n disabled={isSubmitting || !lookedUpTxn || !reason.trim() || !amount}\n className=\"px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isSubmitting\n ? tr('billing.refunds.submitting', 'Submitting...')\n : tr('billing.refunds.submitRequest', 'Submit Request')}\n </button>\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"px-4 py-2 text-sm border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n {tr('billing.common.cancel', 'Cancel')}\n </button>\n </div>\n </form>\n </div>\n )}\n\n {/* Refund history */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.refunds.history', 'Refund History')}\n </h2>\n </div>\n\n {accountsLoading || refundsLoading ? (\n <div className=\"p-8 flex items-center justify-center\">\n <Loader2 className=\"size-5 animate-spin text-text-secondary\" />\n </div>\n ) : refunds.length === 0 ? (\n <div className=\"p-10 flex flex-col items-center text-center gap-3\">\n <RotateCcw className=\"size-8 text-text-secondary\" />\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('billing.refunds.noRefunds', 'No refund requests yet')}\n </p>\n <p className=\"text-xs text-text-secondary max-w-sm\">\n {tr(\n 'billing.refunds.noRefundsHint',\n 'If you have an issue with a payment, click \"Request Refund\" to get started.'\n )}\n </p>\n </div>\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {refunds.map((r: RefundItem) => (\n <li\n key={r.id}\n className=\"flex items-start gap-4 p-4 hover:bg-bg-sunken transition-colors\"\n >\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"text-sm font-medium text-text-primary\">\n {formatCurrency(r.amount, r.currency)}\n </span>\n <StatusBadge status={r.status} />\n {r.purchaseDetail && (\n <span className=\"text-xs text-text-secondary truncate\">\n {r.purchaseDetail}\n </span>\n )}\n </div>\n {r.reason && (\n <p className=\"text-xs text-text-secondary mt-1 line-clamp-2\">{r.reason}</p>\n )}\n {r.errorMessage && r.status === RefundRecordStatus.Failed && (\n <p className=\"text-xs text-status-error-text mt-1\">{r.errorMessage}</p>\n )}\n </div>\n <div className=\"text-right shrink-0\">\n <p className=\"text-xs text-text-secondary\">{formatDateTime(r.createdAt)}</p>\n {r.processedAt && (\n <p className=\"text-xs text-text-secondary mt-0.5\">\n Processed {formatDateTime(r.processedAt)}\n </p>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'billing.refunds.footer',\n 'Refund requests are reviewed by our team within 3–5 business days. For urgent issues, contact support.'\n )}{' '}\n <button\n type=\"button\"\n onClick={() => navigateTo('/transactions/' + selectedAccountId)}\n className=\"underline hover:no-underline\"\n >\n {tr('billing.refunds.viewTransactions', 'View all transactions')}\n </button>\n </p>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -94,7 +94,7 @@ var f = ({ accounts: f, selectedAccountId: p, onSelect: m, isLoading: h = !1, di
94
94
  children: _
95
95
  }),
96
96
  b && !g && /* @__PURE__ */ l("div", {
97
- className: "absolute left-0 right-0 z-50 mt-1 max-h-64 overflow-auto rounded-card border border-border-subtle bg-bg-elevated shadow-elevation-3",
97
+ className: "absolute left-0 right-0 z-50 mt-1 max-h-64 overflow-auto rounded-card border border-border-seam bg-bg-elevated shadow-elevation-3",
98
98
  children: f.map((t) => {
99
99
  let n = t.id === p;
100
100
  return /* @__PURE__ */ u("button", {
@@ -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-bg-sunken animate-pulse rounded\" />\n <div className=\"h-12 bg-bg-sunken 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-subtle p-4 text-center\">\n <Building2 className=\"mx-auto size-6 text-text-secondary\" />\n <p className=\"mt-2 text-sm text-text-secondary\">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-text-primary\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </label>\n {disabled && (\n <span className=\"flex items-center gap-1 text-xs text-text-secondary\">\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-subtle bg-bg-sunken cursor-not-allowed opacity-80'\n : isOpen\n ? 'border-border-strong ring-1 ring-[var(--color-focus-ring)]'\n : 'border-border-subtle hover:border-border-strong'\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\n ? 'bg-bg-sunken text-text-secondary'\n : 'bg-[var(--color-accent-soft)] text-text-link'\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-text-primary truncate\">\n {selectedAccount.name}\n </span>\n {!selectedAccount.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-status-error-bg-subtle text-status-error-text shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary 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-text-primary\">\n <CreditCard className=\"size-3.5 text-text-secondary\" />\n {formatCurrency(selectedAccount.creditAmount, 'CREDITS')}\n </div>\n </div>\n </div>\n ) : (\n <span className=\"text-text-secondary\">Select billing account</span>\n )}\n {disabled ? (\n <Lock className=\"size-4 shrink-0 text-text-secondary\" />\n ) : (\n <ChevronDown\n className={`size-4 shrink-0 text-text-secondary transition-transform ${\n isOpen ? 'rotate-180' : ''\n }`}\n />\n )}\n </button>\n\n {/* Disabled message */}\n {disabled && disabledMessage && (\n <p className=\"text-xs text-text-secondary\">{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-card border border-border-subtle bg-bg-elevated shadow-elevation-3\">\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-[var(--color-accent-soft)]' : 'hover:bg-bg-sunken'}\n `}\n >\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-link\">\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-text-primary truncate\">{account.name}</span>\n {!account.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-status-error-bg-subtle text-status-error-text shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary 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-text-primary\">\n <CreditCard className=\"size-3.5 text-text-secondary\" />\n {formatCurrency(account.creditAmount, 'CREDITS')}\n </div>\n </div>\n {isSelected && <Check className=\"size-4 text-text-link\" />}\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-bg-sunken animate-pulse rounded\" />\n <div className=\"h-12 bg-bg-sunken 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-subtle p-4 text-center\">\n <Building2 className=\"mx-auto size-6 text-text-secondary\" />\n <p className=\"mt-2 text-sm text-text-secondary\">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-text-primary\">\n {tr('billing.checkout.billingAccount', 'Billing Account')}\n </label>\n {disabled && (\n <span className=\"flex items-center gap-1 text-xs text-text-secondary\">\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-subtle bg-bg-sunken cursor-not-allowed opacity-80'\n : isOpen\n ? 'border-border-strong ring-1 ring-[var(--color-focus-ring)]'\n : 'border-border-subtle hover:border-border-strong'\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\n ? 'bg-bg-sunken text-text-secondary'\n : 'bg-[var(--color-accent-soft)] text-text-link'\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-text-primary truncate\">\n {selectedAccount.name}\n </span>\n {!selectedAccount.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-status-error-bg-subtle text-status-error-text shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary 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-text-primary\">\n <CreditCard className=\"size-3.5 text-text-secondary\" />\n {formatCurrency(selectedAccount.creditAmount, 'CREDITS')}\n </div>\n </div>\n </div>\n ) : (\n <span className=\"text-text-secondary\">Select billing account</span>\n )}\n {disabled ? (\n <Lock className=\"size-4 shrink-0 text-text-secondary\" />\n ) : (\n <ChevronDown\n className={`size-4 shrink-0 text-text-secondary transition-transform ${\n isOpen ? 'rotate-180' : ''\n }`}\n />\n )}\n </button>\n\n {/* Disabled message */}\n {disabled && disabledMessage && (\n <p className=\"text-xs text-text-secondary\">{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-card border border-border-seam bg-bg-elevated shadow-elevation-3\">\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-[var(--color-accent-soft)]' : 'hover:bg-bg-sunken'}\n `}\n >\n <div className=\"flex size-8 shrink-0 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-link\">\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-text-primary truncate\">{account.name}</span>\n {!account.isActive && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-status-error-bg-subtle text-status-error-text shrink-0\">\n Inactive\n </span>\n )}\n </div>\n <p className=\"text-sm text-text-secondary 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-text-primary\">\n <CreditCard className=\"size-3.5 text-text-secondary\" />\n {formatCurrency(account.creditAmount, 'CREDITS')}\n </div>\n </div>\n {isSelected && <Check className=\"size-4 text-text-link\" />}\n </div>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
@@ -64,7 +64,7 @@ var d = ({ billingAccountId: u, hasPhone: d, hasAddress: f, onCompleted: p, onCa
64
64
  return /* @__PURE__ */ s("div", {
65
65
  className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay p-4",
66
66
  children: /* @__PURE__ */ c("div", {
67
- className: "bg-bg-surface border border-border-subtle rounded-card shadow-[var(--shadow-elevation-4)] w-full max-w-lg max-h-[90vh] overflow-y-auto",
67
+ className: "bg-bg-surface border border-border-seam rounded-card shadow-[var(--shadow-elevation-4)] w-full max-w-lg max-h-[90vh] overflow-y-auto",
68
68
  children: [
69
69
  /* @__PURE__ */ c("div", {
70
70
  className: "flex items-start justify-between p-6 border-b border-border-subtle",