@burdenoff/microfe-billing 2026.624.1 → 2026.624.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +125 -150
  2. package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
  3. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js +146 -153
  4. package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
  5. package/dist/billing/modules/coupons/pages/CouponDetailPage.js +164 -179
  6. package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
  7. package/dist/billing/modules/coupons/pages/CreateCouponPage.js +1 -1
  8. package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
  9. package/dist/billing/modules/earnings/pages/EarningsPage.js +229 -291
  10. package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
  11. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +69 -74
  12. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  13. package/dist/billing/modules/earnings/pages/PayoutsPage.js +142 -148
  14. package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
  15. package/dist/billing/modules/settings/pages/SettingsPage.js +125 -117
  16. package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
  17. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js +78 -66
  18. package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
  19. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js +68 -83
  20. package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
  21. package/dist/billing/shared/ui/MetricCard.js +1 -1
  22. package/dist/billing/shared/ui/MetricCard.js.map +1 -1
  23. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EarningsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/EarningsPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport {\n AccessDenied,\n EmptyState,\n PageHeader,\n ServerError,\n StatCard,\n} 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 EarningsEntry,\n type EarningsSummary,\n} from '../api';\n\ntype EarningsSourceFilter = 'ALL' | 'AFFILIATE' | 'STORE' | 'OTHER';\n\nexport const EarningsPage: FC = () => {\n const [searchParams] = useSearchParams();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\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 = 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 };\n\n useEffect(() => {\n void loadData();\n }, [billingAccountId, developerOrgId, requestContext]);\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 <EmptyState\n icon={<Wallet className=\"size-8\" />}\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(developerPortalRevenue.summary.totalGrossRevenue, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(developerPortalRevenue.summary.totalNetRevenue, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(developerPortalRevenue.summary.pendingBalance, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(developerPortalRevenue.summary.totalPlatformFees, 'USD'),\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 />\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 <EmptyState\n icon={<Coins className=\"size-8\" />}\n title=\"No sales yet\"\n description=\"Sales will appear here when customers start purchasing your apps.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-subtle text-left text-text-secondary\">\n <th className=\"px-3 py-2\">Application</th>\n <th className=\"px-3 py-2\">Pricing</th>\n <th className=\"px-3 py-2\">Gross</th>\n <th className=\"px-3 py-2\">Net</th>\n <th className=\"px-3 py-2\">Status</th>\n <th className=\"px-3 py-2\">Purchased</th>\n </tr>\n </thead>\n <tbody>\n {developerPortalRevenue.sales.map((sale) => (\n <tr key={sale.id} className=\"border-b border-border-subtle/70 text-text-primary\">\n <td className=\"px-3 py-2 font-medium\">\n {sale.application?.name || sale.application?.slug || 'Unknown app'}\n </td>\n <td className=\"px-3 py-2\">{sale.pricingModel}</td>\n <td className=\"px-3 py-2\">\n {formatCurrency(sale.grossAmount, sale.currency || 'USD')}\n </td>\n <td className=\"px-3 py-2\">\n {formatCurrency(sale.netAmount, sale.currency || 'USD')}\n </td>\n <td className=\"px-3 py-2\">{sale.status}</td>\n <td className=\"px-3 py-2\">{formatDateTime(sale.purchasedAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\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 <EmptyState\n icon={<Wallet className=\"size-8\" />}\n title=\"No payouts yet\"\n description=\"Scheduled and completed payouts will appear here.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-subtle text-left text-text-secondary\">\n <th className=\"px-3 py-2\">Period</th>\n <th className=\"px-3 py-2\">Amount</th>\n <th className=\"px-3 py-2\">Status</th>\n <th className=\"px-3 py-2\">Scheduled</th>\n <th className=\"px-3 py-2\">Completed</th>\n </tr>\n </thead>\n <tbody>\n {developerPortalRevenue.payouts.map((payout) => (\n <tr key={payout.id} className=\"border-b border-border-subtle/70 text-text-primary\">\n <td className=\"px-3 py-2 font-medium\">{payout.periodLabel || '-'}</td>\n <td className=\"px-3 py-2\">\n {formatCurrency(payout.netAmount, payout.currency || 'USD')}\n </td>\n <td className=\"px-3 py-2\">{payout.status}</td>\n <td className=\"px-3 py-2\">\n {payout.scheduledAt ? formatDateTime(payout.scheduledAt) : '-'}\n </td>\n <td className=\"px-3 py-2\">\n {payout.completedAt ? formatDateTime(payout.completedAt) : '-'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </section>\n </div>\n ) : (\n <EmptyState\n icon={<Coins className=\"size-8\" />}\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 <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 {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div key={card.title} className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\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 <EmptyState\n icon={<Coins className=\"size-8\" />}\n title=\"No earnings yet\"\n description=\"Eligible affiliate rewards and other earnings will appear here.\"\n />\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border-subtle text-left text-text-secondary\">\n <th className=\"px-3 py-2\">Category</th>\n <th className=\"px-3 py-2\">Description</th>\n <th className=\"px-3 py-2\">Unit</th>\n <th className=\"px-3 py-2\">Amount</th>\n <th className=\"px-3 py-2\">Status</th>\n <th className=\"px-3 py-2\">Created</th>\n </tr>\n </thead>\n <tbody>\n {filteredEntries.map((entry) => (\n <tr key={entry.id} className=\"border-b border-border-subtle/70 text-text-primary\">\n <td className=\"px-3 py-2 font-medium\">{entry.sourceCategory}</td>\n <td className=\"px-3 py-2\">\n {entry.description || entry.sourceSubcategory || '-'}\n </td>\n <td className=\"px-3 py-2\">{entry.unitType}</td>\n <td className=\"px-3 py-2\">\n {entry.unitType === 'CREDITS'\n ? `${entry.amount.toLocaleString()} credits`\n : formatCurrency(entry.amount, entry.currency || 'USD')}\n </td>\n <td className=\"px-3 py-2\">{entry.status}</td>\n <td className=\"px-3 py-2\">{formatDateTime(entry.createdAt)}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\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 { useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\nimport { ResponsiveTable, type ResponsiveTableColumn } from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport {\n AccessDenied,\n EmptyState,\n PageHeader,\n ServerError,\n StatCard,\n} 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\">\n {formatCurrency(sale.netAmount, sale.currency || 'USD')}\n </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 } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\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 = 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 };\n\n useEffect(() => {\n void loadData();\n }, [billingAccountId, developerOrgId, requestContext]);\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 <EmptyState\n icon={<Wallet className=\"size-8\" />}\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(developerPortalRevenue.summary.totalGrossRevenue, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(developerPortalRevenue.summary.totalNetRevenue, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(developerPortalRevenue.summary.pendingBalance, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(developerPortalRevenue.summary.totalPlatformFees, 'USD'),\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 />\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 <EmptyState\n icon={<Coins className=\"size-8\" />}\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 <EmptyState\n icon={<Wallet className=\"size-8\" />}\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 <EmptyState\n icon={<Coins className=\"size-8\" />}\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 <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 {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div key={card.title} className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\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 <EmptyState\n icon={<Coins className=\"size-8\" />}\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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"}
@@ -13,8 +13,9 @@ import { approvePayoutRequest as u, fetchAdminPayoutRequests as d, fetchAdminPay
13
13
  import { useEffect as h, useMemo as g, useState as _ } from "react";
14
14
  import { AlertTriangle as v, Banknote as y, CheckCircle2 as b, ChevronDown as x, ChevronUp as S, Clock as C, CreditCard as w, ReceiptText as T, RefreshCw as E, XCircle as D } from "lucide-react";
15
15
  import { Fragment as O, jsx as k, jsxs as A } from "react/jsx-runtime";
16
+ import { ResponsiveDialog as j, ResponsiveDialogContent as M, ResponsiveDialogDescription as N, ResponsiveDialogFooter as P, ResponsiveDialogHeader as F, ResponsiveDialogTitle as I } from "@burdenoff/fe-libs/ui";
16
17
  //#region src/billing/modules/earnings/pages/PayoutAdminPage.tsx
17
- var j = {
18
+ var L = {
18
19
  REQUESTED: "Requested",
19
20
  APPROVED: "Approved",
20
21
  REJECTED: "Rejected",
@@ -22,7 +23,7 @@ var j = {
22
23
  PAID: "Paid",
23
24
  FAILED: "Failed",
24
25
  CANCELED: "Canceled"
25
- }, M = {
26
+ }, R = {
26
27
  REQUESTED: "bg-status-warning-bg-subtle text-status-warning-text",
27
28
  APPROVED: "bg-status-info-bg-subtle text-status-info-text",
28
29
  REJECTED: "bg-status-error-bg-subtle text-status-error-text",
@@ -31,13 +32,13 @@ var j = {
31
32
  FAILED: "bg-status-error-bg-subtle text-status-error-text",
32
33
  CANCELED: "bg-bg-sunken text-text-muted"
33
34
  };
34
- function N({ status: e }) {
35
+ function z({ status: e }) {
35
36
  return /* @__PURE__ */ k("span", {
36
- className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${M[e] ?? "bg-bg-sunken text-text-muted"}`,
37
- children: j[e] ?? e
37
+ className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${R[e] ?? "bg-bg-sunken text-text-muted"}`,
38
+ children: L[e] ?? e
38
39
  });
39
40
  }
40
- function P({ account: e }) {
41
+ function B({ account: e }) {
41
42
  let [t, n] = _(!1), r = e.accountDetails;
42
43
  return /* @__PURE__ */ A("div", {
43
44
  className: "rounded-md border border-border-subtle bg-bg-sunken/40 p-3 text-sm",
@@ -145,7 +146,7 @@ function P({ account: e }) {
145
146
  })]
146
147
  });
147
148
  }
148
- function F({ request: e, onApprove: t, onReject: n, onMarkPaid: r }) {
149
+ function V({ request: e, onApprove: t, onReject: n, onMarkPaid: r }) {
149
150
  let i = e.status === "REQUESTED" || e.status === "REJECTED", a = e.status === "REQUESTED" || e.status === "APPROVED", c = e.status === "APPROVED" || e.status === "PROCESSING";
150
151
  return /* @__PURE__ */ A("div", {
151
152
  className: "rounded-card border border-border-subtle bg-bg-surface p-5 space-y-4 shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:shadow-[var(--shadow-elevation-2)]",
@@ -159,7 +160,7 @@ function F({ request: e, onApprove: t, onReject: n, onMarkPaid: r }) {
159
160
  children: [/* @__PURE__ */ k("span", {
160
161
  className: "text-xl font-semibold text-text-primary",
161
162
  children: o(e.requestedAmount, e.currency)
162
- }), /* @__PURE__ */ k(N, { status: e.status })]
163
+ }), /* @__PURE__ */ k(z, { status: e.status })]
163
164
  }), /* @__PURE__ */ A("div", {
164
165
  className: "text-xs text-text-muted space-x-2",
165
166
  children: [
@@ -196,7 +197,7 @@ function F({ request: e, onApprove: t, onReject: n, onMarkPaid: r }) {
196
197
  ]
197
198
  })]
198
199
  }),
199
- e.payoutAccount && /* @__PURE__ */ k(P, { account: e.payoutAccount }),
200
+ e.payoutAccount && /* @__PURE__ */ k(B, { account: e.payoutAccount }),
200
201
  e.userNotes && /* @__PURE__ */ A("div", {
201
202
  className: "rounded-md bg-bg-sunken/40 border border-border-subtle px-3 py-2 text-sm",
202
203
  children: [/* @__PURE__ */ k("span", {
@@ -258,7 +259,7 @@ function F({ request: e, onApprove: t, onReject: n, onMarkPaid: r }) {
258
259
  ]
259
260
  });
260
261
  }
261
- function I({ summary: e }) {
262
+ function H({ summary: e }) {
262
263
  return /* @__PURE__ */ A("div", {
263
264
  className: "grid gap-3 sm:grid-cols-3",
264
265
  children: [
@@ -309,7 +310,7 @@ function I({ summary: e }) {
309
310
  ]
310
311
  });
311
312
  }
312
- function L({ dialog: e, onClose: t, onConfirm: n }) {
313
+ function U({ dialog: e, onClose: t, onConfirm: n }) {
313
314
  let [r, i] = _(""), [a, s] = _(""), [c, l] = _(""), [u, d] = _(!1), f = async () => {
314
315
  e.type === "reject" && !a.trim() || (d(!0), await n({
315
316
  notes: r.trim() || void 0,
@@ -317,26 +318,23 @@ function L({ dialog: e, onClose: t, onConfirm: n }) {
317
318
  externalReference: c.trim() || void 0
318
319
  }), d(!1));
319
320
  };
320
- return /* @__PURE__ */ k("div", {
321
- className: "fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay p-4",
322
- children: /* @__PURE__ */ A("div", {
323
- className: "w-full max-w-md rounded-card border border-border-subtle bg-bg-elevated p-6 shadow-[var(--shadow-elevation-4)] space-y-4",
321
+ return /* @__PURE__ */ k(j, {
322
+ open: !0,
323
+ onOpenChange: (e) => {
324
+ !e && !u && t();
325
+ },
326
+ children: /* @__PURE__ */ A(M, {
327
+ className: "sm:max-w-md",
324
328
  children: [
325
- /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("h3", {
326
- className: "text-base font-semibold text-text-primary",
327
- children: {
328
- approve: "Approve withdrawal request",
329
- reject: "Reject withdrawal request",
330
- mark_paid: "Mark as paid"
331
- }[e.type]
332
- }), /* @__PURE__ */ A("p", {
333
- className: "text-sm text-text-muted mt-1",
334
- children: [
335
- o(e.amount, e.currency),
336
- " · ",
337
- e.accountLabel
338
- ]
339
- })] }),
329
+ /* @__PURE__ */ A(F, { children: [/* @__PURE__ */ k(I, { children: {
330
+ approve: "Approve withdrawal request",
331
+ reject: "Reject withdrawal request",
332
+ mark_paid: "Mark as paid"
333
+ }[e.type] }), /* @__PURE__ */ A(N, { children: [
334
+ o(e.amount, e.currency),
335
+ " · ",
336
+ e.accountLabel
337
+ ] })] }),
340
338
  e.type === "mark_paid" && /* @__PURE__ */ A("div", {
341
339
  className: "space-y-3",
342
340
  children: [/* @__PURE__ */ A("div", { children: [
@@ -389,28 +387,25 @@ function L({ dialog: e, onClose: t, onConfirm: n }) {
389
387
  placeholder: "e.g. Invalid bank details provided, please re-submit with correct IFSC…",
390
388
  className: "w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none"
391
389
  })] }),
392
- /* @__PURE__ */ A("div", {
393
- className: "flex justify-end gap-2 pt-2",
394
- children: [/* @__PURE__ */ k("button", {
395
- type: "button",
396
- onClick: t,
397
- disabled: u,
398
- className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary disabled:opacity-50",
399
- children: "Cancel"
400
- }), /* @__PURE__ */ k("button", {
401
- type: "button",
402
- onClick: () => void f(),
403
- disabled: u || e.type === "reject" && !a.trim(),
404
- className: `rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50 ${e.type === "reject" ? "bg-action-danger-bg text-action-danger-text" : "bg-action-primary-bg text-action-primary-text"}`,
405
- children: u ? "Saving…" : e.type === "approve" ? "Approve" : e.type === "reject" ? "Reject" : "Confirm Payment"
406
- })]
407
- })
390
+ /* @__PURE__ */ A(P, { children: [/* @__PURE__ */ k("button", {
391
+ type: "button",
392
+ onClick: t,
393
+ disabled: u,
394
+ className: "rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary disabled:opacity-50",
395
+ children: "Cancel"
396
+ }), /* @__PURE__ */ k("button", {
397
+ type: "button",
398
+ onClick: () => void f(),
399
+ disabled: u || e.type === "reject" && !a.trim(),
400
+ className: `rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50 ${e.type === "reject" ? "bg-action-danger-bg text-action-danger-text" : "bg-action-primary-bg text-action-primary-text"}`,
401
+ children: u ? "Saving…" : e.type === "approve" ? "Approve" : e.type === "reject" ? "Reject" : "Confirm Payment"
402
+ })] })
408
403
  ]
409
404
  })
410
405
  });
411
406
  }
412
- var R = () => {
413
- let o = l(), { emit: s } = a(), { apiGatewayUrl: v, authToken: y, orgId: x } = e(), [S, C] = _(null), [w, T] = _([]), [D, O] = _(!0), [j, M] = _(null), [N, P] = _("pending"), [R, z] = _(null), B = g(() => ({
407
+ var W = () => {
408
+ let o = l(), { emit: s } = a(), { apiGatewayUrl: v, authToken: y, orgId: x } = e(), [S, C] = _(null), [w, T] = _([]), [D, O] = _(!0), [j, M] = _(null), [N, P] = _("pending"), [F, I] = _(null), L = g(() => ({
414
409
  apiGatewayUrl: v,
415
410
  authToken: y,
416
411
  orgId: x
@@ -418,10 +413,10 @@ var R = () => {
418
413
  v,
419
414
  y,
420
415
  x
421
- ]), V = async () => {
416
+ ]), R = async () => {
422
417
  O(!0), M(null);
423
418
  try {
424
- let [e, t] = await Promise.all([f(B), d(B)]);
419
+ let [e, t] = await Promise.all([f(L), d(L)]);
425
420
  C(e), T(t);
426
421
  } catch (e) {
427
422
  M(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load payout queue"));
@@ -430,15 +425,15 @@ var R = () => {
430
425
  }
431
426
  };
432
427
  if (h(() => {
433
- V();
434
- }, [B]), !o.isBillingAdmin) return /* @__PURE__ */ k(t, { message: "You don't have permission to manage payouts." });
428
+ R();
429
+ }, [L]), !o.isBillingAdmin) return /* @__PURE__ */ k(t, { message: "You don't have permission to manage payouts." });
435
430
  if (j && c(j)) return /* @__PURE__ */ k(i, {
436
431
  title: "Payout queue unavailable",
437
432
  message: j.message,
438
- onRetry: () => void V(),
433
+ onRetry: () => void R(),
439
434
  showRetry: !0
440
435
  });
441
- let H = w.filter((e) => e.status === "REQUESTED"), U = w.filter((e) => e.status === "APPROVED" || e.status === "PROCESSING"), W = w.filter((e) => [
436
+ let z = w.filter((e) => e.status === "REQUESTED"), B = w.filter((e) => e.status === "APPROVED" || e.status === "PROCESSING"), W = w.filter((e) => [
442
437
  "PAID",
443
438
  "REJECTED",
444
439
  "FAILED",
@@ -447,20 +442,20 @@ var R = () => {
447
442
  {
448
443
  id: "pending",
449
444
  label: "Pending",
450
- count: H.length
445
+ count: z.length
451
446
  },
452
447
  {
453
448
  id: "approved",
454
449
  label: "Approved",
455
- count: U.length
450
+ count: B.length
456
451
  },
457
452
  {
458
453
  id: "history",
459
454
  label: "History",
460
455
  count: W.length
461
456
  }
462
- ], K = N === "pending" ? H : N === "approved" ? U : W, q = (e, t) => {
463
- z({
457
+ ], K = N === "pending" ? z : N === "approved" ? B : W, q = (e, t) => {
458
+ I({
464
459
  type: e,
465
460
  requestId: t.id,
466
461
  amount: t.requestedAmount,
@@ -476,12 +471,12 @@ var R = () => {
476
471
  description: "Review withdrawal requests, verify bank details, and mark payments as paid once transferred.",
477
472
  actions: /* @__PURE__ */ A("button", {
478
473
  type: "button",
479
- onClick: () => void V(),
474
+ onClick: () => void R(),
480
475
  className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary",
481
476
  children: [/* @__PURE__ */ k(E, { className: `size-4 ${D ? "animate-spin" : ""}` }), "Refresh"]
482
477
  })
483
478
  }),
484
- S && !D && /* @__PURE__ */ k(I, { summary: S }),
479
+ S && !D && /* @__PURE__ */ k(H, { summary: S }),
485
480
  D && /* @__PURE__ */ k("div", {
486
481
  className: "grid gap-3 sm:grid-cols-3",
487
482
  children: [
@@ -509,7 +504,7 @@ var R = () => {
509
504
  }, e.id))
510
505
  })
511
506
  }),
512
- N === "approved" && U.length > 0 && /* @__PURE__ */ A("div", {
507
+ N === "approved" && B.length > 0 && /* @__PURE__ */ A("div", {
513
508
  className: "rounded-card border border-status-info-border bg-status-info-bg-subtle px-4 py-3 text-sm text-status-info-text",
514
509
  children: [
515
510
  /* @__PURE__ */ k("strong", { children: "How to pay:" }),
@@ -527,32 +522,32 @@ var R = () => {
527
522
  description: N === "pending" ? "New withdrawal requests will appear here." : N === "approved" ? "Approve pending requests first, then send payment and mark as paid." : "Completed and rejected requests will appear here."
528
523
  }) : /* @__PURE__ */ k("div", {
529
524
  className: "space-y-4",
530
- children: K.map((e) => /* @__PURE__ */ k(F, {
525
+ children: K.map((e) => /* @__PURE__ */ k(V, {
531
526
  request: e,
532
527
  onApprove: (e) => q("approve", e),
533
528
  onReject: (e) => q("reject", e),
534
529
  onMarkPaid: (e) => q("mark_paid", e)
535
530
  }, e.id))
536
531
  }),
537
- R && /* @__PURE__ */ k(L, {
538
- dialog: R,
539
- onClose: () => z(null),
532
+ F && /* @__PURE__ */ k(U, {
533
+ dialog: F,
534
+ onClose: () => I(null),
540
535
  onConfirm: async (e) => {
541
- if (R) try {
542
- R.type === "approve" ? (await u(R.requestId, e.notes ?? null, B), s("billing.payout.approved", {
536
+ if (F) try {
537
+ F.type === "approve" ? (await u(F.requestId, e.notes ?? null, L), s("billing.payout.approved", {
543
538
  route: "/billing/payouts",
544
- entityId: R.requestId,
539
+ entityId: F.requestId,
545
540
  source: "payout-admin"
546
- })) : R.type === "reject" ? (await m(R.requestId, e.reason ?? "", B), s("billing.payout.rejected", {
541
+ })) : F.type === "reject" ? (await m(F.requestId, e.reason ?? "", L), s("billing.payout.rejected", {
547
542
  route: "/billing/payouts",
548
- entityId: R.requestId,
543
+ entityId: F.requestId,
549
544
  source: "payout-admin",
550
545
  reason: e.reason
551
- })) : R.type === "mark_paid" && (await p(R.requestId, e.externalReference ?? null, e.notes ?? null, B), s("billing.payout.processed", {
546
+ })) : F.type === "mark_paid" && (await p(F.requestId, e.externalReference ?? null, e.notes ?? null, L), s("billing.payout.processed", {
552
547
  route: "/billing/payouts",
553
- entityId: R.requestId,
548
+ entityId: F.requestId,
554
549
  source: "payout-admin"
555
- })), z(null), await V();
550
+ })), I(null), await R();
556
551
  } catch (e) {
557
552
  M(e instanceof Error ? e : /* @__PURE__ */ Error("Action failed"));
558
553
  }
@@ -562,6 +557,6 @@ var R = () => {
562
557
  });
563
558
  };
564
559
  //#endregion
565
- export { R as PayoutAdminPage };
560
+ export { W as PayoutAdminPage };
566
561
 
567
562
  //# sourceMappingURL=PayoutAdminPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PayoutAdminPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/PayoutAdminPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type FC } from 'react';\nimport {\n AlertTriangle,\n Banknote,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Clock,\n CreditCard,\n RefreshCw,\n ReceiptText,\n XCircle,\n} from 'lucide-react';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, EmptyState, PageHeader, ServerError } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport {\n approvePayoutRequest,\n fetchAdminPayoutRequests,\n fetchAdminPayoutSummary,\n markPayoutPaid,\n rejectPayoutRequest,\n type PayoutAdminSummary,\n type PayoutRequest,\n} from '../api';\n\ntype Tab = 'pending' | 'approved' | 'history';\n\ninterface ActionDialogState {\n type: 'approve' | 'reject' | 'mark_paid';\n requestId: string;\n amount: number;\n currency: string;\n accountLabel: string;\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n REQUESTED: 'Requested',\n APPROVED: 'Approved',\n REJECTED: 'Rejected',\n PROCESSING: 'Processing',\n PAID: 'Paid',\n FAILED: 'Failed',\n CANCELED: 'Canceled',\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n REQUESTED: 'bg-status-warning-bg-subtle text-status-warning-text',\n APPROVED: 'bg-status-info-bg-subtle text-status-info-text',\n REJECTED: 'bg-status-error-bg-subtle text-status-error-text',\n PROCESSING: 'bg-status-info-bg-subtle text-status-info-text',\n PAID: 'bg-status-success-bg-subtle text-status-success-text',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text',\n CANCELED: 'bg-bg-sunken text-text-muted',\n};\n\nfunction StatusBadge({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${STATUS_COLORS[status] ?? 'bg-bg-sunken text-text-muted'}`}\n >\n {STATUS_LABEL[status] ?? status}\n </span>\n );\n}\n\nfunction AccountDetails({ account }: { account: NonNullable<PayoutRequest['payoutAccount']> }) {\n const [expanded, setExpanded] = useState(false);\n const details = account.accountDetails as Record<string, string | null> | null;\n\n return (\n <div className=\"rounded-md border border-border-subtle bg-bg-sunken/40 p-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-text-primary font-medium\">\n <CreditCard className=\"size-4 text-text-muted\" />\n {account.displayName ?? account.label}\n <span className=\"text-xs text-text-muted font-normal\">\n ({account.type === 'UPI' ? 'UPI' : 'Bank'} · {account.country ?? 'Unknown'} ·{' '}\n {account.currency})\n </span>\n </div>\n {details && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"text-text-muted hover:text-text-primary\"\n >\n {expanded ? <ChevronUp className=\"size-4\" /> : <ChevronDown className=\"size-4\" />}\n </button>\n )}\n </div>\n {expanded && details && (\n <div className=\"mt-2 grid gap-1 text-xs\">\n {details.accountHolderName && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Account holder</span>\n <span className=\"text-text-primary\">{details.accountHolderName}</span>\n </div>\n )}\n {details.bankName && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Bank</span>\n <span className=\"text-text-primary\">{details.bankName}</span>\n </div>\n )}\n {account.accountLast4 && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Account (last 4)</span>\n <span className=\"text-text-primary font-mono\">••••{account.accountLast4}</span>\n </div>\n )}\n {details.ifsc && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">IFSC</span>\n <span className=\"text-text-primary font-mono\">{details.ifsc}</span>\n </div>\n )}\n {details.routingNumberLast4 && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Routing (last 4)</span>\n <span className=\"text-text-primary font-mono\">••••{details.routingNumberLast4}</span>\n </div>\n )}\n {details.upiIdMasked && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">UPI ID</span>\n <span className=\"text-text-primary font-mono\">{details.upiIdMasked}</span>\n </div>\n )}\n {details.swift && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">SWIFT</span>\n <span className=\"text-text-primary font-mono\">{details.swift}</span>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction RequestCard({\n request,\n onApprove,\n onReject,\n onMarkPaid,\n}: {\n request: PayoutRequest;\n onApprove: (r: PayoutRequest) => void;\n onReject: (r: PayoutRequest) => void;\n onMarkPaid: (r: PayoutRequest) => void;\n}) {\n const canApprove = request.status === 'REQUESTED' || request.status === 'REJECTED';\n const canReject = request.status === 'REQUESTED' || request.status === 'APPROVED';\n const canMarkPaid = request.status === 'APPROVED' || request.status === 'PROCESSING';\n\n return (\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-5 space-y-4 shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:shadow-[var(--shadow-elevation-2)]\">\n {/* Header row */}\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xl font-semibold text-text-primary\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </span>\n <StatusBadge status={request.status} />\n </div>\n <div className=\"text-xs text-text-muted space-x-2\">\n <span>Requested {formatDateTime(request.createdAt)}</span>\n {request.requesterUserId && (\n <>\n <span>·</span>\n <span>by {request.requesterUserId}</span>\n </>\n )}\n <span>·</span>\n <span className=\"font-mono text-xs\">{request.id.slice(0, 8)}…</span>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {canApprove && (\n <button\n type=\"button\"\n onClick={() => onApprove(request)}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text\"\n >\n <CheckCircle2 className=\"size-3.5\" />\n Approve\n </button>\n )}\n {canMarkPaid && (\n <button\n type=\"button\"\n onClick={() => onMarkPaid(request)}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-status-success-bg-subtle border border-status-success-border px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle/70\"\n >\n <Banknote className=\"size-3.5\" />\n Mark as Paid\n </button>\n )}\n {canReject && (\n <button\n type=\"button\"\n onClick={() => onReject(request)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n <XCircle className=\"size-3.5\" />\n Reject\n </button>\n )}\n </div>\n </div>\n\n {/* Payout account */}\n {request.payoutAccount && <AccountDetails account={request.payoutAccount} />}\n\n {/* User notes */}\n {request.userNotes && (\n <div className=\"rounded-md bg-bg-sunken/40 border border-border-subtle px-3 py-2 text-sm\">\n <span className=\"text-xs font-medium text-text-muted uppercase tracking-wide\">\n User note\n </span>\n <p className=\"mt-1 text-text-primary\">{request.userNotes}</p>\n </div>\n )}\n\n {/* Internal notes / failure / ref */}\n {(request.internalNotes ?? request.failureReason ?? request.externalReference) && (\n <div className=\"grid gap-1 text-xs text-text-muted\">\n {request.externalReference && (\n <div className=\"flex gap-2\">\n <ReceiptText className=\"size-3.5 mt-px shrink-0\" />\n <span>\n Ref:{' '}\n <span className=\"font-mono text-text-primary\">{request.externalReference}</span>\n </span>\n </div>\n )}\n {request.internalNotes && (\n <div className=\"flex gap-2\">\n <span className=\"shrink-0\">Internal note:</span>\n <span className=\"text-text-primary\">{request.internalNotes}</span>\n </div>\n )}\n {request.failureReason && (\n <div className=\"flex gap-2 text-status-error-text\">\n <AlertTriangle className=\"size-3.5 mt-px shrink-0\" />\n <span>{request.failureReason}</span>\n </div>\n )}\n </div>\n )}\n\n {/* Timestamps */}\n {(request.paidAt ?? request.processedAt) && (\n <div className=\"flex flex-wrap gap-4 text-xs text-text-muted\">\n {request.processedAt && (\n <span className=\"flex items-center gap-1\">\n <Clock className=\"size-3\" />\n Processed {formatDateTime(request.processedAt)}\n </span>\n )}\n {request.paidAt && (\n <span className=\"flex items-center gap-1\">\n <CheckCircle2 className=\"size-3\" />\n Paid {formatDateTime(request.paidAt)}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction SummaryBar({ summary }: { summary: PayoutAdminSummary }) {\n return (\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Pending payout</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalRequestedAmount, 'USD')}\n </div>\n <div className=\"text-xs text-text-muted mt-0.5\">{summary.pendingCount} requests</div>\n </div>\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Processing</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalProcessingAmount, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Total paid</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalPaidAmount, 'USD')}\n </div>\n {summary.failedCount > 0 && (\n <div className=\"text-xs text-status-error-text mt-0.5\">{summary.failedCount} failed</div>\n )}\n </div>\n </div>\n );\n}\n\nfunction ActionDialog({\n dialog,\n onClose,\n onConfirm,\n}: {\n dialog: ActionDialogState;\n onClose: () => void;\n onConfirm: (data: {\n notes?: string;\n reason?: string;\n externalReference?: string;\n }) => Promise<void>;\n}) {\n const [notes, setNotes] = useState('');\n const [reason, setReason] = useState('');\n const [txnRef, setTxnRef] = useState('');\n const [submitting, setSubmitting] = useState(false);\n\n const handleSubmit = async () => {\n if (dialog.type === 'reject' && !reason.trim()) return;\n setSubmitting(true);\n await onConfirm({\n notes: notes.trim() || undefined,\n reason: reason.trim() || undefined,\n externalReference: txnRef.trim() || undefined,\n });\n setSubmitting(false);\n };\n\n const titles = {\n approve: 'Approve withdrawal request',\n reject: 'Reject withdrawal request',\n mark_paid: 'Mark as paid',\n };\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-bg-overlay p-4\">\n <div className=\"w-full max-w-md rounded-card border border-border-subtle bg-bg-elevated p-6 shadow-[var(--shadow-elevation-4)] space-y-4\">\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">{titles[dialog.type]}</h3>\n <p className=\"text-sm text-text-muted mt-1\">\n {formatCurrency(dialog.amount, dialog.currency)} · {dialog.accountLabel}\n </p>\n </div>\n\n {dialog.type === 'mark_paid' && (\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Transaction reference / UTR number\n </label>\n <input\n type=\"text\"\n value={txnRef}\n onChange={(e) => setTxnRef(e.target.value)}\n placeholder=\"e.g. UTR123456789012, TXN_abc123\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-muted mt-1\">\n Enter the bank reference number so the user can verify the transfer.\n </p>\n </div>\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Internal notes (optional)\n </label>\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={2}\n placeholder=\"Any internal notes about this payment…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n </div>\n )}\n\n {dialog.type === 'approve' && (\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Internal notes (optional)\n </label>\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder=\"e.g. Verified bank details, approved for transfer…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n )}\n\n {dialog.type === 'reject' && (\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Reason for rejection <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={3}\n placeholder=\"e.g. Invalid bank details provided, please re-submit with correct IFSC…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n )}\n\n <div className=\"flex justify-end gap-2 pt-2\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={submitting}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n disabled={submitting || (dialog.type === 'reject' && !reason.trim())}\n className={`rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50 ${\n dialog.type === 'reject'\n ? 'bg-action-danger-bg text-action-danger-text'\n : 'bg-action-primary-bg text-action-primary-text'\n }`}\n >\n {submitting\n ? 'Saving…'\n : dialog.type === 'approve'\n ? 'Approve'\n : dialog.type === 'reject'\n ? 'Reject'\n : 'Confirm Payment'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport const PayoutAdminPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n\n const [summary, setSummary] = useState<PayoutAdminSummary | null>(null);\n const [requests, setRequests] = useState<PayoutRequest[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [activeTab, setActiveTab] = useState<Tab>('pending');\n const [dialog, setDialog] = useState<ActionDialogState | null>(null);\n\n const requestContext = useMemo(\n () => ({ apiGatewayUrl, authToken, orgId }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [loadedSummary, loadedRequests] = await Promise.all([\n fetchAdminPayoutSummary(requestContext),\n fetchAdminPayoutRequests(requestContext),\n ]);\n setSummary(loadedSummary);\n setRequests(loadedRequests);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load payout queue'));\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, [requestContext]);\n\n if (!permissions.isBillingAdmin) {\n return <AccessDenied message=\"You don't have permission to manage payouts.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Payout queue unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const pending = requests.filter((r) => r.status === 'REQUESTED');\n const approved = requests.filter((r) => r.status === 'APPROVED' || r.status === 'PROCESSING');\n const history = requests.filter((r) =>\n ['PAID', 'REJECTED', 'FAILED', 'CANCELED'].includes(r.status)\n );\n\n const tabItems: { id: Tab; label: string; count: number }[] = [\n { id: 'pending', label: 'Pending', count: pending.length },\n { id: 'approved', label: 'Approved', count: approved.length },\n { id: 'history', label: 'History', count: history.length },\n ];\n\n const visibleRequests =\n activeTab === 'pending' ? pending : activeTab === 'approved' ? approved : history;\n\n const openDialog = (type: ActionDialogState['type'], request: PayoutRequest) => {\n setDialog({\n type,\n requestId: request.id,\n amount: request.requestedAmount,\n currency: request.currency,\n accountLabel:\n request.payoutAccount?.displayName ?? request.payoutAccount?.label ?? 'Unknown account',\n });\n };\n\n const handleConfirm = async (data: {\n notes?: string;\n reason?: string;\n externalReference?: string;\n }) => {\n if (!dialog) return;\n\n try {\n if (dialog.type === 'approve') {\n await approvePayoutRequest(dialog.requestId, data.notes ?? null, requestContext);\n emit('billing.payout.approved', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n });\n } else if (dialog.type === 'reject') {\n await rejectPayoutRequest(dialog.requestId, data.reason ?? '', requestContext);\n emit('billing.payout.rejected', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n reason: data.reason,\n });\n } else if (dialog.type === 'mark_paid') {\n await markPayoutPaid(\n dialog.requestId,\n data.externalReference ?? null,\n data.notes ?? null,\n requestContext\n );\n emit('billing.payout.processed', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n });\n }\n setDialog(null);\n await loadData();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Action failed'));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Payout queue\"\n description=\"Review withdrawal requests, verify bank details, and mark payments as paid once transferred.\"\n actions={\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 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n }\n />\n\n {summary && !loading && <SummaryBar summary={summary} />}\n\n {loading && (\n <div className=\"grid gap-3 sm:grid-cols-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-20 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n )}\n\n {error && !isServerError(error) && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n )}\n\n {/* Tabs */}\n <div className=\"border-b border-border-subtle\">\n <div className=\"flex gap-0\">\n {tabItems.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={`flex items-center gap-2 border-b-2 px-4 py-2.5 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab.label}\n {tab.count > 0 && (\n <span\n className={`rounded-full px-1.5 py-0.5 text-xs ${\n activeTab === tab.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.count}\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n\n {/* How to pay — shown only on the Approved tab */}\n {activeTab === 'approved' && approved.length > 0 && (\n <div className=\"rounded-card border border-status-info-border bg-status-info-bg-subtle px-4 py-3 text-sm text-status-info-text\">\n <strong>How to pay:</strong> Click the account row to expand bank/UPI details → transfer\n the exact amount via your bank → click <strong>Mark as Paid</strong> and enter the UTR /\n transaction reference number.\n </div>\n )}\n\n {/* Request cards */}\n {loading ? (\n <div className=\"space-y-4\">\n {[1, 2].map((i) => (\n <div\n key={i}\n className=\"h-40 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : visibleRequests.length === 0 ? (\n <EmptyState\n icon={<CheckCircle2 className=\"size-8\" />}\n title={\n activeTab === 'pending'\n ? 'No pending requests'\n : activeTab === 'approved'\n ? 'No approved requests awaiting payment'\n : 'No history yet'\n }\n description={\n activeTab === 'pending'\n ? 'New withdrawal requests will appear here.'\n : activeTab === 'approved'\n ? 'Approve pending requests first, then send payment and mark as paid.'\n : 'Completed and rejected requests will appear here.'\n }\n />\n ) : (\n <div className=\"space-y-4\">\n {visibleRequests.map((request) => (\n <RequestCard\n key={request.id}\n request={request}\n onApprove={(r) => openDialog('approve', r)}\n onReject={(r) => openDialog('reject', r)}\n onMarkPaid={(r) => openDialog('mark_paid', r)}\n />\n ))}\n </div>\n )}\n\n {dialog && (\n <ActionDialog dialog={dialog} onClose={() => setDialog(null)} onConfirm={handleConfirm} />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PayoutAdminPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/PayoutAdminPage.tsx"],"sourcesContent":["import { useEffect, useMemo, useState, type FC } from 'react';\nimport {\n AlertTriangle,\n Banknote,\n CheckCircle2,\n ChevronDown,\n ChevronUp,\n Clock,\n CreditCard,\n RefreshCw,\n ReceiptText,\n XCircle,\n} from 'lucide-react';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBillingEventEmitter } from '../../../hooks/useBillingEventEmitter';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, EmptyState, PageHeader, ServerError } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport {\n approvePayoutRequest,\n fetchAdminPayoutRequests,\n fetchAdminPayoutSummary,\n markPayoutPaid,\n rejectPayoutRequest,\n type PayoutAdminSummary,\n type PayoutRequest,\n} from '../api';\n\ntype Tab = 'pending' | 'approved' | 'history';\n\ninterface ActionDialogState {\n type: 'approve' | 'reject' | 'mark_paid';\n requestId: string;\n amount: number;\n currency: string;\n accountLabel: string;\n}\n\nconst STATUS_LABEL: Record<string, string> = {\n REQUESTED: 'Requested',\n APPROVED: 'Approved',\n REJECTED: 'Rejected',\n PROCESSING: 'Processing',\n PAID: 'Paid',\n FAILED: 'Failed',\n CANCELED: 'Canceled',\n};\n\nconst STATUS_COLORS: Record<string, string> = {\n REQUESTED: 'bg-status-warning-bg-subtle text-status-warning-text',\n APPROVED: 'bg-status-info-bg-subtle text-status-info-text',\n REJECTED: 'bg-status-error-bg-subtle text-status-error-text',\n PROCESSING: 'bg-status-info-bg-subtle text-status-info-text',\n PAID: 'bg-status-success-bg-subtle text-status-success-text',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text',\n CANCELED: 'bg-bg-sunken text-text-muted',\n};\n\nfunction StatusBadge({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${STATUS_COLORS[status] ?? 'bg-bg-sunken text-text-muted'}`}\n >\n {STATUS_LABEL[status] ?? status}\n </span>\n );\n}\n\nfunction AccountDetails({ account }: { account: NonNullable<PayoutRequest['payoutAccount']> }) {\n const [expanded, setExpanded] = useState(false);\n const details = account.accountDetails as Record<string, string | null> | null;\n\n return (\n <div className=\"rounded-md border border-border-subtle bg-bg-sunken/40 p-3 text-sm\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2 text-text-primary font-medium\">\n <CreditCard className=\"size-4 text-text-muted\" />\n {account.displayName ?? account.label}\n <span className=\"text-xs text-text-muted font-normal\">\n ({account.type === 'UPI' ? 'UPI' : 'Bank'} · {account.country ?? 'Unknown'} ·{' '}\n {account.currency})\n </span>\n </div>\n {details && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"text-text-muted hover:text-text-primary\"\n >\n {expanded ? <ChevronUp className=\"size-4\" /> : <ChevronDown className=\"size-4\" />}\n </button>\n )}\n </div>\n {expanded && details && (\n <div className=\"mt-2 grid gap-1 text-xs\">\n {details.accountHolderName && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Account holder</span>\n <span className=\"text-text-primary\">{details.accountHolderName}</span>\n </div>\n )}\n {details.bankName && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Bank</span>\n <span className=\"text-text-primary\">{details.bankName}</span>\n </div>\n )}\n {account.accountLast4 && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Account (last 4)</span>\n <span className=\"text-text-primary font-mono\">••••{account.accountLast4}</span>\n </div>\n )}\n {details.ifsc && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">IFSC</span>\n <span className=\"text-text-primary font-mono\">{details.ifsc}</span>\n </div>\n )}\n {details.routingNumberLast4 && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">Routing (last 4)</span>\n <span className=\"text-text-primary font-mono\">••••{details.routingNumberLast4}</span>\n </div>\n )}\n {details.upiIdMasked && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">UPI ID</span>\n <span className=\"text-text-primary font-mono\">{details.upiIdMasked}</span>\n </div>\n )}\n {details.swift && (\n <div className=\"flex gap-2\">\n <span className=\"text-text-muted w-32 shrink-0\">SWIFT</span>\n <span className=\"text-text-primary font-mono\">{details.swift}</span>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction RequestCard({\n request,\n onApprove,\n onReject,\n onMarkPaid,\n}: {\n request: PayoutRequest;\n onApprove: (r: PayoutRequest) => void;\n onReject: (r: PayoutRequest) => void;\n onMarkPaid: (r: PayoutRequest) => void;\n}) {\n const canApprove = request.status === 'REQUESTED' || request.status === 'REJECTED';\n const canReject = request.status === 'REQUESTED' || request.status === 'APPROVED';\n const canMarkPaid = request.status === 'APPROVED' || request.status === 'PROCESSING';\n\n return (\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-5 space-y-4 shadow-[var(--shadow-elevation-1)] transition-all duration-200 hover:shadow-[var(--shadow-elevation-2)]\">\n {/* Header row */}\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"space-y-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xl font-semibold text-text-primary\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </span>\n <StatusBadge status={request.status} />\n </div>\n <div className=\"text-xs text-text-muted space-x-2\">\n <span>Requested {formatDateTime(request.createdAt)}</span>\n {request.requesterUserId && (\n <>\n <span>·</span>\n <span>by {request.requesterUserId}</span>\n </>\n )}\n <span>·</span>\n <span className=\"font-mono text-xs\">{request.id.slice(0, 8)}…</span>\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n {canApprove && (\n <button\n type=\"button\"\n onClick={() => onApprove(request)}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-text\"\n >\n <CheckCircle2 className=\"size-3.5\" />\n Approve\n </button>\n )}\n {canMarkPaid && (\n <button\n type=\"button\"\n onClick={() => onMarkPaid(request)}\n className=\"inline-flex items-center gap-1.5 rounded-button bg-status-success-bg-subtle border border-status-success-border px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle/70\"\n >\n <Banknote className=\"size-3.5\" />\n Mark as Paid\n </button>\n )}\n {canReject && (\n <button\n type=\"button\"\n onClick={() => onReject(request)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text\"\n >\n <XCircle className=\"size-3.5\" />\n Reject\n </button>\n )}\n </div>\n </div>\n\n {/* Payout account */}\n {request.payoutAccount && <AccountDetails account={request.payoutAccount} />}\n\n {/* User notes */}\n {request.userNotes && (\n <div className=\"rounded-md bg-bg-sunken/40 border border-border-subtle px-3 py-2 text-sm\">\n <span className=\"text-xs font-medium text-text-muted uppercase tracking-wide\">\n User note\n </span>\n <p className=\"mt-1 text-text-primary\">{request.userNotes}</p>\n </div>\n )}\n\n {/* Internal notes / failure / ref */}\n {(request.internalNotes ?? request.failureReason ?? request.externalReference) && (\n <div className=\"grid gap-1 text-xs text-text-muted\">\n {request.externalReference && (\n <div className=\"flex gap-2\">\n <ReceiptText className=\"size-3.5 mt-px shrink-0\" />\n <span>\n Ref:{' '}\n <span className=\"font-mono text-text-primary\">{request.externalReference}</span>\n </span>\n </div>\n )}\n {request.internalNotes && (\n <div className=\"flex gap-2\">\n <span className=\"shrink-0\">Internal note:</span>\n <span className=\"text-text-primary\">{request.internalNotes}</span>\n </div>\n )}\n {request.failureReason && (\n <div className=\"flex gap-2 text-status-error-text\">\n <AlertTriangle className=\"size-3.5 mt-px shrink-0\" />\n <span>{request.failureReason}</span>\n </div>\n )}\n </div>\n )}\n\n {/* Timestamps */}\n {(request.paidAt ?? request.processedAt) && (\n <div className=\"flex flex-wrap gap-4 text-xs text-text-muted\">\n {request.processedAt && (\n <span className=\"flex items-center gap-1\">\n <Clock className=\"size-3\" />\n Processed {formatDateTime(request.processedAt)}\n </span>\n )}\n {request.paidAt && (\n <span className=\"flex items-center gap-1\">\n <CheckCircle2 className=\"size-3\" />\n Paid {formatDateTime(request.paidAt)}\n </span>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction SummaryBar({ summary }: { summary: PayoutAdminSummary }) {\n return (\n <div className=\"grid gap-3 sm:grid-cols-3\">\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Pending payout</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalRequestedAmount, 'USD')}\n </div>\n <div className=\"text-xs text-text-muted mt-0.5\">{summary.pendingCount} requests</div>\n </div>\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Processing</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalProcessingAmount, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-subtle bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs text-text-muted uppercase tracking-wide\">Total paid</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(summary.totalPaidAmount, 'USD')}\n </div>\n {summary.failedCount > 0 && (\n <div className=\"text-xs text-status-error-text mt-0.5\">{summary.failedCount} failed</div>\n )}\n </div>\n </div>\n );\n}\n\nfunction ActionDialog({\n dialog,\n onClose,\n onConfirm,\n}: {\n dialog: ActionDialogState;\n onClose: () => void;\n onConfirm: (data: {\n notes?: string;\n reason?: string;\n externalReference?: string;\n }) => Promise<void>;\n}) {\n const [notes, setNotes] = useState('');\n const [reason, setReason] = useState('');\n const [txnRef, setTxnRef] = useState('');\n const [submitting, setSubmitting] = useState(false);\n\n const handleSubmit = async () => {\n if (dialog.type === 'reject' && !reason.trim()) return;\n setSubmitting(true);\n await onConfirm({\n notes: notes.trim() || undefined,\n reason: reason.trim() || undefined,\n externalReference: txnRef.trim() || undefined,\n });\n setSubmitting(false);\n };\n\n const titles = {\n approve: 'Approve withdrawal request',\n reject: 'Reject withdrawal request',\n mark_paid: 'Mark as paid',\n };\n\n return (\n <ResponsiveDialog\n open\n onOpenChange={(open) => {\n if (!open && !submitting) onClose();\n }}\n >\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{titles[dialog.type]}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {formatCurrency(dialog.amount, dialog.currency)} · {dialog.accountLabel}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n {dialog.type === 'mark_paid' && (\n <div className=\"space-y-3\">\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Transaction reference / UTR number\n </label>\n <input\n type=\"text\"\n value={txnRef}\n onChange={(e) => setTxnRef(e.target.value)}\n placeholder=\"e.g. UTR123456789012, TXN_abc123\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <p className=\"text-xs text-text-muted mt-1\">\n Enter the bank reference number so the user can verify the transfer.\n </p>\n </div>\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Internal notes (optional)\n </label>\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={2}\n placeholder=\"Any internal notes about this payment…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n </div>\n )}\n\n {dialog.type === 'approve' && (\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Internal notes (optional)\n </label>\n <textarea\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder=\"e.g. Verified bank details, approved for transfer…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n )}\n\n {dialog.type === 'reject' && (\n <div>\n <label className=\"text-xs font-medium text-text-primary block mb-1\">\n Reason for rejection <span className=\"text-status-error-text\">*</span>\n </label>\n <textarea\n value={reason}\n onChange={(e) => setReason(e.target.value)}\n rows={3}\n placeholder=\"e.g. Invalid bank details provided, please re-submit with correct IFSC…\"\n className=\"w-full rounded-input border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] resize-none\"\n />\n </div>\n )}\n\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n disabled={submitting}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary disabled:opacity-50\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={() => void handleSubmit()}\n disabled={submitting || (dialog.type === 'reject' && !reason.trim())}\n className={`rounded-md px-4 py-2 text-sm font-medium disabled:opacity-50 ${\n dialog.type === 'reject'\n ? 'bg-action-danger-bg text-action-danger-text'\n : 'bg-action-primary-bg text-action-primary-text'\n }`}\n >\n {submitting\n ? 'Saving…'\n : dialog.type === 'approve'\n ? 'Approve'\n : dialog.type === 'reject'\n ? 'Reject'\n : 'Confirm Payment'}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport const PayoutAdminPage: FC = () => {\n const permissions = useBillingPermissions();\n const { emit } = useBillingEventEmitter();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n\n const [summary, setSummary] = useState<PayoutAdminSummary | null>(null);\n const [requests, setRequests] = useState<PayoutRequest[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [activeTab, setActiveTab] = useState<Tab>('pending');\n const [dialog, setDialog] = useState<ActionDialogState | null>(null);\n\n const requestContext = useMemo(\n () => ({ apiGatewayUrl, authToken, orgId }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [loadedSummary, loadedRequests] = await Promise.all([\n fetchAdminPayoutSummary(requestContext),\n fetchAdminPayoutRequests(requestContext),\n ]);\n setSummary(loadedSummary);\n setRequests(loadedRequests);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load payout queue'));\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, [requestContext]);\n\n if (!permissions.isBillingAdmin) {\n return <AccessDenied message=\"You don't have permission to manage payouts.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Payout queue unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const pending = requests.filter((r) => r.status === 'REQUESTED');\n const approved = requests.filter((r) => r.status === 'APPROVED' || r.status === 'PROCESSING');\n const history = requests.filter((r) =>\n ['PAID', 'REJECTED', 'FAILED', 'CANCELED'].includes(r.status)\n );\n\n const tabItems: { id: Tab; label: string; count: number }[] = [\n { id: 'pending', label: 'Pending', count: pending.length },\n { id: 'approved', label: 'Approved', count: approved.length },\n { id: 'history', label: 'History', count: history.length },\n ];\n\n const visibleRequests =\n activeTab === 'pending' ? pending : activeTab === 'approved' ? approved : history;\n\n const openDialog = (type: ActionDialogState['type'], request: PayoutRequest) => {\n setDialog({\n type,\n requestId: request.id,\n amount: request.requestedAmount,\n currency: request.currency,\n accountLabel:\n request.payoutAccount?.displayName ?? request.payoutAccount?.label ?? 'Unknown account',\n });\n };\n\n const handleConfirm = async (data: {\n notes?: string;\n reason?: string;\n externalReference?: string;\n }) => {\n if (!dialog) return;\n\n try {\n if (dialog.type === 'approve') {\n await approvePayoutRequest(dialog.requestId, data.notes ?? null, requestContext);\n emit('billing.payout.approved', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n });\n } else if (dialog.type === 'reject') {\n await rejectPayoutRequest(dialog.requestId, data.reason ?? '', requestContext);\n emit('billing.payout.rejected', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n reason: data.reason,\n });\n } else if (dialog.type === 'mark_paid') {\n await markPayoutPaid(\n dialog.requestId,\n data.externalReference ?? null,\n data.notes ?? null,\n requestContext\n );\n emit('billing.payout.processed', {\n route: '/billing/payouts',\n entityId: dialog.requestId,\n source: 'payout-admin',\n });\n }\n setDialog(null);\n await loadData();\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Action failed'));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Payout queue\"\n description=\"Review withdrawal requests, verify bank details, and mark payments as paid once transferred.\"\n actions={\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 ${loading ? 'animate-spin' : ''}`} />\n Refresh\n </button>\n }\n />\n\n {summary && !loading && <SummaryBar summary={summary} />}\n\n {loading && (\n <div className=\"grid gap-3 sm:grid-cols-3\">\n {[1, 2, 3].map((i) => (\n <div\n key={i}\n className=\"h-20 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n )}\n\n {error && !isServerError(error) && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n )}\n\n {/* Tabs */}\n <div className=\"border-b border-border-subtle\">\n <div className=\"flex gap-0\">\n {tabItems.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n onClick={() => setActiveTab(tab.id)}\n className={`flex items-center gap-2 border-b-2 px-4 py-2.5 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'border-action-primary-bg text-text-primary'\n : 'border-transparent text-text-muted hover:text-text-primary'\n }`}\n >\n {tab.label}\n {tab.count > 0 && (\n <span\n className={`rounded-full px-1.5 py-0.5 text-xs ${\n activeTab === tab.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.count}\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n\n {/* How to pay — shown only on the Approved tab */}\n {activeTab === 'approved' && approved.length > 0 && (\n <div className=\"rounded-card border border-status-info-border bg-status-info-bg-subtle px-4 py-3 text-sm text-status-info-text\">\n <strong>How to pay:</strong> Click the account row to expand bank/UPI details → transfer\n the exact amount via your bank → click <strong>Mark as Paid</strong> and enter the UTR /\n transaction reference number.\n </div>\n )}\n\n {/* Request cards */}\n {loading ? (\n <div className=\"space-y-4\">\n {[1, 2].map((i) => (\n <div\n key={i}\n className=\"h-40 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : visibleRequests.length === 0 ? (\n <EmptyState\n icon={<CheckCircle2 className=\"size-8\" />}\n title={\n activeTab === 'pending'\n ? 'No pending requests'\n : activeTab === 'approved'\n ? 'No approved requests awaiting payment'\n : 'No history yet'\n }\n description={\n activeTab === 'pending'\n ? 'New withdrawal requests will appear here.'\n : activeTab === 'approved'\n ? 'Approve pending requests first, then send payment and mark as paid.'\n : 'Completed and rejected requests will appear here.'\n }\n />\n ) : (\n <div className=\"space-y-4\">\n {visibleRequests.map((request) => (\n <RequestCard\n key={request.id}\n request={request}\n onApprove={(r) => openDialog('approve', r)}\n onReject={(r) => openDialog('reject', r)}\n onMarkPaid={(r) => openDialog('mark_paid', r)}\n />\n ))}\n </div>\n )}\n\n {dialog && (\n <ActionDialog dialog={dialog} onClose={() => setDialog(null)} onConfirm={handleConfirm} />\n )}\n </div>\n );\n};\n"],"mappings":"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"}