@burdenoff/microfe-billing 2026.1013.2 → 2026.1013.4

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 (57) hide show
  1. package/dist/billing/modules/addons/pages/AddonCreatePage.js +4 -4
  2. package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
  3. package/dist/billing/modules/addons/pages/AddonEditPage.js +3 -3
  4. package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
  5. package/dist/billing/modules/analytics/pages/AnalyticsPage.js +1 -1
  6. package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
  7. package/dist/billing/modules/billing/pages/BillingWebhookLogsPage.js +3 -3
  8. package/dist/billing/modules/billing/pages/BillingWebhookLogsPage.js.map +1 -1
  9. package/dist/billing/modules/billing/pages/InvoicesListPage.js +1 -1
  10. package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
  11. package/dist/billing/modules/billing/pages/OrderCallbackLogsPage.js +2 -2
  12. package/dist/billing/modules/billing/pages/OrderCallbackLogsPage.js.map +1 -1
  13. package/dist/billing/modules/billing/pages/RefundsPage.js +2 -2
  14. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  15. package/dist/billing/modules/billing/pages/UserRefundsPage.js +1 -1
  16. package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
  17. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js +1 -1
  18. package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
  19. package/dist/billing/modules/checkout/components/StoreShippingSection.js +1 -1
  20. package/dist/billing/modules/checkout/components/StoreShippingSection.js.map +1 -1
  21. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js +1 -1
  22. package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
  23. package/dist/billing/modules/coupons/pages/CouponsListPage.js +2 -2
  24. package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
  25. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +2 -2
  26. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  27. package/dist/billing/modules/coupons/pages/EditCouponPage.js +1 -1
  28. package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
  29. package/dist/billing/modules/credits/pages/AdminCreditsPage.js +1 -1
  30. package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
  31. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +2 -2
  32. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
  33. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js +2 -2
  34. package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
  35. package/dist/billing/modules/discounts/pages/DiscountsListPage.js +2 -2
  36. package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
  37. package/dist/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.js +1 -1
  38. package/dist/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.js.map +1 -1
  39. package/dist/billing/modules/earnings/pages/EarningsPage.js +1 -1
  40. package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
  41. package/dist/billing/modules/earnings/pages/PayoutsPage.js +3 -3
  42. package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
  43. package/dist/billing/modules/plans/pages/PlanCreatePage.js +3 -3
  44. package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
  45. package/dist/billing/modules/plans/pages/PlanEditPage.js +3 -3
  46. package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
  47. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js +3 -3
  48. package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
  49. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js +2 -2
  50. package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
  51. package/dist/billing/modules/settings/pages/SettingsPage.js +1 -1
  52. package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
  53. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +1 -1
  54. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
  55. package/dist/billing/modules/usage/pages/UsagePage.js +1 -1
  56. package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
  57. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EarningsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/EarningsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { ArrowLeft, Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n EmphasisPanel,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n fetchEarningsEntries,\n fetchEarningsSummary,\n fetchDeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueSale,\n type DeveloperPortalRevenuePayout,\n type EarningsEntry,\n type EarningsSummary,\n} from '../api';\n\ntype EarningsSourceFilter = 'ALL' | 'AFFILIATE' | 'STORE' | 'OTHER';\n\nconst salesColumns: ResponsiveTableColumn<DeveloperPortalRevenueSale>[] = [\n {\n key: 'application',\n header: 'Application',\n priority: 'primary',\n cell: (sale) => sale.application?.name || sale.application?.slug || 'Unknown app',\n },\n { key: 'pricing', header: 'Pricing', cell: (sale) => sale.pricingModel },\n {\n key: 'gross',\n header: 'Gross',\n cell: (sale) => (\n <span className=\"tabular-nums\">\n {formatCurrency(sale.grossAmount, sale.currency || 'USD')}\n </span>\n ),\n },\n {\n key: 'net',\n header: 'Net',\n cell: (sale) => (\n <span className=\"tabular-nums\">{formatCurrency(sale.netAmount, sale.currency || 'USD')}</span>\n ),\n },\n { key: 'status', header: 'Status', cell: (sale) => sale.status },\n {\n key: 'purchased',\n header: 'Purchased',\n cell: (sale) => formatDateTime(sale.purchasedAt),\n },\n];\n\nconst payoutColumns: ResponsiveTableColumn<DeveloperPortalRevenuePayout>[] = [\n {\n key: 'period',\n header: 'Period',\n priority: 'primary',\n cell: (payout) => payout.periodLabel || '-',\n },\n {\n key: 'amount',\n header: 'Amount',\n cell: (payout) => (\n <span className=\"tabular-nums\">\n {formatCurrency(payout.netAmount, payout.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (payout) => payout.status },\n {\n key: 'scheduled',\n header: 'Scheduled',\n cell: (payout) => (payout.scheduledAt ? formatDateTime(payout.scheduledAt) : '-'),\n },\n {\n key: 'completed',\n header: 'Completed',\n cell: (payout) => (payout.completedAt ? formatDateTime(payout.completedAt) : '-'),\n },\n];\n\nconst ledgerColumns: ResponsiveTableColumn<EarningsEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n priority: 'primary',\n cell: (entry) => entry.sourceCategory,\n },\n {\n key: 'description',\n header: 'Description',\n cell: (entry) => entry.description || entry.sourceSubcategory || '-',\n },\n { key: 'unit', header: 'Unit', cell: (entry) => entry.unitType },\n {\n key: 'amount',\n header: 'Amount',\n cell: (entry) => (\n <span className=\"tabular-nums\">\n {entry.unitType === 'CREDITS'\n ? `${entry.amount.toLocaleString()} credits`\n : formatCurrency(entry.amount, entry.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (entry) => entry.status },\n {\n key: 'created',\n header: 'Created',\n cell: (entry) => formatDateTime(entry.createdAt),\n },\n];\n\nexport const EarningsPage: FC = () => {\n const [searchParams] = useSearchParams();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId, navigate } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\n // Set by devportal's OrganizationDetailPage when it links here — lets this\n // page offer a way back without needing to know whether the org is\n // PHYSICAL or DIGITAL (that split isn't in scope on this side).\n const returnTo = searchParams.get('returnTo');\n const { data: billingAccountData, loading: billingAccountLoading } =\n useGetDefaultBillingAccountSettingsQuery({});\n\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n const [summary, setSummary] = useState<EarningsSummary | null>(null);\n const [entries, setEntries] = useState<EarningsEntry[]>([]);\n const [developerPortalRevenue, setDeveloperPortalRevenue] =\n useState<DeveloperPortalRevenueDashboard | null>(null);\n const [sourceFilter, setSourceFilter] = useState<EarningsSourceFilter>('ALL');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n if (developerOrgId) {\n const loadedRevenue = await fetchDeveloperPortalRevenueDashboard(\n developerOrgId,\n requestContext\n );\n setDeveloperPortalRevenue(loadedRevenue);\n setSummary(null);\n setEntries([]);\n return;\n }\n\n if (!billingAccountId) {\n setSummary(null);\n setEntries([]);\n setDeveloperPortalRevenue(null);\n return;\n }\n\n const [loadedSummary, loadedEntries] = await Promise.all([\n fetchEarningsSummary(billingAccountId, requestContext),\n fetchEarningsEntries(billingAccountId, requestContext),\n ]);\n setSummary(loadedSummary);\n setEntries(loadedEntries);\n setDeveloperPortalRevenue(null);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load earnings'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, developerOrgId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view earnings.\" />;\n }\n\n if (!developerOrgId && !billingAccountId && !billingAccountLoading) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No billing account found\"\n description=\"Create a billing account first to view earnings.\"\n />\n );\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Earnings unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const cards = summary\n ? [\n {\n title: 'Available',\n value: formatCurrency(summary.availableAmount, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Reserved',\n value: formatCurrency(summary.reservedAmount, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Paid out',\n value: formatCurrency(summary.paidAmount, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Lifetime',\n value: formatCurrency(summary.totalLifetimeAmount, 'USD'),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const filteredEntries =\n sourceFilter === 'ALL'\n ? entries\n : entries.filter((entry) => entry.sourceCategory === sourceFilter);\n\n const categoryCards =\n summary?.categoryBreakdown?.map((item) => ({\n title: `${item.category} earnings`,\n value: formatCurrency(item.amount, 'USD'),\n helperText: `${item.count} entries`,\n })) ?? [];\n\n const developerPortalCards = developerPortalRevenue?.summary\n ? [\n {\n title: 'Gross revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalGrossRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalNetRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(\n developerPortalRevenue.summary.pendingBalance,\n developerPortalRevenue.summary.currency\n ),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(\n developerPortalRevenue.summary.totalPlatformFees,\n developerPortalRevenue.summary.currency\n ),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const isDeveloperPortalMode = !!developerOrgId;\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={isDeveloperPortalMode ? 'Marketplace earnings' : 'Earnings'}\n description={\n isDeveloperPortalMode\n ? `Developer portal revenue, sales, and payouts${developerOrgName ? ` for ${developerOrgName}` : ''}.`\n : 'Track affiliate, store, and other earning sources in one ledger.'\n }\n actions={\n returnTo ? (\n <button\n type=\"button\"\n onClick={() => navigate?.(returnTo)}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n ) : undefined\n }\n />\n\n <PagePurpose>\n See everything you have earned — from affiliate rewards, store sales and marketplace revenue\n — in one ledger, along with how much has been paid out and what is still pending. Filter by\n source to reconcile a specific stream.\n </PagePurpose>\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : isDeveloperPortalMode ? (\n developerPortalRevenue?.summary ? (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {developerPortalCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent sales</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n\n {developerPortalRevenue.sales.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sales yet\"\n description=\"Sales will appear here when customers start purchasing your apps.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.sales}\n rowKey={(sale) => sale.id}\n columns={salesColumns}\n />\n )}\n </section>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payouts</h2>\n\n {developerPortalRevenue.payouts.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payouts yet\"\n description=\"Scheduled and completed payouts will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.payouts}\n rowKey={(payout) => payout.id}\n columns={payoutColumns}\n />\n )}\n </section>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No developer portal revenue yet\"\n description=\"Marketplace revenue will appear here once your developer organization records sales.\"\n />\n )\n ) : summary ? (\n <div className=\"space-y-4\">\n <EmphasisPanel className=\"p-4 sm:p-5\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {cards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n </EmphasisPanel>\n {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div\n key={card.title}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <p className=\"text-sm text-text-secondary\">{card.title}</p>\n <p className=\"mt-2 text-xl font-semibold text-text-primary\">{card.value}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{card.helperText}</p>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ledger</h2>\n <div className=\"flex items-center gap-3\">\n <select\n value={sourceFilter}\n onChange={(event) => setSourceFilter(event.target.value as EarningsSourceFilter)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"ALL\">All sources</option>\n <option value=\"AFFILIATE\">Affiliate</option>\n <option value=\"STORE\">Store</option>\n <option value=\"OTHER\">Other</option>\n </select>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n </div>\n\n {filteredEntries.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No earnings yet\"\n description=\"Eligible affiliate rewards and other earnings will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={filteredEntries}\n rowKey={(entry) => entry.id}\n columns={ledgerColumns}\n />\n )}\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"EarningsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/EarningsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { ArrowLeft, Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n EmphasisPanel,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n fetchEarningsEntries,\n fetchEarningsSummary,\n fetchDeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueSale,\n type DeveloperPortalRevenuePayout,\n type EarningsEntry,\n type EarningsSummary,\n} from '../api';\n\ntype EarningsSourceFilter = 'ALL' | 'AFFILIATE' | 'STORE' | 'OTHER';\n\nconst salesColumns: ResponsiveTableColumn<DeveloperPortalRevenueSale>[] = [\n {\n key: 'application',\n header: 'Application',\n priority: 'primary',\n cell: (sale) => sale.application?.name || sale.application?.slug || 'Unknown app',\n },\n { key: 'pricing', header: 'Pricing', cell: (sale) => sale.pricingModel },\n {\n key: 'gross',\n header: 'Gross',\n cell: (sale) => (\n <span className=\"tabular-nums\">\n {formatCurrency(sale.grossAmount, sale.currency || 'USD')}\n </span>\n ),\n },\n {\n key: 'net',\n header: 'Net',\n cell: (sale) => (\n <span className=\"tabular-nums\">{formatCurrency(sale.netAmount, sale.currency || 'USD')}</span>\n ),\n },\n { key: 'status', header: 'Status', cell: (sale) => sale.status },\n {\n key: 'purchased',\n header: 'Purchased',\n cell: (sale) => formatDateTime(sale.purchasedAt),\n },\n];\n\nconst payoutColumns: ResponsiveTableColumn<DeveloperPortalRevenuePayout>[] = [\n {\n key: 'period',\n header: 'Period',\n priority: 'primary',\n cell: (payout) => payout.periodLabel || '-',\n },\n {\n key: 'amount',\n header: 'Amount',\n cell: (payout) => (\n <span className=\"tabular-nums\">\n {formatCurrency(payout.netAmount, payout.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (payout) => payout.status },\n {\n key: 'scheduled',\n header: 'Scheduled',\n cell: (payout) => (payout.scheduledAt ? formatDateTime(payout.scheduledAt) : '-'),\n },\n {\n key: 'completed',\n header: 'Completed',\n cell: (payout) => (payout.completedAt ? formatDateTime(payout.completedAt) : '-'),\n },\n];\n\nconst ledgerColumns: ResponsiveTableColumn<EarningsEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n priority: 'primary',\n cell: (entry) => entry.sourceCategory,\n },\n {\n key: 'description',\n header: 'Description',\n cell: (entry) => entry.description || entry.sourceSubcategory || '-',\n },\n { key: 'unit', header: 'Unit', cell: (entry) => entry.unitType },\n {\n key: 'amount',\n header: 'Amount',\n cell: (entry) => (\n <span className=\"tabular-nums\">\n {entry.unitType === 'CREDITS'\n ? `${entry.amount.toLocaleString()} credits`\n : formatCurrency(entry.amount, entry.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (entry) => entry.status },\n {\n key: 'created',\n header: 'Created',\n cell: (entry) => formatDateTime(entry.createdAt),\n },\n];\n\nexport const EarningsPage: FC = () => {\n const [searchParams] = useSearchParams();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId, navigate } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\n // Set by devportal's OrganizationDetailPage when it links here — lets this\n // page offer a way back without needing to know whether the org is\n // PHYSICAL or DIGITAL (that split isn't in scope on this side).\n const returnTo = searchParams.get('returnTo');\n const { data: billingAccountData, loading: billingAccountLoading } =\n useGetDefaultBillingAccountSettingsQuery({});\n\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n const [summary, setSummary] = useState<EarningsSummary | null>(null);\n const [entries, setEntries] = useState<EarningsEntry[]>([]);\n const [developerPortalRevenue, setDeveloperPortalRevenue] =\n useState<DeveloperPortalRevenueDashboard | null>(null);\n const [sourceFilter, setSourceFilter] = useState<EarningsSourceFilter>('ALL');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n if (developerOrgId) {\n const loadedRevenue = await fetchDeveloperPortalRevenueDashboard(\n developerOrgId,\n requestContext\n );\n setDeveloperPortalRevenue(loadedRevenue);\n setSummary(null);\n setEntries([]);\n return;\n }\n\n if (!billingAccountId) {\n setSummary(null);\n setEntries([]);\n setDeveloperPortalRevenue(null);\n return;\n }\n\n const [loadedSummary, loadedEntries] = await Promise.all([\n fetchEarningsSummary(billingAccountId, requestContext),\n fetchEarningsEntries(billingAccountId, requestContext),\n ]);\n setSummary(loadedSummary);\n setEntries(loadedEntries);\n setDeveloperPortalRevenue(null);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load earnings'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, developerOrgId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view earnings.\" />;\n }\n\n if (!developerOrgId && !billingAccountId && !billingAccountLoading) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No billing account found\"\n description=\"Create a billing account first to view earnings.\"\n />\n );\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Earnings unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const cards = summary\n ? [\n {\n title: 'Available',\n value: formatCurrency(summary.availableAmount, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Reserved',\n value: formatCurrency(summary.reservedAmount, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Paid out',\n value: formatCurrency(summary.paidAmount, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Lifetime',\n value: formatCurrency(summary.totalLifetimeAmount, 'USD'),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const filteredEntries =\n sourceFilter === 'ALL'\n ? entries\n : entries.filter((entry) => entry.sourceCategory === sourceFilter);\n\n const categoryCards =\n summary?.categoryBreakdown?.map((item) => ({\n title: `${item.category} earnings`,\n value: formatCurrency(item.amount, 'USD'),\n helperText: `${item.count} entries`,\n })) ?? [];\n\n const developerPortalCards = developerPortalRevenue?.summary\n ? [\n {\n title: 'Gross revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalGrossRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalNetRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(\n developerPortalRevenue.summary.pendingBalance,\n developerPortalRevenue.summary.currency\n ),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(\n developerPortalRevenue.summary.totalPlatformFees,\n developerPortalRevenue.summary.currency\n ),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const isDeveloperPortalMode = !!developerOrgId;\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={isDeveloperPortalMode ? 'Marketplace earnings' : 'Earnings'}\n description={\n isDeveloperPortalMode\n ? `Developer portal revenue, sales, and payouts${developerOrgName ? ` for ${developerOrgName}` : ''}.`\n : 'Track affiliate, store, and other earning sources in one ledger.'\n }\n actions={\n returnTo ? (\n <button\n type=\"button\"\n onClick={() => navigate?.(returnTo)}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back\n </button>\n ) : undefined\n }\n />\n\n <PagePurpose>\n See everything you have earned — from affiliate rewards, store sales and marketplace revenue\n — in one ledger, along with how much has been paid out and what is still pending. Filter by\n source to reconcile a specific stream.\n </PagePurpose>\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : isDeveloperPortalMode ? (\n developerPortalRevenue?.summary ? (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {developerPortalCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent sales</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n\n {developerPortalRevenue.sales.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sales yet\"\n description=\"Sales will appear here when customers start purchasing your apps.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.sales}\n rowKey={(sale) => sale.id}\n columns={salesColumns}\n />\n )}\n </section>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payouts</h2>\n\n {developerPortalRevenue.payouts.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payouts yet\"\n description=\"Scheduled and completed payouts will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.payouts}\n rowKey={(payout) => payout.id}\n columns={payoutColumns}\n />\n )}\n </section>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No developer portal revenue yet\"\n description=\"Marketplace revenue will appear here once your developer organization records sales.\"\n />\n )\n ) : summary ? (\n <div className=\"space-y-4\">\n <EmphasisPanel className=\"p-4 sm:p-5\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {cards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n </EmphasisPanel>\n {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div\n key={card.title}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <p className=\"text-sm text-text-secondary\">{card.title}</p>\n <p className=\"mt-2 text-xl font-semibold text-text-primary\">{card.value}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{card.helperText}</p>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ledger</h2>\n <div className=\"flex items-center gap-3\">\n <select\n value={sourceFilter}\n onChange={(event) => setSourceFilter(event.target.value as EarningsSourceFilter)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"ALL\">All sources</option>\n <option value=\"AFFILIATE\">Affiliate</option>\n <option value=\"STORE\">Store</option>\n <option value=\"OTHER\">Other</option>\n </select>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n </div>\n\n {filteredEntries.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No earnings yet\"\n description=\"Eligible affiliate rewards and other earnings will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={filteredEntries}\n rowKey={(entry) => entry.id}\n columns={ledgerColumns}\n />\n )}\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -193,7 +193,7 @@ var O = [
193
193
  ...t,
194
194
  type: e.target.value
195
195
  })),
196
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
196
+ className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
197
197
  children: [
198
198
  /* @__PURE__ */ y("option", {
199
199
  value: "BANK_ACCOUNT",
@@ -214,7 +214,7 @@ var O = [
214
214
  ...t,
215
215
  providerPreference: e.target.value
216
216
  })),
217
- className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
217
+ className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
218
218
  children: [
219
219
  /* @__PURE__ */ y("option", {
220
220
  value: "AUTO",
@@ -360,7 +360,7 @@ var O = [
360
360
  /* @__PURE__ */ y("select", {
361
361
  value: K,
362
362
  onChange: (e) => q(e.target.value),
363
- className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
363
+ className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
364
364
  children: P.map((e) => /* @__PURE__ */ b("option", {
365
365
  value: e.id,
366
366
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"PayoutsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/PayoutsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { Landmark, RefreshCw, Send } from 'lucide-react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError } from '../../../shared/components';\nimport { PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n addPayoutAccount,\n archivePayoutAccount,\n fetchPayoutAccounts,\n fetchPayoutRequests,\n requestPayout,\n setDefaultPayoutAccount,\n updatePayoutAccount,\n type PayoutAccount,\n type PayoutRequest,\n} from '../api';\n\nconst payoutRequestColumns: ResponsiveTableColumn<PayoutRequest>[] = [\n {\n key: 'amount',\n header: 'Amount',\n priority: 'primary',\n cell: (request) => (\n <span className=\"tabular-nums\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </span>\n ),\n },\n { key: 'provider', header: 'Provider', cell: (request) => request.provider },\n { key: 'status', header: 'Status', cell: (request) => request.status },\n {\n key: 'account',\n header: 'Account',\n cell: (request) => request.payoutAccount?.label || '-',\n },\n {\n key: 'created',\n header: 'Created',\n cell: (request) => formatDateTime(request.createdAt),\n },\n];\n\nexport const PayoutsPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const { data: billingAccountData } = useGetDefaultBillingAccountSettingsQuery({});\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n\n const [accounts, setAccounts] = useState<PayoutAccount[]>([]);\n const [requests, setRequests] = useState<PayoutRequest[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [accountForm, setAccountForm] = useState({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n const [requestAmount, setRequestAmount] = useState('');\n const [selectedAccountId, setSelectedAccountId] = useState<string>('');\n const [editingAccountId, setEditingAccountId] = useState<string | null>(null);\n const [archiveAccountId, setArchiveAccountId] = useState<string | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n if (!billingAccountId) return;\n setLoading(true);\n setError(null);\n try {\n const [loadedAccounts, loadedRequests] = await Promise.all([\n fetchPayoutAccounts(billingAccountId, requestContext),\n fetchPayoutRequests(billingAccountId, requestContext),\n ]);\n setAccounts(loadedAccounts);\n setRequests(loadedRequests);\n setSelectedAccountId((current) => current ?? loadedAccounts[0]?.id);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load payout data'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canManagePaymentMethods) {\n return <AccessDenied message=\"You don't have permission to manage payout accounts.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Payout data unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const handleAddAccount = async () => {\n if (!billingAccountId) return;\n const payload = {\n billingAccountId,\n ...accountForm,\n };\n\n if (editingAccountId) {\n await updatePayoutAccount(editingAccountId, payload, requestContext);\n emit('billing.payout_account.updated', {\n route: '/billing/payouts',\n entityId: editingAccountId,\n source: 'payouts',\n });\n } else {\n await addPayoutAccount(payload, requestContext);\n emit('billing.payout_account.added', {\n route: '/billing/payouts',\n entityId: billingAccountId,\n source: 'payouts',\n });\n }\n\n setAccountForm({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n setEditingAccountId(null);\n await loadData();\n };\n\n const handleSetDefault = async (accountId: string) => {\n await setDefaultPayoutAccount(accountId, requestContext);\n await loadData();\n };\n\n const handleArchive = async (accountId: string) => {\n await archivePayoutAccount(accountId, requestContext);\n emit('billing.payout_account.archived', {\n route: '/billing/payouts',\n entityId: accountId,\n source: 'payouts',\n });\n await loadData();\n };\n\n const handleEditAccount = (account: PayoutAccount) => {\n setEditingAccountId(account.id);\n setAccountForm((current) => ({\n ...current,\n label: account.label,\n type: account.type,\n providerPreference: account.providerPreference,\n country: account.country || current.country,\n currency: account.currency,\n accountHolderName: account.displayName || current.accountHolderName,\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n }));\n };\n\n const handleRequestPayout = async () => {\n if (!billingAccountId || !selectedAccountId || !requestAmount) return;\n await requestPayout(\n {\n billingAccountId,\n payoutAccountId: selectedAccountId,\n amount: Number(requestAmount),\n currency: accounts.find((account) => account.id === selectedAccountId)?.currency || 'USD',\n },\n requestContext\n );\n emit('billing.payout.requested', {\n route: '/billing/payouts',\n entityId: selectedAccountId,\n source: 'payouts',\n amount: Number(requestAmount),\n currency: accounts.find((account) => account.id === selectedAccountId)?.currency || 'USD',\n });\n setRequestAmount('');\n await loadData();\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Payouts\"\n description=\"Register payout accounts, request withdrawals, and track disbursement status.\"\n />\n\n <PagePurpose>\n Get your earnings paid out to a real bank account or UPI. Register where you want to be\n paid, request a withdrawal of your available balance, and track each request from submission\n through to disbursement here.\n </PagePurpose>\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <div className=\"grid gap-6 xl:grid-cols-[1.05fr,1.95fr]\">\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {editingAccountId ? 'Edit payout account' : 'Add payout account'}\n </h2>\n <div className=\"space-y-3\">\n <input\n value={accountForm.label}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, label: event.target.value }))\n }\n placeholder=\"Label\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <div className=\"grid gap-3 md:grid-cols-2\">\n <select\n value={accountForm.type}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, type: event.target.value }))\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"BANK_ACCOUNT\">Bank account</option>\n <option value=\"UPI\">UPI</option>\n <option value=\"WALLET\">Wallet</option>\n </select>\n <select\n value={accountForm.providerPreference}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n providerPreference: event.target.value,\n }))\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"AUTO\">Auto</option>\n <option value=\"STRIPE\">Stripe</option>\n <option value=\"RAZORPAY\">Razorpay</option>\n <option value=\"MANUAL\">Manual</option>\n </select>\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <input\n value={accountForm.country}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n country: event.target.value.toUpperCase(),\n }))\n }\n placeholder=\"Country\"\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={accountForm.currency}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n currency: event.target.value.toUpperCase(),\n }))\n }\n placeholder=\"Currency\"\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <input\n value={accountForm.accountHolderName}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, accountHolderName: event.target.value }))\n }\n placeholder=\"Account holder name\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n {accountForm.type === 'BANK_ACCOUNT' ? (\n <>\n <input\n value={accountForm.bankName}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, bankName: event.target.value }))\n }\n placeholder=\"Bank name\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={accountForm.accountNumber}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, accountNumber: event.target.value }))\n }\n placeholder=\"Account number\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={\n accountForm.country === 'IN' ? accountForm.ifsc : accountForm.routingNumber\n }\n onChange={(event) =>\n setAccountForm((current) =>\n current.country === 'IN'\n ? { ...current, ifsc: event.target.value }\n : { ...current, routingNumber: event.target.value }\n )\n }\n placeholder={accountForm.country === 'IN' ? 'IFSC' : 'Routing number'}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </>\n ) : accountForm.type === 'UPI' ? (\n <input\n value={accountForm.upiId}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, upiId: event.target.value }))\n }\n placeholder=\"UPI ID\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n ) : null}\n </div>\n <button\n type=\"button\"\n onClick={() => void handleAddAccount()}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Landmark className=\"size-4\" />\n {editingAccountId ? 'Update payout account' : 'Save payout account'}\n </button>\n {editingAccountId ? (\n <button\n type=\"button\"\n onClick={() => {\n setEditingAccountId(null);\n setAccountForm({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n }}\n className=\"mt-4 ml-3 inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n Cancel edit\n </button>\n ) : null}\n </section>\n\n <section className=\"space-y-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Request payout</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n {accounts.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No payout accounts yet\"\n description=\"Add a payout account before requesting a withdrawal.\"\n />\n ) : (\n <div className=\"space-y-3\">\n <select\n value={selectedAccountId}\n onChange={(event) => setSelectedAccountId(event.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {accounts.map((account) => (\n <option key={account.id} value={account.id}>\n {account.label} · {account.currency} · {account.status}\n </option>\n ))}\n </select>\n <input\n value={requestAmount}\n onChange={(event) => setRequestAmount(event.target.value)}\n placeholder=\"Amount\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <button\n type=\"button\"\n onClick={() => void handleRequestPayout()}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Send className=\"size-4\" />\n Request payout\n </button>\n </div>\n )}\n\n {accounts.length > 0 ? (\n <div className=\"mt-4 space-y-3 rounded-md border border-border-subtle bg-bg-surface/60 p-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Saved payout accounts</h3>\n {accounts.map((account) => (\n <div\n key={account.id}\n className=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-border-subtle/70 bg-bg-surface px-3 py-2 text-sm\"\n >\n <div>\n <p className=\"font-medium text-text-primary\">\n {account.label} {account.isDefault ? '• Default' : ''}\n </p>\n <p className=\"text-text-secondary\">\n {account.providerPreference} · {account.currency} · {account.status}\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleEditAccount(account)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Edit\n </button>\n {!account.isDefault ? (\n <button\n type=\"button\"\n onClick={() => void handleSetDefault(account.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Make default\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => setArchiveAccountId(account.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n Archive\n </button>\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payout requests</h2>\n {requests.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payout requests yet\"\n description=\"Your payout requests and processing updates will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={requests}\n rowKey={(request) => request.id}\n columns={payoutRequestColumns}\n />\n )}\n </div>\n </section>\n </div>\n\n <AlertDialog\n open={archiveAccountId !== null}\n onOpenChange={(open) => {\n if (!open) setArchiveAccountId(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Archive payout account?</AlertDialogTitle>\n <AlertDialogDescription>\n Archive this payout account? You can add a new one at any time.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() => {\n const id = archiveAccountId;\n setArchiveAccountId(null);\n if (id) void handleArchive(id);\n }}\n >\n Archive\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PayoutsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/PayoutsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { Landmark, RefreshCw, Send } from 'lucide-react';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n ResponsiveTable,\n type ResponsiveTableColumn,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError } from '../../../shared/components';\nimport { PagePurpose, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n addPayoutAccount,\n archivePayoutAccount,\n fetchPayoutAccounts,\n fetchPayoutRequests,\n requestPayout,\n setDefaultPayoutAccount,\n updatePayoutAccount,\n type PayoutAccount,\n type PayoutRequest,\n} from '../api';\n\nconst payoutRequestColumns: ResponsiveTableColumn<PayoutRequest>[] = [\n {\n key: 'amount',\n header: 'Amount',\n priority: 'primary',\n cell: (request) => (\n <span className=\"tabular-nums\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </span>\n ),\n },\n { key: 'provider', header: 'Provider', cell: (request) => request.provider },\n { key: 'status', header: 'Status', cell: (request) => request.status },\n {\n key: 'account',\n header: 'Account',\n cell: (request) => request.payoutAccount?.label || '-',\n },\n {\n key: 'created',\n header: 'Created',\n cell: (request) => formatDateTime(request.createdAt),\n },\n];\n\nexport const PayoutsPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const { data: billingAccountData } = useGetDefaultBillingAccountSettingsQuery({});\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n\n const [accounts, setAccounts] = useState<PayoutAccount[]>([]);\n const [requests, setRequests] = useState<PayoutRequest[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [accountForm, setAccountForm] = useState({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n const [requestAmount, setRequestAmount] = useState('');\n const [selectedAccountId, setSelectedAccountId] = useState<string>('');\n const [editingAccountId, setEditingAccountId] = useState<string | null>(null);\n const [archiveAccountId, setArchiveAccountId] = useState<string | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n if (!billingAccountId) return;\n setLoading(true);\n setError(null);\n try {\n const [loadedAccounts, loadedRequests] = await Promise.all([\n fetchPayoutAccounts(billingAccountId, requestContext),\n fetchPayoutRequests(billingAccountId, requestContext),\n ]);\n setAccounts(loadedAccounts);\n setRequests(loadedRequests);\n setSelectedAccountId((current) => current ?? loadedAccounts[0]?.id);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load payout data'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canManagePaymentMethods) {\n return <AccessDenied message=\"You don't have permission to manage payout accounts.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Payout data unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const handleAddAccount = async () => {\n if (!billingAccountId) return;\n const payload = {\n billingAccountId,\n ...accountForm,\n };\n\n if (editingAccountId) {\n await updatePayoutAccount(editingAccountId, payload, requestContext);\n emit('billing.payout_account.updated', {\n route: '/billing/payouts',\n entityId: editingAccountId,\n source: 'payouts',\n });\n } else {\n await addPayoutAccount(payload, requestContext);\n emit('billing.payout_account.added', {\n route: '/billing/payouts',\n entityId: billingAccountId,\n source: 'payouts',\n });\n }\n\n setAccountForm({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n setEditingAccountId(null);\n await loadData();\n };\n\n const handleSetDefault = async (accountId: string) => {\n await setDefaultPayoutAccount(accountId, requestContext);\n await loadData();\n };\n\n const handleArchive = async (accountId: string) => {\n await archivePayoutAccount(accountId, requestContext);\n emit('billing.payout_account.archived', {\n route: '/billing/payouts',\n entityId: accountId,\n source: 'payouts',\n });\n await loadData();\n };\n\n const handleEditAccount = (account: PayoutAccount) => {\n setEditingAccountId(account.id);\n setAccountForm((current) => ({\n ...current,\n label: account.label,\n type: account.type,\n providerPreference: account.providerPreference,\n country: account.country || current.country,\n currency: account.currency,\n accountHolderName: account.displayName || current.accountHolderName,\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n }));\n };\n\n const handleRequestPayout = async () => {\n if (!billingAccountId || !selectedAccountId || !requestAmount) return;\n await requestPayout(\n {\n billingAccountId,\n payoutAccountId: selectedAccountId,\n amount: Number(requestAmount),\n currency: accounts.find((account) => account.id === selectedAccountId)?.currency || 'USD',\n },\n requestContext\n );\n emit('billing.payout.requested', {\n route: '/billing/payouts',\n entityId: selectedAccountId,\n source: 'payouts',\n amount: Number(requestAmount),\n currency: accounts.find((account) => account.id === selectedAccountId)?.currency || 'USD',\n });\n setRequestAmount('');\n await loadData();\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Payouts\"\n description=\"Register payout accounts, request withdrawals, and track disbursement status.\"\n />\n\n <PagePurpose>\n Get your earnings paid out to a real bank account or UPI. Register where you want to be\n paid, request a withdrawal of your available balance, and track each request from submission\n through to disbursement here.\n </PagePurpose>\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <div className=\"grid gap-6 xl:grid-cols-[1.05fr,1.95fr]\">\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {editingAccountId ? 'Edit payout account' : 'Add payout account'}\n </h2>\n <div className=\"space-y-3\">\n <input\n value={accountForm.label}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, label: event.target.value }))\n }\n placeholder=\"Label\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <div className=\"grid gap-3 md:grid-cols-2\">\n <select\n value={accountForm.type}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, type: event.target.value }))\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"BANK_ACCOUNT\">Bank account</option>\n <option value=\"UPI\">UPI</option>\n <option value=\"WALLET\">Wallet</option>\n </select>\n <select\n value={accountForm.providerPreference}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n providerPreference: event.target.value,\n }))\n }\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"AUTO\">Auto</option>\n <option value=\"STRIPE\">Stripe</option>\n <option value=\"RAZORPAY\">Razorpay</option>\n <option value=\"MANUAL\">Manual</option>\n </select>\n </div>\n <div className=\"grid gap-3 md:grid-cols-2\">\n <input\n value={accountForm.country}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n country: event.target.value.toUpperCase(),\n }))\n }\n placeholder=\"Country\"\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={accountForm.currency}\n onChange={(event) =>\n setAccountForm((current) => ({\n ...current,\n currency: event.target.value.toUpperCase(),\n }))\n }\n placeholder=\"Currency\"\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <input\n value={accountForm.accountHolderName}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, accountHolderName: event.target.value }))\n }\n placeholder=\"Account holder name\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n {accountForm.type === 'BANK_ACCOUNT' ? (\n <>\n <input\n value={accountForm.bankName}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, bankName: event.target.value }))\n }\n placeholder=\"Bank name\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={accountForm.accountNumber}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, accountNumber: event.target.value }))\n }\n placeholder=\"Account number\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <input\n value={\n accountForm.country === 'IN' ? accountForm.ifsc : accountForm.routingNumber\n }\n onChange={(event) =>\n setAccountForm((current) =>\n current.country === 'IN'\n ? { ...current, ifsc: event.target.value }\n : { ...current, routingNumber: event.target.value }\n )\n }\n placeholder={accountForm.country === 'IN' ? 'IFSC' : 'Routing number'}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </>\n ) : accountForm.type === 'UPI' ? (\n <input\n value={accountForm.upiId}\n onChange={(event) =>\n setAccountForm((current) => ({ ...current, upiId: event.target.value }))\n }\n placeholder=\"UPI ID\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n ) : null}\n </div>\n <button\n type=\"button\"\n onClick={() => void handleAddAccount()}\n className=\"mt-4 inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Landmark className=\"size-4\" />\n {editingAccountId ? 'Update payout account' : 'Save payout account'}\n </button>\n {editingAccountId ? (\n <button\n type=\"button\"\n onClick={() => {\n setEditingAccountId(null);\n setAccountForm({\n label: '',\n type: 'BANK_ACCOUNT',\n providerPreference: 'AUTO',\n country: 'US',\n currency: 'USD',\n accountHolderName: '',\n bankName: '',\n accountNumber: '',\n routingNumber: '',\n ifsc: '',\n upiId: '',\n });\n }}\n className=\"mt-4 ml-3 inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n Cancel edit\n </button>\n ) : null}\n </section>\n\n <section className=\"space-y-4\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Request payout</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n {accounts.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No payout accounts yet\"\n description=\"Add a payout account before requesting a withdrawal.\"\n />\n ) : (\n <div className=\"space-y-3\">\n <select\n value={selectedAccountId}\n onChange={(event) => setSelectedAccountId(event.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n {accounts.map((account) => (\n <option key={account.id} value={account.id}>\n {account.label} · {account.currency} · {account.status}\n </option>\n ))}\n </select>\n <input\n value={requestAmount}\n onChange={(event) => setRequestAmount(event.target.value)}\n placeholder=\"Amount\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n <button\n type=\"button\"\n onClick={() => void handleRequestPayout()}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text\"\n >\n <Send className=\"size-4\" />\n Request payout\n </button>\n </div>\n )}\n\n {accounts.length > 0 ? (\n <div className=\"mt-4 space-y-3 rounded-md border border-border-subtle bg-bg-surface/60 p-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Saved payout accounts</h3>\n {accounts.map((account) => (\n <div\n key={account.id}\n className=\"flex flex-wrap items-center justify-between gap-3 rounded-md border border-border-subtle/70 bg-bg-surface px-3 py-2 text-sm\"\n >\n <div>\n <p className=\"font-medium text-text-primary\">\n {account.label} {account.isDefault ? '• Default' : ''}\n </p>\n <p className=\"text-text-secondary\">\n {account.providerPreference} · {account.currency} · {account.status}\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n onClick={() => handleEditAccount(account)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Edit\n </button>\n {!account.isDefault ? (\n <button\n type=\"button\"\n onClick={() => void handleSetDefault(account.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary\"\n >\n Make default\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => setArchiveAccountId(account.id)}\n className=\"rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n Archive\n </button>\n </div>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payout requests</h2>\n {requests.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payout requests yet\"\n description=\"Your payout requests and processing updates will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={requests}\n rowKey={(request) => request.id}\n columns={payoutRequestColumns}\n />\n )}\n </div>\n </section>\n </div>\n\n <AlertDialog\n open={archiveAccountId !== null}\n onOpenChange={(open) => {\n if (!open) setArchiveAccountId(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Archive payout account?</AlertDialogTitle>\n <AlertDialogDescription>\n Archive this payout account? You can add a new one at any time.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() => {\n const id = archiveAccountId;\n setArchiveAccountId(null);\n if (id) void handleArchive(id);\n }}\n >\n Archive\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -178,7 +178,7 @@ var m = () => {
178
178
  id: "currency",
179
179
  value: E,
180
180
  onChange: (e) => D(e.target.value),
181
- className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
181
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
182
182
  children: [
183
183
  /* @__PURE__ */ u("option", {
184
184
  value: "USD",
@@ -223,7 +223,7 @@ var m = () => {
223
223
  id: "duration",
224
224
  value: O,
225
225
  onChange: (e) => k(e.target.value),
226
- className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
226
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
227
227
  children: [/* @__PURE__ */ u("option", {
228
228
  value: r.MONTHLY,
229
229
  children: "Monthly"
@@ -282,7 +282,7 @@ var m = () => {
282
282
  children: [/* @__PURE__ */ d("select", {
283
283
  value: e.quotaId,
284
284
  onChange: (e) => W(t, "quotaId", e.target.value),
285
- className: `flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${e.quotaId === "" ? "text-text-muted" : "text-text-primary"}`,
285
+ className: `flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${e.quotaId === "" ? "text-text-muted" : "text-text-primary"}`,
286
286
  children: [/* @__PURE__ */ u("option", {
287
287
  value: "",
288
288
  disabled: !0,
@@ -1 +1 @@
1
- {"version":3,"file":"PlanCreatePage.js","names":[],"sources":["../../../../../src/billing/modules/plans/pages/PlanCreatePage.tsx"],"sourcesContent":["/**\n * Plans Module - Plan Create Page\n * Form to create a new plan\n */\n\nimport { useState, type FC, type FormEvent } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePlanMutations, useQuotas } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, CurrencyPriceOverridesEditor, PageHeader } from '../../../shared/components';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n PlanDuration,\n type CreatePlanInput,\n type CurrencyPriceOverrideInput,\n} from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface QuotaAllocation {\n quotaId: string;\n quantity: number;\n}\n\nexport const PlanCreatePage: 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 { quotas, isLoading: isQuotasLoading } = useQuotas({ onlyActive: true });\n const { createPlan, isCreating } = usePlanMutations();\n\n // Form state\n const [name, setName] = useState('');\n const [price, setPrice] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [duration, setDuration] = useState<PlanDuration>(PlanDuration.MONTHLY);\n const [productId, setProductId] = useState('');\n const [isPurchasable, setIsPurchasable] = useState(true);\n const [quotaAllocations, setQuotaAllocations] = useState<QuotaAllocation[]>([]);\n const [currencyPriceOverrides, setCurrencyPriceOverrides] = useState<\n CurrencyPriceOverrideInput[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n\n // Permission check\n if (!permissions.canManagePlans) {\n return (\n <AccessDenied\n message={tr(\n 'billing.plans.noCreatePermission',\n \"You don't have permission to create plans.\"\n )}\n />\n );\n }\n\n // Loading state\n if (isQuotasLoading) {\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=\"max-w-2xl space-y-4\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n const handleAddQuota = () => {\n // Add new quota at the top with empty quotaId (placeholder)\n setQuotaAllocations([{ quotaId: '', quantity: 1 }, ...quotaAllocations]);\n };\n\n const handleRemoveQuota = (index: number) => {\n setQuotaAllocations(quotaAllocations.filter((_, i) => i !== index));\n };\n\n const handleQuotaChange = (\n index: number,\n field: 'quotaId' | 'quantity',\n value: string | number\n ) => {\n const updated = [...quotaAllocations];\n if (field === 'quotaId') {\n updated[index].quotaId = value as string;\n } else {\n updated[index].quantity = Number(value);\n }\n setQuotaAllocations(updated);\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(false);\n\n // Validation\n if (!name.trim()) {\n setError('Plan name is required');\n return;\n }\n if (!price || isNaN(Number(price)) || Number(price) < 0) {\n setError('Valid price is required');\n return;\n }\n if (!productId.trim()) {\n setError('Product ID is required');\n return;\n }\n if (quotaAllocations.length === 0) {\n setError('At least one quota is required');\n return;\n }\n // Check for unselected quotas\n const unselectedQuotas = quotaAllocations.filter((a) => a.quotaId === '');\n if (unselectedQuotas.length > 0) {\n setError('Please select a quota for all allocations');\n return;\n }\n\n const input: CreatePlanInput = {\n name: name.trim(),\n price: Number(price),\n currency,\n duration,\n productId: productId.trim(),\n isPurchasable,\n quotas: quotaAllocations.map((a) => ({\n quotaId: a.quotaId,\n quantity: a.quantity,\n })),\n ...(currencyPriceOverrides.length > 0 ? { currencyPriceOverrides } : {}),\n };\n\n try {\n await createPlan(input);\n setSuccess(true);\n // Navigate back after short delay\n setTimeout(() => navigateTo('/plans'), 1500);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create plan');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.plans.createNewPlan', 'Create New Plan')}\n description={tr('billing.plans.createNewPlanDesc', 'Set up a new pricing plan with quotas')}\n />\n\n <PagePurpose>\n {tr(\n 'billing.plans.createPurpose',\n 'Define a new subscription tier customers can buy — its price and billing period, optional per-currency and per-seat pricing, and the quotas it includes. Once active, it appears on the Plans page for purchase.'\n )}\n </PagePurpose>\n\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Error/Success Messages */}\n {error && (\n <div className=\"p-4 bg-status-error-bg-subtle border border-border-subtle rounded-lg\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n </div>\n )}\n {success && (\n <div className=\"p-4 bg-status-success-bg-subtle border border-border-subtle rounded-lg\">\n <p className=\"text-sm text-status-success-text\">\n {tr('billing.plans.createSuccess', 'Plan created successfully! Redirecting...')}\n </p>\n </div>\n )}\n\n {/* Two-column layout on desktop */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Basic Info */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)] h-fit\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken/30\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.plans.basicInfo', 'Basic Information')}\n </h2>\n </div>\n <div className=\"p-4 space-y-4\">\n {/* Name */}\n <div>\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.plans.planNameLabel', 'Plan Name')} *\n </label>\n <input\n id=\"name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder={tr('billing.plans.planNamePlaceholder', 'e.g., Pro Plan')}\n required\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label\n htmlFor=\"productId\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.productId', 'Product ID')} *\n </label>\n <input\n id=\"productId\"\n type=\"text\"\n value={productId}\n onChange={(e) => setProductId(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder={tr('billing.plans.productIdPlaceholder', 'e.g., prod_abc123')}\n required\n />\n <p className=\"text-xs text-text-muted mt-1\">\n {tr('billing.plans.productIdDesc', 'The product this plan belongs to')}\n </p>\n </div>\n\n {/* Price & Currency */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"price\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.priceLabel', 'Price')} *\n </label>\n <input\n id=\"price\"\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder=\"49.99\"\n required\n />\n </div>\n <div>\n <label\n htmlFor=\"currency\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.currencyLabel', 'Currency')} *\n </label>\n <select\n id=\"currency\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"USD\">USD ($)</option>\n <option value=\"EUR\">EUR</option>\n <option value=\"GBP\">GBP</option>\n <option value=\"INR\">INR</option>\n <option value=\"AUD\">AUD</option>\n <option value=\"CAD\">CAD</option>\n <option value=\"JPY\">JPY</option>\n <option value=\"SGD\">SGD</option>\n </select>\n </div>\n </div>\n\n {/* Duration */}\n <div>\n <label\n htmlFor=\"duration\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.billingPeriodLabel', 'Billing Period')} *\n </label>\n <select\n id=\"duration\"\n value={duration}\n onChange={(e) => setDuration(e.target.value as PlanDuration)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value={PlanDuration.MONTHLY}>Monthly</option>\n <option value={PlanDuration.YEARLY}>Yearly</option>\n </select>\n </div>\n\n {/* Purchasable toggle */}\n <div className=\"flex items-start justify-between gap-4 pt-1\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('billing.plans.isPurchasableLabel', 'Publicly purchasable')}\n </p>\n <p className=\"text-xs text-text-muted mt-0.5\">\n {isPurchasable\n ? tr(\n 'billing.plans.isPurchasableOn',\n 'Visible on pricing page — users can subscribe directly.'\n )\n : tr(\n 'billing.plans.isPurchasableOff',\n 'Internal / custom plan — hidden from pricing page, assign via API only.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPurchasable}\n onClick={() => setIsPurchasable((v) => !v)}\n className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] focus:ring-offset-2 ${\n isPurchasable ? 'bg-action-primary-bg' : 'bg-text-muted/30'\n }`}\n >\n <span\n className={`inline-block h-5 w-5 transform rounded-full bg-bg-surface shadow transition-transform ${\n isPurchasable ? 'translate-x-5' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n </div>\n </div>\n\n {/* Quota Allocations */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)] h-fit\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken/30 flex items-center justify-between\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.plans.quotaAllocations', 'Quota Allocations')} *\n </h2>\n <button\n type=\"button\"\n onClick={handleAddQuota}\n disabled={quotas.length === 0}\n className=\"px-3 py-1 text-sm font-medium text-text-link hover:bg-[var(--color-accent-soft)] rounded-md transition-colors disabled:opacity-50\"\n >\n + Add Quota\n </button>\n </div>\n <div className=\"p-4 space-y-3\">\n {quotas.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n {tr(\n 'billing.plans.noQuotasAvailable',\n 'No quotas available. Please create quotas first.'\n )}\n </p>\n ) : quotaAllocations.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n {tr(\n 'billing.plans.noQuotasAllocated',\n 'No quotas allocated. Click \"Add Quota\" to add one.'\n )}\n </p>\n ) : (\n quotaAllocations.map((allocation, index) => {\n const selectedQuota = quotas.find((q) => q.id === allocation.quotaId);\n const limits = selectedQuota?.limits as { type?: string; value?: number } | null;\n const limitType = limits?.type ?? 'unknown';\n\n return (\n <div\n key={index}\n className=\"p-3 border border-border-subtle rounded-lg bg-bg-sunken/20 space-y-3\"\n >\n <div className=\"flex items-center gap-3\">\n <select\n value={allocation.quotaId}\n onChange={(e) => handleQuotaChange(index, 'quotaId', e.target.value)}\n className={`flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${\n allocation.quotaId === '' ? 'text-text-muted' : 'text-text-primary'\n }`}\n >\n <option value=\"\" disabled>\n {tr('billing.plans.selectQuota', 'Select a quota...')}\n </option>\n {quotas.map((quota) => (\n <option key={quota.id} value={quota.id}>\n {quota.name}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n onClick={() => handleRemoveQuota(index)}\n className=\"p-2 text-status-error-text hover:bg-status-error-bg-subtle rounded-md transition-colors\"\n title=\"Remove quota\"\n >\n <svg\n className=\"size-5\"\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=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n </button>\n </div>\n\n {/* Quota Info - only show when quota is selected */}\n {selectedQuota && (\n <>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"capitalize text-text-muted\">Type: {limitType}</span>\n </div>\n\n {/* Limit value — allocation.quantity is the absolute limit */}\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-muted\">\n {tr('billing.plans.limit', 'Limit')}:\n </label>\n <input\n type=\"number\"\n min=\"1\"\n value={allocation.quantity}\n onChange={(e) => handleQuotaChange(index, 'quantity', e.target.value)}\n className=\"w-36 px-3 py-1.5 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-center\"\n />\n </div>\n </>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n </div>\n\n <CurrencyPriceOverridesEditor\n overrides={currencyPriceOverrides}\n onChange={setCurrencyPriceOverrides}\n />\n\n {/* Actions */}\n <div className=\"flex items-center gap-3 pt-4\">\n <button\n type=\"submit\"\n disabled={isCreating || quotas.length === 0}\n className=\"px-6 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 {isCreating\n ? tr('billing.plans.creating', 'Creating...')\n : tr('billing.plans.createPlanBtn', 'Create Plan')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"px-6 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Cancel\n </button>\n </div>\n </form>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PlanCreatePage.js","names":[],"sources":["../../../../../src/billing/modules/plans/pages/PlanCreatePage.tsx"],"sourcesContent":["/**\n * Plans Module - Plan Create Page\n * Form to create a new plan\n */\n\nimport { useState, type FC, type FormEvent } from 'react';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { usePlanMutations, useQuotas } from '../hooks';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, CurrencyPriceOverridesEditor, PageHeader } from '../../../shared/components';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n PlanDuration,\n type CreatePlanInput,\n type CurrencyPriceOverrideInput,\n} from '../../../shared/types';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\ninterface QuotaAllocation {\n quotaId: string;\n quantity: number;\n}\n\nexport const PlanCreatePage: 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 { quotas, isLoading: isQuotasLoading } = useQuotas({ onlyActive: true });\n const { createPlan, isCreating } = usePlanMutations();\n\n // Form state\n const [name, setName] = useState('');\n const [price, setPrice] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [duration, setDuration] = useState<PlanDuration>(PlanDuration.MONTHLY);\n const [productId, setProductId] = useState('');\n const [isPurchasable, setIsPurchasable] = useState(true);\n const [quotaAllocations, setQuotaAllocations] = useState<QuotaAllocation[]>([]);\n const [currencyPriceOverrides, setCurrencyPriceOverrides] = useState<\n CurrencyPriceOverrideInput[]\n >([]);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n\n // Permission check\n if (!permissions.canManagePlans) {\n return (\n <AccessDenied\n message={tr(\n 'billing.plans.noCreatePermission',\n \"You don't have permission to create plans.\"\n )}\n />\n );\n }\n\n // Loading state\n if (isQuotasLoading) {\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=\"max-w-2xl space-y-4\">\n {[1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-16 bg-bg-sunken animate-pulse rounded\" />\n ))}\n </div>\n </div>\n );\n }\n\n const handleAddQuota = () => {\n // Add new quota at the top with empty quotaId (placeholder)\n setQuotaAllocations([{ quotaId: '', quantity: 1 }, ...quotaAllocations]);\n };\n\n const handleRemoveQuota = (index: number) => {\n setQuotaAllocations(quotaAllocations.filter((_, i) => i !== index));\n };\n\n const handleQuotaChange = (\n index: number,\n field: 'quotaId' | 'quantity',\n value: string | number\n ) => {\n const updated = [...quotaAllocations];\n if (field === 'quotaId') {\n updated[index].quotaId = value as string;\n } else {\n updated[index].quantity = Number(value);\n }\n setQuotaAllocations(updated);\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccess(false);\n\n // Validation\n if (!name.trim()) {\n setError('Plan name is required');\n return;\n }\n if (!price || isNaN(Number(price)) || Number(price) < 0) {\n setError('Valid price is required');\n return;\n }\n if (!productId.trim()) {\n setError('Product ID is required');\n return;\n }\n if (quotaAllocations.length === 0) {\n setError('At least one quota is required');\n return;\n }\n // Check for unselected quotas\n const unselectedQuotas = quotaAllocations.filter((a) => a.quotaId === '');\n if (unselectedQuotas.length > 0) {\n setError('Please select a quota for all allocations');\n return;\n }\n\n const input: CreatePlanInput = {\n name: name.trim(),\n price: Number(price),\n currency,\n duration,\n productId: productId.trim(),\n isPurchasable,\n quotas: quotaAllocations.map((a) => ({\n quotaId: a.quotaId,\n quantity: a.quantity,\n })),\n ...(currencyPriceOverrides.length > 0 ? { currencyPriceOverrides } : {}),\n };\n\n try {\n await createPlan(input);\n setSuccess(true);\n // Navigate back after short delay\n setTimeout(() => navigateTo('/plans'), 1500);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create plan');\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={tr('billing.plans.createNewPlan', 'Create New Plan')}\n description={tr('billing.plans.createNewPlanDesc', 'Set up a new pricing plan with quotas')}\n />\n\n <PagePurpose>\n {tr(\n 'billing.plans.createPurpose',\n 'Define a new subscription tier customers can buy — its price and billing period, optional per-currency and per-seat pricing, and the quotas it includes. Once active, it appears on the Plans page for purchase.'\n )}\n </PagePurpose>\n\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Error/Success Messages */}\n {error && (\n <div className=\"p-4 bg-status-error-bg-subtle border border-border-subtle rounded-lg\">\n <p className=\"text-sm text-status-error-text\">{error}</p>\n </div>\n )}\n {success && (\n <div className=\"p-4 bg-status-success-bg-subtle border border-border-subtle rounded-lg\">\n <p className=\"text-sm text-status-success-text\">\n {tr('billing.plans.createSuccess', 'Plan created successfully! Redirecting...')}\n </p>\n </div>\n )}\n\n {/* Two-column layout on desktop */}\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Basic Info */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)] h-fit\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken/30\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.plans.basicInfo', 'Basic Information')}\n </h2>\n </div>\n <div className=\"p-4 space-y-4\">\n {/* Name */}\n <div>\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('billing.plans.planNameLabel', 'Plan Name')} *\n </label>\n <input\n id=\"name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder={tr('billing.plans.planNamePlaceholder', 'e.g., Pro Plan')}\n required\n />\n </div>\n\n {/* Product ID */}\n <div>\n <label\n htmlFor=\"productId\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.productId', 'Product ID')} *\n </label>\n <input\n id=\"productId\"\n type=\"text\"\n value={productId}\n onChange={(e) => setProductId(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder={tr('billing.plans.productIdPlaceholder', 'e.g., prod_abc123')}\n required\n />\n <p className=\"text-xs text-text-muted mt-1\">\n {tr('billing.plans.productIdDesc', 'The product this plan belongs to')}\n </p>\n </div>\n\n {/* Price & Currency */}\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label\n htmlFor=\"price\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.priceLabel', 'Price')} *\n </label>\n <input\n id=\"price\"\n type=\"number\"\n step=\"0.01\"\n min=\"0\"\n value={price}\n onChange={(e) => setPrice(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n placeholder=\"49.99\"\n required\n />\n </div>\n <div>\n <label\n htmlFor=\"currency\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.currencyLabel', 'Currency')} *\n </label>\n <select\n id=\"currency\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value=\"USD\">USD ($)</option>\n <option value=\"EUR\">EUR</option>\n <option value=\"GBP\">GBP</option>\n <option value=\"INR\">INR</option>\n <option value=\"AUD\">AUD</option>\n <option value=\"CAD\">CAD</option>\n <option value=\"JPY\">JPY</option>\n <option value=\"SGD\">SGD</option>\n </select>\n </div>\n </div>\n\n {/* Duration */}\n <div>\n <label\n htmlFor=\"duration\"\n className=\"block text-sm font-medium text-text-primary mb-1\"\n >\n {tr('billing.plans.billingPeriodLabel', 'Billing Period')} *\n </label>\n <select\n id=\"duration\"\n value={duration}\n onChange={(e) => setDuration(e.target.value as PlanDuration)}\n className=\"w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary\"\n >\n <option value={PlanDuration.MONTHLY}>Monthly</option>\n <option value={PlanDuration.YEARLY}>Yearly</option>\n </select>\n </div>\n\n {/* Purchasable toggle */}\n <div className=\"flex items-start justify-between gap-4 pt-1\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {tr('billing.plans.isPurchasableLabel', 'Publicly purchasable')}\n </p>\n <p className=\"text-xs text-text-muted mt-0.5\">\n {isPurchasable\n ? tr(\n 'billing.plans.isPurchasableOn',\n 'Visible on pricing page — users can subscribe directly.'\n )\n : tr(\n 'billing.plans.isPurchasableOff',\n 'Internal / custom plan — hidden from pricing page, assign via API only.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isPurchasable}\n onClick={() => setIsPurchasable((v) => !v)}\n className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] focus:ring-offset-2 ${\n isPurchasable ? 'bg-action-primary-bg' : 'bg-text-muted/30'\n }`}\n >\n <span\n className={`inline-block h-5 w-5 transform rounded-full bg-bg-surface shadow transition-transform ${\n isPurchasable ? 'translate-x-5' : 'translate-x-0'\n }`}\n />\n </button>\n </div>\n </div>\n </div>\n\n {/* Quota Allocations */}\n <div className=\"border border-border-seam rounded-card bg-bg-surface overflow-hidden shadow-[var(--shadow-elevation-1)] h-fit\">\n <div className=\"p-4 border-b border-border-subtle bg-bg-sunken/30 flex items-center justify-between\">\n <h2 className=\"font-semibold text-text-primary\">\n {tr('billing.plans.quotaAllocations', 'Quota Allocations')} *\n </h2>\n <button\n type=\"button\"\n onClick={handleAddQuota}\n disabled={quotas.length === 0}\n className=\"px-3 py-1 text-sm font-medium text-text-link hover:bg-[var(--color-accent-soft)] rounded-md transition-colors disabled:opacity-50\"\n >\n + Add Quota\n </button>\n </div>\n <div className=\"p-4 space-y-3\">\n {quotas.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n {tr(\n 'billing.plans.noQuotasAvailable',\n 'No quotas available. Please create quotas first.'\n )}\n </p>\n ) : quotaAllocations.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n {tr(\n 'billing.plans.noQuotasAllocated',\n 'No quotas allocated. Click \"Add Quota\" to add one.'\n )}\n </p>\n ) : (\n quotaAllocations.map((allocation, index) => {\n const selectedQuota = quotas.find((q) => q.id === allocation.quotaId);\n const limits = selectedQuota?.limits as { type?: string; value?: number } | null;\n const limitType = limits?.type ?? 'unknown';\n\n return (\n <div\n key={index}\n className=\"p-3 border border-border-subtle rounded-lg bg-bg-sunken/20 space-y-3\"\n >\n <div className=\"flex items-center gap-3\">\n <select\n value={allocation.quotaId}\n onChange={(e) => handleQuotaChange(index, 'quotaId', e.target.value)}\n className={`flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${\n allocation.quotaId === '' ? 'text-text-muted' : 'text-text-primary'\n }`}\n >\n <option value=\"\" disabled>\n {tr('billing.plans.selectQuota', 'Select a quota...')}\n </option>\n {quotas.map((quota) => (\n <option key={quota.id} value={quota.id}>\n {quota.name}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n onClick={() => handleRemoveQuota(index)}\n className=\"p-2 text-status-error-text hover:bg-status-error-bg-subtle rounded-md transition-colors\"\n title=\"Remove quota\"\n >\n <svg\n className=\"size-5\"\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=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\"\n />\n </svg>\n </button>\n </div>\n\n {/* Quota Info - only show when quota is selected */}\n {selectedQuota && (\n <>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"capitalize text-text-muted\">Type: {limitType}</span>\n </div>\n\n {/* Limit value — allocation.quantity is the absolute limit */}\n <div className=\"flex items-center gap-2\">\n <label className=\"text-sm text-text-muted\">\n {tr('billing.plans.limit', 'Limit')}:\n </label>\n <input\n type=\"number\"\n min=\"1\"\n value={allocation.quantity}\n onChange={(e) => handleQuotaChange(index, 'quantity', e.target.value)}\n className=\"w-36 px-3 py-1.5 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] text-center\"\n />\n </div>\n </>\n )}\n </div>\n );\n })\n )}\n </div>\n </div>\n </div>\n\n <CurrencyPriceOverridesEditor\n overrides={currencyPriceOverrides}\n onChange={setCurrencyPriceOverrides}\n />\n\n {/* Actions */}\n <div className=\"flex items-center gap-3 pt-4\">\n <button\n type=\"submit\"\n disabled={isCreating || quotas.length === 0}\n className=\"px-6 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 {isCreating\n ? tr('billing.plans.creating', 'Creating...')\n : tr('billing.plans.createPlanBtn', 'Create Plan')}\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/plans')}\n className=\"px-6 py-2 text-sm font-medium border border-border-subtle text-text-primary rounded-button hover:bg-bg-sunken transition-colors\"\n >\n Cancel\n </button>\n </div>\n </form>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -206,7 +206,7 @@ var b = () => {
206
206
  id: "currency",
207
207
  value: I,
208
208
  onChange: (e) => L(e.target.value),
209
- className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
209
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
210
210
  children: [
211
211
  /* @__PURE__ */ g("option", {
212
212
  value: "USD",
@@ -251,7 +251,7 @@ var b = () => {
251
251
  id: "duration",
252
252
  value: R,
253
253
  onChange: (e) => z(e.target.value),
254
- className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
254
+ className: "w-full px-3 py-2 border border-border-subtle rounded-input bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary",
255
255
  children: [/* @__PURE__ */ g("option", {
256
256
  value: i.MONTHLY,
257
257
  children: "Monthly"
@@ -320,7 +320,7 @@ var b = () => {
320
320
  children: [/* @__PURE__ */ _("select", {
321
321
  value: e.quotaId,
322
322
  onChange: (e) => $(t, "quotaId", e.target.value),
323
- className: `flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${e.quotaId === "" ? "text-text-muted" : "text-text-primary"}`,
323
+ className: `flex-1 px-3 py-2 border border-border-subtle rounded-input bg-bg-surface scheme-normal dark:scheme-dark [&_option]:bg-bg-surface [&_option]:text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] ${e.quotaId === "" ? "text-text-muted" : "text-text-primary"}`,
324
324
  children: [/* @__PURE__ */ g("option", {
325
325
  value: "",
326
326
  disabled: !0,