@burdenoff/microfe-billing 2026.912.6 → 2026.914.1

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 (47) hide show
  1. package/dist/billing/BillingAdminRoutes.js +100 -74
  2. package/dist/billing/BillingAdminRoutes.js.map +1 -1
  3. package/dist/billing/modules/billing/hooks/useRefunds.js.map +1 -1
  4. package/dist/billing/modules/billing/index.js +5 -4
  5. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js +90 -87
  6. package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
  7. package/dist/billing/modules/billing/pages/RefundIssueLogsPage.js +240 -0
  8. package/dist/billing/modules/billing/pages/RefundIssueLogsPage.js.map +1 -0
  9. package/dist/billing/modules/billing/pages/RefundsPage.js +116 -108
  10. package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
  11. package/dist/billing/modules/billing/pages/index.js +1 -0
  12. package/dist/billing/modules/checkout/components/OrderSummary.js +22 -19
  13. package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
  14. package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
  15. package/dist/billing/modules/checkout/hooks/useCheckout.js +174 -157
  16. package/dist/billing/modules/checkout/hooks/useCheckout.js.map +1 -1
  17. package/dist/billing/modules/checkout/pages/CheckoutPage.js +189 -182
  18. package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
  19. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js +293 -274
  20. package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
  21. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js +140 -250
  22. package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
  23. package/dist/billing/modules/earnings/api.js +79 -42
  24. package/dist/billing/modules/earnings/api.js.map +1 -1
  25. package/dist/billing/modules/earnings/index.js +4 -3
  26. package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js +103 -310
  27. package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js.map +1 -1
  28. package/dist/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.js +545 -0
  29. package/dist/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.js.map +1 -0
  30. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +246 -196
  31. package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
  32. package/dist/billing/modules/subscriptions/hooks/useSubscriptions.js +44 -28
  33. package/dist/billing/modules/subscriptions/hooks/useSubscriptions.js.map +1 -1
  34. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js +317 -270
  35. package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
  36. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js +153 -150
  37. package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
  38. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js +1 -1
  39. package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
  40. package/dist/billing/modules/usage/hooks/useUsage.js +74 -48
  41. package/dist/billing/modules/usage/hooks/useUsage.js.map +1 -1
  42. package/dist/generated/global-operations.js +221 -183
  43. package/dist/generated/global-operations.js.map +1 -1
  44. package/dist/generated/global-types.js.map +1 -1
  45. package/dist/node_modules/sonner/dist/index.js +163 -0
  46. package/dist/node_modules/sonner/dist/index.js.map +1 -0
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DeveloperRevenueAdminPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/DeveloperRevenueAdminPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { Building2, CreditCard, DollarSign, Loader2, Receipt, Wallet } from 'lucide-react';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader, ServerError } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport {\n PagePurpose,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport {\n fetchAdminDeveloperRevenueOrgDetail,\n fetchAdminDeveloperRevenueOrgs,\n retrySaleCreditSync,\n type AdminDeveloperRevenueOrg,\n type AdminDeveloperRevenueOrgDetail,\n} from '../api';\n\nfunction SummaryCards({ orgs }: { orgs: AdminDeveloperRevenueOrg[] }) {\n const totals = useMemo(\n () =>\n orgs.reduce(\n (acc, org) => ({\n totalRevenue: acc.totalRevenue + org.totalRevenue,\n totalPlatformFees: acc.totalPlatformFees + org.totalPlatformFees,\n pendingBalance: acc.pendingBalance + org.pendingBalance,\n totalPayouts: acc.totalPayouts + org.totalPayouts,\n }),\n { totalRevenue: 0, totalPlatformFees: 0, pendingBalance: 0, totalPayouts: 0 }\n ),\n [orgs]\n );\n\n return (\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-4\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Gross revenue</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <DollarSign className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalRevenue, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Platform fees</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Receipt className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalPlatformFees, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">\n Pending earned credits\n </div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Wallet className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.pendingBalance, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Already withdrawn</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Building2 className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalPayouts, 'USD')}\n </div>\n </div>\n </div>\n );\n}\n\nfunction RevenueDetailDialog({\n org,\n detail,\n loading,\n error,\n retryingSaleId,\n onRetrySale,\n onClose,\n}: {\n org: AdminDeveloperRevenueOrg | null;\n detail: AdminDeveloperRevenueOrgDetail | null;\n loading: boolean;\n error: Error | null;\n retryingSaleId: string | null;\n onRetrySale: (saleId: string) => void;\n onClose: () => void;\n}) {\n return (\n <ResponsiveDialog open={org !== null} onOpenChange={(open) => !open && onClose()}>\n <ResponsiveDialogContent className=\"sm:max-w-4xl\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {org ? `${org.name} revenue details` : 'Revenue details'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Store revenue is credited into the linked billing account as earned credits. Developers\n withdraw those credits later through the billing withdrawal flow.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n {loading ? (\n <div className=\"flex items-center justify-center py-14 text-text-secondary\">\n <Loader2 className=\"size-7 animate-spin\" />\n </div>\n ) : 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 ) : detail && org ? (\n <div className=\"space-y-5\">\n <div className=\"grid gap-3 md:grid-cols-4\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">\n Linked billing account\n </div>\n <div className=\"mt-1 text-sm font-semibold text-text-primary\">\n {org.billingAccountId ? 'Connected' : 'Not linked'}\n </div>\n <div className=\"mt-1 break-all text-xs text-text-muted\">\n {org.billingAccountId ??\n 'Revenue cannot be credited until a billing account is linked.'}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">\n Earned credits awaiting withdrawal\n </div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {formatCurrency(detail.summary?.pendingBalance ?? org.pendingBalance, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Unpaid sales</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {detail.unpaidSales.totalCount}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Total sales</div>\n <div className=\"mt-1 text-lg font-semibold text-text-primary\">\n {detail.summary?.totalSales ?? 0}\n </div>\n </div>\n </div>\n\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <div className=\"flex items-start gap-3\">\n <CreditCard className=\"mt-0.5 size-5 text-text-muted\" />\n <div className=\"space-y-1 text-sm\">\n <p className=\"font-medium text-text-primary\">Correct payout model</p>\n <p className=\"text-text-muted\">\n Revenue from Store sales is posted into the developer organization&apos;s linked\n billing account as <strong>earned credits</strong>. We do not directly send cash\n to developer-org payment methods from this page.\n </p>\n <p className=\"text-text-muted\">\n If the developer wants to cash out, they use the billing withdrawal flow from\n their own billing account and payout methods.\n </p>\n </div>\n </div>\n </div>\n\n <section className=\"rounded-card border border-border-seam bg-bg-surface p-4\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n Sales currently contributing to earned credits\n </h3>\n <p className=\"mt-1 text-xs text-text-muted\">\n These sales represent revenue that should exist as earned credits in the linked\n billing account until the developer withdraws them.\n </p>\n <div className=\"mt-4 overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead className=\"bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted\">\n <tr>\n <th className=\"px-3 py-2\">Application</th>\n <th className=\"px-3 py-2\">Purchased</th>\n <th className=\"px-3 py-2\">Net revenue</th>\n <th className=\"px-3 py-2\">Credit sync</th>\n <th className=\"px-3 py-2\">Status</th>\n </tr>\n </thead>\n <tbody>\n {detail.unpaidSales.items.length === 0 ? (\n <tr>\n <td colSpan={5} className=\"px-3 py-5 text-center text-sm text-text-muted\">\n No outstanding unpaid sales. Revenue has either not started yet or has\n already been withdrawn through billing.\n </td>\n </tr>\n ) : (\n detail.unpaidSales.items.map((sale) => (\n <tr key={sale.id} className=\"border-t border-border-seam\">\n <td className=\"px-3 py-2\">\n <div className=\"font-medium text-text-primary\">\n {sale.application?.name ?? 'Unknown app'}\n </div>\n <div className=\"text-xs text-text-muted\">\n /{sale.application?.slug ?? 'unknown'}\n </div>\n </td>\n <td className=\"px-3 py-2 text-text-secondary\">\n {formatDateTime(sale.purchasedAt)}\n </td>\n <td className=\"px-3 py-2 text-text-primary\">\n {formatCurrency(sale.netAmount, sale.currency)}\n </td>\n <td className=\"px-3 py-2 text-text-secondary\">\n <div>{sale.billingCreditSyncStatus ?? 'UNKNOWN'}</div>\n {sale.billingCreditSyncError && (\n <div className=\"mt-1 text-xs text-status-error-text\">\n {sale.billingCreditSyncError}\n </div>\n )}\n {sale.billingCreditSyncStatus !== 'SYNCED' && org.billingAccountId && (\n <button\n type=\"button\"\n onClick={() => onRetrySale(sale.id)}\n disabled={retryingSaleId === sale.id}\n className=\"mt-2 rounded-md border border-border-subtle px-2 py-1 text-xs font-medium text-text-primary disabled:opacity-50\"\n >\n {retryingSaleId === sale.id ? 'Retrying…' : 'Retry sync'}\n </button>\n )}\n </td>\n <td className=\"px-3 py-2 text-text-secondary\">{sale.status}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </section>\n </div>\n ) : null}\n\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n Close\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport const DeveloperRevenueAdminPage: FC = () => {\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId, navigate, basePath } = useBilling();\n const [orgs, setOrgs] = useState<AdminDeveloperRevenueOrg[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [selectedOrg, setSelectedOrg] = useState<AdminDeveloperRevenueOrg | null>(null);\n const [detail, setDetail] = useState<AdminDeveloperRevenueOrgDetail | null>(null);\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailError, setDetailError] = useState<Error | null>(null);\n const [retryingSaleId, setRetryingSaleId] = useState<string | null>(null);\n\n const requestContext = useMemo(\n () => ({ apiGatewayUrl, authToken, orgId }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadOrgs = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchAdminDeveloperRevenueOrgs(requestContext);\n setOrgs(\n result.filter(\n (org) => org.totalRevenue > 0 || org.pendingBalance > 0 || org.totalPayouts > 0\n )\n );\n } catch (loadError) {\n setError(\n loadError instanceof Error ? loadError : new Error('Failed to load developer revenue')\n );\n } finally {\n setLoading(false);\n }\n }, [requestContext]);\n\n const loadDetail = async (org: AdminDeveloperRevenueOrg) => {\n setSelectedOrg(org);\n setDetailLoading(true);\n setDetailError(null);\n try {\n setDetail(await fetchAdminDeveloperRevenueOrgDetail(org.id, requestContext));\n } catch (loadError) {\n setDetail(null);\n setDetailError(\n loadError instanceof Error ? loadError : new Error('Failed to load revenue detail')\n );\n } finally {\n setDetailLoading(false);\n }\n };\n\n useEffect(() => {\n if (!permissions.isBillingAdmin) return;\n void loadOrgs();\n }, [loadOrgs, permissions.isBillingAdmin]);\n\n if (!permissions.isBillingAdmin) {\n return <AccessDenied message=\"You don't have permission to view developer revenue.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Developer revenue unavailable\"\n message={error.message}\n showRetry\n onRetry={() => void loadOrgs()}\n />\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Developer revenue\"\n description=\"See store-generated revenue across developer organizations and confirm that the earnings are flowing into linked billing accounts as earned credits.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigate?.(`${basePath}/payouts`)}\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 Open billing withdrawal queue\n </button>\n }\n />\n\n <PagePurpose>\n Developer portal revenue does not pay out directly from this page. Each Store sale is\n credited into the developer organization&apos;s linked billing account as earned credits.\n Developers then withdraw those credits later using the billing withdrawal flow and their own\n payout methods.\n </PagePurpose>\n\n {loading ? (\n <div className=\"flex items-center justify-center py-16 text-text-secondary\">\n <Loader2 className=\"size-8 animate-spin\" />\n </div>\n ) : (\n <>\n <SummaryCards orgs={orgs} />\n\n <div className=\"overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]\">\n <div className=\"border-b border-border-seam px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">Organizations</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Click a row to inspect billing linkage and the unpaid sales behind the current\n earned-credit balance.\n </p>\n </div>\n\n {orgs.length === 0 ? (\n <div className=\"px-5 py-12 text-center text-sm text-text-muted\">\n No developer revenue has been recorded yet.\n </div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead className=\"bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted\">\n <tr>\n <th className=\"px-4 py-3\">Organization</th>\n <th className=\"px-4 py-3\">Billing linked</th>\n <th className=\"px-4 py-3\">Revenue</th>\n <th className=\"px-4 py-3\">Platform fee</th>\n <th className=\"px-4 py-3\">Earned credits pending withdrawal</th>\n <th className=\"px-4 py-3\">Already withdrawn</th>\n </tr>\n </thead>\n <tbody>\n {[...orgs]\n .sort((a, b) => b.pendingBalance - a.pendingBalance)\n .map((org) => (\n <tr\n key={org.id}\n className=\"cursor-pointer border-t border-border-seam transition-colors hover:bg-bg-sunken/30\"\n onClick={() => void loadDetail(org)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"font-medium text-text-primary\">{org.name}</div>\n <div className=\"text-xs text-text-muted\">/{org.slug}</div>\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {org.billingAccountId ? 'Yes' : 'No'}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(org.totalRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(org.totalPlatformFees, 'USD')}\n </td>\n <td className=\"px-4 py-3 font-medium text-status-warning-text\">\n {formatCurrency(org.pendingBalance, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(org.totalPayouts, 'USD')}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </>\n )}\n\n <RevenueDetailDialog\n org={selectedOrg}\n detail={detail}\n loading={detailLoading}\n error={detailError}\n retryingSaleId={retryingSaleId}\n onRetrySale={(saleId) => {\n if (!selectedOrg) return;\n void (async () => {\n setRetryingSaleId(saleId);\n setDetailError(null);\n try {\n await retrySaleCreditSync(saleId, requestContext);\n await loadDetail(selectedOrg);\n } catch (retryError) {\n setDetailError(\n retryError instanceof Error ? retryError : new Error('Failed to retry credit sync')\n );\n } finally {\n setRetryingSaleId(null);\n }\n })();\n }}\n onClose={() => {\n setSelectedOrg(null);\n setDetail(null);\n setDetailError(null);\n }}\n />\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"DeveloperRevenueAdminPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/DeveloperRevenueAdminPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { Building2, DollarSign, Loader2, Receipt, Search, Wallet } from 'lucide-react';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader, ServerError } from '../../../shared/components';\nimport { formatCurrency, isServerError } from '../../../shared/utils';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { fetchAdminDeveloperRevenueOrgs, type AdminDeveloperRevenueOrg } from '../api';\n\nfunction SummaryCards({ orgs }: { orgs: AdminDeveloperRevenueOrg[] }) {\n const totals = useMemo(\n () =>\n orgs.reduce(\n (acc, org) => ({\n totalRevenue: acc.totalRevenue + org.totalRevenue,\n totalPlatformFees: acc.totalPlatformFees + org.totalPlatformFees,\n pendingBalance: acc.pendingBalance + org.pendingBalance,\n totalPayouts: acc.totalPayouts + org.totalPayouts,\n }),\n { totalRevenue: 0, totalPlatformFees: 0, pendingBalance: 0, totalPayouts: 0 }\n ),\n [orgs]\n );\n\n return (\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-4\">\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Gross revenue</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <DollarSign className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalRevenue, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Platform fees</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Receipt className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalPlatformFees, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">\n Pending earned credits\n </div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Wallet className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.pendingBalance, 'USD')}\n </div>\n </div>\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-[var(--shadow-elevation-1)]\">\n <div className=\"text-xs uppercase tracking-wide text-text-muted\">Already withdrawn</div>\n <div className=\"mt-1 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Building2 className=\"size-4 text-text-muted\" />\n {formatCurrency(totals.totalPayouts, 'USD')}\n </div>\n </div>\n </div>\n );\n}\n\nexport const DeveloperRevenueAdminPage: FC = () => {\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const navigateTo = useBillingNavigate();\n const [orgs, setOrgs] = useState<AdminDeveloperRevenueOrg[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [search, setSearch] = useState('');\n\n const requestContext = useMemo(\n () => ({ apiGatewayUrl, authToken, orgId }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadOrgs = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchAdminDeveloperRevenueOrgs(requestContext);\n setOrgs(\n result.filter(\n (org) => org.totalRevenue > 0 || org.pendingBalance > 0 || org.totalPayouts > 0\n )\n );\n } catch (loadError) {\n setError(\n loadError instanceof Error ? loadError : new Error('Failed to load developer revenue')\n );\n } finally {\n setLoading(false);\n }\n }, [requestContext]);\n\n useEffect(() => {\n if (!permissions.isBillingAdmin) return;\n void loadOrgs();\n }, [loadOrgs, permissions.isBillingAdmin]);\n\n if (!permissions.isBillingAdmin) {\n return <AccessDenied message=\"You don't have permission to view developer revenue.\" />;\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Developer revenue unavailable\"\n message={error.message}\n showRetry\n onRetry={() => void loadOrgs()}\n />\n );\n }\n\n const normalizedSearch = search.trim().toLowerCase();\n const visibleOrgs = normalizedSearch\n ? orgs.filter(\n (org) =>\n org.name.toLowerCase().includes(normalizedSearch) ||\n org.slug.toLowerCase().includes(normalizedSearch) ||\n org.id.toLowerCase() === normalizedSearch\n )\n : orgs;\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title=\"Developer revenue\"\n description=\"See store-generated revenue across developer organizations and confirm that the earnings are flowing into linked billing accounts as earned credits.\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/payouts')}\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 Open billing withdrawal queue\n </button>\n }\n />\n\n <PagePurpose>\n Developer portal revenue does not pay out directly from this page. Each Store sale is\n credited into the developer organization&apos;s linked billing account as earned credits.\n Developers then withdraw those credits later using the billing withdrawal flow and their own\n payout methods. Open an organization to see its full revenue history, current credit\n balance, and withdrawal status.\n </PagePurpose>\n\n {loading ? (\n <div className=\"flex items-center justify-center py-16 text-text-secondary\">\n <Loader2 className=\"size-8 animate-spin\" />\n </div>\n ) : (\n <>\n <SummaryCards orgs={orgs} />\n\n <div className=\"overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]\">\n <div className=\"border-b border-border-seam px-5 py-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Organizations</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Click a row to open its full revenue analysis — balance, monthly trend, and\n withdrawal history.\n </p>\n </div>\n <div className=\"relative w-full max-w-xs\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-muted\" />\n <input\n type=\"text\"\n value={search}\n onChange={(event) => setSearch(event.target.value)}\n placeholder=\"Search by name, slug, or org ID…\"\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-muted\"\n />\n </div>\n </div>\n </div>\n\n {orgs.length === 0 ? (\n <div className=\"px-5 py-12 text-center text-sm text-text-muted\">\n No developer revenue has been recorded yet.\n </div>\n ) : visibleOrgs.length === 0 ? (\n <div className=\"px-5 py-12 text-center text-sm text-text-muted\">\n No organization matches &quot;{search}&quot;.\n </div>\n ) : (\n <div className=\"overflow-x-auto\">\n <table className=\"min-w-full text-sm\">\n <thead className=\"bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted\">\n <tr>\n <th className=\"px-4 py-3\">Organization</th>\n <th className=\"px-4 py-3\">Billing linked</th>\n <th className=\"px-4 py-3\">Revenue</th>\n <th className=\"px-4 py-3\">Platform fee</th>\n <th className=\"px-4 py-3\">Earned credits pending withdrawal</th>\n <th className=\"px-4 py-3\">Already withdrawn</th>\n </tr>\n </thead>\n <tbody>\n {[...visibleOrgs]\n .sort((a, b) => b.pendingBalance - a.pendingBalance)\n .map((org) => (\n <tr\n key={org.id}\n className=\"cursor-pointer border-t border-border-seam transition-colors hover:bg-bg-sunken/30\"\n onClick={() => navigateTo(`/developer-revenue/${org.id}`)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"font-medium text-text-primary\">{org.name}</div>\n <div className=\"text-xs text-text-muted\">/{org.slug}</div>\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {org.billingAccountId ? 'Yes' : 'No'}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(org.totalRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(org.totalPlatformFees, 'USD')}\n </td>\n <td className=\"px-4 py-3 font-medium text-status-warning-text\">\n {formatCurrency(org.pendingBalance, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(org.totalPayouts, 'USD')}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,545 @@
1
+ import { useBilling as e } from "../../../providers/BillingProvider.js";
2
+ import { AccessDenied as t } from "../../../shared/components/AccessDenied.js";
3
+ import { PageHeader as n } from "../../../shared/components/PageHeader.js";
4
+ import { StatCard as r } from "../../../shared/components/StatCard.js";
5
+ import { ServerError as i } from "../../../shared/components/ServerError.js";
6
+ import "../../../shared/components/index.js";
7
+ import { formatCredits as a, formatCurrency as o, formatDateTime as s } from "../../../shared/utils/format.js";
8
+ import { isServerError as ee } from "../../../shared/utils/error.js";
9
+ import "../../../shared/utils/index.js";
10
+ import { useBillingPermissions as te } from "../../../hooks/useBillingPermissions.js";
11
+ import { useBillingNavigate as ne } from "../../../hooks/useBillingNavigate.js";
12
+ import { fetchAdminDeveloperRevenueOrg as re, fetchAdminDeveloperRevenueOrgDetail as c, fetchAdminDeveloperRevenueOrgMonthly as l, fetchAdminPayoutRequests as u, fetchBillingAccountCreditBalance as ie, fetchCreditCost as ae, retrySaleCreditSync as oe } from "../api.js";
13
+ import { useCallback as d, useEffect as f, useMemo as p, useState as m } from "react";
14
+ import { ArrowLeft as h, BadgeCheck as se, CreditCard as ce, Loader2 as g, TrendingDown as _, TrendingUp as v, Wallet as le } from "lucide-react";
15
+ import { useParams as ue } from "react-router";
16
+ import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
17
+ import { PagePurpose as S } from "@burdenoff/fe-libs/ui";
18
+ //#region src/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.tsx
19
+ var C = "all", w = {
20
+ REQUESTED: "Requested",
21
+ APPROVED: "Approved",
22
+ REJECTED: "Rejected",
23
+ PROCESSING: "Processing",
24
+ PAID: "Paid",
25
+ FAILED: "Failed",
26
+ CANCELED: "Canceled"
27
+ }, T = {
28
+ REQUESTED: "bg-status-warning-bg-subtle text-status-warning-text",
29
+ APPROVED: "bg-status-info-bg-subtle text-status-info-text",
30
+ REJECTED: "bg-status-error-bg-subtle text-status-error-text",
31
+ PROCESSING: "bg-status-info-bg-subtle text-status-info-text",
32
+ PAID: "bg-status-success-bg-subtle text-status-success-text",
33
+ FAILED: "bg-status-error-bg-subtle text-status-error-text",
34
+ CANCELED: "bg-bg-sunken text-text-muted"
35
+ };
36
+ function E({ status: e }) {
37
+ return /* @__PURE__ */ b("span", {
38
+ className: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${T[e] ?? "bg-bg-sunken text-text-muted"}`,
39
+ children: w[e] ?? e
40
+ });
41
+ }
42
+ function D(e) {
43
+ return new Date(e).toLocaleDateString("en-US", {
44
+ month: "short",
45
+ year: "numeric"
46
+ });
47
+ }
48
+ function de(e) {
49
+ if (e === C) return {};
50
+ let t = new Date(e);
51
+ return Number.isNaN(t.getTime()) ? {} : {
52
+ startDate: new Date(Date.UTC(t.getUTCFullYear(), t.getUTCMonth(), 1)).toISOString(),
53
+ endDate: (/* @__PURE__ */ new Date(Date.UTC(t.getUTCFullYear(), t.getUTCMonth() + 1, 1) - 1)).toISOString()
54
+ };
55
+ }
56
+ function fe({ points: e }) {
57
+ return e.length === 0 ? /* @__PURE__ */ b("div", {
58
+ className: "px-5 py-10 text-center text-sm text-text-muted",
59
+ children: "No sales recorded yet — the revenue trend will appear once the first sale comes in."
60
+ }) : /* @__PURE__ */ b("div", {
61
+ className: "overflow-x-auto",
62
+ children: /* @__PURE__ */ x("table", {
63
+ className: "min-w-full text-sm",
64
+ children: [/* @__PURE__ */ b("thead", {
65
+ className: "bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted",
66
+ children: /* @__PURE__ */ x("tr", { children: [
67
+ /* @__PURE__ */ b("th", {
68
+ className: "px-4 py-3",
69
+ children: "Month"
70
+ }),
71
+ /* @__PURE__ */ b("th", {
72
+ className: "px-4 py-3",
73
+ children: "Gross revenue"
74
+ }),
75
+ /* @__PURE__ */ b("th", {
76
+ className: "px-4 py-3",
77
+ children: "Platform fee"
78
+ }),
79
+ /* @__PURE__ */ b("th", {
80
+ className: "px-4 py-3",
81
+ children: "Net revenue"
82
+ }),
83
+ /* @__PURE__ */ b("th", {
84
+ className: "px-4 py-3",
85
+ children: "Sales"
86
+ }),
87
+ /* @__PURE__ */ b("th", {
88
+ className: "px-4 py-3",
89
+ children: "Growth (MoM)"
90
+ })
91
+ ] })
92
+ }), /* @__PURE__ */ b("tbody", { children: e.map((t, n) => {
93
+ let r = n > 0 ? e[n - 1] : null, i = r && r.grossRevenue > 0 ? (t.grossRevenue - r.grossRevenue) / r.grossRevenue * 100 : null;
94
+ return /* @__PURE__ */ x("tr", {
95
+ className: "border-t border-border-seam",
96
+ children: [
97
+ /* @__PURE__ */ b("td", {
98
+ className: "px-4 py-3 font-medium text-text-primary",
99
+ children: D(t.month)
100
+ }),
101
+ /* @__PURE__ */ b("td", {
102
+ className: "px-4 py-3 text-text-primary",
103
+ children: o(t.grossRevenue, "USD")
104
+ }),
105
+ /* @__PURE__ */ b("td", {
106
+ className: "px-4 py-3 text-text-secondary",
107
+ children: o(t.platformFees, "USD")
108
+ }),
109
+ /* @__PURE__ */ b("td", {
110
+ className: "px-4 py-3 text-text-secondary",
111
+ children: o(t.netRevenue, "USD")
112
+ }),
113
+ /* @__PURE__ */ b("td", {
114
+ className: "px-4 py-3 text-text-secondary",
115
+ children: t.salesCount
116
+ }),
117
+ /* @__PURE__ */ b("td", {
118
+ className: "px-4 py-3",
119
+ children: i === null ? /* @__PURE__ */ b("span", {
120
+ className: "text-text-muted",
121
+ children: "—"
122
+ }) : /* @__PURE__ */ x("span", {
123
+ className: `inline-flex items-center gap-1 font-medium ${i >= 0 ? "text-status-success-text" : "text-status-error-text"}`,
124
+ children: [
125
+ b(i >= 0 ? v : _, { className: "size-3.5" }),
126
+ i >= 0 ? "+" : "",
127
+ i.toFixed(1),
128
+ "%"
129
+ ]
130
+ })
131
+ })
132
+ ]
133
+ }, t.month);
134
+ }) })]
135
+ })
136
+ });
137
+ }
138
+ function pe({ requests: e }) {
139
+ return e.length === 0 ? /* @__PURE__ */ b("div", {
140
+ className: "px-5 py-10 text-center text-sm text-text-muted",
141
+ children: "No withdrawal requests in this period."
142
+ }) : /* @__PURE__ */ b("div", {
143
+ className: "overflow-x-auto",
144
+ children: /* @__PURE__ */ x("table", {
145
+ className: "min-w-full text-sm",
146
+ children: [/* @__PURE__ */ b("thead", {
147
+ className: "bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted",
148
+ children: /* @__PURE__ */ x("tr", { children: [
149
+ /* @__PURE__ */ b("th", {
150
+ className: "px-4 py-3",
151
+ children: "Requested"
152
+ }),
153
+ /* @__PURE__ */ b("th", {
154
+ className: "px-4 py-3",
155
+ children: "Kind"
156
+ }),
157
+ /* @__PURE__ */ b("th", {
158
+ className: "px-4 py-3",
159
+ children: "Amount"
160
+ }),
161
+ /* @__PURE__ */ b("th", {
162
+ className: "px-4 py-3",
163
+ children: "Status"
164
+ }),
165
+ /* @__PURE__ */ b("th", {
166
+ className: "px-4 py-3",
167
+ children: "Paid"
168
+ }),
169
+ /* @__PURE__ */ b("th", {
170
+ className: "px-4 py-3",
171
+ children: "Notes"
172
+ })
173
+ ] })
174
+ }), /* @__PURE__ */ b("tbody", { children: e.map((e) => /* @__PURE__ */ x("tr", {
175
+ className: "border-t border-border-seam",
176
+ children: [
177
+ /* @__PURE__ */ b("td", {
178
+ className: "px-4 py-3 text-text-secondary",
179
+ children: s(e.createdAt)
180
+ }),
181
+ /* @__PURE__ */ b("td", {
182
+ className: "px-4 py-3 text-text-secondary",
183
+ children: e.requestKind === "CREDIT_CONVERSION" ? "Revenue-share credits" : "Cash payout"
184
+ }),
185
+ /* @__PURE__ */ b("td", {
186
+ className: "px-4 py-3 font-medium text-text-primary",
187
+ children: o(e.requestedAmount, e.currency)
188
+ }),
189
+ /* @__PURE__ */ b("td", {
190
+ className: "px-4 py-3",
191
+ children: /* @__PURE__ */ b(E, { status: e.status })
192
+ }),
193
+ /* @__PURE__ */ b("td", {
194
+ className: "px-4 py-3 text-text-secondary",
195
+ children: e.paidAt ? s(e.paidAt) : "—"
196
+ }),
197
+ /* @__PURE__ */ b("td", {
198
+ className: "px-4 py-3 text-text-muted",
199
+ children: e.failureReason || e.userNotes || "—"
200
+ })
201
+ ]
202
+ }, e.id)) })]
203
+ })
204
+ });
205
+ }
206
+ var O = () => {
207
+ let { organizationId: _ } = ue(), w = te(), { apiGatewayUrl: T, authToken: E, orgId: O } = e(), k = ne(), [A, j] = m(null), [M, N] = m([]), [P, F] = m(null), [I, L] = m(null), [R, z] = m([]), [B, me] = m(null), [he, ge] = m([]), [V, H] = m(C), [_e, U] = m(!0), [W, G] = m(!1), [K, q] = m(null), [J, Y] = m(null), X = p(() => ({
208
+ apiGatewayUrl: T,
209
+ authToken: E,
210
+ orgId: O
211
+ }), [
212
+ T,
213
+ E,
214
+ O
215
+ ]), Z = d(async (e, t, n) => {
216
+ let r = de(n), [i, a] = await Promise.all([c(e, X, r), t ? u(X, {
217
+ limit: 100,
218
+ filter: {
219
+ billingAccountId: t,
220
+ ...r
221
+ }
222
+ }) : Promise.resolve({
223
+ items: [],
224
+ totalCount: 0,
225
+ hasMore: !1
226
+ })]);
227
+ me(i), ge(a.items);
228
+ }, [X]), Q = d(async () => {
229
+ if (_) {
230
+ U(!0), q(null);
231
+ try {
232
+ let [e, t] = await Promise.all([re(_, X), l(_, X, 12)]);
233
+ j(e), N(t);
234
+ let n = e?.billingAccountId ?? null, r = t.length > 0 ? t[t.length - 1].month : C;
235
+ H(r);
236
+ let [i, a] = await Promise.all([
237
+ n ? ie(n, X) : Promise.resolve(null),
238
+ n ? u(X, {
239
+ limit: 100,
240
+ filter: { billingAccountId: n }
241
+ }) : Promise.resolve({
242
+ items: [],
243
+ totalCount: 0,
244
+ hasMore: !1
245
+ }),
246
+ Z(_, n, r)
247
+ ]);
248
+ F(i), z(a.items), i && i.total > 0 ? ae(i.total, "USD", X).then(L).catch(() => L(null)) : L(0);
249
+ } catch (e) {
250
+ q(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load revenue detail"));
251
+ } finally {
252
+ U(!1);
253
+ }
254
+ }
255
+ }, [
256
+ _,
257
+ X,
258
+ Z
259
+ ]);
260
+ f(() => {
261
+ w.isBillingAdmin && Q();
262
+ }, [Q, w.isBillingAdmin]);
263
+ let ve = (e) => {
264
+ !_ || !A || (H(e), G(!0), Z(_, A.billingAccountId, e).catch((e) => {
265
+ q(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load period data"));
266
+ }).finally(() => G(!1)));
267
+ };
268
+ if (!w.isBillingAdmin) return /* @__PURE__ */ b(t, { message: "You don't have permission to view developer revenue." });
269
+ if (K && ee(K)) return /* @__PURE__ */ b(i, {
270
+ title: "Developer revenue unavailable",
271
+ message: K.message,
272
+ showRetry: !0,
273
+ onRetry: () => void Q()
274
+ });
275
+ if (_e || !A) return /* @__PURE__ */ b("div", {
276
+ className: "flex items-center justify-center py-20 text-text-secondary",
277
+ children: /* @__PURE__ */ b(g, { className: "size-8 animate-spin" })
278
+ });
279
+ let ye = R.filter((e) => e.status === "PAID").reduce((e, t) => e + (t.approvedAmount ?? t.requestedAmount), 0), $ = R.filter((e) => [
280
+ "REQUESTED",
281
+ "APPROVED",
282
+ "PROCESSING"
283
+ ].includes(e.status)).reduce((e, t) => e + t.requestedAmount, 0), be = [...M].reverse();
284
+ return /* @__PURE__ */ x("div", {
285
+ className: "space-y-6 p-6",
286
+ children: [
287
+ /* @__PURE__ */ b(n, {
288
+ title: A.name,
289
+ description: `/${A.slug}${A.isVerified ? " · Verified developer organization" : ""}`,
290
+ actions: /* @__PURE__ */ x("button", {
291
+ type: "button",
292
+ onClick: () => k("/developer-revenue"),
293
+ className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary",
294
+ children: [/* @__PURE__ */ b(h, { className: "size-4" }), "Back to developer revenue"]
295
+ })
296
+ }),
297
+ /* @__PURE__ */ b(S, { children: "Store revenue for this org is credited into its linked billing account as earned credits. The developer withdraws those credits later through their own billing withdrawal flow — this page is a read-and-verify view of that whole loop, from sale to payout." }),
298
+ /* @__PURE__ */ x("div", {
299
+ className: "grid gap-3 md:grid-cols-2 xl:grid-cols-4",
300
+ children: [
301
+ /* @__PURE__ */ b(r, {
302
+ label: "Gross revenue (all time)",
303
+ value: o(A.totalRevenue, "USD"),
304
+ icon: /* @__PURE__ */ b(v, { className: "size-4" })
305
+ }),
306
+ /* @__PURE__ */ b(r, {
307
+ label: "Platform fees (all time)",
308
+ value: o(A.totalPlatformFees, "USD"),
309
+ icon: /* @__PURE__ */ b(ce, { className: "size-4" })
310
+ }),
311
+ /* @__PURE__ */ b(r, {
312
+ label: "Pending earned credits",
313
+ value: o(B?.summary?.pendingBalance ?? A.pendingBalance, "USD"),
314
+ icon: /* @__PURE__ */ b(le, { className: "size-4" })
315
+ }),
316
+ /* @__PURE__ */ b(r, {
317
+ label: "Already withdrawn (all time)",
318
+ value: o(ye, "USD"),
319
+ icon: /* @__PURE__ */ b(se, { className: "size-4" })
320
+ })
321
+ ]
322
+ }),
323
+ /* @__PURE__ */ x("section", {
324
+ className: "overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]",
325
+ children: [
326
+ /* @__PURE__ */ x("div", {
327
+ className: "border-b border-border-seam px-5 py-4",
328
+ children: [/* @__PURE__ */ b("h2", {
329
+ className: "text-base font-semibold text-text-primary",
330
+ children: "Billing account balance"
331
+ }), /* @__PURE__ */ b("p", {
332
+ className: "mt-1 text-sm text-text-muted",
333
+ children: "The current credit ledger on the org's linked billing account, right now. These are credit units, not currency — 1 credit is worth a small fraction of $1 at the platform's current credit rate."
334
+ })]
335
+ }),
336
+ A.billingAccountId ? P ? /* @__PURE__ */ x(y, { children: [/* @__PURE__ */ x("div", {
337
+ className: "grid gap-3 p-5 md:grid-cols-3 xl:grid-cols-5",
338
+ children: [
339
+ /* @__PURE__ */ b(r, {
340
+ label: "Earned",
341
+ value: a(P.earned)
342
+ }),
343
+ /* @__PURE__ */ b(r, {
344
+ label: "Purchased",
345
+ value: a(P.purchased)
346
+ }),
347
+ /* @__PURE__ */ b(r, {
348
+ label: "Granted",
349
+ value: a(P.granted)
350
+ }),
351
+ /* @__PURE__ */ b(r, {
352
+ label: "Withdrawable",
353
+ value: a(P.withdrawable)
354
+ }),
355
+ /* @__PURE__ */ b(r, {
356
+ label: "Total balance",
357
+ value: a(P.total)
358
+ })
359
+ ]
360
+ }), /* @__PURE__ */ b("div", {
361
+ className: "px-5 pb-4 text-xs text-text-muted",
362
+ children: I === null ? "Estimated cash value could not be loaded." : `≈ ${o(I, "USD")} total at the current credit rate.`
363
+ })] }) : /* @__PURE__ */ b("div", {
364
+ className: "px-5 py-8 text-center text-sm text-text-muted",
365
+ children: "Credit balance could not be loaded."
366
+ }) : /* @__PURE__ */ b("div", {
367
+ className: "px-5 py-8 text-center text-sm text-text-muted",
368
+ children: "No billing account is linked yet — revenue cannot be credited until this org links one."
369
+ }),
370
+ $ > 0 && /* @__PURE__ */ x("div", {
371
+ className: "border-t border-border-seam bg-status-warning-bg-subtle px-5 py-3 text-xs text-status-warning-text",
372
+ children: [o($, "USD"), " is currently tied up in a pending or approved withdrawal request — it has already left the withdrawable balance above."]
373
+ })
374
+ ]
375
+ }),
376
+ /* @__PURE__ */ x("section", {
377
+ className: "overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]",
378
+ children: [/* @__PURE__ */ x("div", {
379
+ className: "border-b border-border-seam px-5 py-4",
380
+ children: [/* @__PURE__ */ b("h2", {
381
+ className: "text-base font-semibold text-text-primary",
382
+ children: "Monthly revenue trend"
383
+ }), /* @__PURE__ */ b("p", {
384
+ className: "mt-1 text-sm text-text-muted",
385
+ children: "Last 12 months of gross/net revenue for this org, computed from completed sales."
386
+ })]
387
+ }), /* @__PURE__ */ b(fe, { points: M })]
388
+ }),
389
+ /* @__PURE__ */ x("div", {
390
+ className: "flex flex-wrap items-center justify-between gap-3 rounded-card border border-border-seam bg-bg-surface px-5 py-4 shadow-[var(--shadow-elevation-1)]",
391
+ children: [/* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("h2", {
392
+ className: "text-sm font-semibold text-text-primary",
393
+ children: "Viewing activity for"
394
+ }), /* @__PURE__ */ b("p", {
395
+ className: "mt-1 text-xs text-text-muted",
396
+ children: "Scopes both the withdrawal history and sales tables below — pick a single month to keep long-running orgs easy to review, or switch to all time."
397
+ })] }), /* @__PURE__ */ x("div", {
398
+ className: "flex items-center gap-2",
399
+ children: [W && /* @__PURE__ */ b(g, { className: "size-4 animate-spin text-text-muted" }), /* @__PURE__ */ x("select", {
400
+ value: V,
401
+ onChange: (e) => ve(e.target.value),
402
+ disabled: W,
403
+ className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary disabled:opacity-50",
404
+ children: [/* @__PURE__ */ b("option", {
405
+ value: C,
406
+ children: "All time"
407
+ }), be.map((e) => /* @__PURE__ */ b("option", {
408
+ value: e.month,
409
+ children: D(e.month)
410
+ }, e.month))]
411
+ })]
412
+ })]
413
+ }),
414
+ /* @__PURE__ */ x("section", {
415
+ className: "overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]",
416
+ children: [/* @__PURE__ */ x("div", {
417
+ className: "border-b border-border-seam px-5 py-4",
418
+ children: [/* @__PURE__ */ b("h2", {
419
+ className: "text-base font-semibold text-text-primary",
420
+ children: "Withdrawal history"
421
+ }), /* @__PURE__ */ x("p", {
422
+ className: "mt-1 text-sm text-text-muted",
423
+ children: [
424
+ "Payout requests this org made in",
425
+ " ",
426
+ V === C ? "all time" : D(V),
427
+ " — both revenue-share credit conversions and cash payouts — with current status."
428
+ ]
429
+ })]
430
+ }), /* @__PURE__ */ b("div", {
431
+ className: W ? "pointer-events-none opacity-50" : void 0,
432
+ children: /* @__PURE__ */ b(pe, { requests: he })
433
+ })]
434
+ }),
435
+ /* @__PURE__ */ x("section", {
436
+ className: "overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-[var(--shadow-elevation-1)]",
437
+ children: [/* @__PURE__ */ x("div", {
438
+ className: "border-b border-border-seam px-5 py-4",
439
+ children: [/* @__PURE__ */ b("h2", {
440
+ className: "text-base font-semibold text-text-primary",
441
+ children: "Sales currently contributing to earned credits"
442
+ }), /* @__PURE__ */ x("p", {
443
+ className: "mt-1 text-xs text-text-muted",
444
+ children: [
445
+ "Unpaid sales purchased in",
446
+ " ",
447
+ V === C ? "all time" : D(V),
448
+ " that should exist as earned credits in the linked billing account until the developer withdraws them."
449
+ ]
450
+ })]
451
+ }), /* @__PURE__ */ b("div", {
452
+ className: `overflow-x-auto ${W ? "pointer-events-none opacity-50" : ""}`,
453
+ children: /* @__PURE__ */ x("table", {
454
+ className: "min-w-full text-sm",
455
+ children: [/* @__PURE__ */ b("thead", {
456
+ className: "bg-bg-sunken/60 text-left text-xs uppercase tracking-wide text-text-muted",
457
+ children: /* @__PURE__ */ x("tr", { children: [
458
+ /* @__PURE__ */ b("th", {
459
+ className: "px-4 py-3",
460
+ children: "Application"
461
+ }),
462
+ /* @__PURE__ */ b("th", {
463
+ className: "px-4 py-3",
464
+ children: "Purchased"
465
+ }),
466
+ /* @__PURE__ */ b("th", {
467
+ className: "px-4 py-3",
468
+ children: "Net revenue"
469
+ }),
470
+ /* @__PURE__ */ b("th", {
471
+ className: "px-4 py-3",
472
+ children: "Credit sync"
473
+ }),
474
+ /* @__PURE__ */ b("th", {
475
+ className: "px-4 py-3",
476
+ children: "Status"
477
+ })
478
+ ] })
479
+ }), /* @__PURE__ */ b("tbody", { children: !B || B.unpaidSales.items.length === 0 ? /* @__PURE__ */ b("tr", { children: /* @__PURE__ */ b("td", {
480
+ colSpan: 5,
481
+ className: "px-4 py-8 text-center text-sm text-text-muted",
482
+ children: "No outstanding unpaid sales in this period."
483
+ }) }) : B.unpaidSales.items.map((e) => /* @__PURE__ */ x("tr", {
484
+ className: "border-t border-border-seam",
485
+ children: [
486
+ /* @__PURE__ */ x("td", {
487
+ className: "px-4 py-3",
488
+ children: [/* @__PURE__ */ b("div", {
489
+ className: "font-medium text-text-primary",
490
+ children: e.application?.name ?? "Unknown app"
491
+ }), /* @__PURE__ */ x("div", {
492
+ className: "text-xs text-text-muted",
493
+ children: ["/", e.application?.slug ?? "unknown"]
494
+ })]
495
+ }),
496
+ /* @__PURE__ */ b("td", {
497
+ className: "px-4 py-3 text-text-secondary",
498
+ children: s(e.purchasedAt)
499
+ }),
500
+ /* @__PURE__ */ b("td", {
501
+ className: "px-4 py-3 text-text-primary",
502
+ children: o(e.netAmount, e.currency)
503
+ }),
504
+ /* @__PURE__ */ x("td", {
505
+ className: "px-4 py-3 text-text-secondary",
506
+ children: [
507
+ /* @__PURE__ */ b("div", { children: e.billingCreditSyncStatus ?? "UNKNOWN" }),
508
+ e.billingCreditSyncError && /* @__PURE__ */ b("div", {
509
+ className: "mt-1 text-xs text-status-error-text",
510
+ children: e.billingCreditSyncError
511
+ }),
512
+ e.billingCreditSyncStatus !== "SYNCED" && A.billingAccountId && /* @__PURE__ */ b("button", {
513
+ type: "button",
514
+ onClick: () => {
515
+ _ && (async () => {
516
+ Y(e.id);
517
+ try {
518
+ await oe(e.id, X), await Z(_, A.billingAccountId, V);
519
+ } finally {
520
+ Y(null);
521
+ }
522
+ })();
523
+ },
524
+ disabled: J === e.id,
525
+ className: "mt-2 rounded-md border border-border-subtle px-2 py-1 text-xs font-medium text-text-primary disabled:opacity-50",
526
+ children: J === e.id ? "Retrying…" : "Retry sync"
527
+ })
528
+ ]
529
+ }),
530
+ /* @__PURE__ */ b("td", {
531
+ className: "px-4 py-3 text-text-secondary",
532
+ children: e.status
533
+ })
534
+ ]
535
+ }, e.id)) })]
536
+ })
537
+ })]
538
+ })
539
+ ]
540
+ });
541
+ };
542
+ //#endregion
543
+ export { O as DeveloperRevenueOrgDetailPage };
544
+
545
+ //# sourceMappingURL=DeveloperRevenueOrgDetailPage.js.map