@burdenoff/microfe-billing 2026.625.3 → 2026.625.5

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 (98) hide show
  1. package/dist/billing/lib/native-purchases.js +2 -44
  2. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +192 -187
  3. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
  4. package/dist/billing/modules/addons/pages/AddonCreatePage.js +322 -317
  5. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  6. package/dist/billing/modules/addons/pages/AddonDetailPage.js +190 -185
  7. package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
  8. package/dist/billing/modules/addons/pages/AddonEditPage.js +297 -292
  9. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  10. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +60 -75
  11. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
  12. package/dist/billing/modules/addons/pages/AddonsListPage.js +86 -101
  13. package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
  14. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +124 -121
  15. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  16. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +103 -111
  17. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  18. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +196 -160
  19. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  20. package/dist/billing/modules/billing/pages/InvoicesListPage.js +58 -73
  21. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  22. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +65 -75
  23. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
  24. package/dist/billing/modules/billing/pages/RefundsPage.js +399 -399
  25. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  26. package/dist/billing/modules/billing/pages/TransactionsPage.js +49 -48
  27. package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
  28. package/dist/billing/modules/billing/pages/UserRefundsPage.js +144 -151
  29. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  30. package/dist/billing/modules/checkout/pages/CheckoutPage.js +430 -425
  31. package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
  32. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +121 -93
  33. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  34. package/dist/billing/modules/coupons/pages/CouponsListPage.js +154 -152
  35. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  36. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +467 -462
  37. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  38. package/dist/billing/modules/coupons/pages/EditCouponPage.js +294 -286
  39. package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
  40. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +123 -117
  41. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  42. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +43 -42
  43. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
  44. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +192 -207
  45. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
  46. package/dist/billing/modules/credits/pages/CreditsPage.js +40 -56
  47. package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
  48. package/dist/billing/modules/dashboard/pages/OverviewPage.js +128 -121
  49. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  50. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +165 -180
  51. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  52. package/dist/billing/modules/earnings/pages/EarningsPage.js +103 -100
  53. package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
  54. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +175 -175
  55. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  56. package/dist/billing/modules/earnings/pages/PayoutsPage.js +96 -96
  57. package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
  58. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +42 -40
  59. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  60. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +45 -38
  61. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  62. package/dist/billing/modules/plans/pages/PlanCreatePage.js +339 -334
  63. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  64. package/dist/billing/modules/plans/pages/PlanDetailPage.js +80 -74
  65. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  66. package/dist/billing/modules/plans/pages/PlanEditPage.js +342 -337
  67. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  68. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +38 -53
  69. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  70. package/dist/billing/modules/plans/pages/PlansListPage.js +60 -75
  71. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  72. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +242 -237
  73. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  74. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +29 -39
  75. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
  76. package/dist/billing/modules/quota/pages/QuotaPage.js +1 -0
  77. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +299 -294
  78. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  79. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +191 -186
  80. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
  81. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +308 -303
  82. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  83. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +57 -78
  84. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
  85. package/dist/billing/modules/settings/pages/SettingsPage.js +79 -78
  86. package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
  87. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +15 -13
  88. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
  89. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +338 -299
  90. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  91. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +82 -103
  92. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  93. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +59 -54
  94. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
  95. package/dist/billing/modules/usage/pages/UsagePage.js +172 -215
  96. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  97. package/package.json +2 -2
  98. package/dist/billing/lib/native-purchases.js.map +0 -1
@@ -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-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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"}
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 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 { PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\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 <PagePurpose>\n {tr(\n 'billing.refunds.userPurpose',\n 'Request money back for a payment and follow where each request stands. Paste the transaction ID of the charge you want refunded, tell us how much and why, and track every request here from \"In Review\" through to \"Refunded\".'\n )}\n </PagePurpose>\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 <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('billing.refunds.noRefunds', 'No refund requests yet')}\n description={tr(\n 'billing.refunds.noRefundsHint',\n 'If you have an issue with a payment, click \"Request Refund\" to get started.'\n )}\n />\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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"}