@burdenoff/microfe-billing 2026.623.3 → 2026.624.2

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 (43) hide show
  1. package/dist/billing/BillingUserRoutes.js +3 -3
  2. package/dist/billing/BillingUserRoutes.js.map +1 -1
  3. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js +34 -34
  4. package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
  5. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js +94 -94
  6. package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
  7. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +162 -187
  8. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  9. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +146 -153
  10. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  11. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +10 -10
  12. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
  13. package/dist/billing/modules/billing/pages/TransactionsPage.js +62 -62
  14. package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
  15. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +164 -179
  16. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  17. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +8 -8
  18. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  19. package/dist/billing/modules/earnings/pages/EarningsPage.js +243 -305
  20. package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
  21. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +73 -78
  22. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  23. package/dist/billing/modules/earnings/pages/PayoutsPage.js +173 -179
  24. package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
  25. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js +4 -4
  26. package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
  27. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js +4 -4
  28. package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
  29. package/dist/billing/modules/settings/pages/SettingsPage.js +181 -173
  30. package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
  31. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +111 -99
  32. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
  33. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +68 -83
  34. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
  35. package/dist/billing/shared/components/AccessDenied.js +4 -4
  36. package/dist/billing/shared/components/AccessDenied.js.map +1 -1
  37. package/dist/billing/shared/components/ActorIdentity.js +8 -8
  38. package/dist/billing/shared/components/ActorIdentity.js.map +1 -1
  39. package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js +11 -11
  40. package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
  41. package/dist/billing/shared/ui/MetricCard.js +1 -1
  42. package/dist/billing/shared/ui/MetricCard.js.map +1 -1
  43. package/package.json +1 -1
@@ -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';\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 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-subtle 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 <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead className=\"bg-bg-sunken\">\n <tr>\n <th className=\"text-left px-4 py-3 text-sm font-medium text-text-secondary\">\n Description\n </th>\n <th className=\"text-right px-4 py-3 text-sm font-medium text-text-secondary\">\n Qty\n </th>\n <th className=\"text-right px-4 py-3 text-sm font-medium text-text-secondary\">\n Unit Price\n </th>\n <th className=\"text-right px-4 py-3 text-sm font-medium text-text-secondary\">\n Amount\n </th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-subtle\">\n {items.map((item) => (\n <tr key={item.id} className=\"hover:bg-bg-sunken transition-colors\">\n <td className=\"p-4 text-sm text-text-primary\">{item.description}</td>\n <td className=\"p-4 text-sm text-text-secondary text-right\">\n {item.quantity}\n </td>\n <td className=\"p-4 text-sm text-text-secondary text-right\">\n {formatCurrency(item.unitPrice, invoice.currency)}\n </td>\n <td className=\"p-4 text-sm font-medium text-text-primary text-right\">\n {formatCurrency(item.amount, invoice.currency)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\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-subtle 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-subtle 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-subtle 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-subtle 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-subtle 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 { 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-subtle 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-subtle 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-subtle 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-subtle 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-subtle 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-subtle 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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"}
@@ -37,13 +37,13 @@ var h = {
37
37
  S.replace(/\/+$/, "").endsWith("/payment-methods/add") && D(!0);
38
38
  }, [S]), _.canViewPaymentMethods ? T ? /* @__PURE__ */ p("div", {
39
39
  className: "space-y-6 p-6",
40
- children: [/* @__PURE__ */ f("div", { className: "h-8 w-48 bg-muted animate-pulse rounded" }), /* @__PURE__ */ f("div", {
40
+ children: [/* @__PURE__ */ f("div", { className: "h-8 w-48 bg-bg-sunken animate-pulse rounded" }), /* @__PURE__ */ f("div", {
41
41
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
42
42
  children: [
43
43
  1,
44
44
  2,
45
45
  3
46
- ].map((e) => /* @__PURE__ */ f("div", { className: "h-32 bg-muted animate-pulse rounded-lg" }, e))
46
+ ].map((e) => /* @__PURE__ */ f("div", { className: "h-32 bg-bg-sunken animate-pulse rounded-lg" }, e))
47
47
  })]
48
48
  }) : /* @__PURE__ */ p("div", {
49
49
  className: "space-y-6 p-6",
@@ -54,13 +54,13 @@ var h = {
54
54
  actions: _.canManagePaymentMethods && /* @__PURE__ */ f("button", {
55
55
  type: "button",
56
56
  onClick: k,
57
- className: "px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors",
57
+ className: "px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 transition-colors",
58
58
  children: g("billing.paymentMethods.add", "Add payment method")
59
59
  })
60
60
  }),
61
61
  w.length === 0 ? /* @__PURE__ */ f(r, {
62
62
  icon: /* @__PURE__ */ f("svg", {
63
- className: "size-6 text-muted-foreground",
63
+ className: "size-6 text-text-secondary",
64
64
  fill: "none",
65
65
  viewBox: "0 0 24 24",
66
66
  stroke: "currentColor",
@@ -76,7 +76,7 @@ var h = {
76
76
  action: _.canManagePaymentMethods && /* @__PURE__ */ f("button", {
77
77
  type: "button",
78
78
  onClick: () => D(!0),
79
- className: "px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90",
79
+ className: "px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90",
80
80
  children: "Add Payment Method"
81
81
  })
82
82
  }) : /* @__PURE__ */ f("div", {
@@ -107,7 +107,7 @@ var h = {
107
107
  }, v = ({ method: e, canManage: t }) => {
108
108
  let n = e.expiryYear && e.expiryMonth ? new Date(e.expiryYear, e.expiryMonth - 1) < /* @__PURE__ */ new Date() : !1;
109
109
  return /* @__PURE__ */ p("div", {
110
- className: `border rounded-lg bg-card p-4 ${e.isDefault ? "border-primary" : "border-border"}`,
110
+ className: `border rounded-lg bg-bg-surface p-4 ${e.isDefault ? "border-primary" : "border-border-subtle"}`,
111
111
  children: [/* @__PURE__ */ f("div", {
112
112
  className: "flex items-start justify-between",
113
113
  children: /* @__PURE__ */ p("div", {
@@ -118,18 +118,18 @@ var h = {
118
118
  }), /* @__PURE__ */ p("div", { children: [/* @__PURE__ */ p("div", {
119
119
  className: "flex items-center gap-2",
120
120
  children: [/* @__PURE__ */ p("p", {
121
- className: "font-medium text-foreground",
121
+ className: "font-medium text-text-primary",
122
122
  children: [
123
123
  e.brand ?? g[e.type],
124
124
  " •••• ",
125
125
  e.last4
126
126
  ]
127
127
  }), e.isDefault && /* @__PURE__ */ f("span", {
128
- className: "px-1.5 py-0.5 text-xs font-medium bg-primary/10 text-primary rounded",
128
+ className: "px-1.5 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-primary rounded",
129
129
  children: "Default"
130
130
  })]
131
131
  }), e.expiryMonth && e.expiryYear && /* @__PURE__ */ p("p", {
132
- className: `text-sm ${n ? "text-status-error-text" : "text-muted-foreground"}`,
132
+ className: `text-sm ${n ? "text-status-error-text" : "text-text-secondary"}`,
133
133
  children: [
134
134
  n ? "Expired" : "Expires",
135
135
  " ",
@@ -140,7 +140,7 @@ var h = {
140
140
  })] })]
141
141
  })
142
142
  }), t && /* @__PURE__ */ p("div", {
143
- className: "flex items-center gap-2 mt-4 pt-4 border-t border-border",
143
+ className: "flex items-center gap-2 mt-4 pt-4 border-t border-border-subtle",
144
144
  children: [!e.isDefault && /* @__PURE__ */ f("button", {
145
145
  type: "button",
146
146
  className: "text-sm text-primary hover:underline",
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentMethodsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/PaymentMethodsPage.tsx"],"sourcesContent":["/**\n * Billing Module - Payment Methods Page\n * Displays and manages payment methods\n */\n\nimport { useCallback, useEffect, useState, type FC } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useDefaultDashboardAccount } from '../../dashboard/hooks';\nimport { AccessDenied, PageHeader, EmptyState } from '../../../shared/components';\nimport { AddPaymentMethodModal } from '../../dashboard/components/AddPaymentMethodModal';\nimport type { PaymentMethod, PaymentMethodType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst CARD_ICONS: Record<string, string> = {\n visa: '💳',\n mastercard: '💳',\n amex: '💳',\n default: '💳',\n};\n\nconst METHOD_TYPE_LABELS: Record<PaymentMethodType, string> = {\n CREDIT_CARD: 'Credit Card',\n DEBIT_CARD: 'Debit Card',\n WALLET: 'Digital Wallet',\n NETBANKING: 'Net Banking',\n BANK_TRANSFER: 'Bank Transfer',\n PAYPAL: 'PayPal',\n CRYPTO: 'Cryptocurrency',\n};\n\nexport const PaymentMethodsPage: 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 permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { navigate, basePath } = useBilling();\n const { pathname } = useLocation();\n const { billingAccount, paymentMethods, isLoading } = useDefaultDashboardAccount();\n const [showAddModal, setShowAddModal] = useState(false);\n\n // basePath-aware path join, mirroring OverviewPage's navigateTo helper.\n const toFullPath = useCallback(\n (path: string) => {\n if (basePath && basePath !== '/') {\n const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n return `${base}/${path}`;\n }\n return `/${path}`;\n },\n [basePath]\n );\n\n // Navigate (basePath-aware) to the dedicated add-payment-method route.\n const navigateToAdd = useCallback(() => {\n navigate(toFullPath('payment-methods/add'));\n }, [navigate, toFullPath]);\n\n // The /payment-methods/add route renders this same page; open the add modal\n // automatically when landing there so the route is actually functional.\n useEffect(() => {\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n setShowAddModal(true);\n }\n }, [pathname]);\n\n if (!permissions.canViewPaymentMethods) {\n return (\n <AccessDenied\n message={tr(\n 'billing.paymentMethods.noViewPermission',\n \"You don't have permission to view payment methods.\"\n )}\n />\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-muted animate-pulse rounded\" />\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-32 bg-muted animate-pulse rounded-lg\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.paymentMethods.title', 'Payment Methods')}\n description={tr('billing.paymentMethods.subtitle', 'Manage your saved payment methods')}\n actions={\n permissions.canManagePaymentMethods && (\n <button\n type=\"button\"\n onClick={navigateToAdd}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors\"\n >\n {tr('billing.paymentMethods.add', 'Add payment method')}\n </button>\n )\n }\n />\n\n {/* Payment Methods List */}\n {paymentMethods.length === 0 ? (\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-muted-foreground\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\"\n />\n </svg>\n }\n title={tr('billing.paymentMethods.noPaymentMethods', 'No payment methods')}\n description={tr(\n 'billing.paymentMethods.noPaymentMethodsDesc',\n 'Add a payment method to make purchases and manage subscriptions.'\n )}\n action={\n permissions.canManagePaymentMethods && (\n <button\n type=\"button\"\n onClick={() => setShowAddModal(true)}\n className=\"px-4 py-2 text-sm font-medium bg-primary text-primary-foreground rounded-md hover:bg-primary/90\"\n >\n Add Payment Method\n </button>\n )\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {paymentMethods.map((method) => (\n <PaymentMethodCard\n key={method.id}\n method={method}\n canManage={permissions.canManagePaymentMethods}\n />\n ))}\n </div>\n )}\n\n {/* Add Payment Method Modal (Stripe + Razorpay) */}\n <AddPaymentMethodModal\n isOpen={showAddModal}\n onClose={() => {\n setShowAddModal(false);\n // If we arrived via the /add route, return to the list URL.\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n navigate(toFullPath('payment-methods'));\n }\n }}\n billingAccountId={billingAccount?.id ?? ''}\n currency={billingAccount?.currency ?? 'USD'}\n country={billingAccount?.billingAddresses?.[0]?.country ?? undefined}\n onSuccess={() => {\n emit('billing.payment_method.added', {\n route: '/billing/payment-methods',\n entityId: billingAccount?.id,\n source: 'payment-methods',\n });\n // Refetch billing account to get updated payment methods\n setShowAddModal(false);\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n navigate(toFullPath('payment-methods'));\n }\n }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// Payment Method Card Component\n// ============================================================================\n\ninterface PaymentMethodCardProps {\n method: PaymentMethod;\n canManage: boolean;\n}\n\nconst PaymentMethodCard: FC<PaymentMethodCardProps> = ({ method, canManage }) => {\n const isExpired =\n method.expiryYear && method.expiryMonth\n ? new Date(method.expiryYear, method.expiryMonth - 1) < new Date()\n : false;\n\n return (\n <div\n className={`border rounded-lg bg-card p-4 ${\n method.isDefault ? 'border-primary' : 'border-border'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-2xl\">{CARD_ICONS[method.brand?.toLowerCase() ?? 'default']}</span>\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-foreground\">\n {method.brand ?? METHOD_TYPE_LABELS[method.type]} •••• {method.last4}\n </p>\n {method.isDefault && (\n <span className=\"px-1.5 py-0.5 text-xs font-medium bg-primary/10 text-primary rounded\">\n Default\n </span>\n )}\n </div>\n {method.expiryMonth && method.expiryYear && (\n <p\n className={`text-sm ${isExpired ? 'text-status-error-text' : 'text-muted-foreground'}`}\n >\n {isExpired ? 'Expired' : 'Expires'} {method.expiryMonth}/{method.expiryYear}\n </p>\n )}\n </div>\n </div>\n </div>\n\n {canManage && (\n <div className=\"flex items-center gap-2 mt-4 pt-4 border-t border-border\">\n {!method.isDefault && (\n <button type=\"button\" className=\"text-sm text-primary hover:underline\">\n Set as default\n </button>\n )}\n <button type=\"button\" className=\"text-sm text-status-error-text hover:underline ml-auto\">\n Remove\n </button>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PaymentMethodsPage.js","names":[],"sources":["../../../../../src/billing/modules/billing/pages/PaymentMethodsPage.tsx"],"sourcesContent":["/**\n * Billing Module - Payment Methods Page\n * Displays and manages payment methods\n */\n\nimport { useCallback, useEffect, useState, type FC } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useDefaultDashboardAccount } from '../../dashboard/hooks';\nimport { AccessDenied, PageHeader, EmptyState } from '../../../shared/components';\nimport { AddPaymentMethodModal } from '../../dashboard/components/AddPaymentMethodModal';\nimport type { PaymentMethod, PaymentMethodType } from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nconst CARD_ICONS: Record<string, string> = {\n visa: '💳',\n mastercard: '💳',\n amex: '💳',\n default: '💳',\n};\n\nconst METHOD_TYPE_LABELS: Record<PaymentMethodType, string> = {\n CREDIT_CARD: 'Credit Card',\n DEBIT_CARD: 'Debit Card',\n WALLET: 'Digital Wallet',\n NETBANKING: 'Net Banking',\n BANK_TRANSFER: 'Bank Transfer',\n PAYPAL: 'PayPal',\n CRYPTO: 'Cryptocurrency',\n};\n\nexport const PaymentMethodsPage: 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 permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { navigate, basePath } = useBilling();\n const { pathname } = useLocation();\n const { billingAccount, paymentMethods, isLoading } = useDefaultDashboardAccount();\n const [showAddModal, setShowAddModal] = useState(false);\n\n // basePath-aware path join, mirroring OverviewPage's navigateTo helper.\n const toFullPath = useCallback(\n (path: string) => {\n if (basePath && basePath !== '/') {\n const base = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n return `${base}/${path}`;\n }\n return `/${path}`;\n },\n [basePath]\n );\n\n // Navigate (basePath-aware) to the dedicated add-payment-method route.\n const navigateToAdd = useCallback(() => {\n navigate(toFullPath('payment-methods/add'));\n }, [navigate, toFullPath]);\n\n // The /payment-methods/add route renders this same page; open the add modal\n // automatically when landing there so the route is actually functional.\n useEffect(() => {\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n setShowAddModal(true);\n }\n }, [pathname]);\n\n if (!permissions.canViewPaymentMethods) {\n return (\n <AccessDenied\n message={tr(\n 'billing.paymentMethods.noViewPermission',\n \"You don't have permission to view payment methods.\"\n )}\n />\n );\n }\n\n if (isLoading) {\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"h-8 w-48 bg-bg-sunken animate-pulse rounded\" />\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-32 bg-bg-sunken animate-pulse rounded-lg\" />\n ))}\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.paymentMethods.title', 'Payment Methods')}\n description={tr('billing.paymentMethods.subtitle', 'Manage your saved payment methods')}\n actions={\n permissions.canManagePaymentMethods && (\n <button\n type=\"button\"\n onClick={navigateToAdd}\n className=\"px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 transition-colors\"\n >\n {tr('billing.paymentMethods.add', 'Add payment method')}\n </button>\n )\n }\n />\n\n {/* Payment Methods List */}\n {paymentMethods.length === 0 ? (\n <EmptyState\n icon={\n <svg\n className=\"size-6 text-text-secondary\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z\"\n />\n </svg>\n }\n title={tr('billing.paymentMethods.noPaymentMethods', 'No payment methods')}\n description={tr(\n 'billing.paymentMethods.noPaymentMethodsDesc',\n 'Add a payment method to make purchases and manage subscriptions.'\n )}\n action={\n permissions.canManagePaymentMethods && (\n <button\n type=\"button\"\n onClick={() => setShowAddModal(true)}\n className=\"px-4 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90\"\n >\n Add Payment Method\n </button>\n )\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {paymentMethods.map((method) => (\n <PaymentMethodCard\n key={method.id}\n method={method}\n canManage={permissions.canManagePaymentMethods}\n />\n ))}\n </div>\n )}\n\n {/* Add Payment Method Modal (Stripe + Razorpay) */}\n <AddPaymentMethodModal\n isOpen={showAddModal}\n onClose={() => {\n setShowAddModal(false);\n // If we arrived via the /add route, return to the list URL.\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n navigate(toFullPath('payment-methods'));\n }\n }}\n billingAccountId={billingAccount?.id ?? ''}\n currency={billingAccount?.currency ?? 'USD'}\n country={billingAccount?.billingAddresses?.[0]?.country ?? undefined}\n onSuccess={() => {\n emit('billing.payment_method.added', {\n route: '/billing/payment-methods',\n entityId: billingAccount?.id,\n source: 'payment-methods',\n });\n // Refetch billing account to get updated payment methods\n setShowAddModal(false);\n if (pathname.replace(/\\/+$/, '').endsWith('/payment-methods/add')) {\n navigate(toFullPath('payment-methods'));\n }\n }}\n />\n </div>\n );\n};\n\n// ============================================================================\n// Payment Method Card Component\n// ============================================================================\n\ninterface PaymentMethodCardProps {\n method: PaymentMethod;\n canManage: boolean;\n}\n\nconst PaymentMethodCard: FC<PaymentMethodCardProps> = ({ method, canManage }) => {\n const isExpired =\n method.expiryYear && method.expiryMonth\n ? new Date(method.expiryYear, method.expiryMonth - 1) < new Date()\n : false;\n\n return (\n <div\n className={`border rounded-lg bg-bg-surface p-4 ${\n method.isDefault ? 'border-primary' : 'border-border-subtle'\n }`}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3\">\n <span className=\"text-2xl\">{CARD_ICONS[method.brand?.toLowerCase() ?? 'default']}</span>\n <div>\n <div className=\"flex items-center gap-2\">\n <p className=\"font-medium text-text-primary\">\n {method.brand ?? METHOD_TYPE_LABELS[method.type]} •••• {method.last4}\n </p>\n {method.isDefault && (\n <span className=\"px-1.5 py-0.5 text-xs font-medium bg-action-primary-bg/10 text-primary rounded\">\n Default\n </span>\n )}\n </div>\n {method.expiryMonth && method.expiryYear && (\n <p\n className={`text-sm ${isExpired ? 'text-status-error-text' : 'text-text-secondary'}`}\n >\n {isExpired ? 'Expired' : 'Expires'} {method.expiryMonth}/{method.expiryYear}\n </p>\n )}\n </div>\n </div>\n </div>\n\n {canManage && (\n <div className=\"flex items-center gap-2 mt-4 pt-4 border-t border-border-subtle\">\n {!method.isDefault && (\n <button type=\"button\" className=\"text-sm text-primary hover:underline\">\n Set as default\n </button>\n )}\n <button type=\"button\" className=\"text-sm text-status-error-text hover:underline ml-auto\">\n Remove\n </button>\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}