@burdenoff/microfe-billing 2026.625.4 → 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 (96) hide show
  1. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +192 -187
  2. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
  3. package/dist/billing/modules/addons/pages/AddonCreatePage.js +322 -317
  4. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  5. package/dist/billing/modules/addons/pages/AddonDetailPage.js +190 -185
  6. package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
  7. package/dist/billing/modules/addons/pages/AddonEditPage.js +297 -292
  8. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  9. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +60 -75
  10. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
  11. package/dist/billing/modules/addons/pages/AddonsListPage.js +86 -101
  12. package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
  13. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +124 -121
  14. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  15. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +103 -111
  16. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  17. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +196 -160
  18. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  19. package/dist/billing/modules/billing/pages/InvoicesListPage.js +58 -73
  20. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  21. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +65 -75
  22. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
  23. package/dist/billing/modules/billing/pages/RefundsPage.js +399 -399
  24. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  25. package/dist/billing/modules/billing/pages/TransactionsPage.js +49 -48
  26. package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
  27. package/dist/billing/modules/billing/pages/UserRefundsPage.js +144 -151
  28. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  29. package/dist/billing/modules/checkout/pages/CheckoutPage.js +430 -425
  30. package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
  31. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +121 -93
  32. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  33. package/dist/billing/modules/coupons/pages/CouponsListPage.js +154 -152
  34. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  35. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +467 -462
  36. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  37. package/dist/billing/modules/coupons/pages/EditCouponPage.js +294 -286
  38. package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
  39. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +123 -117
  40. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  41. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js +43 -42
  42. package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
  43. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +192 -207
  44. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
  45. package/dist/billing/modules/credits/pages/CreditsPage.js +40 -56
  46. package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
  47. package/dist/billing/modules/dashboard/pages/OverviewPage.js +128 -121
  48. package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
  49. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +165 -180
  50. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  51. package/dist/billing/modules/earnings/pages/EarningsPage.js +103 -100
  52. package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
  53. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +175 -175
  54. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  55. package/dist/billing/modules/earnings/pages/PayoutsPage.js +96 -96
  56. package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
  57. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +42 -40
  58. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  59. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js +45 -38
  60. package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
  61. package/dist/billing/modules/plans/pages/PlanCreatePage.js +339 -334
  62. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  63. package/dist/billing/modules/plans/pages/PlanDetailPage.js +80 -74
  64. package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
  65. package/dist/billing/modules/plans/pages/PlanEditPage.js +342 -337
  66. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  67. package/dist/billing/modules/plans/pages/PlansBrowsePage.js +38 -53
  68. package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
  69. package/dist/billing/modules/plans/pages/PlansListPage.js +60 -75
  70. package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
  71. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +242 -237
  72. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  73. package/dist/billing/modules/promotions/pages/PromotionsListPage.js +29 -39
  74. package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
  75. package/dist/billing/modules/quota/pages/QuotaPage.js +1 -0
  76. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +299 -294
  77. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  78. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js +191 -186
  79. package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
  80. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +308 -303
  81. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  82. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js +57 -78
  83. package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
  84. package/dist/billing/modules/settings/pages/SettingsPage.js +79 -78
  85. package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
  86. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +15 -13
  87. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
  88. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +338 -299
  89. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  90. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +82 -103
  91. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  92. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +59 -54
  93. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
  94. package/dist/billing/modules/usage/pages/UsagePage.js +172 -215
  95. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  96. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"InvoiceDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/InvoiceDetailPage.tsx"],"sourcesContent":["/**\n * Billing Module - Invoice Detail Page\n * Displays detailed information about a single invoice\n */\n\nimport { type FC, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingAccountSelection } from '../../../hooks/useBillingAccountSelection';\nimport { useInvoice, useInvoiceMutations } from '../hooks/useInvoices';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useGetDefaultBillingAccountDashboardQuery } from '../../../../generated/global-operations';\nimport {\n formatCurrency,\n formatDate,\n formatInvoiceStatus,\n formatInvoiceNumber,\n} from '../../../shared/utils/format';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport { getInvoiceStatusColor, getStatusBadgeClasses } from '../../../shared/utils/status';\nimport type { InvoiceStatus } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\n\nexport const InvoiceDetailPage: 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 { invoiceId } = useParams<{ invoiceId: string }>();\n const navigateTo = useBillingNavigate();\n const { orgId } = useBilling();\n const permissions = useBillingPermissions();\n const { selectedAccountId } = useBillingAccountSelection({\n orgId,\n syncFromUrl: true,\n urlParamName: 'billingAccountId',\n });\n const { data: defaultBillingAccountData } = useGetDefaultBillingAccountDashboardQuery({\n fetchPolicy: 'cache-first',\n });\n const billingAccountId =\n selectedAccountId ?? defaultBillingAccountData?.getDefaultBillingAccount?.id ?? undefined;\n const { invoice, isLoading, error, refetch } = useInvoice(invoiceId, billingAccountId);\n const { payInvoice, voidInvoice, isPaying, isVoiding } = useInvoiceMutations();\n const defaultPaymentMethodId =\n defaultBillingAccountData?.getDefaultBillingAccount?.defaultPaymentMethod;\n\n // Action error state\n const [actionError, setActionError] = useState<string | null>(null);\n\n // Handle pay invoice\n const handlePayInvoice = async () => {\n if (!invoice) return;\n if (!defaultPaymentMethodId) {\n setActionError('Add and set a default payment method before paying this invoice.');\n return;\n }\n\n if (!billingAccountId) {\n setActionError('No billing account context');\n return;\n }\n setActionError(null);\n try {\n await payInvoice(invoice.id, defaultPaymentMethodId, billingAccountId);\n await refetch();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Failed to pay invoice');\n }\n };\n\n // Handle void invoice\n const handleVoidInvoice = async () => {\n if (!invoice) return;\n if (!billingAccountId) {\n setActionError('No billing account context');\n return;\n }\n\n setActionError(null);\n try {\n await voidInvoice(invoice.id, billingAccountId);\n await refetch();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Failed to void invoice');\n }\n };\n\n // Permission check\n if (!permissions.canViewInvoices) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-bg-sunken flex items-center justify-center\">\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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary max-w-sm\">\n {tr('billing.invoices.noViewPermission', \"You don't have permission to view invoices.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading) {\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"space-y-2\">\n <div className=\"h-8 w-48 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-32 bg-bg-sunken animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-32 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-full bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-3/4 bg-bg-sunken animate-pulse rounded\" />\n </div>\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-bg-sunken animate-pulse rounded\" />\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex items-center gap-4\">\n <div className=\"h-4 flex-1 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-16 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-16 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-20 bg-bg-sunken animate-pulse rounded\" />\n </div>\n ))}\n </div>\n </div>\n <div className=\"space-y-6\">\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-bg-sunken animate-pulse rounded\" />\n {[1, 2, 3, 4].map((i) => (\n <div key={i} className=\"space-y-1\">\n <div className=\"h-3 w-20 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-28 bg-bg-sunken animate-pulse rounded\" />\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error || !invoice) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-6 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.invoiceNotFound', 'Invoice not found')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {error?.message ||\n tr(\n 'billing.invoices.invoiceNotFoundMessage',\n 'The invoice you are looking for does not exist.'\n )}\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <button\n type=\"button\"\n onClick={() => refetch()}\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\"\n >\n Try Again\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(withBillingAccountId('/invoices', billingAccountId))}\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Back to Invoices\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n const statusColor = getInvoiceStatusColor(invoice.status);\n const isOpen = invoice.status === ('OPEN' as InvoiceStatus);\n const isDraft = invoice.status === ('DRAFT' as InvoiceStatus);\n const items = invoice.items || [];\n const amountDue = invoice.total - invoice.amountPaid;\n\n const lineItemColumns: ResponsiveTableColumn<(typeof items)[number]>[] = [\n {\n key: 'description',\n header: 'Description',\n priority: 'primary',\n cell: (item) => item.description,\n },\n {\n key: 'quantity',\n header: 'Qty',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (item) => <span className=\"tabular-nums\">{item.quantity}</span>,\n },\n {\n key: 'unitPrice',\n header: 'Unit Price',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (item) => (\n <span className=\"tabular-nums\">{formatCurrency(item.unitPrice, invoice.currency)}</span>\n ),\n },\n {\n key: 'amount',\n header: 'Amount',\n headerClassName: 'text-right',\n cellClassName: 'text-right font-medium',\n cell: (item) => (\n <span className=\"tabular-nums\">{formatCurrency(item.amount, invoice.currency)}</span>\n ),\n },\n ];\n\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <button\n type=\"button\"\n onClick={() => navigateTo(withBillingAccountId('/invoices', billingAccountId))}\n className=\"p-2 -ml-2 text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-button transition-colors\"\n >\n <svg className=\"size-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-text-primary\">\n Invoice {formatInvoiceNumber(invoice.invoiceNumber)}\n </h1>\n <span\n className={`px-2 py-1 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {formatInvoiceStatus(invoice.status)}\n </span>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n Created {formatDate(invoice.createdAt, 'short')}\n {invoice.dueDate && ` · Due ${formatDate(invoice.dueDate, 'short')}`}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 flex-wrap\">\n {invoice.pdfUrl && (\n <a\n href={invoice.pdfUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Download PDF\n </a>\n )}\n {invoice.invoiceUrl && (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n View on Portal\n </a>\n )}\n {isOpen && permissions.canPayInvoice && (\n <button\n type=\"button\"\n onClick={handlePayInvoice}\n disabled={isPaying || !defaultPaymentMethodId}\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\"\n >\n {!defaultPaymentMethodId\n ? 'Default Payment Method Required'\n : isPaying\n ? 'Processing...'\n : 'Pay Invoice'}\n </button>\n )}\n {(isOpen || isDraft) && permissions.canVoidInvoice && (\n <button\n type=\"button\"\n onClick={handleVoidInvoice}\n disabled={isVoiding}\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-status-error-text rounded-button hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n {isVoiding\n ? tr('billing.invoices.voiding', 'Voiding...')\n : tr('billing.invoices.voidInvoice', 'Void Invoice')}\n </button>\n )}\n </div>\n </div>\n\n {/* Action Error */}\n {actionError && (\n <div className=\"p-3 bg-status-error-bg-subtle border border-status-error-border rounded-button\">\n <p className=\"text-sm text-status-error-text\">{actionError}</p>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Line Items */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.lineItems', 'Line Items')} ({items.length})\n </h2>\n </div>\n {items.length === 0 ? (\n <div className=\"p-6\">\n <p className=\"text-sm text-text-secondary\">\n {tr('billing.invoices.noLineItems', 'No line items on this invoice.')}\n </p>\n </div>\n ) : (\n <ResponsiveTable\n data={items}\n rowKey={(item) => item.id}\n columns={lineItemColumns}\n />\n )}\n\n {/* Totals */}\n <div className=\"border-t border-border-subtle p-4\">\n <div className=\"max-w-xs ml-auto space-y-2\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('billing.invoices.subtotal', 'Subtotal')}\n </span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.subtotal, invoice.currency)}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">{tr('billing.invoices.tax', 'Tax')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.tax, invoice.currency)}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm font-semibold border-t border-border-subtle pt-2\">\n <span className=\"text-text-primary\">{tr('billing.invoices.total', 'Total')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.total, invoice.currency)}\n </span>\n </div>\n {invoice.amountPaid > 0 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('billing.invoices.amountPaid', 'Amount Paid')}\n </span>\n <span className=\"text-status-success-text\">\n -{formatCurrency(invoice.amountPaid, invoice.currency)}\n </span>\n </div>\n )}\n {amountDue > 0 && (\n <div className=\"flex items-center justify-between text-sm font-semibold border-t border-border-subtle pt-2\">\n <span className=\"text-text-primary\">\n {tr('billing.invoices.amountDue', 'Amount Due')}\n </span>\n <span className=\"text-status-warning-text\">\n {formatCurrency(amountDue, invoice.currency)}\n </span>\n </div>\n )}\n </div>\n </div>\n </div>\n\n {/* Subscription Info */}\n {invoice.subscription && (\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.subscription', 'Subscription')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium text-text-primary\">\n {invoice.subscription.plan?.name || 'Unknown Plan'}\n </p>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n Subscription ID:{' '}\n <span className=\"font-mono text-xs\">{invoice.subscription.id}</span>\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${invoice.subscription!.id}`,\n billingAccountId\n )\n )\n }\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors\"\n >\n View\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Payment Info */}\n {invoice.payment && (\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.payment', 'Payment')}\n </h2>\n </div>\n <div className=\"p-6\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Payment ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">\n {invoice.payment.id}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Amount</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatCurrency(invoice.payment.amount, invoice.payment.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.status.toLowerCase()}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Method</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.method.toLowerCase().replace(/_/g, ' ')}\n </p>\n </div>\n {invoice.payment.provider && (\n <div>\n <p className=\"text-sm text-text-secondary\">Provider</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.provider}\n </p>\n </div>\n )}\n {invoice.payment.paidAt && (\n <div>\n <p className=\"text-sm text-text-secondary\">Paid At</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatDate(invoice.payment.paidAt, 'short')}\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Invoice Summary */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.details', 'Details')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invoice ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">{invoice.id}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invoice Number</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </p>\n </div>\n {invoice.itemDescription && (\n <div>\n <p className=\"text-sm text-text-secondary\">Description</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{invoice.itemDescription}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <span\n className={`inline-flex mt-0.5 px-2 py-1 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {formatInvoiceStatus(invoice.status)}\n </span>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Currency</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{invoice.currency}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Total</p>\n <p className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {formatCurrency(invoice.total, invoice.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Amount Paid</p>\n <p className=\"text-sm text-status-success-text mt-0.5\">\n {formatCurrency(invoice.amountPaid, invoice.currency)}\n </p>\n </div>\n {amountDue > 0 && (\n <div>\n <p className=\"text-sm text-text-secondary\">Amount Due</p>\n <p className=\"text-sm font-semibold text-status-warning-text mt-0.5\">\n {formatCurrency(amountDue, invoice.currency)}\n </p>\n </div>\n )}\n </div>\n </div>\n\n {/* Dates */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.dates', 'Dates')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Created</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.createdAt)}</p>\n </div>\n {invoice.dueDate && (\n <div>\n <p className=\"text-sm text-text-secondary\">Due Date</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.dueDate)}</p>\n </div>\n )}\n {invoice.paidAt && (\n <div>\n <p className=\"text-sm text-text-secondary\">Paid At</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.paidAt)}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Last Updated</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.updatedAt)}</p>\n </div>\n </div>\n </div>\n\n {/* Organization */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.organization', 'Organization')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Organization ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">\n {invoice.orgId}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"InvoiceDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/InvoiceDetailPage.tsx"],"sourcesContent":["/**\n * Billing Module - Invoice Detail Page\n * Displays detailed information about a single invoice\n */\n\nimport { type FC, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingAccountSelection } from '../../../hooks/useBillingAccountSelection';\nimport { useInvoice, useInvoiceMutations } from '../hooks/useInvoices';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useGetDefaultBillingAccountDashboardQuery } from '../../../../generated/global-operations';\nimport {\n formatCurrency,\n formatDate,\n formatInvoiceStatus,\n formatInvoiceNumber,\n} from '../../../shared/utils/format';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport { getInvoiceStatusColor, getStatusBadgeClasses } from '../../../shared/utils/status';\nimport type { InvoiceStatus } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n EmphasisPanel,\n NextSteps,\n type NextStep,\n} from '@burdenoff/fe-libs/ui';\n\nexport const InvoiceDetailPage: 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 { invoiceId } = useParams<{ invoiceId: string }>();\n const navigateTo = useBillingNavigate();\n const { orgId } = useBilling();\n const permissions = useBillingPermissions();\n const { selectedAccountId } = useBillingAccountSelection({\n orgId,\n syncFromUrl: true,\n urlParamName: 'billingAccountId',\n });\n const { data: defaultBillingAccountData } = useGetDefaultBillingAccountDashboardQuery({\n fetchPolicy: 'cache-first',\n });\n const billingAccountId =\n selectedAccountId ?? defaultBillingAccountData?.getDefaultBillingAccount?.id ?? undefined;\n const { invoice, isLoading, error, refetch } = useInvoice(invoiceId, billingAccountId);\n const { payInvoice, voidInvoice, isPaying, isVoiding } = useInvoiceMutations();\n const defaultPaymentMethodId =\n defaultBillingAccountData?.getDefaultBillingAccount?.defaultPaymentMethod;\n\n // Action error state\n const [actionError, setActionError] = useState<string | null>(null);\n\n // Handle pay invoice\n const handlePayInvoice = async () => {\n if (!invoice) return;\n if (!defaultPaymentMethodId) {\n setActionError('Add and set a default payment method before paying this invoice.');\n return;\n }\n\n if (!billingAccountId) {\n setActionError('No billing account context');\n return;\n }\n setActionError(null);\n try {\n await payInvoice(invoice.id, defaultPaymentMethodId, billingAccountId);\n await refetch();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Failed to pay invoice');\n }\n };\n\n // Handle void invoice\n const handleVoidInvoice = async () => {\n if (!invoice) return;\n if (!billingAccountId) {\n setActionError('No billing account context');\n return;\n }\n\n setActionError(null);\n try {\n await voidInvoice(invoice.id, billingAccountId);\n await refetch();\n } catch (err) {\n setActionError(err instanceof Error ? err.message : 'Failed to void invoice');\n }\n };\n\n // Permission check\n if (!permissions.canViewInvoices) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-bg-sunken flex items-center justify-center\">\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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary max-w-sm\">\n {tr('billing.invoices.noViewPermission', \"You don't have permission to view invoices.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading) {\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"space-y-2\">\n <div className=\"h-8 w-48 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-32 bg-bg-sunken animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n <div className=\"lg:col-span-2 space-y-6\">\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-32 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-full bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-3/4 bg-bg-sunken animate-pulse rounded\" />\n </div>\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-bg-sunken animate-pulse rounded\" />\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex items-center gap-4\">\n <div className=\"h-4 flex-1 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-16 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-16 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-20 bg-bg-sunken animate-pulse rounded\" />\n </div>\n ))}\n </div>\n </div>\n <div className=\"space-y-6\">\n <div className=\"border border-border-subtle rounded-lg p-6 space-y-4\">\n <div className=\"h-6 w-24 bg-bg-sunken animate-pulse rounded\" />\n {[1, 2, 3, 4].map((i) => (\n <div key={i} className=\"space-y-1\">\n <div className=\"h-3 w-20 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-4 w-28 bg-bg-sunken animate-pulse rounded\" />\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n );\n }\n\n // Error state\n if (error || !invoice) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-6 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.invoiceNotFound', 'Invoice not found')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {error?.message ||\n tr(\n 'billing.invoices.invoiceNotFoundMessage',\n 'The invoice you are looking for does not exist.'\n )}\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <button\n type=\"button\"\n onClick={() => refetch()}\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\"\n >\n Try Again\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(withBillingAccountId('/invoices', billingAccountId))}\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Back to Invoices\n </button>\n </div>\n </div>\n </div>\n );\n }\n\n const statusColor = getInvoiceStatusColor(invoice.status);\n const isOpen = invoice.status === ('OPEN' as InvoiceStatus);\n const isDraft = invoice.status === ('DRAFT' as InvoiceStatus);\n const items = invoice.items || [];\n const amountDue = invoice.total - invoice.amountPaid;\n\n const lineItemColumns: ResponsiveTableColumn<(typeof items)[number]>[] = [\n {\n key: 'description',\n header: 'Description',\n priority: 'primary',\n cell: (item) => item.description,\n },\n {\n key: 'quantity',\n header: 'Qty',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (item) => <span className=\"tabular-nums\">{item.quantity}</span>,\n },\n {\n key: 'unitPrice',\n header: 'Unit Price',\n headerClassName: 'text-right',\n cellClassName: 'text-right',\n cell: (item) => (\n <span className=\"tabular-nums\">{formatCurrency(item.unitPrice, invoice.currency)}</span>\n ),\n },\n {\n key: 'amount',\n header: 'Amount',\n headerClassName: 'text-right',\n cellClassName: 'text-right font-medium',\n cell: (item) => (\n <span className=\"tabular-nums\">{formatCurrency(item.amount, invoice.currency)}</span>\n ),\n },\n ];\n\n // Recommended next actions for this invoice\n const nextSteps: NextStep[] = [\n ...(isOpen && permissions.canPayInvoice\n ? [\n {\n id: 'pay',\n label: 'Pay this invoice',\n description: defaultPaymentMethodId\n ? 'Settle the outstanding amount with your default payment method.'\n : 'Add a default payment method first, then pay.',\n onClick: handlePayInvoice,\n },\n ]\n : []),\n ...(invoice.pdfUrl\n ? [\n {\n id: 'download',\n label: 'Download the PDF',\n description: 'Save a copy of this invoice for your records.',\n href: invoice.pdfUrl,\n },\n ]\n : []),\n ...(invoice.subscription\n ? [\n {\n id: 'view-subscription',\n label: 'View the related subscription',\n description: 'See the plan and quotas this invoice billed for.',\n onClick: () =>\n navigateTo(\n withBillingAccountId(`/subscriptions/${invoice.subscription!.id}`, billingAccountId)\n ),\n },\n ]\n : []),\n {\n id: 'request-refund',\n label: 'Have an issue? Request a refund',\n description: 'Raise a refund request for a charge on this account.',\n onClick: () => navigateTo(withBillingAccountId('/refunds', billingAccountId)),\n },\n ];\n\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <button\n type=\"button\"\n onClick={() => navigateTo(withBillingAccountId('/invoices', billingAccountId))}\n className=\"p-2 -ml-2 text-text-secondary hover:text-text-primary hover:bg-bg-sunken rounded-button transition-colors\"\n >\n <svg className=\"size-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-text-primary\">\n Invoice {formatInvoiceNumber(invoice.invoiceNumber)}\n </h1>\n <span\n className={`px-2 py-1 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {formatInvoiceStatus(invoice.status)}\n </span>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n Created {formatDate(invoice.createdAt, 'short')}\n {invoice.dueDate && ` · Due ${formatDate(invoice.dueDate, 'short')}`}\n </p>\n <PagePurpose className=\"mt-3\">\n {tr(\n 'billing.invoices.detailPurpose',\n 'The full breakdown of a single invoice — its line items, taxes, what has been paid and what is still due. Use it to download the PDF, pay an outstanding balance, jump to the subscription it covers, or raise a refund.'\n )}\n </PagePurpose>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 flex-wrap\">\n {invoice.pdfUrl && (\n <a\n href={invoice.pdfUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Download PDF\n </a>\n )}\n {invoice.invoiceUrl && (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n View on Portal\n </a>\n )}\n {isOpen && permissions.canPayInvoice && (\n <button\n type=\"button\"\n onClick={handlePayInvoice}\n disabled={isPaying || !defaultPaymentMethodId}\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\"\n >\n {!defaultPaymentMethodId\n ? 'Default Payment Method Required'\n : isPaying\n ? 'Processing...'\n : 'Pay Invoice'}\n </button>\n )}\n {(isOpen || isDraft) && permissions.canVoidInvoice && (\n <button\n type=\"button\"\n onClick={handleVoidInvoice}\n disabled={isVoiding}\n className=\"px-4 py-2 text-sm font-medium border border-border-subtle text-status-error-text rounded-button hover:bg-status-error-bg-subtle transition-colors disabled:opacity-50\"\n >\n {isVoiding\n ? tr('billing.invoices.voiding', 'Voiding...')\n : tr('billing.invoices.voidInvoice', 'Void Invoice')}\n </button>\n )}\n </div>\n </div>\n\n {/* Action Error */}\n {actionError && (\n <div className=\"p-3 bg-status-error-bg-subtle border border-status-error-border rounded-button\">\n <p className=\"text-sm text-status-error-text\">{actionError}</p>\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Main Content */}\n <div className=\"lg:col-span-2 space-y-6\">\n {/* Line Items — primary emphasis zone (what was billed & what is due) */}\n <EmphasisPanel className=\"overflow-hidden p-0\">\n <div className=\"p-6 border-b border-border-subtle\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.lineItems', 'Line Items')} ({items.length})\n </h2>\n </div>\n {items.length === 0 ? (\n <div className=\"p-6\">\n <p className=\"text-sm text-text-secondary\">\n {tr('billing.invoices.noLineItems', 'No line items on this invoice.')}\n </p>\n </div>\n ) : (\n <ResponsiveTable data={items} rowKey={(item) => item.id} columns={lineItemColumns} />\n )}\n\n {/* Totals */}\n <div className=\"border-t border-border-subtle p-4\">\n <div className=\"max-w-xs ml-auto space-y-2\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('billing.invoices.subtotal', 'Subtotal')}\n </span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.subtotal, invoice.currency)}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">{tr('billing.invoices.tax', 'Tax')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.tax, invoice.currency)}\n </span>\n </div>\n <div className=\"flex items-center justify-between text-sm font-semibold border-t border-border-subtle pt-2\">\n <span className=\"text-text-primary\">{tr('billing.invoices.total', 'Total')}</span>\n <span className=\"text-text-primary\">\n {formatCurrency(invoice.total, invoice.currency)}\n </span>\n </div>\n {invoice.amountPaid > 0 && (\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('billing.invoices.amountPaid', 'Amount Paid')}\n </span>\n <span className=\"text-status-success-text\">\n -{formatCurrency(invoice.amountPaid, invoice.currency)}\n </span>\n </div>\n )}\n {amountDue > 0 && (\n <div className=\"flex items-center justify-between text-sm font-semibold border-t border-border-subtle pt-2\">\n <span className=\"text-text-primary\">\n {tr('billing.invoices.amountDue', 'Amount Due')}\n </span>\n <span className=\"text-status-warning-text\">\n {formatCurrency(amountDue, invoice.currency)}\n </span>\n </div>\n )}\n </div>\n </div>\n </EmphasisPanel>\n\n {/* Subscription Info */}\n {invoice.subscription && (\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.subscription', 'Subscription')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <p className=\"font-medium text-text-primary\">\n {invoice.subscription.plan?.name || 'Unknown Plan'}\n </p>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n Subscription ID:{' '}\n <span className=\"font-mono text-xs\">{invoice.subscription.id}</span>\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(\n withBillingAccountId(\n `/subscriptions/${invoice.subscription!.id}`,\n billingAccountId\n )\n )\n }\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors\"\n >\n View\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Payment Info */}\n {invoice.payment && (\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.payment', 'Payment')}\n </h2>\n </div>\n <div className=\"p-6\">\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Payment ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">\n {invoice.payment.id}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Amount</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatCurrency(invoice.payment.amount, invoice.payment.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.status.toLowerCase()}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Method</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.method.toLowerCase().replace(/_/g, ' ')}\n </p>\n </div>\n {invoice.payment.provider && (\n <div>\n <p className=\"text-sm text-text-secondary\">Provider</p>\n <p className=\"text-sm text-text-primary mt-0.5 capitalize\">\n {invoice.payment.provider}\n </p>\n </div>\n )}\n {invoice.payment.paidAt && (\n <div>\n <p className=\"text-sm text-text-secondary\">Paid At</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatDate(invoice.payment.paidAt, 'short')}\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-6\">\n {/* Next steps guidance */}\n <NextSteps storageKey=\"billing-invoice-detail\" steps={nextSteps} />\n\n {/* Invoice Summary */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.details', 'Details')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Invoice ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">{invoice.id}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Invoice Number</p>\n <p className=\"text-sm text-text-primary mt-0.5\">\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </p>\n </div>\n {invoice.itemDescription && (\n <div>\n <p className=\"text-sm text-text-secondary\">Description</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{invoice.itemDescription}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Status</p>\n <span\n className={`inline-flex mt-0.5 px-2 py-1 text-xs font-medium rounded ${getStatusBadgeClasses(statusColor)}`}\n >\n {formatInvoiceStatus(invoice.status)}\n </span>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Currency</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{invoice.currency}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Total</p>\n <p className=\"text-sm font-semibold text-text-primary mt-0.5\">\n {formatCurrency(invoice.total, invoice.currency)}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">Amount Paid</p>\n <p className=\"text-sm text-status-success-text mt-0.5\">\n {formatCurrency(invoice.amountPaid, invoice.currency)}\n </p>\n </div>\n {amountDue > 0 && (\n <div>\n <p className=\"text-sm text-text-secondary\">Amount Due</p>\n <p className=\"text-sm font-semibold text-status-warning-text mt-0.5\">\n {formatCurrency(amountDue, invoice.currency)}\n </p>\n </div>\n )}\n </div>\n </div>\n\n {/* Dates */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.dates', 'Dates')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Created</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.createdAt)}</p>\n </div>\n {invoice.dueDate && (\n <div>\n <p className=\"text-sm text-text-secondary\">Due Date</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.dueDate)}</p>\n </div>\n )}\n {invoice.paidAt && (\n <div>\n <p className=\"text-sm text-text-secondary\">Paid At</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.paidAt)}</p>\n </div>\n )}\n <div>\n <p className=\"text-sm text-text-secondary\">Last Updated</p>\n <p className=\"text-sm text-text-primary mt-0.5\">{formatDate(invoice.updatedAt)}</p>\n </div>\n </div>\n </div>\n\n {/* Organization */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <div className=\"p-6 border-b border-border-subtle bg-bg-sunken\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.organization', 'Organization')}\n </h2>\n </div>\n <div className=\"p-6 space-y-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">Organization ID</p>\n <p className=\"font-mono text-sm text-text-primary mt-0.5 break-all\">\n {invoice.orgId}\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -12,29 +12,30 @@ import { RotateCcw as h } from "lucide-react";
12
12
  import { useSearchParams as g } from "react-router-dom";
13
13
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
14
14
  import { useI18n as b } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
15
+ import { IllustratedEmptyState as x, PagePurpose as S } from "@burdenoff/fe-libs/ui";
15
16
  //#region src/billing/modules/billing/pages/InvoicesListPage.tsx
16
- var x = () => {
17
+ var C = () => {
17
18
  let { t: e } = b(), t = (t, n) => {
18
19
  let r = e(t);
19
20
  return r === t ? n : r;
20
- }, n = c(), r = o(), [a] = g(), x = a.get("billingAccountId") ?? void 0, { data: C } = s({ fetchPolicy: "cache-first" }), w = C?.getBillingAccountsByOrg ?? [], [T, E] = m(x);
21
+ }, n = c(), r = o(), [a] = g(), C = a.get("billingAccountId") ?? void 0, { data: T } = s({ fetchPolicy: "cache-first" }), E = T?.getBillingAccountsByOrg ?? [], [D, O] = m(C);
21
22
  d(() => {
22
- E(x);
23
- }, [x]);
24
- let D = f(() => (w.find((e) => e.isDefault) ?? w[0])?.id ?? void 0, [w]), O = T === void 0 ? D ?? null : T, [k, A] = m("all"), [j, M] = m(""), [N, P] = m(""), [F, I] = m(1), L = p(null);
25
- d(() => (L.current && clearTimeout(L.current), L.current = setTimeout(() => {
26
- P(j), I(1);
23
+ O(C);
24
+ }, [C]);
25
+ let k = f(() => (E.find((e) => e.isDefault) ?? E[0])?.id ?? void 0, [E]), A = D === void 0 ? k ?? null : D, [j, M] = m("all"), [N, P] = m(""), [F, I] = m(""), [L, R] = m(1), z = p(null);
26
+ d(() => (z.current && clearTimeout(z.current), z.current = setTimeout(() => {
27
+ I(N), R(1);
27
28
  }, 400), () => {
28
- L.current && clearTimeout(L.current);
29
- }), [j]);
30
- let { invoices: R, totalPages: z, isLoading: B, error: V, refetch: H } = u({
31
- billingAccountId: O ?? void 0,
32
- status: k === "all" ? void 0 : k,
33
- search: N || void 0,
34
- page: F,
29
+ z.current && clearTimeout(z.current);
30
+ }), [N]);
31
+ let { invoices: B, totalPages: V, isLoading: H, error: U, refetch: W } = u({
32
+ billingAccountId: A ?? void 0,
33
+ status: j === "all" ? void 0 : j,
34
+ search: F || void 0,
35
+ page: L,
35
36
  pageSize: 20
36
37
  });
37
- return r.canViewInvoices ? B && R.length === 0 ? /* @__PURE__ */ y("div", {
38
+ return r.canViewInvoices ? H && B.length === 0 ? /* @__PURE__ */ y("div", {
38
39
  className: "space-y-6 p-6",
39
40
  children: [/* @__PURE__ */ v("div", { className: "h-8 w-48 bg-bg-sunken animate-pulse rounded" }), /* @__PURE__ */ v("div", {
40
41
  className: "space-y-3",
@@ -55,7 +56,7 @@ var x = () => {
55
56
  })
56
57
  }, e))
57
58
  })]
58
- }) : V ? /* @__PURE__ */ v("div", {
59
+ }) : U ? /* @__PURE__ */ v("div", {
59
60
  className: "flex items-center justify-center h-full min-h-[400px]",
60
61
  children: /* @__PURE__ */ y("div", {
61
62
  className: "text-center space-y-4",
@@ -81,11 +82,11 @@ var x = () => {
81
82
  }),
82
83
  /* @__PURE__ */ v("p", {
83
84
  className: "text-sm text-text-secondary",
84
- children: V.message
85
+ children: U.message
85
86
  }),
86
87
  /* @__PURE__ */ v("button", {
87
88
  type: "button",
88
- onClick: () => H(),
89
+ onClick: () => W(),
89
90
  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",
90
91
  children: "Try Again"
91
92
  })
@@ -96,32 +97,39 @@ var x = () => {
96
97
  children: [
97
98
  /* @__PURE__ */ y("div", {
98
99
  className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
99
- children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
100
- className: "text-2xl md:text-3xl font-semibold tracking-tight text-text-primary",
101
- children: t("billing.invoices.title", "Invoices")
102
- }), /* @__PURE__ */ v("p", {
103
- className: "text-sm text-text-secondary mt-1",
104
- children: t("billing.invoices.subtitle", "View and manage your billing invoices")
105
- })] }), /* @__PURE__ */ y("div", {
100
+ children: [/* @__PURE__ */ y("div", { children: [
101
+ /* @__PURE__ */ v("h1", {
102
+ className: "text-2xl md:text-3xl font-semibold tracking-tight text-text-primary",
103
+ children: t("billing.invoices.title", "Invoices")
104
+ }),
105
+ /* @__PURE__ */ v("p", {
106
+ className: "text-sm text-text-secondary mt-1",
107
+ children: t("billing.invoices.subtitle", "View and manage your billing invoices")
108
+ }),
109
+ /* @__PURE__ */ v(S, {
110
+ className: "mt-3",
111
+ children: t("billing.invoices.purpose", "A record of everything you have been billed for — subscriptions, add-ons and one-off charges. Open an invoice to see line items, download the PDF, pay an outstanding amount, or request a refund.")
112
+ })
113
+ ] }), /* @__PURE__ */ y("div", {
106
114
  className: "flex items-center gap-3",
107
115
  children: [/* @__PURE__ */ y("button", {
108
116
  type: "button",
109
117
  onClick: () => n("/refunds"),
110
118
  className: "inline-flex items-center gap-2 px-3 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken hover:border-border-strong transition-all duration-200",
111
119
  children: [/* @__PURE__ */ v(h, { className: "size-4" }), t("billing.invoices.myRefunds", "My Refunds")]
112
- }), w.length > 1 && /* @__PURE__ */ y("div", {
120
+ }), E.length > 1 && /* @__PURE__ */ y("div", {
113
121
  className: "flex items-center gap-2",
114
122
  children: [/* @__PURE__ */ v("label", {
115
123
  className: "text-sm text-text-secondary whitespace-nowrap",
116
124
  children: "Billing Account"
117
125
  }), /* @__PURE__ */ y("select", {
118
- value: O ?? "",
119
- onChange: (e) => E(e.target.value || null),
126
+ value: A ?? "",
127
+ onChange: (e) => O(e.target.value || null),
120
128
  className: "text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
121
129
  children: [/* @__PURE__ */ v("option", {
122
130
  value: "",
123
131
  children: "All Accounts"
124
- }), w.map((e) => /* @__PURE__ */ y("option", {
132
+ }), E.map((e) => /* @__PURE__ */ y("option", {
125
133
  value: e.id ?? "",
126
134
  children: [e.name ?? e.email ?? e.id, e.isDefault ? " (Default)" : ""]
127
135
  }, e.id ?? ""))]
@@ -142,9 +150,9 @@ var x = () => {
142
150
  ].map((e) => /* @__PURE__ */ v("button", {
143
151
  type: "button",
144
152
  onClick: () => {
145
- A(e), I(1);
153
+ M(e), R(1);
146
154
  },
147
- className: `px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${k === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
155
+ className: `px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${j === e ? "bg-bg-surface text-text-primary shadow-sm" : "text-text-secondary hover:text-text-primary"}`,
148
156
  children: e === "all" ? "All" : i(e)
149
157
  }, e))
150
158
  }), /* @__PURE__ */ y("div", {
@@ -163,39 +171,16 @@ var x = () => {
163
171
  }), /* @__PURE__ */ v("input", {
164
172
  type: "text",
165
173
  placeholder: t("billing.invoices.searchPlaceholder", "Search by invoice number..."),
166
- value: j,
167
- onChange: (e) => M(e.target.value),
174
+ value: N,
175
+ onChange: (e) => P(e.target.value),
168
176
  className: "w-full pl-[3.25rem] pr-4 py-2 text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] focus:border-transparent"
169
177
  })]
170
178
  })]
171
179
  }),
172
- !B && R.length === 0 ? /* @__PURE__ */ y("div", {
173
- className: "flex flex-col items-center justify-center py-12 border border-dashed border-border-seam rounded-card",
174
- children: [
175
- /* @__PURE__ */ v("div", {
176
- className: "size-12 rounded-full bg-[var(--color-accent-soft)] flex items-center justify-center mb-4",
177
- children: /* @__PURE__ */ v("svg", {
178
- className: "size-6 text-text-secondary",
179
- fill: "none",
180
- viewBox: "0 0 24 24",
181
- stroke: "currentColor",
182
- children: /* @__PURE__ */ v("path", {
183
- strokeLinecap: "round",
184
- strokeLinejoin: "round",
185
- strokeWidth: 2,
186
- d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
187
- })
188
- })
189
- }),
190
- /* @__PURE__ */ v("h3", {
191
- className: "text-lg font-medium text-text-primary",
192
- children: t("billing.invoices.noInvoicesFound", "No invoices found")
193
- }),
194
- /* @__PURE__ */ v("p", {
195
- className: "text-sm text-text-secondary mt-1",
196
- children: k !== "all" || N ? t("billing.invoices.noInvoicesFiltered", "No invoices match your filters.") : t("billing.invoices.noInvoicesYet", "You don't have any invoices yet.")
197
- })
198
- ]
180
+ !H && B.length === 0 ? /* @__PURE__ */ v(x, {
181
+ illustration: j !== "all" || F ? "empty-search" : "empty-files",
182
+ title: t("billing.invoices.noInvoicesFound", "No invoices found"),
183
+ description: j !== "all" || F ? t("billing.invoices.noInvoicesFiltered", "No invoices match your filters.") : t("billing.invoices.noInvoicesYet", "You don't have any invoices yet.")
199
184
  }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("div", {
200
185
  className: "border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden",
201
186
  children: /* @__PURE__ */ y("table", {
@@ -211,7 +196,7 @@ var x = () => {
211
196
  className: "text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted",
212
197
  children: "Status"
213
198
  }),
214
- !O && w.length > 1 && /* @__PURE__ */ v("th", {
199
+ !A && E.length > 1 && /* @__PURE__ */ v("th", {
215
200
  className: "text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden lg:table-cell",
216
201
  children: "Account"
217
202
  }),
@@ -234,38 +219,38 @@ var x = () => {
234
219
  ] })
235
220
  }), /* @__PURE__ */ v("tbody", {
236
221
  className: "divide-y divide-border-subtle",
237
- children: R.map((e) => /* @__PURE__ */ v(S, {
222
+ children: B.map((e) => /* @__PURE__ */ v(w, {
238
223
  invoice: e,
239
224
  onView: () => n(l(`/invoices/${e.id}`, e.billingAccountId)),
240
225
  canPay: r.canPayInvoice,
241
226
  canVoid: r.canVoidInvoice,
242
- showAccount: !O && w.length > 1,
243
- accountName: w.find((t) => t.id === e.billingAccountId)?.name ?? null
227
+ showAccount: !A && E.length > 1,
228
+ accountName: E.find((t) => t.id === e.billingAccountId)?.name ?? null
244
229
  }, e.id))
245
230
  })]
246
231
  })
247
- }), z > 1 && /* @__PURE__ */ y("div", {
232
+ }), V > 1 && /* @__PURE__ */ y("div", {
248
233
  className: "flex items-center justify-between pt-2",
249
234
  children: [/* @__PURE__ */ y("p", {
250
235
  className: "text-sm text-text-secondary",
251
236
  children: [
252
237
  "Page ",
253
- F,
238
+ L,
254
239
  " of ",
255
- z
240
+ V
256
241
  ]
257
242
  }), /* @__PURE__ */ y("div", {
258
243
  className: "flex items-center gap-2",
259
244
  children: [/* @__PURE__ */ v("button", {
260
245
  type: "button",
261
- onClick: () => I((e) => Math.max(1, e - 1)),
262
- disabled: F <= 1,
246
+ onClick: () => R((e) => Math.max(1, e - 1)),
247
+ disabled: L <= 1,
263
248
  className: "px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
264
249
  children: "Previous"
265
250
  }), /* @__PURE__ */ v("button", {
266
251
  type: "button",
267
- onClick: () => I((e) => Math.min(z, e + 1)),
268
- disabled: F >= z,
252
+ onClick: () => R((e) => Math.min(V, e + 1)),
253
+ disabled: L >= V,
269
254
  className: "px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
270
255
  children: "Next"
271
256
  })]
@@ -303,7 +288,7 @@ var x = () => {
303
288
  ]
304
289
  })
305
290
  });
306
- }, S = ({ invoice: o, onView: s, canPay: c, canVoid: l, showAccount: u = !1, accountName: d }) => {
291
+ }, w = ({ invoice: o, onView: s, canPay: c, canVoid: l, showAccount: u = !1, accountName: d }) => {
307
292
  let f = a(o.status), p = o.status === "OPEN", m = o.status === "DRAFT";
308
293
  return /* @__PURE__ */ y("tr", {
309
294
  className: "hover:bg-bg-sunken transition-colors",
@@ -397,6 +382,6 @@ var x = () => {
397
382
  });
398
383
  };
399
384
  //#endregion
400
- export { x as InvoicesListPage };
385
+ export { C as InvoicesListPage };
401
386
 
402
387
  //# sourceMappingURL=InvoicesListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InvoicesListPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/InvoicesListPage.tsx"],"sourcesContent":["/**\n * Billing Module - Invoices List Page\n * Displays all invoices for the current tenant\n */\n\nimport { useEffect, useState, useMemo, useRef, type FC } from 'react';\nimport { RotateCcw } from 'lucide-react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePaginatedInvoices } from '../hooks/useInvoices';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n useGetBillingAccountsByOrgQuery,\n type GetBillingAccountsByOrgQuery,\n} from '../../../../generated/global-operations';\n\ntype BillingAccountItem = GetBillingAccountsByOrgQuery['getBillingAccountsByOrg'][number];\nimport {\n formatCurrency,\n formatDate,\n formatInvoiceStatus,\n formatInvoiceNumber,\n} from '../../../shared/utils/format';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport { getInvoiceStatusColor } from '../../../shared/utils/status';\nimport { StatusPill } from '../../../shared/ui';\nimport type { Invoice, InvoiceStatus } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ntype FilterStatus = 'all' | InvoiceStatus;\n\nexport const InvoicesListPage: 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 navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const [searchParams] = useSearchParams();\n const urlBillingAccountId = searchParams.get('billingAccountId') ?? undefined;\n\n const { data: accountsData } = useGetBillingAccountsByOrgQuery({ fetchPolicy: 'cache-first' });\n const billingAccounts = accountsData?.getBillingAccountsByOrg ?? [];\n\n // undefined = user hasn't explicitly chosen yet → auto-pick default\n // null = user explicitly chose \"All Accounts\"\n // string = user explicitly chose a specific account\n const [explicitAccountId, setExplicitAccountId] = useState<string | null | undefined>(\n urlBillingAccountId\n );\n\n useEffect(() => {\n setExplicitAccountId(urlBillingAccountId);\n }, [urlBillingAccountId]);\n\n const defaultAccountId = useMemo(\n () =>\n (billingAccounts.find((a: BillingAccountItem) => a.isDefault) ?? billingAccounts[0])?.id ??\n undefined,\n [billingAccounts]\n );\n\n // Resolved selection: explicit choice wins; before any choice, use the default\n const selectedAccountId: string | null =\n explicitAccountId !== undefined ? explicitAccountId : (defaultAccountId ?? null);\n\n const [filterStatus, setFilterStatus] = useState<FilterStatus>('all');\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [page, setPage] = useState(1);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n debounceTimer.current = setTimeout(() => {\n setDebouncedSearch(searchQuery);\n setPage(1);\n }, 400);\n return () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n };\n }, [searchQuery]);\n\n const { invoices, totalPages, isLoading, error, refetch } = usePaginatedInvoices({\n billingAccountId: selectedAccountId ?? undefined,\n status: filterStatus !== 'all' ? (filterStatus as InvoiceStatus) : undefined,\n search: debouncedSearch || undefined,\n page,\n pageSize: 20,\n });\n\n // Permission check\n if (!permissions.canViewInvoices) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-bg-sunken flex items-center justify-center\">\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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary max-w-sm\">\n {tr('billing.invoices.noViewPermission', \"You don't have permission to view invoices.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading && invoices.length === 0) {\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-3\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"flex-1 space-y-2\">\n <div className=\"h-4 w-32 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-3 w-48 bg-bg-sunken animate-pulse rounded\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-6 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.failedToLoad', 'Failed to load invoices')}\n </h2>\n <p className=\"text-sm text-text-secondary\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\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\"\n >\n Try Again\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-text-primary\">\n {tr('billing.invoices.title', 'Invoices')}\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr('billing.invoices.subtitle', 'View and manage your billing invoices')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/refunds')}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken hover:border-border-strong transition-all duration-200\"\n >\n <RotateCcw className=\"size-4\" />\n {tr('billing.invoices.myRefunds', 'My Refunds')}\n </button>\n {billingAccounts.length > 1 && (\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-secondary whitespace-nowrap\">\n Billing Account\n </label>\n <select\n value={selectedAccountId ?? ''}\n onChange={(e) => setExplicitAccountId(e.target.value || null)}\n className=\"text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Accounts</option>\n {billingAccounts.map((account: BillingAccountItem) => (\n <option key={account.id ?? ''} value={account.id ?? ''}>\n {account.name ?? account.email ?? account.id}\n {account.isDefault ? ' (Default)' : ''}\n </option>\n ))}\n </select>\n </div>\n )}\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle\">\n {/* Status Filter */}\n <div className=\"inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken flex-wrap\">\n {(['all', 'OPEN', 'PAID', 'DRAFT', 'VOID'] as FilterStatus[]).map((status) => (\n <button\n type=\"button\"\n key={status}\n onClick={() => {\n setFilterStatus(status);\n setPage(1);\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${\n filterStatus === status\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {status === 'all' ? 'All' : formatInvoiceStatus(status as InvoiceStatus)}\n </button>\n ))}\n </div>\n\n {/* Search */}\n <div className=\"relative flex-1 min-w-0 w-full sm:max-w-md\">\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 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=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder={tr('billing.invoices.searchPlaceholder', 'Search by invoice number...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] focus:border-transparent\"\n />\n </div>\n </div>\n\n {/* Invoices Table */}\n {!isLoading && invoices.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-12 border border-dashed border-border-seam rounded-card\">\n <div className=\"size-12 rounded-full bg-[var(--color-accent-soft)] flex items-center justify-center mb-4\">\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 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-text-primary\">\n {tr('billing.invoices.noInvoicesFound', 'No invoices found')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-1\">\n {filterStatus !== 'all' || debouncedSearch\n ? tr('billing.invoices.noInvoicesFiltered', 'No invoices match your filters.')\n : tr('billing.invoices.noInvoicesYet', \"You don't have any invoices yet.\")}\n </p>\n </div>\n ) : (\n <>\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <table className=\"w-full\">\n <thead className=\"bg-bg-sunken\">\n <tr>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Invoice\n </th>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Status\n </th>\n {!selectedAccountId && billingAccounts.length > 1 && (\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden lg:table-cell\">\n Account\n </th>\n )}\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden sm:table-cell\">\n Date\n </th>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden md:table-cell\">\n Due Date\n </th>\n <th className=\"text-right px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Amount\n </th>\n <th className=\"text-right px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-subtle\">\n {invoices.map((invoice) => (\n <InvoiceRow\n key={invoice.id}\n invoice={invoice}\n onView={() =>\n navigateTo(\n withBillingAccountId(`/invoices/${invoice.id}`, invoice.billingAccountId)\n )\n }\n canPay={permissions.canPayInvoice}\n canVoid={permissions.canVoidInvoice}\n showAccount={!selectedAccountId && billingAccounts.length > 1}\n accountName={\n billingAccounts.find(\n (a: BillingAccountItem) => a.id === invoice.billingAccountId\n )?.name ?? null\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {totalPages > 1 && (\n <div className=\"flex items-center justify-between pt-2\">\n <p className=\"text-sm text-text-secondary\">\n Page {page} of {totalPages}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Invoice Row Component\n// ============================================================================\n\ninterface InvoiceRowProps {\n invoice: Invoice;\n onView: () => void;\n canPay: boolean;\n canVoid: boolean;\n showAccount?: boolean;\n accountName?: string | null;\n}\n\nconst InvoiceRow: FC<InvoiceRowProps> = ({\n invoice,\n onView,\n canPay,\n canVoid,\n showAccount = false,\n accountName,\n}) => {\n const statusColor = getInvoiceStatusColor(invoice.status);\n const isOpen = invoice.status === ('OPEN' as InvoiceStatus);\n const isDraft = invoice.status === ('DRAFT' as InvoiceStatus);\n\n return (\n <tr className=\"hover:bg-bg-sunken transition-colors\">\n <td className=\"p-4\">\n {invoice.invoiceUrl ? (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-text-primary hover:text-text-link transition-colors\"\n >\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onView}\n className=\"font-medium text-text-primary hover:text-text-link transition-colors\"\n >\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </button>\n )}\n {(invoice.itemDescription ?? invoice.subscription?.plan?.name) && (\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {invoice.itemDescription ?? invoice.subscription?.plan?.name}\n </p>\n )}\n </td>\n <td className=\"p-4\">\n <StatusPill status={statusColor} dot>\n {formatInvoiceStatus(invoice.status)}\n </StatusPill>\n </td>\n {showAccount && (\n <td className=\"p-4 hidden lg:table-cell\">\n {accountName ? (\n <span className=\"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-bg-sunken text-text-secondary border border-border-subtle\">\n {accountName}\n </span>\n ) : (\n <span className=\"text-sm text-text-secondary\">, </span>\n )}\n </td>\n )}\n <td className=\"p-4 text-sm text-text-secondary hidden sm:table-cell\">\n {formatDate(invoice.createdAt, 'short')}\n </td>\n <td className=\"p-4 text-sm text-text-secondary hidden md:table-cell\">\n {invoice.dueDate ? formatDate(invoice.dueDate, 'short') : '—'}\n </td>\n <td className=\"p-4 text-right font-medium text-text-primary\">\n {formatCurrency(invoice.total, invoice.currency)}\n </td>\n <td className=\"p-4 text-right\">\n <div className=\"flex items-center justify-end gap-2\">\n {invoice.invoiceUrl ? (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors duration-200\"\n >\n View\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onView}\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors duration-200\"\n >\n View\n </button>\n )}\n {invoice.pdfUrl && (\n <a\n href={invoice.pdfUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-3 py-1.5 text-sm font-medium text-text-link hover:bg-[var(--color-accent-softHover)] rounded-button transition-colors duration-200\"\n >\n PDF\n </a>\n )}\n {isOpen && canPay && (\n <button\n type=\"button\"\n className=\"px-3 py-1.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors duration-200\"\n >\n Pay\n </button>\n )}\n {(isOpen || isDraft) && canVoid && (\n <button\n type=\"button\"\n className=\"px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle rounded-button transition-colors duration-200\"\n >\n Void\n </button>\n )}\n </div>\n </td>\n </tr>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;AA+BA,IAAa,UAA6B;CACxC,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAA6B;EACpD,IAAM,IAAa,EAAE,EAAI;AACzB,SAAO,MAAe,IAAM,IAAW;IAEnC,IAAa,GAAoB,EACjC,IAAc,GAAuB,EACrC,CAAC,KAAgB,GAAiB,EAClC,IAAsB,EAAa,IAAI,mBAAmB,IAAI,KAAA,GAE9D,EAAE,MAAM,MAAiB,EAAgC,EAAE,aAAa,eAAe,CAAC,EACxF,IAAkB,GAAc,2BAA2B,EAAE,EAK7D,CAAC,GAAmB,KAAwB,EAChD,EACD;AAED,SAAgB;AACd,IAAqB,EAAoB;IACxC,CAAC,EAAoB,CAAC;CAEzB,IAAM,IAAmB,SAEpB,EAAgB,MAAM,MAA0B,EAAE,UAAU,IAAI,EAAgB,KAAK,MACtF,KAAA,GACF,CAAC,EAAgB,CAClB,EAGK,IACJ,MAAsB,KAAA,IAAiC,KAAoB,OAAzC,GAE9B,CAAC,GAAc,KAAmB,EAAuB,MAAM,EAC/D,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAiB,KAAsB,EAAS,GAAG,EACpD,CAAC,GAAM,KAAW,EAAS,EAAE,EAC7B,IAAgB,EAA6C,KAAK;AAExE,UACM,EAAc,WAAS,aAAa,EAAc,QAAQ,EAC9D,EAAc,UAAU,iBAAiB;AAEvC,EADA,EAAmB,EAAY,EAC/B,EAAQ,EAAE;IACT,IAAI,QACM;AACX,EAAI,EAAc,WAAS,aAAa,EAAc,QAAQ;KAE/D,CAAC,EAAY,CAAC;CAEjB,IAAM,EAAE,aAAU,eAAY,cAAW,UAAO,eAAY,EAAqB;EAC/E,kBAAkB,KAAqB,KAAA;EACvC,QAAQ,MAAiB,QAA0C,KAAA,IAAjC;EAClC,QAAQ,KAAmB,KAAA;EAC3B;EACA,UAAU;EACX,CAAC;AA2FF,QAxFK,EAAY,kBA+Bb,KAAa,EAAS,WAAW,IAEjC,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;IAAa,WAAU;cACrB,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAK,WAAU,8CAA+C,CAAA,EAC9D,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD,EAAK,WAAU,+CAAgD,CAAA,EAC/D,kBAAC,OAAD,EAAK,WAAU,+CAAgD,CAAA,CAC3D;QACF;;IACF,EARI,EAQJ,CACN;GACE,CAAA,CACF;MAKN,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MACE,WAAU;MACV,MAAK;MACL,SAAQ;MACR,QAAO;gBAEP,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA;KACF,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,iCAAiC,0BAA0B;KAC5D,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eAA+B,EAAM;KAAY,CAAA;IAC9D,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,GAAS;KACxB,WAAU;eACX;KAEQ,CAAA;IACL;;EACF,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,0BAA0B,WAAW;KACtC,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,6BAA6B,wCAAwC;KACvE,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,WAAW;MACrC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,EAC/B,EAAG,8BAA8B,aAAa,CACxC;SACR,EAAgB,SAAS,KACxB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,SAAD;OAAO,WAAU;iBAAgD;OAEzD,CAAA,EACR,kBAAC,UAAD;OACE,OAAO,KAAqB;OAC5B,WAAW,MAAM,EAAqB,EAAE,OAAO,SAAS,KAAK;OAC7D,WAAU;iBAHZ,CAKE,kBAAC,UAAD;QAAQ,OAAM;kBAAG;QAAqB,CAAA,EACrC,EAAgB,KAAK,MACpB,kBAAC,UAAD;QAA+B,OAAO,EAAQ,MAAM;kBAApD,CACG,EAAQ,QAAQ,EAAQ,SAAS,EAAQ,IACzC,EAAQ,YAAY,eAAe,GAC7B;UAHI,EAAQ,MAAM,GAGlB,CACT,CACK;SACL;QAEJ;OACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,OAAD;KAAK,WAAU;eACX;MAAC;MAAO;MAAQ;MAAQ;MAAS;MAAO,CAAoB,KAAK,MACjE,kBAAC,UAAD;MACE,MAAK;MAEL,eAAe;AAEb,OADA,EAAgB,EAAO,EACvB,EAAQ,EAAE;;MAEZ,WAAW,oEACT,MAAiB,IACb,8CACA;gBAGL,MAAW,QAAQ,QAAQ,EAAoB,EAAwB;MACjE,EAZF,EAYE,CACT;KACE,CAAA,EAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MACE,WAAU;MACV,MAAK;MACL,SAAQ;MACR,QAAO;gBAEP,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA,EACN,kBAAC,SAAD;MACE,MAAK;MACL,aAAa,EAAG,sCAAsC,8BAA8B;MACpF,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,WAAU;MACV,CAAA,CACE;OACF;;GAGL,CAAC,KAAa,EAAS,WAAW,IACjC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,MAAK;OACL,SAAQ;OACR,QAAO;iBAEP,kBAAC,QAAD;QACE,eAAc;QACd,gBAAe;QACf,aAAa;QACb,GAAE;QACF,CAAA;OACE,CAAA;MACF,CAAA;KACN,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,oCAAoC,oBAAoB;MACzD,CAAA;KACL,kBAAC,KAAD;MAAG,WAAU;gBACV,MAAiB,SAAS,IACvB,EAAG,uCAAuC,kCAAkC,GAC5E,EAAG,kCAAkC,mCAAmC;MAC1E,CAAA;KACA;QAEN,kBAAA,GAAA,EAAA,UAAA,CACE,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;kBAAkF;QAE3F,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAkF;QAE3F,CAAA;OACJ,CAAC,KAAqB,EAAgB,SAAS,KAC9C,kBAAC,MAAD;QAAI,WAAU;kBAAuG;QAEhH,CAAA;OAEP,kBAAC,MAAD;QAAI,WAAU;kBAAuG;QAEhH,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAuG;QAEhH,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAmF;QAE5F,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBAAmF;QAE5F,CAAA;OACF,EAAA,CAAA;MACC,CAAA,EACR,kBAAC,SAAD;MAAO,WAAU;gBACd,EAAS,KAAK,MACb,kBAAC,GAAD;OAEW;OACT,cACE,EACE,EAAqB,aAAa,EAAQ,MAAM,EAAQ,iBAAiB,CAC1E;OAEH,QAAQ,EAAY;OACpB,SAAS,EAAY;OACrB,aAAa,CAAC,KAAqB,EAAgB,SAAS;OAC5D,aACE,EAAgB,MACb,MAA0B,EAAE,OAAO,EAAQ,iBAC7C,EAAE,QAAQ;OAEb,EAfK,EAAQ,GAeb,CACF;MACI,CAAA,CACF;;IACJ,CAAA,EAEL,IAAa,KACZ,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAb;MAA2C;MACnC;MAAK;MAAK;MACd;QACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAS,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC;MACjD,UAAU,KAAQ;MAClB,WAAU;gBACX;MAEQ,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,GAAS,MAAM,KAAK,IAAI,GAAY,IAAI,EAAE,CAAC;MAC1D,UAAU,KAAQ;MAClB,WAAU;gBACX;MAEQ,CAAA,CACL;OACF;MAEP,EAAA,CAAA;GAED;MA/RJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MACE,WAAU;MACV,MAAK;MACL,SAAQ;MACR,QAAO;gBAEP,kBAAC,QAAD;OACE,eAAc;OACd,gBAAe;OACf,aAAa;OACb,GAAE;OACF,CAAA;MACE,CAAA;KACF,CAAA;IACN,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,8BAA8B,gBAAgB;KAC/C,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,qCAAqC,8CAA8C;KACrF,CAAA;IACA;;EACF,CAAA;GAwRN,KAAmC,EACvC,YACA,WACA,WACA,YACA,iBAAc,IACd,qBACI;CACJ,IAAM,IAAc,EAAsB,EAAQ,OAAO,EACnD,IAAS,EAAQ,WAAY,QAC7B,IAAU,EAAQ,WAAY;AAEpC,QACE,kBAAC,MAAD;EAAI,WAAU;YAAd;GACE,kBAAC,MAAD;IAAI,WAAU;cAAd,CACG,EAAQ,aACP,kBAAC,KAAD;KACE,MAAM,EAAQ;KACd,QAAO;KACP,KAAI;KACJ,WAAU;eAET,EAAoB,EAAQ,cAAc;KACzC,CAAA,GAEJ,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAET,EAAoB,EAAQ,cAAc;KACpC,CAAA,GAET,EAAQ,mBAAmB,EAAQ,cAAc,MAAM,SACvD,kBAAC,KAAD;KAAG,WAAU;eACV,EAAQ,mBAAmB,EAAQ,cAAc,MAAM;KACtD,CAAA,CAEH;;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,GAAD;KAAY,QAAQ;KAAa,KAAA;eAC9B,EAAoB,EAAQ,OAAO;KACzB,CAAA;IACV,CAAA;GACJ,KACC,kBAAC,MAAD;IAAI,WAAU;cACX,IACC,kBAAC,QAAD;KAAM,WAAU;eACb;KACI,CAAA,GAEP,kBAAC,QAAD;KAAM,WAAU;eAA8B;KAAS,CAAA;IAEtD,CAAA;GAEP,kBAAC,MAAD;IAAI,WAAU;cACX,EAAW,EAAQ,WAAW,QAAQ;IACpC,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACX,EAAQ,UAAU,EAAW,EAAQ,SAAS,QAAQ,GAAG;IACvD,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACX,EAAe,EAAQ,OAAO,EAAQ,SAAS;IAC7C,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAQ,aACP,kBAAC,KAAD;OACE,MAAM,EAAQ;OACd,QAAO;OACP,KAAI;OACJ,WAAU;iBACX;OAEG,CAAA,GAEJ,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU;iBACX;OAEQ,CAAA;MAEV,EAAQ,UACP,kBAAC,KAAD;OACE,MAAM,EAAQ;OACd,QAAO;OACP,KAAI;OACJ,WAAU;iBACX;OAEG,CAAA;MAEL,KAAU,KACT,kBAAC,UAAD;OACE,MAAK;OACL,WAAU;iBACX;OAEQ,CAAA;OAET,KAAU,MAAY,KACtB,kBAAC,UAAD;OACE,MAAK;OACL,WAAU;iBACX;OAEQ,CAAA;MAEP;;IACH,CAAA;GACF"}
1
+ {"version":3,"file":"InvoicesListPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/InvoicesListPage.tsx"],"sourcesContent":["/**\n * Billing Module - Invoices List Page\n * Displays all invoices for the current tenant\n */\n\nimport { useEffect, useState, useMemo, useRef, type FC } from 'react';\nimport { RotateCcw } from 'lucide-react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePaginatedInvoices } from '../hooks/useInvoices';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport {\n useGetBillingAccountsByOrgQuery,\n type GetBillingAccountsByOrgQuery,\n} from '../../../../generated/global-operations';\n\ntype BillingAccountItem = GetBillingAccountsByOrgQuery['getBillingAccountsByOrg'][number];\nimport {\n formatCurrency,\n formatDate,\n formatInvoiceStatus,\n formatInvoiceNumber,\n} from '../../../shared/utils/format';\nimport { withBillingAccountId } from '../../../shared/utils/navigation';\nimport { getInvoiceStatusColor } from '../../../shared/utils/status';\nimport { StatusPill } from '../../../shared/ui';\nimport type { Invoice, InvoiceStatus } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\n\ntype FilterStatus = 'all' | InvoiceStatus;\n\nexport const InvoicesListPage: 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 navigateTo = useBillingNavigate();\n const permissions = useBillingPermissions();\n const [searchParams] = useSearchParams();\n const urlBillingAccountId = searchParams.get('billingAccountId') ?? undefined;\n\n const { data: accountsData } = useGetBillingAccountsByOrgQuery({ fetchPolicy: 'cache-first' });\n const billingAccounts = accountsData?.getBillingAccountsByOrg ?? [];\n\n // undefined = user hasn't explicitly chosen yet → auto-pick default\n // null = user explicitly chose \"All Accounts\"\n // string = user explicitly chose a specific account\n const [explicitAccountId, setExplicitAccountId] = useState<string | null | undefined>(\n urlBillingAccountId\n );\n\n useEffect(() => {\n setExplicitAccountId(urlBillingAccountId);\n }, [urlBillingAccountId]);\n\n const defaultAccountId = useMemo(\n () =>\n (billingAccounts.find((a: BillingAccountItem) => a.isDefault) ?? billingAccounts[0])?.id ??\n undefined,\n [billingAccounts]\n );\n\n // Resolved selection: explicit choice wins; before any choice, use the default\n const selectedAccountId: string | null =\n explicitAccountId !== undefined ? explicitAccountId : (defaultAccountId ?? null);\n\n const [filterStatus, setFilterStatus] = useState<FilterStatus>('all');\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [page, setPage] = useState(1);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n debounceTimer.current = setTimeout(() => {\n setDebouncedSearch(searchQuery);\n setPage(1);\n }, 400);\n return () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n };\n }, [searchQuery]);\n\n const { invoices, totalPages, isLoading, error, refetch } = usePaginatedInvoices({\n billingAccountId: selectedAccountId ?? undefined,\n status: filterStatus !== 'all' ? (filterStatus as InvoiceStatus) : undefined,\n search: debouncedSearch || undefined,\n page,\n pageSize: 20,\n });\n\n // Permission check\n if (!permissions.canViewInvoices) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <div className=\"size-12 mx-auto rounded-full bg-bg-sunken flex items-center justify-center\">\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 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.accessDenied.title', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary max-w-sm\">\n {tr('billing.invoices.noViewPermission', \"You don't have permission to view invoices.\")}\n </p>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (isLoading && invoices.length === 0) {\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-3\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"border border-border-subtle rounded-lg p-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"size-10 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"flex-1 space-y-2\">\n <div className=\"h-4 w-32 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"h-3 w-48 bg-bg-sunken animate-pulse rounded\" />\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[400px]\">\n <div className=\"text-center space-y-4\">\n <div className=\"size-12 mx-auto rounded-full bg-status-error-bg-subtle flex items-center justify-center\">\n <svg\n className=\"size-6 text-status-error-text\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n </div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('billing.invoices.failedToLoad', 'Failed to load invoices')}\n </h2>\n <p className=\"text-sm text-text-secondary\">{error.message}</p>\n <button\n type=\"button\"\n onClick={() => refetch()}\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\"\n >\n Try Again\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 px-6 lg:px-8 py-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl md:text-3xl font-semibold tracking-tight text-text-primary\">\n {tr('billing.invoices.title', 'Invoices')}\n </h1>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr('billing.invoices.subtitle', 'View and manage your billing invoices')}\n </p>\n <PagePurpose className=\"mt-3\">\n {tr(\n 'billing.invoices.purpose',\n 'A record of everything you have been billed for — subscriptions, add-ons and one-off charges. Open an invoice to see line items, download the PDF, pay an outstanding amount, or request a refund.'\n )}\n </PagePurpose>\n </div>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/refunds')}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken hover:border-border-strong transition-all duration-200\"\n >\n <RotateCcw className=\"size-4\" />\n {tr('billing.invoices.myRefunds', 'My Refunds')}\n </button>\n {billingAccounts.length > 1 && (\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-secondary whitespace-nowrap\">\n Billing Account\n </label>\n <select\n value={selectedAccountId ?? ''}\n onChange={(e) => setExplicitAccountId(e.target.value || null)}\n className=\"text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary px-3 py-2 focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Accounts</option>\n {billingAccounts.map((account: BillingAccountItem) => (\n <option key={account.id ?? ''} value={account.id ?? ''}>\n {account.name ?? account.email ?? account.id}\n {account.isDefault ? ' (Default)' : ''}\n </option>\n ))}\n </select>\n </div>\n )}\n </div>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-wrap items-center gap-4 pb-4 border-b border-border-subtle\">\n {/* Status Filter */}\n <div className=\"inline-flex rounded-lg border border-border-subtle p-1 bg-bg-sunken flex-wrap\">\n {(['all', 'OPEN', 'PAID', 'DRAFT', 'VOID'] as FilterStatus[]).map((status) => (\n <button\n type=\"button\"\n key={status}\n onClick={() => {\n setFilterStatus(status);\n setPage(1);\n }}\n className={`px-3 py-1.5 text-sm font-medium rounded-button transition-colors ${\n filterStatus === status\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-secondary hover:text-text-primary'\n }`}\n >\n {status === 'all' ? 'All' : formatInvoiceStatus(status as InvoiceStatus)}\n </button>\n ))}\n </div>\n\n {/* Search */}\n <div className=\"relative flex-1 min-w-0 w-full sm:max-w-md\">\n <svg\n className=\"absolute left-3 top-1/2 -translate-y-1/2 size-4 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=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\"\n />\n </svg>\n <input\n type=\"text\"\n placeholder={tr('billing.invoices.searchPlaceholder', 'Search by invoice number...')}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 text-sm border border-border-subtle rounded-button bg-bg-surface text-text-primary placeholder:text-text-placeholder focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] focus:border-transparent\"\n />\n </div>\n </div>\n\n {/* Invoices Table */}\n {!isLoading && invoices.length === 0 ? (\n <IllustratedEmptyState\n illustration={filterStatus !== 'all' || debouncedSearch ? 'empty-search' : 'empty-files'}\n title={tr('billing.invoices.noInvoicesFound', 'No invoices found')}\n description={\n filterStatus !== 'all' || debouncedSearch\n ? tr('billing.invoices.noInvoicesFiltered', 'No invoices match your filters.')\n : tr('billing.invoices.noInvoicesYet', \"You don't have any invoices yet.\")\n }\n />\n ) : (\n <>\n <div className=\"border border-border-seam rounded-card bg-bg-surface shadow-elevation-1 overflow-hidden\">\n <table className=\"w-full\">\n <thead className=\"bg-bg-sunken\">\n <tr>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Invoice\n </th>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Status\n </th>\n {!selectedAccountId && billingAccounts.length > 1 && (\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden lg:table-cell\">\n Account\n </th>\n )}\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden sm:table-cell\">\n Date\n </th>\n <th className=\"text-left px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted hidden md:table-cell\">\n Due Date\n </th>\n <th className=\"text-right px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Amount\n </th>\n <th className=\"text-right px-4 py-3 text-xs font-medium uppercase tracking-wide text-text-muted\">\n Actions\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-subtle\">\n {invoices.map((invoice) => (\n <InvoiceRow\n key={invoice.id}\n invoice={invoice}\n onView={() =>\n navigateTo(\n withBillingAccountId(`/invoices/${invoice.id}`, invoice.billingAccountId)\n )\n }\n canPay={permissions.canPayInvoice}\n canVoid={permissions.canVoidInvoice}\n showAccount={!selectedAccountId && billingAccounts.length > 1}\n accountName={\n billingAccounts.find(\n (a: BillingAccountItem) => a.id === invoice.billingAccountId\n )?.name ?? null\n }\n />\n ))}\n </tbody>\n </table>\n </div>\n\n {totalPages > 1 && (\n <div className=\"flex items-center justify-between pt-2\">\n <p className=\"text-sm text-text-secondary\">\n Page {page} of {totalPages}\n </p>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n className=\"px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n Previous\n </button>\n <button\n type=\"button\"\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n disabled={page >= totalPages}\n className=\"px-3 py-1.5 text-sm font-medium border border-border-subtle rounded-button bg-bg-surface text-text-primary hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n Next\n </button>\n </div>\n </div>\n )}\n </>\n )}\n </div>\n );\n};\n\n// ============================================================================\n// Invoice Row Component\n// ============================================================================\n\ninterface InvoiceRowProps {\n invoice: Invoice;\n onView: () => void;\n canPay: boolean;\n canVoid: boolean;\n showAccount?: boolean;\n accountName?: string | null;\n}\n\nconst InvoiceRow: FC<InvoiceRowProps> = ({\n invoice,\n onView,\n canPay,\n canVoid,\n showAccount = false,\n accountName,\n}) => {\n const statusColor = getInvoiceStatusColor(invoice.status);\n const isOpen = invoice.status === ('OPEN' as InvoiceStatus);\n const isDraft = invoice.status === ('DRAFT' as InvoiceStatus);\n\n return (\n <tr className=\"hover:bg-bg-sunken transition-colors\">\n <td className=\"p-4\">\n {invoice.invoiceUrl ? (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-text-primary hover:text-text-link transition-colors\"\n >\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onView}\n className=\"font-medium text-text-primary hover:text-text-link transition-colors\"\n >\n {formatInvoiceNumber(invoice.invoiceNumber)}\n </button>\n )}\n {(invoice.itemDescription ?? invoice.subscription?.plan?.name) && (\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {invoice.itemDescription ?? invoice.subscription?.plan?.name}\n </p>\n )}\n </td>\n <td className=\"p-4\">\n <StatusPill status={statusColor} dot>\n {formatInvoiceStatus(invoice.status)}\n </StatusPill>\n </td>\n {showAccount && (\n <td className=\"p-4 hidden lg:table-cell\">\n {accountName ? (\n <span className=\"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-bg-sunken text-text-secondary border border-border-subtle\">\n {accountName}\n </span>\n ) : (\n <span className=\"text-sm text-text-secondary\">, </span>\n )}\n </td>\n )}\n <td className=\"p-4 text-sm text-text-secondary hidden sm:table-cell\">\n {formatDate(invoice.createdAt, 'short')}\n </td>\n <td className=\"p-4 text-sm text-text-secondary hidden md:table-cell\">\n {invoice.dueDate ? formatDate(invoice.dueDate, 'short') : '—'}\n </td>\n <td className=\"p-4 text-right font-medium text-text-primary\">\n {formatCurrency(invoice.total, invoice.currency)}\n </td>\n <td className=\"p-4 text-right\">\n <div className=\"flex items-center justify-end gap-2\">\n {invoice.invoiceUrl ? (\n <a\n href={invoice.invoiceUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors duration-200\"\n >\n View\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={onView}\n className=\"px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken rounded-button transition-colors duration-200\"\n >\n View\n </button>\n )}\n {invoice.pdfUrl && (\n <a\n href={invoice.pdfUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"px-3 py-1.5 text-sm font-medium text-text-link hover:bg-[var(--color-accent-softHover)] rounded-button transition-colors duration-200\"\n >\n PDF\n </a>\n )}\n {isOpen && canPay && (\n <button\n type=\"button\"\n className=\"px-3 py-1.5 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-button hover:bg-action-primary-bgHover transition-colors duration-200\"\n >\n Pay\n </button>\n )}\n {(isOpen || isDraft) && canVoid && (\n <button\n type=\"button\"\n className=\"px-3 py-1.5 text-sm font-medium text-status-error-text hover:bg-status-error-bg-subtle rounded-button transition-colors duration-200\"\n >\n Void\n </button>\n )}\n </div>\n </td>\n </tr>\n );\n};\n"],"mappings":"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"}