@burdenoff/microfe-billing 2026.821.1 → 2026.825.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.
- package/dist/billing/BillingAdminRoutes.js.map +1 -1
- package/dist/billing/BillingRoot.js.map +1 -1
- package/dist/billing/BillingUserRoutes.js.map +1 -1
- package/dist/billing/hooks/useBillingAccountSelection.js.map +1 -1
- package/dist/billing/hooks/useBillingEventEmitter.js.map +1 -1
- package/dist/billing/hooks/useBillingNavigate.js.map +1 -1
- package/dist/billing/hooks/useBillingPermissions.js.map +1 -1
- package/dist/billing/hooks/useDefaultBillingCurrency.js.map +1 -1
- package/dist/billing/modules/addons/components/FloatingCartDrawer.js.map +1 -1
- package/dist/billing/modules/addons/hooks/useAddons.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonCreatePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonDetailPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonEditPage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsBrowsePage.js.map +1 -1
- package/dist/billing/modules/addons/pages/AddonsListPage.js.map +1 -1
- package/dist/billing/modules/addons/store/addonCartStore.js.map +1 -1
- package/dist/billing/modules/affiliate/api.js.map +1 -1
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js +107 -107
- package/dist/billing/modules/affiliate/pages/AffiliateDashboardPage.js.map +1 -1
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js +80 -81
- package/dist/billing/modules/analytics/pages/AnalyticsPage.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useInvoices.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useRefunds.js.map +1 -1
- package/dist/billing/modules/billing/hooks/useTransactions.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoiceDetailPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js +1 -1
- package/dist/billing/modules/billing/pages/InvoicesListPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/PaymentMethodsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/RefundsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/TransactionsPage.js.map +1 -1
- package/dist/billing/modules/billing/pages/UserRefundsPage.js +127 -127
- package/dist/billing/modules/billing/pages/UserRefundsPage.js.map +1 -1
- package/dist/billing/modules/checkout/components/BillingAccountSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/CompleteBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/checkout/components/CreditsAmountInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/NativeCheckoutView.js.map +1 -1
- package/dist/billing/modules/checkout/components/OrderSummary.js.map +1 -1
- package/dist/billing/modules/checkout/components/PromoCodeInput.js.map +1 -1
- package/dist/billing/modules/checkout/components/RazorpayPaymentButton.js.map +1 -1
- package/dist/billing/modules/checkout/components/SimpleAutoPayToggle.js.map +1 -1
- package/dist/billing/modules/checkout/components/StoreShippingSection.js.map +1 -1
- package/dist/billing/modules/checkout/components/StripePaymentForm.js.map +1 -1
- package/dist/billing/modules/checkout/components/SubscriptionSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/UnifiedPaymentMethodSelector.js.map +1 -1
- package/dist/billing/modules/checkout/components/WorkspaceQuotaAssignmentModal.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useCheckout.js +0 -1
- package/dist/billing/modules/checkout/hooks/useCheckout.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useNativeCheckout.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/usePaymentProviders.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/usePaymentStatusPolling.js.map +1 -1
- package/dist/billing/modules/checkout/hooks/useStoreShipping.js.map +1 -1
- package/dist/billing/modules/checkout/pages/CheckoutPage.js +412 -395
- package/dist/billing/modules/checkout/pages/CheckoutPage.js.map +1 -1
- package/dist/billing/modules/checkout/utils/storeOrder.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponDetailPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CouponsListPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/CreateCouponPage.js.map +1 -1
- package/dist/billing/modules/coupons/pages/EditCouponPage.js.map +1 -1
- package/dist/billing/modules/credits/hooks/useCredits.js.map +1 -1
- package/dist/billing/modules/credits/pages/AdminCreditsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditTransactionsPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditsPage.js.map +1 -1
- package/dist/billing/modules/dashboard/components/ActiveSubscriptionCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/AddPaymentMethodModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/BillingAccountCard.js.map +1 -1
- package/dist/billing/modules/dashboard/components/CreateBillingAccountModal.js.map +1 -1
- package/dist/billing/modules/dashboard/components/PaymentMethodsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/components/RecommendedAddonsSection.js.map +1 -1
- package/dist/billing/modules/dashboard/hooks/useBillingOverviewData.js.map +1 -1
- package/dist/billing/modules/dashboard/hooks/useDashboard.js.map +1 -1
- package/dist/billing/modules/dashboard/pages/OverviewPage.js.map +1 -1
- package/dist/billing/modules/discounts/pages/DiscountsListPage.js.map +1 -1
- package/dist/billing/modules/earnings/api.js.map +1 -1
- package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js +145 -145
- package/dist/billing/modules/earnings/pages/DeveloperRevenueAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +133 -133
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +7 -9
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutsPage.js +95 -95
- package/dist/billing/modules/earnings/pages/PayoutsPage.js.map +1 -1
- package/dist/billing/modules/plans/constants/featuredQuotas.js.map +1 -1
- package/dist/billing/modules/plans/hooks/usePlans.js.map +1 -1
- package/dist/billing/modules/plans/hooks/useQuotas.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanAssignFreePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanBrowseDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanCreatePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanDetailPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlanEditPage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansBrowsePage.js.map +1 -1
- package/dist/billing/modules/plans/pages/PlansListPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/CreatePromotionPage.js.map +1 -1
- package/dist/billing/modules/promotions/pages/PromotionsListPage.js.map +1 -1
- package/dist/billing/modules/quota/hooks/useQuotaTemplates.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaAssignFreePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateCreatePage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateDetailPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplateEditPage.js.map +1 -1
- package/dist/billing/modules/quota/pages/QuotaTemplatesListPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/SettingsPage.js.map +1 -1
- package/dist/billing/modules/settings/pages/TeamPermissionsPage.js.map +1 -1
- package/dist/billing/modules/store/pages/StoreCheckoutPage.js +5 -6
- package/dist/billing/modules/store/pages/StoreCheckoutPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/components/ManageSeatsModal.js.map +1 -1
- package/dist/billing/modules/subscriptions/hooks/useSubscriptions.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionDetailPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/SubscriptionsListPage.js.map +1 -1
- package/dist/billing/modules/subscriptions/pages/UpgradeSubscriptionPage.js.map +1 -1
- package/dist/billing/modules/usage/hooks/useUsage.js +14 -9
- package/dist/billing/modules/usage/hooks/useUsage.js.map +1 -1
- package/dist/billing/modules/usage/pages/UsagePage.js +481 -453
- package/dist/billing/modules/usage/pages/UsagePage.js.map +1 -1
- package/dist/billing/providers/BillingProvider.js.map +1 -1
- package/dist/billing/shared/components/AccessDenied.js.map +1 -1
- package/dist/billing/shared/components/ActorIdentity.js.map +1 -1
- package/dist/billing/shared/components/CurrencyPriceOverridesEditor.js.map +1 -1
- package/dist/billing/shared/components/EmptyState.js.map +1 -1
- package/dist/billing/shared/components/PageHeader.js.map +1 -1
- package/dist/billing/shared/components/ServerError.js.map +1 -1
- package/dist/billing/shared/components/StatCard.js.map +1 -1
- package/dist/billing/shared/hooks/useActorProfiles.js.map +1 -1
- package/dist/billing/shared/types/graphql.js.map +1 -1
- package/dist/billing/shared/ui/Card.js.map +1 -1
- package/dist/billing/shared/ui/MetricCard.js.map +1 -1
- package/dist/billing/shared/ui/ProgressBar.js.map +1 -1
- package/dist/billing/shared/ui/StatusPill.js.map +1 -1
- package/dist/billing/shared/utils/directBillingGraphql.js.map +1 -1
- package/dist/billing/shared/utils/error.js.map +1 -1
- package/dist/billing/shared/utils/format.js.map +1 -1
- package/dist/billing/shared/utils/gatewayGraphql.js.map +1 -1
- package/dist/billing/shared/utils/navigation.js.map +1 -1
- package/dist/billing/shared/utils/paymentTheme.js.map +1 -1
- package/dist/billing/shared/utils/planFeatureQuantity.js.map +1 -1
- package/dist/billing/shared/utils/status.js.map +1 -1
- package/dist/billing/shared/utils/tokens.js.map +1 -1
- package/dist/generated/global-operations.js +5 -1
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.js.map +1 -1
- package/dist/generated/wspace-operations.js +1 -1
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/node_modules/@capacitor/core/dist/index.js +1 -1
- package/dist/node_modules/@capacitor/core/dist/index.js.map +1 -1
- package/package.json +13 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeveloperRevenueAdminPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/DeveloperRevenueAdminPage.tsx"],"sourcesContent":["import { 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\">Pending earned credits</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>{org ? `${org.name} revenue details` : 'Revenue details'}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Store revenue is credited into the linked billing account as earned credits. Developers 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\">Linked billing account</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 ?? '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\">Earned credits awaiting withdrawal</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\">{detail.unpaidSales.totalCount}</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\">{detail.summary?.totalSales ?? 0}</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's linked billing account as <strong>earned credits</strong>. We do not directly send cash 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 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\">Sales currently contributing to earned credits</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 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 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\">{sale.application?.name ?? 'Unknown app'}</div>\n <div className=\"text-xs text-text-muted\">/{sale.application?.slug ?? 'unknown'}</div>\n </td>\n <td className=\"px-3 py-2 text-text-secondary\">{formatDateTime(sale.purchasedAt)}</td>\n <td className=\"px-3 py-2 text-text-primary\">{formatCurrency(sale.netAmount, sale.currency)}</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\">{sale.billingCreditSyncError}</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(() => ({ apiGatewayUrl, authToken, orgId }), [apiGatewayUrl, authToken, orgId]);\n\n const loadOrgs = async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchAdminDeveloperRevenueOrgs(requestContext);\n setOrgs(result.filter((org) => org.totalRevenue > 0 || org.pendingBalance > 0 || org.totalPayouts > 0));\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load developer revenue'));\n } finally {\n setLoading(false);\n }\n };\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(loadError instanceof Error ? loadError : new Error('Failed to load revenue detail'));\n } finally {\n setDetailLoading(false);\n }\n };\n\n useEffect(() => {\n if (!permissions.isBillingAdmin) return;\n void loadOrgs();\n }, [permissions.isBillingAdmin, requestContext]);\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 credited into the developer organization's linked billing account as earned credits. Developers then withdraw those credits later using the billing withdrawal flow and their own 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\">Click a row to inspect billing linkage and the unpaid sales behind the current earned-credit balance.</p>\n </div>\n\n {orgs.length === 0 ? (\n <div className=\"px-5 py-12 text-center text-sm text-text-muted\">No developer revenue has been recorded yet.</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].sort((a, b) => b.pendingBalance - a.pendingBalance).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\">{org.billingAccountId ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-3 text-text-primary\">{formatCurrency(org.totalRevenue, 'USD')}</td>\n <td className=\"px-4 py-3 text-text-secondary\">{formatCurrency(org.totalPlatformFees, 'USD')}</td>\n <td className=\"px-4 py-3 font-medium text-status-warning-text\">{formatCurrency(org.pendingBalance, 'USD')}</td>\n <td className=\"px-4 py-3 text-text-secondary\">{formatCurrency(org.totalPayouts, 'USD')}</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(retryError instanceof Error ? retryError : new Error('Failed to retry credit sync'));\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, 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'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'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,22 +1,22 @@
|
|
|
1
1
|
import { useBilling as e } from "../../../providers/BillingProvider.js";
|
|
2
2
|
import { AccessDenied as t } from "../../../shared/components/AccessDenied.js";
|
|
3
|
-
import { PageHeader as
|
|
4
|
-
import { StatCard as
|
|
5
|
-
import { ServerError as
|
|
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
6
|
import "../../../shared/components/index.js";
|
|
7
|
-
import { formatCurrency as
|
|
8
|
-
import { isServerError as
|
|
7
|
+
import { formatCurrency as a, formatDateTime as o } from "../../../shared/utils/format.js";
|
|
8
|
+
import { isServerError as s } from "../../../shared/utils/error.js";
|
|
9
9
|
import "../../../shared/utils/index.js";
|
|
10
|
-
import { useBillingPermissions as
|
|
11
|
-
import { useGetDefaultBillingAccountSettingsQuery as
|
|
12
|
-
import { fetchDeveloperPortalRevenueDashboard as
|
|
13
|
-
import { useEffect as
|
|
14
|
-
import { Coins as
|
|
15
|
-
import { useSearchParams as
|
|
16
|
-
import { jsx as
|
|
17
|
-
import { EmphasisPanel as
|
|
10
|
+
import { useBillingPermissions as c } from "../../../hooks/useBillingPermissions.js";
|
|
11
|
+
import { useGetDefaultBillingAccountSettingsQuery as l } from "../../../../generated/global-operations.js";
|
|
12
|
+
import { fetchDeveloperPortalRevenueDashboard as u, fetchEarningsEntries as d, fetchEarningsSummary as f } from "../api.js";
|
|
13
|
+
import { useCallback as p, useEffect as m, useMemo as h, useState as g } from "react";
|
|
14
|
+
import { Coins as _, HandCoins as v, RefreshCw as y, Wallet as b } from "lucide-react";
|
|
15
|
+
import { useSearchParams as x } from "react-router";
|
|
16
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
17
|
+
import { EmphasisPanel as w, IllustratedEmptyState as T, PagePurpose as E, ResponsiveTable as D } from "@burdenoff/fe-libs/ui";
|
|
18
18
|
//#region src/billing/modules/earnings/pages/EarningsPage.tsx
|
|
19
|
-
var
|
|
19
|
+
var ee = [
|
|
20
20
|
{
|
|
21
21
|
key: "application",
|
|
22
22
|
header: "Application",
|
|
@@ -31,17 +31,17 @@ var w = [
|
|
|
31
31
|
{
|
|
32
32
|
key: "gross",
|
|
33
33
|
header: "Gross",
|
|
34
|
-
cell: (e) => /* @__PURE__ */
|
|
34
|
+
cell: (e) => /* @__PURE__ */ S("span", {
|
|
35
35
|
className: "tabular-nums",
|
|
36
|
-
children:
|
|
36
|
+
children: a(e.grossAmount, e.currency || "USD")
|
|
37
37
|
})
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
key: "net",
|
|
41
41
|
header: "Net",
|
|
42
|
-
cell: (e) => /* @__PURE__ */
|
|
42
|
+
cell: (e) => /* @__PURE__ */ S("span", {
|
|
43
43
|
className: "tabular-nums",
|
|
44
|
-
children:
|
|
44
|
+
children: a(e.netAmount, e.currency || "USD")
|
|
45
45
|
})
|
|
46
46
|
},
|
|
47
47
|
{
|
|
@@ -52,9 +52,9 @@ var w = [
|
|
|
52
52
|
{
|
|
53
53
|
key: "purchased",
|
|
54
54
|
header: "Purchased",
|
|
55
|
-
cell: (e) =>
|
|
55
|
+
cell: (e) => o(e.purchasedAt)
|
|
56
56
|
}
|
|
57
|
-
],
|
|
57
|
+
], O = [
|
|
58
58
|
{
|
|
59
59
|
key: "period",
|
|
60
60
|
header: "Period",
|
|
@@ -64,9 +64,9 @@ var w = [
|
|
|
64
64
|
{
|
|
65
65
|
key: "amount",
|
|
66
66
|
header: "Amount",
|
|
67
|
-
cell: (e) => /* @__PURE__ */
|
|
67
|
+
cell: (e) => /* @__PURE__ */ S("span", {
|
|
68
68
|
className: "tabular-nums",
|
|
69
|
-
children:
|
|
69
|
+
children: a(e.netAmount, e.currency || "USD")
|
|
70
70
|
})
|
|
71
71
|
},
|
|
72
72
|
{
|
|
@@ -77,14 +77,14 @@ var w = [
|
|
|
77
77
|
{
|
|
78
78
|
key: "scheduled",
|
|
79
79
|
header: "Scheduled",
|
|
80
|
-
cell: (e) => e.scheduledAt ?
|
|
80
|
+
cell: (e) => e.scheduledAt ? o(e.scheduledAt) : "-"
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
83
|
key: "completed",
|
|
84
84
|
header: "Completed",
|
|
85
|
-
cell: (e) => e.completedAt ?
|
|
85
|
+
cell: (e) => e.completedAt ? o(e.completedAt) : "-"
|
|
86
86
|
}
|
|
87
|
-
],
|
|
87
|
+
], k = [
|
|
88
88
|
{
|
|
89
89
|
key: "category",
|
|
90
90
|
header: "Category",
|
|
@@ -104,9 +104,9 @@ var w = [
|
|
|
104
104
|
{
|
|
105
105
|
key: "amount",
|
|
106
106
|
header: "Amount",
|
|
107
|
-
cell: (e) => /* @__PURE__ */
|
|
107
|
+
cell: (e) => /* @__PURE__ */ S("span", {
|
|
108
108
|
className: "tabular-nums",
|
|
109
|
-
children: e.unitType === "CREDITS" ? `${e.amount.toLocaleString()} credits` :
|
|
109
|
+
children: e.unitType === "CREDITS" ? `${e.amount.toLocaleString()} credits` : a(e.amount, e.currency || "USD")
|
|
110
110
|
})
|
|
111
111
|
},
|
|
112
112
|
{
|
|
@@ -117,197 +117,197 @@ var w = [
|
|
|
117
117
|
{
|
|
118
118
|
key: "created",
|
|
119
119
|
header: "Created",
|
|
120
|
-
cell: (e) =>
|
|
120
|
+
cell: (e) => o(e.createdAt)
|
|
121
121
|
}
|
|
122
|
-
],
|
|
123
|
-
let [
|
|
124
|
-
apiGatewayUrl:
|
|
125
|
-
authToken:
|
|
126
|
-
orgId:
|
|
122
|
+
], A = () => {
|
|
123
|
+
let [o] = x(), A = c(), { apiGatewayUrl: j, authToken: M, orgId: N } = e(), P = o.get("developerOrgId"), F = o.get("developerOrgName"), { data: te, loading: ne } = l({}), I = te?.getDefaultBillingAccount?.id, [L, R] = g(null), [z, B] = g([]), [V, H] = g(null), [U, W] = g("ALL"), [G, K] = g(!0), [q, J] = g(null), Y = h(() => ({
|
|
124
|
+
apiGatewayUrl: j,
|
|
125
|
+
authToken: M,
|
|
126
|
+
orgId: N
|
|
127
127
|
}), [
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
]),
|
|
132
|
-
|
|
128
|
+
j,
|
|
129
|
+
M,
|
|
130
|
+
N
|
|
131
|
+
]), X = p(async () => {
|
|
132
|
+
K(!0), J(null);
|
|
133
133
|
try {
|
|
134
|
-
if (
|
|
135
|
-
|
|
134
|
+
if (P) {
|
|
135
|
+
H(await u(P, Y)), R(null), B([]);
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
|
-
if (!
|
|
139
|
-
|
|
138
|
+
if (!I) {
|
|
139
|
+
R(null), B([]), H(null);
|
|
140
140
|
return;
|
|
141
141
|
}
|
|
142
|
-
let [e, t] = await Promise.all([
|
|
143
|
-
|
|
142
|
+
let [e, t] = await Promise.all([f(I, Y), d(I, Y)]);
|
|
143
|
+
R(e), B(t), H(null);
|
|
144
144
|
} catch (e) {
|
|
145
|
-
|
|
145
|
+
J(e instanceof Error ? e : /* @__PURE__ */ Error("Failed to load earnings"));
|
|
146
146
|
} finally {
|
|
147
|
-
|
|
147
|
+
K(!1);
|
|
148
148
|
}
|
|
149
|
-
};
|
|
150
|
-
if (u(() => {
|
|
151
|
-
Y();
|
|
152
149
|
}, [
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
])
|
|
157
|
-
if (
|
|
150
|
+
I,
|
|
151
|
+
P,
|
|
152
|
+
Y
|
|
153
|
+
]);
|
|
154
|
+
if (m(() => {
|
|
155
|
+
X();
|
|
156
|
+
}, [X]), !A.canViewBillingAccount) return /* @__PURE__ */ S(t, { message: "You don't have permission to view earnings." });
|
|
157
|
+
if (!P && !I && !ne) return /* @__PURE__ */ S(T, {
|
|
158
158
|
illustration: "empty-generic",
|
|
159
159
|
title: "No billing account found",
|
|
160
160
|
description: "Create a billing account first to view earnings."
|
|
161
161
|
});
|
|
162
|
-
if (
|
|
162
|
+
if (q && s(q)) return /* @__PURE__ */ S(i, {
|
|
163
163
|
title: "Earnings unavailable",
|
|
164
|
-
message:
|
|
165
|
-
onRetry: () => void
|
|
164
|
+
message: q.message,
|
|
165
|
+
onRetry: () => void X(),
|
|
166
166
|
showRetry: !0
|
|
167
167
|
});
|
|
168
|
-
let
|
|
168
|
+
let re = L ? [
|
|
169
169
|
{
|
|
170
170
|
title: "Available",
|
|
171
|
-
value:
|
|
172
|
-
icon: /* @__PURE__ */ v
|
|
171
|
+
value: a(L.availableAmount, "USD"),
|
|
172
|
+
icon: /* @__PURE__ */ S(v, { className: "size-5" })
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
175
|
title: "Reserved",
|
|
176
|
-
value:
|
|
177
|
-
icon: /* @__PURE__ */
|
|
176
|
+
value: a(L.reservedAmount, "USD"),
|
|
177
|
+
icon: /* @__PURE__ */ S(_, { className: "size-5" })
|
|
178
178
|
},
|
|
179
179
|
{
|
|
180
180
|
title: "Paid out",
|
|
181
|
-
value:
|
|
182
|
-
icon: /* @__PURE__ */
|
|
181
|
+
value: a(L.paidAmount, "USD"),
|
|
182
|
+
icon: /* @__PURE__ */ S(b, { className: "size-5" })
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
title: "Lifetime",
|
|
186
|
-
value:
|
|
187
|
-
icon: /* @__PURE__ */
|
|
186
|
+
value: a(L.totalLifetimeAmount, "USD"),
|
|
187
|
+
icon: /* @__PURE__ */ S(y, { className: "size-5" })
|
|
188
188
|
}
|
|
189
|
-
] : [], Z =
|
|
189
|
+
] : [], Z = U === "ALL" ? z : z.filter((e) => e.sourceCategory === U), Q = L?.categoryBreakdown?.map((e) => ({
|
|
190
190
|
title: `${e.category} earnings`,
|
|
191
|
-
value:
|
|
191
|
+
value: a(e.amount, "USD"),
|
|
192
192
|
helperText: `${e.count} entries`
|
|
193
|
-
})) ?? [],
|
|
193
|
+
})) ?? [], ie = V?.summary ? [
|
|
194
194
|
{
|
|
195
195
|
title: "Gross revenue",
|
|
196
|
-
value:
|
|
197
|
-
icon: /* @__PURE__ */ v
|
|
196
|
+
value: a(V.summary.totalGrossRevenue, "USD"),
|
|
197
|
+
icon: /* @__PURE__ */ S(v, { className: "size-5" })
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
title: "Net revenue",
|
|
201
|
-
value:
|
|
202
|
-
icon: /* @__PURE__ */
|
|
201
|
+
value: a(V.summary.totalNetRevenue, "USD"),
|
|
202
|
+
icon: /* @__PURE__ */ S(b, { className: "size-5" })
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
205
|
title: "Pending balance",
|
|
206
|
-
value:
|
|
207
|
-
icon: /* @__PURE__ */
|
|
206
|
+
value: a(V.summary.pendingBalance, "USD"),
|
|
207
|
+
icon: /* @__PURE__ */ S(_, { className: "size-5" })
|
|
208
208
|
},
|
|
209
209
|
{
|
|
210
210
|
title: "Platform fees",
|
|
211
|
-
value:
|
|
212
|
-
icon: /* @__PURE__ */
|
|
211
|
+
value: a(V.summary.totalPlatformFees, "USD"),
|
|
212
|
+
icon: /* @__PURE__ */ S(y, { className: "size-5" })
|
|
213
213
|
}
|
|
214
|
-
] : [], $ = !!
|
|
215
|
-
return /* @__PURE__ */
|
|
214
|
+
] : [], $ = !!P;
|
|
215
|
+
return /* @__PURE__ */ C("div", {
|
|
216
216
|
className: "space-y-6 p-6",
|
|
217
217
|
children: [
|
|
218
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ S(n, {
|
|
219
219
|
title: $ ? "Marketplace earnings" : "Earnings",
|
|
220
|
-
description: $ ? `Developer portal revenue, sales, and payouts${
|
|
220
|
+
description: $ ? `Developer portal revenue, sales, and payouts${F ? ` for ${F}` : ""}.` : "Track affiliate, store, and other earning sources in one ledger."
|
|
221
221
|
}),
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
-
|
|
222
|
+
/* @__PURE__ */ S(E, { children: "See everything you have earned — from affiliate rewards, store sales and marketplace revenue — in one ledger, along with how much has been paid out and what is still pending. Filter by source to reconcile a specific stream." }),
|
|
223
|
+
G ? /* @__PURE__ */ S("div", {
|
|
224
224
|
className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4",
|
|
225
225
|
children: [
|
|
226
226
|
1,
|
|
227
227
|
2,
|
|
228
228
|
3,
|
|
229
229
|
4
|
|
230
|
-
].map((e) => /* @__PURE__ */
|
|
231
|
-
}) : $ ?
|
|
230
|
+
].map((e) => /* @__PURE__ */ S("div", { className: "h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface" }, e))
|
|
231
|
+
}) : $ ? V?.summary ? /* @__PURE__ */ C("div", {
|
|
232
232
|
className: "space-y-6",
|
|
233
233
|
children: [
|
|
234
|
-
/* @__PURE__ */
|
|
234
|
+
/* @__PURE__ */ S("div", {
|
|
235
235
|
className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4",
|
|
236
|
-
children:
|
|
236
|
+
children: ie.map((e) => /* @__PURE__ */ S(r, {
|
|
237
237
|
label: e.title,
|
|
238
238
|
value: e.value,
|
|
239
239
|
icon: e.icon
|
|
240
240
|
}, e.title))
|
|
241
241
|
}),
|
|
242
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ C("section", {
|
|
243
243
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
244
|
-
children: [/* @__PURE__ */
|
|
244
|
+
children: [/* @__PURE__ */ C("div", {
|
|
245
245
|
className: "mb-4 flex items-center justify-between",
|
|
246
|
-
children: [/* @__PURE__ */
|
|
246
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
247
247
|
className: "text-lg font-semibold text-text-primary",
|
|
248
248
|
children: "Recent sales"
|
|
249
|
-
}), /* @__PURE__ */
|
|
249
|
+
}), /* @__PURE__ */ C("button", {
|
|
250
250
|
type: "button",
|
|
251
|
-
onClick: () => void
|
|
251
|
+
onClick: () => void X(),
|
|
252
252
|
className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary",
|
|
253
|
-
children: [/* @__PURE__ */
|
|
253
|
+
children: [/* @__PURE__ */ S(y, { className: "size-4" }), "Refresh"]
|
|
254
254
|
})]
|
|
255
|
-
}),
|
|
255
|
+
}), V.sales.length === 0 ? /* @__PURE__ */ S(T, {
|
|
256
256
|
illustration: "empty-data",
|
|
257
257
|
title: "No sales yet",
|
|
258
258
|
description: "Sales will appear here when customers start purchasing your apps."
|
|
259
|
-
}) : /* @__PURE__ */
|
|
260
|
-
data:
|
|
259
|
+
}) : /* @__PURE__ */ S(D, {
|
|
260
|
+
data: V.sales,
|
|
261
261
|
rowKey: (e) => e.id,
|
|
262
|
-
columns:
|
|
262
|
+
columns: ee
|
|
263
263
|
})]
|
|
264
264
|
}),
|
|
265
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ C("section", {
|
|
266
266
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
267
|
-
children: [/* @__PURE__ */
|
|
267
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
268
268
|
className: "mb-4 text-lg font-semibold text-text-primary",
|
|
269
269
|
children: "Payouts"
|
|
270
|
-
}),
|
|
270
|
+
}), V.payouts.length === 0 ? /* @__PURE__ */ S(T, {
|
|
271
271
|
illustration: "empty-data",
|
|
272
272
|
title: "No payouts yet",
|
|
273
273
|
description: "Scheduled and completed payouts will appear here."
|
|
274
|
-
}) : /* @__PURE__ */
|
|
275
|
-
data:
|
|
274
|
+
}) : /* @__PURE__ */ S(D, {
|
|
275
|
+
data: V.payouts,
|
|
276
276
|
rowKey: (e) => e.id,
|
|
277
|
-
columns:
|
|
277
|
+
columns: O
|
|
278
278
|
})]
|
|
279
279
|
})
|
|
280
280
|
]
|
|
281
|
-
}) : /* @__PURE__ */
|
|
281
|
+
}) : /* @__PURE__ */ S(T, {
|
|
282
282
|
illustration: "empty-data",
|
|
283
283
|
title: "No developer portal revenue yet",
|
|
284
284
|
description: "Marketplace revenue will appear here once your developer organization records sales."
|
|
285
|
-
}) :
|
|
285
|
+
}) : L ? /* @__PURE__ */ C("div", {
|
|
286
286
|
className: "space-y-4",
|
|
287
|
-
children: [/* @__PURE__ */
|
|
287
|
+
children: [/* @__PURE__ */ S(w, {
|
|
288
288
|
className: "p-4 sm:p-5",
|
|
289
|
-
children: /* @__PURE__ */
|
|
289
|
+
children: /* @__PURE__ */ S("div", {
|
|
290
290
|
className: "grid gap-4 md:grid-cols-2 xl:grid-cols-4",
|
|
291
|
-
children:
|
|
291
|
+
children: re.map((e) => /* @__PURE__ */ S(r, {
|
|
292
292
|
label: e.title,
|
|
293
293
|
value: e.value,
|
|
294
294
|
icon: e.icon
|
|
295
295
|
}, e.title))
|
|
296
296
|
})
|
|
297
|
-
}), Q.length > 0 ? /* @__PURE__ */
|
|
297
|
+
}), Q.length > 0 ? /* @__PURE__ */ S("div", {
|
|
298
298
|
className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3",
|
|
299
|
-
children: Q.map((e) => /* @__PURE__ */
|
|
299
|
+
children: Q.map((e) => /* @__PURE__ */ C("div", {
|
|
300
300
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
301
301
|
children: [
|
|
302
|
-
/* @__PURE__ */
|
|
302
|
+
/* @__PURE__ */ S("p", {
|
|
303
303
|
className: "text-sm text-text-secondary",
|
|
304
304
|
children: e.title
|
|
305
305
|
}),
|
|
306
|
-
/* @__PURE__ */
|
|
306
|
+
/* @__PURE__ */ S("p", {
|
|
307
307
|
className: "mt-2 text-xl font-semibold text-text-primary",
|
|
308
308
|
children: e.value
|
|
309
309
|
}),
|
|
310
|
-
/* @__PURE__ */
|
|
310
|
+
/* @__PURE__ */ S("p", {
|
|
311
311
|
className: "mt-1 text-xs text-text-secondary",
|
|
312
312
|
children: e.helperText
|
|
313
313
|
})
|
|
@@ -315,62 +315,62 @@ var w = [
|
|
|
315
315
|
}, e.title))
|
|
316
316
|
}) : null]
|
|
317
317
|
}) : null,
|
|
318
|
-
|
|
318
|
+
q && !s(q) ? /* @__PURE__ */ S("div", {
|
|
319
319
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text",
|
|
320
|
-
children:
|
|
320
|
+
children: q.message
|
|
321
321
|
}) : null,
|
|
322
|
-
/* @__PURE__ */
|
|
322
|
+
/* @__PURE__ */ C("section", {
|
|
323
323
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
324
|
-
children: [/* @__PURE__ */
|
|
324
|
+
children: [/* @__PURE__ */ C("div", {
|
|
325
325
|
className: "mb-4 flex items-center justify-between",
|
|
326
|
-
children: [/* @__PURE__ */
|
|
326
|
+
children: [/* @__PURE__ */ S("h2", {
|
|
327
327
|
className: "text-lg font-semibold text-text-primary",
|
|
328
328
|
children: "Ledger"
|
|
329
|
-
}), /* @__PURE__ */
|
|
329
|
+
}), /* @__PURE__ */ C("div", {
|
|
330
330
|
className: "flex items-center gap-3",
|
|
331
|
-
children: [/* @__PURE__ */
|
|
332
|
-
value:
|
|
333
|
-
onChange: (e) =>
|
|
331
|
+
children: [/* @__PURE__ */ C("select", {
|
|
332
|
+
value: U,
|
|
333
|
+
onChange: (e) => W(e.target.value),
|
|
334
334
|
className: "rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary",
|
|
335
335
|
children: [
|
|
336
|
-
/* @__PURE__ */
|
|
336
|
+
/* @__PURE__ */ S("option", {
|
|
337
337
|
value: "ALL",
|
|
338
338
|
children: "All sources"
|
|
339
339
|
}),
|
|
340
|
-
/* @__PURE__ */
|
|
340
|
+
/* @__PURE__ */ S("option", {
|
|
341
341
|
value: "AFFILIATE",
|
|
342
342
|
children: "Affiliate"
|
|
343
343
|
}),
|
|
344
|
-
/* @__PURE__ */
|
|
344
|
+
/* @__PURE__ */ S("option", {
|
|
345
345
|
value: "STORE",
|
|
346
346
|
children: "Store"
|
|
347
347
|
}),
|
|
348
|
-
/* @__PURE__ */
|
|
348
|
+
/* @__PURE__ */ S("option", {
|
|
349
349
|
value: "OTHER",
|
|
350
350
|
children: "Other"
|
|
351
351
|
})
|
|
352
352
|
]
|
|
353
|
-
}), /* @__PURE__ */
|
|
353
|
+
}), /* @__PURE__ */ C("button", {
|
|
354
354
|
type: "button",
|
|
355
|
-
onClick: () => void
|
|
355
|
+
onClick: () => void X(),
|
|
356
356
|
className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary",
|
|
357
|
-
children: [/* @__PURE__ */
|
|
357
|
+
children: [/* @__PURE__ */ S(y, { className: "size-4" }), "Refresh"]
|
|
358
358
|
})]
|
|
359
359
|
})]
|
|
360
|
-
}), Z.length === 0 && !
|
|
360
|
+
}), Z.length === 0 && !G ? /* @__PURE__ */ S(T, {
|
|
361
361
|
illustration: "empty-data",
|
|
362
362
|
title: "No earnings yet",
|
|
363
363
|
description: "Eligible affiliate rewards and other earnings will appear here."
|
|
364
|
-
}) : /* @__PURE__ */
|
|
364
|
+
}) : /* @__PURE__ */ S(D, {
|
|
365
365
|
data: Z,
|
|
366
366
|
rowKey: (e) => e.id,
|
|
367
|
-
columns:
|
|
367
|
+
columns: k
|
|
368
368
|
})]
|
|
369
369
|
})
|
|
370
370
|
]
|
|
371
371
|
});
|
|
372
372
|
};
|
|
373
373
|
//#endregion
|
|
374
|
-
export {
|
|
374
|
+
export { A as EarningsPage };
|
|
375
375
|
|
|
376
376
|
//# sourceMappingURL=EarningsPage.js.map
|