@burdenoff/microfe-billing 2026.915.2 → 2026.915.3
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/modules/checkout/hooks/useCheckout.js.map +1 -1
- package/dist/billing/modules/credits/pages/CreditWithdrawalPage.js.map +1 -1
- package/dist/billing/modules/earnings/api.js.map +1 -1
- package/dist/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/EarningsPage.js +4 -4
- package/dist/billing/modules/earnings/pages/EarningsPage.js.map +1 -1
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js +3 -2
- package/dist/billing/modules/earnings/pages/PayoutAdminPage.js.map +1 -1
- package/dist/generated/global-operations.js +1 -0
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/generated/global-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","names":[],"sources":["../../../../src/billing/modules/earnings/api.ts"],"sourcesContent":["import { directBillingGraphqlRequest } from '../../shared/utils';\nimport { gatewayGraphqlRequest } from '../../shared/utils/gatewayGraphql';\nimport {\n AddPayoutAccountDocument,\n AdminDeveloperRevenueOrgDetailDocument,\n AdminDeveloperRevenueOrgDocument,\n AdminDeveloperRevenueOrgMonthlyDocument,\n AdminDeveloperRevenueOrgsDocument,\n AdminPayoutRequestsDocument,\n AdminPayoutSummaryDocument,\n ApprovePayoutRequestDocument,\n ArchivePayoutAccountDocument,\n BillingDeveloperPortalRevenueDocument,\n GetCostOfCreditsDocument,\n GetCreditBalanceByTypeDocument,\n MarkPayoutPaidDocument,\n MyEarningsEntriesDocument,\n MyEarningsSummaryDocument,\n MyPayoutAccountsDocument,\n MyPayoutRequestsDocument,\n ProcessPayoutRequestDocument,\n RejectPayoutRequestDocument,\n RetrySaleCreditSyncDocument,\n SetDefaultPayoutAccountDocument,\n UpdatePayoutAccountDocument,\n} from '../../../generated/global-operations';\n\nexport interface EarningsSummary {\n totalLifetimeAmount: number;\n availableAmount: number;\n reservedAmount: number;\n paidAmount: number;\n pendingAmount: number;\n moneyAmount: number;\n creditsAmount: number;\n categoryBreakdown?: Array<{\n category: 'AFFILIATE' | 'STORE' | 'OTHER';\n amount: number;\n count: number;\n }>;\n}\n\nexport interface EarningsEntry {\n id: string;\n sourceCategory: 'AFFILIATE' | 'STORE' | 'OTHER';\n sourceSubcategory?: string | null;\n description?: string | null;\n unitType: 'MONEY' | 'CREDITS';\n amount: number;\n currency: string;\n status: 'AVAILABLE' | 'RESERVED' | 'PAID' | 'REVERSED';\n createdAt: string;\n}\n\nexport interface PayoutAccount {\n id: string;\n label: string;\n type: 'BANK_ACCOUNT' | 'UPI' | 'WALLET';\n providerPreference: 'AUTO' | 'STRIPE' | 'RAZORPAY' | 'MANUAL';\n status: 'PENDING_VERIFICATION' | 'ACTIVE' | 'FAILED_VERIFICATION' | 'ARCHIVED';\n displayName?: string | null;\n accountLast4?: string | null;\n country?: string | null;\n currency: string;\n isDefault: boolean;\n accountDetails?: Record<string, unknown> | null;\n}\n\nexport interface PayoutRequest {\n id: string;\n billingAccountId?: string | null;\n requesterUserId?: string | null;\n requestedAmount: number;\n approvedAmount?: number | null;\n currency: string;\n provider: 'AUTO' | 'STRIPE' | 'RAZORPAY' | 'MANUAL';\n status: 'REQUESTED' | 'APPROVED' | 'REJECTED' | 'PROCESSING' | 'PAID' | 'FAILED' | 'CANCELED';\n /** See PayoutRequestKind on the backend — what approving this request actually does. */\n requestKind: 'CREDIT_CONVERSION' | 'CASH_PAYOUT';\n externalReference?: string | null;\n failureReason?: string | null;\n internalNotes?: string | null;\n userNotes?: string | null;\n createdAt: string;\n processedAt?: string | null;\n paidAt?: string | null;\n payoutAccount?: PayoutAccount | null;\n}\n\nexport interface PayoutAdminSummary {\n totalRequestedAmount: number;\n totalProcessingAmount: number;\n totalPaidAmount: number;\n pendingCount: number;\n failedCount: number;\n statusBreakdown?: Array<{ status: string; count: number; totalAmount: number }>;\n providerBreakdown?: Array<{ provider: string; count: number; totalAmount: number }>;\n}\n\nexport interface AdminPayoutRequestsPage {\n items: PayoutRequest[];\n totalCount: number;\n hasMore: boolean;\n}\n\nexport interface PayoutRequestFilter {\n billingAccountId?: string;\n provider?: PayoutRequest['provider'];\n status?: PayoutRequest['status'];\n startDate?: string;\n endDate?: string;\n}\n\nexport interface CreditBalanceByType {\n purchased: number;\n earned: number;\n granted: number;\n withdrawable: number;\n total: number;\n}\n\nexport interface DeveloperOrgMonthlyRevenuePoint {\n month: string;\n grossRevenue: number;\n platformFees: number;\n netRevenue: number;\n refunds: number;\n salesCount: number;\n}\n\nexport interface DeveloperPortalRevenueSummary {\n totalGrossRevenue: number;\n totalNetRevenue: number;\n totalPlatformFees: number;\n totalRefunds: number;\n totalRefundsCount: number;\n totalSales: number;\n pendingBalance: number;\n nextPayoutDate?: string | null;\n nextPayoutAmount?: number | null;\n}\n\nexport interface DeveloperPortalRevenueSale {\n id: string;\n grossAmount: number;\n netAmount: number;\n currency: string;\n pricingModel: string;\n status: string;\n billingCreditSyncStatus?: string | null;\n billingCreditSyncError?: string | null;\n billingCreditSyncedAt?: string | null;\n purchasedAt: string;\n application?: {\n id: string;\n name: string;\n slug: string;\n } | null;\n}\n\nexport interface DeveloperPortalRevenuePayout {\n id: string;\n periodLabel?: string | null;\n netAmount: number;\n currency: string;\n status: string;\n scheduledAt?: string | null;\n completedAt?: string | null;\n}\n\nexport interface DeveloperPortalRevenueDashboard {\n summary: DeveloperPortalRevenueSummary | null;\n sales: DeveloperPortalRevenueSale[];\n payouts: DeveloperPortalRevenuePayout[];\n}\n\nexport interface AdminDeveloperRevenueOrg {\n id: string;\n name: string;\n slug: string;\n billingAccountId?: string | null;\n isVerified: boolean;\n totalApps: number;\n publishedApps: number;\n totalInstalls: number;\n activeInstalls: number;\n averageRating?: number | null;\n totalRevenue: number;\n totalPlatformFees: number;\n totalPayouts: number;\n pendingBalance: number;\n lifetimeRevenue: number;\n platformFeeRate: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface AdminDeveloperRevenueOrgDetail {\n summary: DeveloperPortalRevenueSummary | null;\n unpaidSales: {\n totalCount: number;\n items: DeveloperPortalRevenueSale[];\n };\n}\n\ninterface GatewayContext {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n}\n\nexport async function fetchDeveloperPortalRevenueDashboard(\n organizationId: string,\n context: GatewayContext\n): Promise<DeveloperPortalRevenueDashboard> {\n type RevenueQueryResult = {\n developerOrgRevenueSummary: DeveloperPortalRevenueSummary | null;\n developerOrgSales: { edges: Array<{ node: DeveloperPortalRevenueSale }> };\n developerOrgPayouts: { edges: Array<{ node: DeveloperPortalRevenuePayout }> };\n };\n\n const data = await gatewayGraphqlRequest<RevenueQueryResult, { organizationId: string }>({\n ...context,\n query: BillingDeveloperPortalRevenueDocument,\n variables: { organizationId },\n });\n\n return {\n summary: data.developerOrgRevenueSummary,\n sales: data.developerOrgSales.edges.map((edge) => edge.node),\n payouts: data.developerOrgPayouts.edges.map((edge) => edge.node),\n };\n}\n\nexport async function fetchEarningsSummary(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myEarningsSummary: EarningsSummary;\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyEarningsSummaryDocument,\n variables: { billingAccountId },\n });\n\n return data.myEarningsSummary;\n}\n\nexport async function fetchEarningsEntries(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myEarningsEntries: { items: EarningsEntry[] };\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyEarningsEntriesDocument,\n variables: { billingAccountId },\n });\n\n return data.myEarningsEntries.items;\n}\n\nexport async function fetchPayoutAccounts(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myPayoutAccounts: PayoutAccount[];\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyPayoutAccountsDocument,\n variables: { billingAccountId },\n });\n\n return data.myPayoutAccounts;\n}\n\nexport async function fetchPayoutRequests(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myPayoutRequests: { items: PayoutRequest[] };\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyPayoutRequestsDocument,\n variables: { billingAccountId },\n });\n\n return data.myPayoutRequests.items;\n}\n\nexport async function addPayoutAccount(input: Record<string, unknown>, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n addPayoutAccount: { id: string };\n },\n { input: Record<string, unknown> }\n >({\n ...context,\n query: AddPayoutAccountDocument,\n variables: { input },\n });\n}\n\nexport async function updatePayoutAccount(\n id: string,\n input: Record<string, unknown>,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n { updatePayoutAccount: { id: string } },\n { id: string; input: Record<string, unknown> }\n >({\n ...context,\n query: UpdatePayoutAccountDocument,\n variables: { id, input },\n });\n}\n\nexport async function setDefaultPayoutAccount(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<{ setDefaultPayoutAccount: { id: string } }, { id: string }>({\n ...context,\n query: SetDefaultPayoutAccountDocument,\n variables: { id },\n });\n}\n\nexport async function archivePayoutAccount(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<{ archivePayoutAccount: boolean }, { id: string }>({\n ...context,\n query: ArchivePayoutAccountDocument,\n variables: { id },\n });\n}\n\nexport async function requestPayout(_input: Record<string, unknown>, _context: GatewayContext) {\n throw new Error('Payout request not yet implemented');\n}\n\nexport async function fetchAdminPayoutSummary(context: GatewayContext) {\n const data = await directBillingGraphqlRequest<{\n adminPayoutSummary: PayoutAdminSummary;\n }>({\n ...context,\n query: AdminPayoutSummaryDocument,\n });\n\n return data.adminPayoutSummary;\n}\n\nexport async function fetchAdminPayoutRequests(\n context: GatewayContext,\n pagination: { limit?: number; offset?: number; filter?: PayoutRequestFilter } = {}\n) {\n const data = await directBillingGraphqlRequest<\n {\n adminPayoutRequests: AdminPayoutRequestsPage;\n },\n {\n limit: number;\n offset: number;\n filter?: PayoutRequestFilter;\n }\n >({\n ...context,\n query: AdminPayoutRequestsDocument,\n variables: {\n limit: pagination.limit ?? 50,\n offset: pagination.offset ?? 0,\n filter: pagination.filter,\n },\n });\n\n return data.adminPayoutRequests;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgs(context: GatewayContext) {\n const data = await gatewayGraphqlRequest<{\n developerOrganizations: {\n edges: Array<{ node: AdminDeveloperRevenueOrg }>;\n };\n }>({\n ...context,\n query: AdminDeveloperRevenueOrgsDocument,\n });\n\n return data.developerOrganizations.edges.map((edge) => edge.node);\n}\n\nexport async function fetchAdminDeveloperRevenueOrg(\n organizationId: string,\n context: GatewayContext\n) {\n const data = await gatewayGraphqlRequest<\n { developerOrganization: AdminDeveloperRevenueOrg | null },\n { organizationId: string }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgDocument,\n variables: { organizationId },\n });\n\n return data.developerOrganization;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgDetail(\n organizationId: string,\n context: GatewayContext,\n range: { startDate?: string; endDate?: string } = {}\n) {\n const data = await gatewayGraphqlRequest<\n {\n developerOrgRevenueSummary: DeveloperPortalRevenueSummary | null;\n developerOrgSales: { totalCount: number; edges: Array<{ node: DeveloperPortalRevenueSale }> };\n },\n {\n organizationId: string;\n period: string;\n salesLimit: number;\n salesOffset: number;\n startDate?: string;\n endDate?: string;\n }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgDetailDocument,\n variables: {\n organizationId,\n period: 'monthly',\n salesLimit: 50,\n salesOffset: 0,\n startDate: range.startDate,\n endDate: range.endDate,\n },\n });\n\n return {\n summary: data.developerOrgRevenueSummary,\n unpaidSales: {\n totalCount: data.developerOrgSales.totalCount,\n items: data.developerOrgSales.edges.map((edge) => edge.node),\n },\n } satisfies AdminDeveloperRevenueOrgDetail;\n}\n\n/**\n * Estimated fiat cost of a raw credit amount at the current global credit\n * rate (1 credit = $0.01 by default). Credit-balance figures from\n * getCreditBalanceByType are raw credit units, NOT currency — never format\n * them with formatCurrency directly.\n */\nexport async function fetchCreditCost(\n creditAmount: number,\n currency: string,\n context: GatewayContext\n) {\n const data = await directBillingGraphqlRequest<\n { getCostOfCredits: { amount: number } },\n { creditAmount: number; currency: string }\n >({\n ...context,\n query: GetCostOfCreditsDocument,\n variables: { creditAmount, currency },\n });\n\n return data.getCostOfCredits.amount;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgMonthly(\n organizationId: string,\n context: GatewayContext,\n months = 12\n) {\n const data = await gatewayGraphqlRequest<\n { developerOrgMonthlyRevenue: DeveloperOrgMonthlyRevenuePoint[] },\n { organizationId: string; months: number }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgMonthlyDocument,\n variables: { organizationId, months },\n });\n\n return data.developerOrgMonthlyRevenue;\n}\n\n/**\n * Current credit balance for a devorg's linked billing account. Callable for\n * any billingAccountId as a billing admin — getCreditBalanceByType's\n * `scopeType: \"billing\"` RBAC bypasses org ownership for super_admin actors.\n */\nexport async function fetchBillingAccountCreditBalance(\n billingAccountId: string,\n context: GatewayContext\n) {\n const data = await directBillingGraphqlRequest<\n { getCreditBalanceByType: CreditBalanceByType },\n { billingAccountId: string }\n >({\n ...context,\n query: GetCreditBalanceByTypeDocument,\n variables: { billingAccountId },\n });\n\n return data.getCreditBalanceByType;\n}\n\nexport async function retrySaleCreditSync(saleId: string, context: GatewayContext) {\n const data = await gatewayGraphqlRequest<\n {\n retrySaleCreditSync: Pick<\n DeveloperPortalRevenueSale,\n 'id' | 'billingCreditSyncStatus' | 'billingCreditSyncError' | 'billingCreditSyncedAt'\n >;\n },\n { saleId: string }\n >({\n ...context,\n query: RetrySaleCreditSyncDocument,\n variables: { saleId },\n });\n\n return data.retrySaleCreditSync;\n}\n\nexport async function approvePayoutRequest(\n id: string,\n notes: string | null,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n {\n approvePayoutRequest: { id: string };\n },\n { id: string; notes: string | null }\n >({\n ...context,\n query: ApprovePayoutRequestDocument,\n variables: { id, notes },\n });\n}\n\nexport async function rejectPayoutRequest(id: string, reason: string, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n rejectPayoutRequest: { id: string };\n },\n { id: string; reason: string }\n >({\n ...context,\n query: RejectPayoutRequestDocument,\n variables: { id, reason },\n });\n}\n\nexport async function processPayoutRequest(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n processPayoutRequest: { id: string };\n },\n { id: string }\n >({\n ...context,\n query: ProcessPayoutRequestDocument,\n variables: { id },\n });\n}\n\nexport async function markPayoutPaid(\n id: string,\n externalReference: string | null,\n notes: string | null,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n { markPayoutPaid: { id: string } },\n { id: string; externalReference: string | null; notes: string | null }\n >({\n ...context,\n query: MarkPayoutPaidDocument,\n variables: { id, externalReference, notes },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.js","names":[],"sources":["../../../../src/billing/modules/earnings/api.ts"],"sourcesContent":["import { directBillingGraphqlRequest } from '../../shared/utils';\nimport { gatewayGraphqlRequest } from '../../shared/utils/gatewayGraphql';\nimport {\n AddPayoutAccountDocument,\n AdminDeveloperRevenueOrgDetailDocument,\n AdminDeveloperRevenueOrgDocument,\n AdminDeveloperRevenueOrgMonthlyDocument,\n AdminDeveloperRevenueOrgsDocument,\n AdminPayoutRequestsDocument,\n AdminPayoutSummaryDocument,\n ApprovePayoutRequestDocument,\n ArchivePayoutAccountDocument,\n BillingDeveloperPortalRevenueDocument,\n GetCostOfCreditsDocument,\n GetCreditBalanceByTypeDocument,\n MarkPayoutPaidDocument,\n MyEarningsEntriesDocument,\n MyEarningsSummaryDocument,\n MyPayoutAccountsDocument,\n MyPayoutRequestsDocument,\n ProcessPayoutRequestDocument,\n RejectPayoutRequestDocument,\n RetrySaleCreditSyncDocument,\n SetDefaultPayoutAccountDocument,\n UpdatePayoutAccountDocument,\n} from '../../../generated/global-operations';\n\nexport interface EarningsSummary {\n totalLifetimeAmount: number;\n availableAmount: number;\n reservedAmount: number;\n paidAmount: number;\n pendingAmount: number;\n moneyAmount: number;\n creditsAmount: number;\n categoryBreakdown?: Array<{\n category: 'AFFILIATE' | 'STORE' | 'OTHER';\n amount: number;\n count: number;\n }>;\n}\n\nexport interface EarningsEntry {\n id: string;\n sourceCategory: 'AFFILIATE' | 'STORE' | 'OTHER';\n sourceSubcategory?: string | null;\n description?: string | null;\n unitType: 'MONEY' | 'CREDITS';\n amount: number;\n currency: string;\n status: 'AVAILABLE' | 'RESERVED' | 'PAID' | 'REVERSED';\n createdAt: string;\n}\n\nexport interface PayoutAccount {\n id: string;\n label: string;\n type: 'BANK_ACCOUNT' | 'UPI' | 'WALLET';\n providerPreference: 'AUTO' | 'STRIPE' | 'RAZORPAY' | 'MANUAL';\n status: 'PENDING_VERIFICATION' | 'ACTIVE' | 'FAILED_VERIFICATION' | 'ARCHIVED';\n displayName?: string | null;\n accountLast4?: string | null;\n country?: string | null;\n currency: string;\n isDefault: boolean;\n accountDetails?: Record<string, unknown> | null;\n}\n\nexport interface PayoutRequest {\n id: string;\n billingAccountId?: string | null;\n requesterUserId?: string | null;\n requestedAmount: number;\n approvedAmount?: number | null;\n currency: string;\n provider: 'AUTO' | 'STRIPE' | 'RAZORPAY' | 'MANUAL';\n status: 'REQUESTED' | 'APPROVED' | 'REJECTED' | 'PROCESSING' | 'PAID' | 'FAILED' | 'CANCELED';\n /** See PayoutRequestKind on the backend — what approving this request actually does. */\n requestKind: 'CREDIT_CONVERSION' | 'CASH_PAYOUT';\n externalReference?: string | null;\n failureReason?: string | null;\n internalNotes?: string | null;\n userNotes?: string | null;\n createdAt: string;\n processedAt?: string | null;\n paidAt?: string | null;\n payoutAccount?: PayoutAccount | null;\n}\n\nexport interface PayoutAdminSummary {\n totalRequestedAmount: number;\n totalProcessingAmount: number;\n totalPaidAmount: number;\n pendingCount: number;\n failedCount: number;\n statusBreakdown?: Array<{ status: string; count: number; totalAmount: number }>;\n providerBreakdown?: Array<{ provider: string; count: number; totalAmount: number }>;\n}\n\nexport interface AdminPayoutRequestsPage {\n items: PayoutRequest[];\n totalCount: number;\n hasMore: boolean;\n}\n\nexport interface PayoutRequestFilter {\n billingAccountId?: string;\n provider?: PayoutRequest['provider'];\n status?: PayoutRequest['status'];\n startDate?: string;\n endDate?: string;\n}\n\nexport interface CreditBalanceByType {\n purchased: number;\n earned: number;\n granted: number;\n withdrawable: number;\n total: number;\n}\n\nexport interface DeveloperOrgMonthlyRevenuePoint {\n month: string;\n grossRevenue: number;\n platformFees: number;\n netRevenue: number;\n refunds: number;\n salesCount: number;\n}\n\nexport interface DeveloperPortalRevenueSummary {\n currency: string;\n totalGrossRevenue: number;\n totalNetRevenue: number;\n totalPlatformFees: number;\n totalRefunds: number;\n totalRefundsCount: number;\n totalSales: number;\n pendingBalance: number;\n nextPayoutDate?: string | null;\n nextPayoutAmount?: number | null;\n}\n\nexport interface DeveloperPortalRevenueSale {\n id: string;\n grossAmount: number;\n netAmount: number;\n currency: string;\n pricingModel: string;\n status: string;\n billingCreditSyncStatus?: string | null;\n billingCreditSyncError?: string | null;\n billingCreditSyncedAt?: string | null;\n purchasedAt: string;\n application?: {\n id: string;\n name: string;\n slug: string;\n } | null;\n}\n\nexport interface DeveloperPortalRevenuePayout {\n id: string;\n periodLabel?: string | null;\n netAmount: number;\n currency: string;\n status: string;\n scheduledAt?: string | null;\n completedAt?: string | null;\n}\n\nexport interface DeveloperPortalRevenueDashboard {\n summary: DeveloperPortalRevenueSummary | null;\n sales: DeveloperPortalRevenueSale[];\n payouts: DeveloperPortalRevenuePayout[];\n}\n\nexport interface AdminDeveloperRevenueOrg {\n id: string;\n name: string;\n slug: string;\n billingAccountId?: string | null;\n isVerified: boolean;\n totalApps: number;\n publishedApps: number;\n totalInstalls: number;\n activeInstalls: number;\n averageRating?: number | null;\n totalRevenue: number;\n totalPlatformFees: number;\n totalPayouts: number;\n pendingBalance: number;\n lifetimeRevenue: number;\n platformFeeRate: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface AdminDeveloperRevenueOrgDetail {\n summary: DeveloperPortalRevenueSummary | null;\n unpaidSales: {\n totalCount: number;\n items: DeveloperPortalRevenueSale[];\n };\n}\n\ninterface GatewayContext {\n apiGatewayUrl?: string;\n authToken?: string;\n orgId?: string;\n}\n\nexport async function fetchDeveloperPortalRevenueDashboard(\n organizationId: string,\n context: GatewayContext\n): Promise<DeveloperPortalRevenueDashboard> {\n type RevenueQueryResult = {\n developerOrgRevenueSummary: DeveloperPortalRevenueSummary | null;\n developerOrgSales: { edges: Array<{ node: DeveloperPortalRevenueSale }> };\n developerOrgPayouts: { edges: Array<{ node: DeveloperPortalRevenuePayout }> };\n };\n\n const data = await gatewayGraphqlRequest<RevenueQueryResult, { organizationId: string }>({\n ...context,\n query: BillingDeveloperPortalRevenueDocument,\n variables: { organizationId },\n });\n\n return {\n summary: data.developerOrgRevenueSummary,\n sales: data.developerOrgSales.edges.map((edge) => edge.node),\n payouts: data.developerOrgPayouts.edges.map((edge) => edge.node),\n };\n}\n\nexport async function fetchEarningsSummary(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myEarningsSummary: EarningsSummary;\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyEarningsSummaryDocument,\n variables: { billingAccountId },\n });\n\n return data.myEarningsSummary;\n}\n\nexport async function fetchEarningsEntries(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myEarningsEntries: { items: EarningsEntry[] };\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyEarningsEntriesDocument,\n variables: { billingAccountId },\n });\n\n return data.myEarningsEntries.items;\n}\n\nexport async function fetchPayoutAccounts(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myPayoutAccounts: PayoutAccount[];\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyPayoutAccountsDocument,\n variables: { billingAccountId },\n });\n\n return data.myPayoutAccounts;\n}\n\nexport async function fetchPayoutRequests(billingAccountId: string, context: GatewayContext) {\n const data = await directBillingGraphqlRequest<\n {\n myPayoutRequests: { items: PayoutRequest[] };\n },\n { billingAccountId: string }\n >({\n ...context,\n query: MyPayoutRequestsDocument,\n variables: { billingAccountId },\n });\n\n return data.myPayoutRequests.items;\n}\n\nexport async function addPayoutAccount(input: Record<string, unknown>, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n addPayoutAccount: { id: string };\n },\n { input: Record<string, unknown> }\n >({\n ...context,\n query: AddPayoutAccountDocument,\n variables: { input },\n });\n}\n\nexport async function updatePayoutAccount(\n id: string,\n input: Record<string, unknown>,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n { updatePayoutAccount: { id: string } },\n { id: string; input: Record<string, unknown> }\n >({\n ...context,\n query: UpdatePayoutAccountDocument,\n variables: { id, input },\n });\n}\n\nexport async function setDefaultPayoutAccount(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<{ setDefaultPayoutAccount: { id: string } }, { id: string }>({\n ...context,\n query: SetDefaultPayoutAccountDocument,\n variables: { id },\n });\n}\n\nexport async function archivePayoutAccount(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<{ archivePayoutAccount: boolean }, { id: string }>({\n ...context,\n query: ArchivePayoutAccountDocument,\n variables: { id },\n });\n}\n\nexport async function requestPayout(_input: Record<string, unknown>, _context: GatewayContext) {\n throw new Error('Payout request not yet implemented');\n}\n\nexport async function fetchAdminPayoutSummary(context: GatewayContext) {\n const data = await directBillingGraphqlRequest<{\n adminPayoutSummary: PayoutAdminSummary;\n }>({\n ...context,\n query: AdminPayoutSummaryDocument,\n });\n\n return data.adminPayoutSummary;\n}\n\nexport async function fetchAdminPayoutRequests(\n context: GatewayContext,\n pagination: { limit?: number; offset?: number; filter?: PayoutRequestFilter } = {}\n) {\n const data = await directBillingGraphqlRequest<\n {\n adminPayoutRequests: AdminPayoutRequestsPage;\n },\n {\n limit: number;\n offset: number;\n filter?: PayoutRequestFilter;\n }\n >({\n ...context,\n query: AdminPayoutRequestsDocument,\n variables: {\n limit: pagination.limit ?? 50,\n offset: pagination.offset ?? 0,\n filter: pagination.filter,\n },\n });\n\n return data.adminPayoutRequests;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgs(context: GatewayContext) {\n const data = await gatewayGraphqlRequest<{\n developerOrganizations: {\n edges: Array<{ node: AdminDeveloperRevenueOrg }>;\n };\n }>({\n ...context,\n query: AdminDeveloperRevenueOrgsDocument,\n });\n\n return data.developerOrganizations.edges.map((edge) => edge.node);\n}\n\nexport async function fetchAdminDeveloperRevenueOrg(\n organizationId: string,\n context: GatewayContext\n) {\n const data = await gatewayGraphqlRequest<\n { developerOrganization: AdminDeveloperRevenueOrg | null },\n { organizationId: string }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgDocument,\n variables: { organizationId },\n });\n\n return data.developerOrganization;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgDetail(\n organizationId: string,\n context: GatewayContext,\n range: { startDate?: string; endDate?: string } = {}\n) {\n const data = await gatewayGraphqlRequest<\n {\n developerOrgRevenueSummary: DeveloperPortalRevenueSummary | null;\n developerOrgSales: { totalCount: number; edges: Array<{ node: DeveloperPortalRevenueSale }> };\n },\n {\n organizationId: string;\n period: string;\n salesLimit: number;\n salesOffset: number;\n startDate?: string;\n endDate?: string;\n }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgDetailDocument,\n variables: {\n organizationId,\n period: 'monthly',\n salesLimit: 50,\n salesOffset: 0,\n startDate: range.startDate,\n endDate: range.endDate,\n },\n });\n\n return {\n summary: data.developerOrgRevenueSummary,\n unpaidSales: {\n totalCount: data.developerOrgSales.totalCount,\n items: data.developerOrgSales.edges.map((edge) => edge.node),\n },\n } satisfies AdminDeveloperRevenueOrgDetail;\n}\n\n/**\n * Estimated fiat cost of a raw credit amount at the current global credit\n * rate (1 credit = $0.01 by default). Credit-balance figures from\n * getCreditBalanceByType are raw credit units, NOT currency — never format\n * them with formatCurrency directly.\n */\nexport async function fetchCreditCost(\n creditAmount: number,\n currency: string,\n context: GatewayContext\n) {\n const data = await directBillingGraphqlRequest<\n { getCostOfCredits: { amount: number } },\n { creditAmount: number; currency: string }\n >({\n ...context,\n query: GetCostOfCreditsDocument,\n variables: { creditAmount, currency },\n });\n\n return data.getCostOfCredits.amount;\n}\n\nexport async function fetchAdminDeveloperRevenueOrgMonthly(\n organizationId: string,\n context: GatewayContext,\n months = 12\n) {\n const data = await gatewayGraphqlRequest<\n { developerOrgMonthlyRevenue: DeveloperOrgMonthlyRevenuePoint[] },\n { organizationId: string; months: number }\n >({\n ...context,\n query: AdminDeveloperRevenueOrgMonthlyDocument,\n variables: { organizationId, months },\n });\n\n return data.developerOrgMonthlyRevenue;\n}\n\n/**\n * Current credit balance for a devorg's linked billing account. Callable for\n * any billingAccountId as a billing admin — getCreditBalanceByType's\n * `scopeType: \"billing\"` RBAC bypasses org ownership for super_admin actors.\n */\nexport async function fetchBillingAccountCreditBalance(\n billingAccountId: string,\n context: GatewayContext\n) {\n const data = await directBillingGraphqlRequest<\n { getCreditBalanceByType: CreditBalanceByType },\n { billingAccountId: string }\n >({\n ...context,\n query: GetCreditBalanceByTypeDocument,\n variables: { billingAccountId },\n });\n\n return data.getCreditBalanceByType;\n}\n\nexport async function retrySaleCreditSync(saleId: string, context: GatewayContext) {\n const data = await gatewayGraphqlRequest<\n {\n retrySaleCreditSync: Pick<\n DeveloperPortalRevenueSale,\n 'id' | 'billingCreditSyncStatus' | 'billingCreditSyncError' | 'billingCreditSyncedAt'\n >;\n },\n { saleId: string }\n >({\n ...context,\n query: RetrySaleCreditSyncDocument,\n variables: { saleId },\n });\n\n return data.retrySaleCreditSync;\n}\n\nexport async function approvePayoutRequest(\n id: string,\n notes: string | null,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n {\n approvePayoutRequest: { id: string };\n },\n { id: string; notes: string | null }\n >({\n ...context,\n query: ApprovePayoutRequestDocument,\n variables: { id, notes },\n });\n}\n\nexport async function rejectPayoutRequest(id: string, reason: string, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n rejectPayoutRequest: { id: string };\n },\n { id: string; reason: string }\n >({\n ...context,\n query: RejectPayoutRequestDocument,\n variables: { id, reason },\n });\n}\n\nexport async function processPayoutRequest(id: string, context: GatewayContext) {\n await directBillingGraphqlRequest<\n {\n processPayoutRequest: { id: string };\n },\n { id: string }\n >({\n ...context,\n query: ProcessPayoutRequestDocument,\n variables: { id },\n });\n}\n\nexport async function markPayoutPaid(\n id: string,\n externalReference: string | null,\n notes: string | null,\n context: GatewayContext\n) {\n await directBillingGraphqlRequest<\n { markPayoutPaid: { id: string } },\n { id: string; externalReference: string | null; notes: string | null }\n >({\n ...context,\n query: MarkPayoutPaidDocument,\n variables: { id, externalReference, notes },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeveloperRevenueOrgDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n BadgeCheck,\n CreditCard,\n Loader2,\n TrendingDown,\n TrendingUp,\n Wallet,\n} from 'lucide-react';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { formatCredits, formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport {\n fetchAdminDeveloperRevenueOrg,\n fetchAdminDeveloperRevenueOrgDetail,\n fetchAdminDeveloperRevenueOrgMonthly,\n fetchAdminPayoutRequests,\n fetchBillingAccountCreditBalance,\n fetchCreditCost,\n retrySaleCreditSync,\n type AdminDeveloperRevenueOrg,\n type AdminDeveloperRevenueOrgDetail,\n type CreditBalanceByType,\n type DeveloperOrgMonthlyRevenuePoint,\n type PayoutRequest,\n} from '../api';\n\nconst ALL_TIME = 'all';\n\nconst PAYOUT_STATUS_LABEL: Record<string, string> = {\n REQUESTED: 'Requested',\n APPROVED: 'Approved',\n REJECTED: 'Rejected',\n PROCESSING: 'Processing',\n PAID: 'Paid',\n FAILED: 'Failed',\n CANCELED: 'Canceled',\n};\n\nconst PAYOUT_STATUS_COLORS: Record<string, string> = {\n REQUESTED: 'bg-status-warning-bg-subtle text-status-warning-text',\n APPROVED: 'bg-status-info-bg-subtle text-status-info-text',\n REJECTED: 'bg-status-error-bg-subtle text-status-error-text',\n PROCESSING: 'bg-status-info-bg-subtle text-status-info-text',\n PAID: 'bg-status-success-bg-subtle text-status-success-text',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text',\n CANCELED: 'bg-bg-sunken text-text-muted',\n};\n\nfunction PayoutStatusBadge({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${PAYOUT_STATUS_COLORS[status] ?? 'bg-bg-sunken text-text-muted'}`}\n >\n {PAYOUT_STATUS_LABEL[status] ?? status}\n </span>\n );\n}\n\nfunction formatMonthLabel(iso: string): string {\n return new Date(iso).toLocaleDateString('en-US', { month: 'short', year: 'numeric' });\n}\n\n/**\n * Turns a month-start ISO string (as returned by developerOrgMonthlyRevenue,\n * always the first instant of a calendar month) into a [startDate, endDate]\n * range covering that whole month, for scoping the sales/withdrawal queries.\n * ALL_TIME returns an empty range (no filtering).\n */\nfunction monthRangeFor(month: string): { startDate?: string; endDate?: string } {\n if (month === ALL_TIME) return {};\n const start = new Date(month);\n if (Number.isNaN(start.getTime())) return {};\n const startDate = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), 1)).toISOString();\n const endDate = new Date(\n Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, 1) - 1\n ).toISOString();\n return { startDate, endDate };\n}\n\nfunction MonthlyRevenueTrend({ points }: { points: DeveloperOrgMonthlyRevenuePoint[] }) {\n if (points.length === 0) {\n return (\n <div className=\"px-5 py-10 text-center text-sm text-text-muted\">\n No sales recorded yet — the revenue trend will appear once the first sale comes in.\n </div>\n );\n }\n\n return (\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\">Month</th>\n <th className=\"px-4 py-3\">Gross revenue</th>\n <th className=\"px-4 py-3\">Platform fee</th>\n <th className=\"px-4 py-3\">Net revenue</th>\n <th className=\"px-4 py-3\">Sales</th>\n <th className=\"px-4 py-3\">Growth (MoM)</th>\n </tr>\n </thead>\n <tbody>\n {points.map((point, index) => {\n const prior = index > 0 ? points[index - 1] : null;\n const growthPct =\n prior && prior.grossRevenue > 0\n ? ((point.grossRevenue - prior.grossRevenue) / prior.grossRevenue) * 100\n : null;\n\n return (\n <tr key={point.month} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-3 font-medium text-text-primary\">\n {formatMonthLabel(point.month)}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(point.grossRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(point.platformFees, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(point.netRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">{point.salesCount}</td>\n <td className=\"px-4 py-3\">\n {growthPct === null ? (\n <span className=\"text-text-muted\">—</span>\n ) : (\n <span\n className={`inline-flex items-center gap-1 font-medium ${\n growthPct >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {growthPct >= 0 ? (\n <TrendingUp className=\"size-3.5\" />\n ) : (\n <TrendingDown className=\"size-3.5\" />\n )}\n {growthPct >= 0 ? '+' : ''}\n {growthPct.toFixed(1)}%\n </span>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction WithdrawalHistory({ requests }: { requests: PayoutRequest[] }) {\n if (requests.length === 0) {\n return (\n <div className=\"px-5 py-10 text-center text-sm text-text-muted\">\n No withdrawal requests in this period.\n </div>\n );\n }\n\n return (\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\">Requested</th>\n <th className=\"px-4 py-3\">Kind</th>\n <th className=\"px-4 py-3\">Amount</th>\n <th className=\"px-4 py-3\">Status</th>\n <th className=\"px-4 py-3\">Paid</th>\n <th className=\"px-4 py-3\">Notes</th>\n </tr>\n </thead>\n <tbody>\n {requests.map((request) => (\n <tr key={request.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-3 text-text-secondary\">{formatDateTime(request.createdAt)}</td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {request.requestKind === 'CREDIT_CONVERSION' ? 'Revenue-share credits' : 'Cash payout'}\n </td>\n <td className=\"px-4 py-3 font-medium text-text-primary\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </td>\n <td className=\"px-4 py-3\">\n <PayoutStatusBadge status={request.status} />\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {request.paidAt ? formatDateTime(request.paidAt) : '—'}\n </td>\n <td className=\"px-4 py-3 text-text-muted\">\n {request.failureReason || request.userNotes || '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport const DeveloperRevenueOrgDetailPage: FC = () => {\n const { organizationId } = useParams<{ organizationId: string }>();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const navigateTo = useBillingNavigate();\n\n const [org, setOrg] = useState<AdminDeveloperRevenueOrg | null>(null);\n const [monthly, setMonthly] = useState<DeveloperOrgMonthlyRevenuePoint[]>([]);\n const [creditBalance, setCreditBalance] = useState<CreditBalanceByType | null>(null);\n const [creditBalanceUsd, setCreditBalanceUsd] = useState<number | null>(null);\n // Lifetime (unscoped) withdrawal history — drives the \"Already withdrawn\" /\n // in-flight totals up top, which must stay accurate regardless of which\n // month the tables below are currently scoped to.\n const [lifetimePayouts, setLifetimePayouts] = useState<PayoutRequest[]>([]);\n // Period-scoped data — re-fetched whenever selectedMonth changes.\n const [detail, setDetail] = useState<AdminDeveloperRevenueOrgDetail | null>(null);\n const [payoutHistory, setPayoutHistory] = useState<PayoutRequest[]>([]);\n const [selectedMonth, setSelectedMonth] = useState<string>(ALL_TIME);\n\n const [loading, setLoading] = useState(true);\n const [periodLoading, setPeriodLoading] = useState(false);\n const [error, setError] = 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 loadPeriod = useCallback(\n async (organizationIdValue: string, billingAccountId: string | null | undefined, month: string) => {\n const range = monthRangeFor(month);\n const [detailResult, payoutsResult] = await Promise.all([\n fetchAdminDeveloperRevenueOrgDetail(organizationIdValue, requestContext, range),\n billingAccountId\n ? fetchAdminPayoutRequests(requestContext, {\n limit: 100,\n filter: { billingAccountId, ...range },\n })\n : Promise.resolve({ items: [], totalCount: 0, hasMore: false }),\n ]);\n setDetail(detailResult);\n setPayoutHistory(payoutsResult.items);\n },\n [requestContext]\n );\n\n const load = useCallback(async () => {\n if (!organizationId) return;\n setLoading(true);\n setError(null);\n try {\n const [orgResult, monthlyResult] = await Promise.all([\n fetchAdminDeveloperRevenueOrg(organizationId, requestContext),\n fetchAdminDeveloperRevenueOrgMonthly(organizationId, requestContext, 12),\n ]);\n setOrg(orgResult);\n setMonthly(monthlyResult);\n\n const billingAccountId = orgResult?.billingAccountId ?? null;\n const defaultMonth =\n monthlyResult.length > 0 ? monthlyResult[monthlyResult.length - 1].month : ALL_TIME;\n setSelectedMonth(defaultMonth);\n\n const [balanceResult, lifetimeResult] = await Promise.all([\n billingAccountId\n ? fetchBillingAccountCreditBalance(billingAccountId, requestContext)\n : Promise.resolve(null),\n billingAccountId\n ? fetchAdminPayoutRequests(requestContext, { limit: 100, filter: { billingAccountId } })\n : Promise.resolve({ items: [], totalCount: 0, hasMore: false }),\n loadPeriod(organizationId, billingAccountId, defaultMonth),\n ]);\n setCreditBalance(balanceResult);\n setLifetimePayouts(lifetimeResult.items);\n\n if (balanceResult && balanceResult.total > 0) {\n fetchCreditCost(balanceResult.total, 'USD', requestContext)\n .then(setCreditBalanceUsd)\n .catch(() => setCreditBalanceUsd(null));\n } else {\n setCreditBalanceUsd(0);\n }\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load revenue detail'));\n } finally {\n setLoading(false);\n }\n }, [organizationId, requestContext, loadPeriod]);\n\n useEffect(() => {\n if (!permissions.isBillingAdmin) return;\n void load();\n }, [load, permissions.isBillingAdmin]);\n\n const handleMonthChange = (month: string) => {\n if (!organizationId || !org) return;\n setSelectedMonth(month);\n setPeriodLoading(true);\n void loadPeriod(organizationId, org.billingAccountId, month)\n .catch((loadError) => {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load period data'));\n })\n .finally(() => setPeriodLoading(false));\n };\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 load()}\n />\n );\n }\n\n if (loading || !org) {\n return (\n <div className=\"flex items-center justify-center py-20 text-text-secondary\">\n <Loader2 className=\"size-8 animate-spin\" />\n </div>\n );\n }\n\n const withdrawn = lifetimePayouts\n .filter((request) => request.status === 'PAID')\n .reduce((sum, request) => sum + (request.approvedAmount ?? request.requestedAmount), 0);\n const inFlight = lifetimePayouts\n .filter((request) => ['REQUESTED', 'APPROVED', 'PROCESSING'].includes(request.status))\n .reduce((sum, request) => sum + request.requestedAmount, 0);\n\n // Most-recent-first for the dropdown; `monthly` itself stays ascending\n // (oldest first) since that's what the trend table's MoM math needs.\n const monthOptions = [...monthly].reverse();\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={org.name}\n description={`/${org.slug}${org.isVerified ? ' · Verified developer organization' : ''}`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/developer-revenue')}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back to developer revenue\n </button>\n }\n />\n\n <PagePurpose>\n Store revenue for this org is credited into its linked billing account as earned credits.\n The developer withdraws those credits later through their own billing withdrawal flow — this\n page is a read-and-verify view of that whole loop, from sale to payout.\n </PagePurpose>\n\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-4\">\n <StatCard\n label=\"Gross revenue (all time)\"\n value={formatCurrency(org.totalRevenue, 'USD')}\n icon={<TrendingUp className=\"size-4\" />}\n />\n <StatCard\n label=\"Platform fees (all time)\"\n value={formatCurrency(org.totalPlatformFees, 'USD')}\n icon={<CreditCard className=\"size-4\" />}\n />\n <StatCard\n label=\"Pending earned credits\"\n value={formatCurrency(detail?.summary?.pendingBalance ?? org.pendingBalance, 'USD')}\n icon={<Wallet className=\"size-4\" />}\n />\n <StatCard\n label=\"Already withdrawn (all time)\"\n value={formatCurrency(withdrawn, 'USD')}\n icon={<BadgeCheck className=\"size-4\" />}\n />\n </div>\n\n <section 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\">Billing account balance</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n The current credit ledger on the org's linked billing account, right now. These are\n credit units, not currency — 1 credit is worth a small fraction of $1 at the platform's\n current credit rate.\n </p>\n </div>\n {!org.billingAccountId ? (\n <div className=\"px-5 py-8 text-center text-sm text-text-muted\">\n No billing account is linked yet — revenue cannot be credited until this org links one.\n </div>\n ) : !creditBalance ? (\n <div className=\"px-5 py-8 text-center text-sm text-text-muted\">\n Credit balance could not be loaded.\n </div>\n ) : (\n <>\n <div className=\"grid gap-3 p-5 md:grid-cols-3 xl:grid-cols-5\">\n <StatCard label=\"Earned\" value={formatCredits(creditBalance.earned)} />\n <StatCard label=\"Purchased\" value={formatCredits(creditBalance.purchased)} />\n <StatCard label=\"Granted\" value={formatCredits(creditBalance.granted)} />\n <StatCard label=\"Withdrawable\" value={formatCredits(creditBalance.withdrawable)} />\n <StatCard label=\"Total balance\" value={formatCredits(creditBalance.total)} />\n </div>\n <div className=\"px-5 pb-4 text-xs text-text-muted\">\n {creditBalanceUsd === null\n ? 'Estimated cash value could not be loaded.'\n : `≈ ${formatCurrency(creditBalanceUsd, 'USD')} total at the current credit rate.`}\n </div>\n </>\n )}\n {inFlight > 0 && (\n <div className=\"border-t border-border-seam bg-status-warning-bg-subtle px-5 py-3 text-xs text-status-warning-text\">\n {formatCurrency(inFlight, 'USD')} is currently tied up in a pending or approved\n withdrawal request — it has already left the withdrawable balance above.\n </div>\n )}\n </section>\n\n <section 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\">Monthly revenue trend</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Last 12 months of gross/net revenue for this org, computed from completed sales.\n </p>\n </div>\n <MonthlyRevenueTrend points={monthly} />\n </section>\n\n <div 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)]\">\n <div>\n <h2 className=\"text-sm font-semibold text-text-primary\">Viewing activity for</h2>\n <p className=\"mt-1 text-xs text-text-muted\">\n Scopes both the withdrawal history and sales tables below — pick a single month to keep\n long-running orgs easy to review, or switch to all time.\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n {periodLoading && <Loader2 className=\"size-4 animate-spin text-text-muted\" />}\n <select\n value={selectedMonth}\n onChange={(event) => handleMonthChange(event.target.value)}\n disabled={periodLoading}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary disabled:opacity-50\"\n >\n <option value={ALL_TIME}>All time</option>\n {monthOptions.map((point) => (\n <option key={point.month} value={point.month}>\n {formatMonthLabel(point.month)}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <section 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\">Withdrawal history</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Payout requests this org made in{' '}\n {selectedMonth === ALL_TIME ? 'all time' : formatMonthLabel(selectedMonth)} — both\n revenue-share credit conversions and cash payouts — with current status.\n </p>\n </div>\n <div className={periodLoading ? 'pointer-events-none opacity-50' : undefined}>\n <WithdrawalHistory requests={payoutHistory} />\n </div>\n </section>\n\n <section 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\">\n Sales currently contributing to earned credits\n </h2>\n <p className=\"mt-1 text-xs text-text-muted\">\n Unpaid sales purchased in{' '}\n {selectedMonth === ALL_TIME ? 'all time' : formatMonthLabel(selectedMonth)} that should\n exist as earned credits in the linked billing account until the developer withdraws them.\n </p>\n </div>\n <div\n className={`overflow-x-auto ${periodLoading ? 'pointer-events-none opacity-50' : ''}`}\n >\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\">Application</th>\n <th className=\"px-4 py-3\">Purchased</th>\n <th className=\"px-4 py-3\">Net revenue</th>\n <th className=\"px-4 py-3\">Credit sync</th>\n <th className=\"px-4 py-3\">Status</th>\n </tr>\n </thead>\n <tbody>\n {!detail || detail.unpaidSales.items.length === 0 ? (\n <tr>\n <td colSpan={5} className=\"px-4 py-8 text-center text-sm text-text-muted\">\n No outstanding unpaid sales in this period.\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-4 py-3\">\n <div className=\"font-medium text-text-primary\">\n {sale.application?.name ?? 'Unknown app'}\n </div>\n <div className=\"text-xs text-text-muted\">/{sale.application?.slug ?? 'unknown'}</div>\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatDateTime(sale.purchasedAt)}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(sale.netAmount, sale.currency)}\n </td>\n <td className=\"px-4 py-3 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={() => {\n if (!organizationId) return;\n void (async () => {\n setRetryingSaleId(sale.id);\n try {\n await retrySaleCreditSync(sale.id, requestContext);\n await loadPeriod(organizationId, org.billingAccountId, selectedMonth);\n } finally {\n setRetryingSaleId(null);\n }\n })();\n }}\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-4 py-3 text-text-secondary\">{sale.status}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeveloperRevenueOrgDetailPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/DeveloperRevenueOrgDetailPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n BadgeCheck,\n CreditCard,\n Loader2,\n TrendingDown,\n TrendingUp,\n Wallet,\n} from 'lucide-react';\n\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { useBillingNavigate } from '../../../hooks/useBillingNavigate';\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport {\n formatCredits,\n formatCurrency,\n formatDateTime,\n isServerError,\n} from '../../../shared/utils';\nimport {\n fetchAdminDeveloperRevenueOrg,\n fetchAdminDeveloperRevenueOrgDetail,\n fetchAdminDeveloperRevenueOrgMonthly,\n fetchAdminPayoutRequests,\n fetchBillingAccountCreditBalance,\n fetchCreditCost,\n retrySaleCreditSync,\n type AdminDeveloperRevenueOrg,\n type AdminDeveloperRevenueOrgDetail,\n type CreditBalanceByType,\n type DeveloperOrgMonthlyRevenuePoint,\n type PayoutRequest,\n} from '../api';\n\nconst ALL_TIME = 'all';\n\nconst PAYOUT_STATUS_LABEL: Record<string, string> = {\n REQUESTED: 'Requested',\n APPROVED: 'Approved',\n REJECTED: 'Rejected',\n PROCESSING: 'Processing',\n PAID: 'Paid',\n FAILED: 'Failed',\n CANCELED: 'Canceled',\n};\n\nconst PAYOUT_STATUS_COLORS: Record<string, string> = {\n REQUESTED: 'bg-status-warning-bg-subtle text-status-warning-text',\n APPROVED: 'bg-status-info-bg-subtle text-status-info-text',\n REJECTED: 'bg-status-error-bg-subtle text-status-error-text',\n PROCESSING: 'bg-status-info-bg-subtle text-status-info-text',\n PAID: 'bg-status-success-bg-subtle text-status-success-text',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text',\n CANCELED: 'bg-bg-sunken text-text-muted',\n};\n\nfunction PayoutStatusBadge({ status }: { status: string }) {\n return (\n <span\n className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${PAYOUT_STATUS_COLORS[status] ?? 'bg-bg-sunken text-text-muted'}`}\n >\n {PAYOUT_STATUS_LABEL[status] ?? status}\n </span>\n );\n}\n\nfunction formatMonthLabel(iso: string): string {\n return new Date(iso).toLocaleDateString('en-US', { month: 'short', year: 'numeric' });\n}\n\n/**\n * Turns a month-start ISO string (as returned by developerOrgMonthlyRevenue,\n * always the first instant of a calendar month) into a [startDate, endDate]\n * range covering that whole month, for scoping the sales/withdrawal queries.\n * ALL_TIME returns an empty range (no filtering).\n */\nfunction monthRangeFor(month: string): { startDate?: string; endDate?: string } {\n if (month === ALL_TIME) return {};\n const start = new Date(month);\n if (Number.isNaN(start.getTime())) return {};\n const startDate = new Date(\n Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), 1)\n ).toISOString();\n const endDate = new Date(\n Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, 1) - 1\n ).toISOString();\n return { startDate, endDate };\n}\n\nfunction MonthlyRevenueTrend({ points }: { points: DeveloperOrgMonthlyRevenuePoint[] }) {\n if (points.length === 0) {\n return (\n <div className=\"px-5 py-10 text-center text-sm text-text-muted\">\n No sales recorded yet — the revenue trend will appear once the first sale comes in.\n </div>\n );\n }\n\n return (\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\">Month</th>\n <th className=\"px-4 py-3\">Gross revenue</th>\n <th className=\"px-4 py-3\">Platform fee</th>\n <th className=\"px-4 py-3\">Net revenue</th>\n <th className=\"px-4 py-3\">Sales</th>\n <th className=\"px-4 py-3\">Growth (MoM)</th>\n </tr>\n </thead>\n <tbody>\n {points.map((point, index) => {\n const prior = index > 0 ? points[index - 1] : null;\n const growthPct =\n prior && prior.grossRevenue > 0\n ? ((point.grossRevenue - prior.grossRevenue) / prior.grossRevenue) * 100\n : null;\n\n return (\n <tr key={point.month} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-3 font-medium text-text-primary\">\n {formatMonthLabel(point.month)}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(point.grossRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(point.platformFees, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {formatCurrency(point.netRevenue, 'USD')}\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">{point.salesCount}</td>\n <td className=\"px-4 py-3\">\n {growthPct === null ? (\n <span className=\"text-text-muted\">—</span>\n ) : (\n <span\n className={`inline-flex items-center gap-1 font-medium ${\n growthPct >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {growthPct >= 0 ? (\n <TrendingUp className=\"size-3.5\" />\n ) : (\n <TrendingDown className=\"size-3.5\" />\n )}\n {growthPct >= 0 ? '+' : ''}\n {growthPct.toFixed(1)}%\n </span>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\nfunction WithdrawalHistory({ requests }: { requests: PayoutRequest[] }) {\n if (requests.length === 0) {\n return (\n <div className=\"px-5 py-10 text-center text-sm text-text-muted\">\n No withdrawal requests in this period.\n </div>\n );\n }\n\n return (\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\">Requested</th>\n <th className=\"px-4 py-3\">Kind</th>\n <th className=\"px-4 py-3\">Amount</th>\n <th className=\"px-4 py-3\">Status</th>\n <th className=\"px-4 py-3\">Paid</th>\n <th className=\"px-4 py-3\">Notes</th>\n </tr>\n </thead>\n <tbody>\n {requests.map((request) => (\n <tr key={request.id} className=\"border-t border-border-seam\">\n <td className=\"px-4 py-3 text-text-secondary\">{formatDateTime(request.createdAt)}</td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {request.requestKind === 'CREDIT_CONVERSION'\n ? 'Revenue-share credits'\n : 'Cash payout'}\n </td>\n <td className=\"px-4 py-3 font-medium text-text-primary\">\n {formatCurrency(request.requestedAmount, request.currency)}\n </td>\n <td className=\"px-4 py-3\">\n <PayoutStatusBadge status={request.status} />\n </td>\n <td className=\"px-4 py-3 text-text-secondary\">\n {request.paidAt ? formatDateTime(request.paidAt) : '—'}\n </td>\n <td className=\"px-4 py-3 text-text-muted\">\n {request.failureReason || request.userNotes || '—'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\nexport const DeveloperRevenueOrgDetailPage: FC = () => {\n const { organizationId } = useParams<{ organizationId: string }>();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const navigateTo = useBillingNavigate();\n\n const [org, setOrg] = useState<AdminDeveloperRevenueOrg | null>(null);\n const [monthly, setMonthly] = useState<DeveloperOrgMonthlyRevenuePoint[]>([]);\n const [creditBalance, setCreditBalance] = useState<CreditBalanceByType | null>(null);\n const [creditBalanceUsd, setCreditBalanceUsd] = useState<number | null>(null);\n // Lifetime (unscoped) withdrawal history — drives the \"Already withdrawn\" /\n // in-flight totals up top, which must stay accurate regardless of which\n // month the tables below are currently scoped to.\n const [lifetimePayouts, setLifetimePayouts] = useState<PayoutRequest[]>([]);\n // Period-scoped data — re-fetched whenever selectedMonth changes.\n const [detail, setDetail] = useState<AdminDeveloperRevenueOrgDetail | null>(null);\n const [payoutHistory, setPayoutHistory] = useState<PayoutRequest[]>([]);\n const [selectedMonth, setSelectedMonth] = useState<string>(ALL_TIME);\n\n const [loading, setLoading] = useState(true);\n const [periodLoading, setPeriodLoading] = useState(false);\n const [error, setError] = 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 loadPeriod = useCallback(\n async (\n organizationIdValue: string,\n billingAccountId: string | null | undefined,\n month: string\n ) => {\n const range = monthRangeFor(month);\n const [detailResult, payoutsResult] = await Promise.all([\n fetchAdminDeveloperRevenueOrgDetail(organizationIdValue, requestContext, range),\n billingAccountId\n ? fetchAdminPayoutRequests(requestContext, {\n limit: 100,\n filter: { billingAccountId, ...range },\n })\n : Promise.resolve({ items: [], totalCount: 0, hasMore: false }),\n ]);\n setDetail(detailResult);\n setPayoutHistory(payoutsResult.items);\n },\n [requestContext]\n );\n\n const load = useCallback(async () => {\n if (!organizationId) return;\n setLoading(true);\n setError(null);\n try {\n const [orgResult, monthlyResult] = await Promise.all([\n fetchAdminDeveloperRevenueOrg(organizationId, requestContext),\n fetchAdminDeveloperRevenueOrgMonthly(organizationId, requestContext, 12),\n ]);\n setOrg(orgResult);\n setMonthly(monthlyResult);\n\n const billingAccountId = orgResult?.billingAccountId ?? null;\n const defaultMonth =\n monthlyResult.length > 0 ? monthlyResult[monthlyResult.length - 1].month : ALL_TIME;\n setSelectedMonth(defaultMonth);\n\n const [balanceResult, lifetimeResult] = await Promise.all([\n billingAccountId\n ? fetchBillingAccountCreditBalance(billingAccountId, requestContext)\n : Promise.resolve(null),\n billingAccountId\n ? fetchAdminPayoutRequests(requestContext, { limit: 100, filter: { billingAccountId } })\n : Promise.resolve({ items: [], totalCount: 0, hasMore: false }),\n loadPeriod(organizationId, billingAccountId, defaultMonth),\n ]);\n setCreditBalance(balanceResult);\n setLifetimePayouts(lifetimeResult.items);\n\n if (balanceResult && balanceResult.total > 0) {\n fetchCreditCost(balanceResult.total, 'USD', requestContext)\n .then(setCreditBalanceUsd)\n .catch(() => setCreditBalanceUsd(null));\n } else {\n setCreditBalanceUsd(0);\n }\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load revenue detail'));\n } finally {\n setLoading(false);\n }\n }, [organizationId, requestContext, loadPeriod]);\n\n useEffect(() => {\n if (!permissions.isBillingAdmin) return;\n void load();\n }, [load, permissions.isBillingAdmin]);\n\n const handleMonthChange = (month: string) => {\n if (!organizationId || !org) return;\n setSelectedMonth(month);\n setPeriodLoading(true);\n void loadPeriod(organizationId, org.billingAccountId, month)\n .catch((loadError) => {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load period data'));\n })\n .finally(() => setPeriodLoading(false));\n };\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 load()}\n />\n );\n }\n\n if (loading || !org) {\n return (\n <div className=\"flex items-center justify-center py-20 text-text-secondary\">\n <Loader2 className=\"size-8 animate-spin\" />\n </div>\n );\n }\n\n const withdrawn = lifetimePayouts\n .filter((request) => request.status === 'PAID')\n .reduce((sum, request) => sum + (request.approvedAmount ?? request.requestedAmount), 0);\n const inFlight = lifetimePayouts\n .filter((request) => ['REQUESTED', 'APPROVED', 'PROCESSING'].includes(request.status))\n .reduce((sum, request) => sum + request.requestedAmount, 0);\n\n // Most-recent-first for the dropdown; `monthly` itself stays ascending\n // (oldest first) since that's what the trend table's MoM math needs.\n const monthOptions = [...monthly].reverse();\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={org.name}\n description={`/${org.slug}${org.isVerified ? ' · Verified developer organization' : ''}`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/developer-revenue')}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary\"\n >\n <ArrowLeft className=\"size-4\" />\n Back to developer revenue\n </button>\n }\n />\n\n <PagePurpose>\n Store revenue for this org is credited into its linked billing account as earned credits.\n The developer withdraws those credits later through their own billing withdrawal flow — this\n page is a read-and-verify view of that whole loop, from sale to payout.\n </PagePurpose>\n\n <div className=\"grid gap-3 md:grid-cols-2 xl:grid-cols-4\">\n <StatCard\n label=\"Gross revenue (all time)\"\n value={formatCurrency(org.totalRevenue, 'USD')}\n icon={<TrendingUp className=\"size-4\" />}\n />\n <StatCard\n label=\"Platform fees (all time)\"\n value={formatCurrency(org.totalPlatformFees, 'USD')}\n icon={<CreditCard className=\"size-4\" />}\n />\n <StatCard\n label=\"Pending earned credits\"\n value={formatCurrency(detail?.summary?.pendingBalance ?? org.pendingBalance, 'USD')}\n icon={<Wallet className=\"size-4\" />}\n />\n <StatCard\n label=\"Already withdrawn (all time)\"\n value={formatCurrency(withdrawn, 'USD')}\n icon={<BadgeCheck className=\"size-4\" />}\n />\n </div>\n\n <section 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\">Billing account balance</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n The current credit ledger on the org's linked billing account, right now. These are\n credit units, not currency — 1 credit is worth a small fraction of $1 at the\n platform's current credit rate.\n </p>\n </div>\n {!org.billingAccountId ? (\n <div className=\"px-5 py-8 text-center text-sm text-text-muted\">\n No billing account is linked yet — revenue cannot be credited until this org links one.\n </div>\n ) : !creditBalance ? (\n <div className=\"px-5 py-8 text-center text-sm text-text-muted\">\n Credit balance could not be loaded.\n </div>\n ) : (\n <>\n <div className=\"grid gap-3 p-5 md:grid-cols-3 xl:grid-cols-5\">\n <StatCard label=\"Earned\" value={formatCredits(creditBalance.earned)} />\n <StatCard label=\"Purchased\" value={formatCredits(creditBalance.purchased)} />\n <StatCard label=\"Granted\" value={formatCredits(creditBalance.granted)} />\n <StatCard label=\"Withdrawable\" value={formatCredits(creditBalance.withdrawable)} />\n <StatCard label=\"Total balance\" value={formatCredits(creditBalance.total)} />\n </div>\n <div className=\"px-5 pb-4 text-xs text-text-muted\">\n {creditBalanceUsd === null\n ? 'Estimated cash value could not be loaded.'\n : `≈ ${formatCurrency(creditBalanceUsd, 'USD')} total at the current credit rate.`}\n </div>\n </>\n )}\n {inFlight > 0 && (\n <div className=\"border-t border-border-seam bg-status-warning-bg-subtle px-5 py-3 text-xs text-status-warning-text\">\n {formatCurrency(inFlight, 'USD')} is currently tied up in a pending or approved\n withdrawal request — it has already left the withdrawable balance above.\n </div>\n )}\n </section>\n\n <section 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\">Monthly revenue trend</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Last 12 months of gross/net revenue for this org, computed from completed sales.\n </p>\n </div>\n <MonthlyRevenueTrend points={monthly} />\n </section>\n\n <div 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)]\">\n <div>\n <h2 className=\"text-sm font-semibold text-text-primary\">Viewing activity for</h2>\n <p className=\"mt-1 text-xs text-text-muted\">\n Scopes both the withdrawal history and sales tables below — pick a single month to keep\n long-running orgs easy to review, or switch to all time.\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n {periodLoading && <Loader2 className=\"size-4 animate-spin text-text-muted\" />}\n <select\n value={selectedMonth}\n onChange={(event) => handleMonthChange(event.target.value)}\n disabled={periodLoading}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary disabled:opacity-50\"\n >\n <option value={ALL_TIME}>All time</option>\n {monthOptions.map((point) => (\n <option key={point.month} value={point.month}>\n {formatMonthLabel(point.month)}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n <section 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\">Withdrawal history</h2>\n <p className=\"mt-1 text-sm text-text-muted\">\n Payout requests this org made in{' '}\n {selectedMonth === ALL_TIME ? 'all time' : formatMonthLabel(selectedMonth)} — both\n revenue-share credit conversions and cash payouts — with current status.\n </p>\n </div>\n <div className={periodLoading ? 'pointer-events-none opacity-50' : undefined}>\n <WithdrawalHistory requests={payoutHistory} />\n </div>\n </section>\n\n <section 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\">\n Sales currently contributing to earned credits\n </h2>\n <p className=\"mt-1 text-xs text-text-muted\">\n Unpaid sales purchased in{' '}\n {selectedMonth === ALL_TIME ? 'all time' : formatMonthLabel(selectedMonth)} that should\n exist as earned credits in the linked billing account until the developer withdraws\n them.\n </p>\n </div>\n <div className={`overflow-x-auto ${periodLoading ? 'pointer-events-none opacity-50' : ''}`}>\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\">Application</th>\n <th className=\"px-4 py-3\">Purchased</th>\n <th className=\"px-4 py-3\">Net revenue</th>\n <th className=\"px-4 py-3\">Credit sync</th>\n <th className=\"px-4 py-3\">Status</th>\n </tr>\n </thead>\n <tbody>\n {!detail || detail.unpaidSales.items.length === 0 ? (\n <tr>\n <td colSpan={5} className=\"px-4 py-8 text-center text-sm text-text-muted\">\n No outstanding unpaid sales in this period.\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-4 py-3\">\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-4 py-3 text-text-secondary\">\n {formatDateTime(sale.purchasedAt)}\n </td>\n <td className=\"px-4 py-3 text-text-primary\">\n {formatCurrency(sale.netAmount, sale.currency)}\n </td>\n <td className=\"px-4 py-3 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={() => {\n if (!organizationId) return;\n void (async () => {\n setRetryingSaleId(sale.id);\n try {\n await retrySaleCreditSync(sale.id, requestContext);\n await loadPeriod(\n organizationId,\n org.billingAccountId,\n selectedMonth\n );\n } finally {\n setRetryingSaleId(null);\n }\n })();\n }}\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-4 py-3 text-text-secondary\">{sale.status}</td>\n </tr>\n ))\n )}\n </tbody>\n </table>\n </div>\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -193,22 +193,22 @@ var ee = [
|
|
|
193
193
|
})) ?? [], ie = V?.summary ? [
|
|
194
194
|
{
|
|
195
195
|
title: "Gross revenue",
|
|
196
|
-
value: a(V.summary.totalGrossRevenue,
|
|
196
|
+
value: a(V.summary.totalGrossRevenue, V.summary.currency),
|
|
197
197
|
icon: /* @__PURE__ */ S(v, { className: "size-5" })
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
title: "Net revenue",
|
|
201
|
-
value: a(V.summary.totalNetRevenue,
|
|
201
|
+
value: a(V.summary.totalNetRevenue, V.summary.currency),
|
|
202
202
|
icon: /* @__PURE__ */ S(b, { className: "size-5" })
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
205
|
title: "Pending balance",
|
|
206
|
-
value: a(V.summary.pendingBalance,
|
|
206
|
+
value: a(V.summary.pendingBalance, V.summary.currency),
|
|
207
207
|
icon: /* @__PURE__ */ S(_, { className: "size-5" })
|
|
208
208
|
},
|
|
209
209
|
{
|
|
210
210
|
title: "Platform fees",
|
|
211
|
-
value: a(V.summary.totalPlatformFees,
|
|
211
|
+
value: a(V.summary.totalPlatformFees, V.summary.currency),
|
|
212
212
|
icon: /* @__PURE__ */ S(y, { className: "size-5" })
|
|
213
213
|
}
|
|
214
214
|
] : [], $ = !!P;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EarningsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/EarningsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n EmphasisPanel,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n fetchEarningsEntries,\n fetchEarningsSummary,\n fetchDeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueSale,\n type DeveloperPortalRevenuePayout,\n type EarningsEntry,\n type EarningsSummary,\n} from '../api';\n\ntype EarningsSourceFilter = 'ALL' | 'AFFILIATE' | 'STORE' | 'OTHER';\n\nconst salesColumns: ResponsiveTableColumn<DeveloperPortalRevenueSale>[] = [\n {\n key: 'application',\n header: 'Application',\n priority: 'primary',\n cell: (sale) => sale.application?.name || sale.application?.slug || 'Unknown app',\n },\n { key: 'pricing', header: 'Pricing', cell: (sale) => sale.pricingModel },\n {\n key: 'gross',\n header: 'Gross',\n cell: (sale) => (\n <span className=\"tabular-nums\">\n {formatCurrency(sale.grossAmount, sale.currency || 'USD')}\n </span>\n ),\n },\n {\n key: 'net',\n header: 'Net',\n cell: (sale) => (\n <span className=\"tabular-nums\">{formatCurrency(sale.netAmount, sale.currency || 'USD')}</span>\n ),\n },\n { key: 'status', header: 'Status', cell: (sale) => sale.status },\n {\n key: 'purchased',\n header: 'Purchased',\n cell: (sale) => formatDateTime(sale.purchasedAt),\n },\n];\n\nconst payoutColumns: ResponsiveTableColumn<DeveloperPortalRevenuePayout>[] = [\n {\n key: 'period',\n header: 'Period',\n priority: 'primary',\n cell: (payout) => payout.periodLabel || '-',\n },\n {\n key: 'amount',\n header: 'Amount',\n cell: (payout) => (\n <span className=\"tabular-nums\">\n {formatCurrency(payout.netAmount, payout.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (payout) => payout.status },\n {\n key: 'scheduled',\n header: 'Scheduled',\n cell: (payout) => (payout.scheduledAt ? formatDateTime(payout.scheduledAt) : '-'),\n },\n {\n key: 'completed',\n header: 'Completed',\n cell: (payout) => (payout.completedAt ? formatDateTime(payout.completedAt) : '-'),\n },\n];\n\nconst ledgerColumns: ResponsiveTableColumn<EarningsEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n priority: 'primary',\n cell: (entry) => entry.sourceCategory,\n },\n {\n key: 'description',\n header: 'Description',\n cell: (entry) => entry.description || entry.sourceSubcategory || '-',\n },\n { key: 'unit', header: 'Unit', cell: (entry) => entry.unitType },\n {\n key: 'amount',\n header: 'Amount',\n cell: (entry) => (\n <span className=\"tabular-nums\">\n {entry.unitType === 'CREDITS'\n ? `${entry.amount.toLocaleString()} credits`\n : formatCurrency(entry.amount, entry.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (entry) => entry.status },\n {\n key: 'created',\n header: 'Created',\n cell: (entry) => formatDateTime(entry.createdAt),\n },\n];\n\nexport const EarningsPage: FC = () => {\n const [searchParams] = useSearchParams();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\n const { data: billingAccountData, loading: billingAccountLoading } =\n useGetDefaultBillingAccountSettingsQuery({});\n\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n const [summary, setSummary] = useState<EarningsSummary | null>(null);\n const [entries, setEntries] = useState<EarningsEntry[]>([]);\n const [developerPortalRevenue, setDeveloperPortalRevenue] =\n useState<DeveloperPortalRevenueDashboard | null>(null);\n const [sourceFilter, setSourceFilter] = useState<EarningsSourceFilter>('ALL');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n if (developerOrgId) {\n const loadedRevenue = await fetchDeveloperPortalRevenueDashboard(\n developerOrgId,\n requestContext\n );\n setDeveloperPortalRevenue(loadedRevenue);\n setSummary(null);\n setEntries([]);\n return;\n }\n\n if (!billingAccountId) {\n setSummary(null);\n setEntries([]);\n setDeveloperPortalRevenue(null);\n return;\n }\n\n const [loadedSummary, loadedEntries] = await Promise.all([\n fetchEarningsSummary(billingAccountId, requestContext),\n fetchEarningsEntries(billingAccountId, requestContext),\n ]);\n setSummary(loadedSummary);\n setEntries(loadedEntries);\n setDeveloperPortalRevenue(null);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load earnings'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, developerOrgId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view earnings.\" />;\n }\n\n if (!developerOrgId && !billingAccountId && !billingAccountLoading) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No billing account found\"\n description=\"Create a billing account first to view earnings.\"\n />\n );\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Earnings unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const cards = summary\n ? [\n {\n title: 'Available',\n value: formatCurrency(summary.availableAmount, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Reserved',\n value: formatCurrency(summary.reservedAmount, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Paid out',\n value: formatCurrency(summary.paidAmount, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Lifetime',\n value: formatCurrency(summary.totalLifetimeAmount, 'USD'),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const filteredEntries =\n sourceFilter === 'ALL'\n ? entries\n : entries.filter((entry) => entry.sourceCategory === sourceFilter);\n\n const categoryCards =\n summary?.categoryBreakdown?.map((item) => ({\n title: `${item.category} earnings`,\n value: formatCurrency(item.amount, 'USD'),\n helperText: `${item.count} entries`,\n })) ?? [];\n\n const developerPortalCards = developerPortalRevenue?.summary\n ? [\n {\n title: 'Gross revenue',\n value: formatCurrency(developerPortalRevenue.summary.totalGrossRevenue, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(developerPortalRevenue.summary.totalNetRevenue, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(developerPortalRevenue.summary.pendingBalance, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(developerPortalRevenue.summary.totalPlatformFees, 'USD'),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const isDeveloperPortalMode = !!developerOrgId;\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={isDeveloperPortalMode ? 'Marketplace earnings' : 'Earnings'}\n description={\n isDeveloperPortalMode\n ? `Developer portal revenue, sales, and payouts${developerOrgName ? ` for ${developerOrgName}` : ''}.`\n : 'Track affiliate, store, and other earning sources in one ledger.'\n }\n />\n\n <PagePurpose>\n See everything you have earned — from affiliate rewards, store sales and marketplace revenue\n — in one ledger, along with how much has been paid out and what is still pending. Filter by\n source to reconcile a specific stream.\n </PagePurpose>\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : isDeveloperPortalMode ? (\n developerPortalRevenue?.summary ? (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {developerPortalCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent sales</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n\n {developerPortalRevenue.sales.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sales yet\"\n description=\"Sales will appear here when customers start purchasing your apps.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.sales}\n rowKey={(sale) => sale.id}\n columns={salesColumns}\n />\n )}\n </section>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payouts</h2>\n\n {developerPortalRevenue.payouts.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payouts yet\"\n description=\"Scheduled and completed payouts will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.payouts}\n rowKey={(payout) => payout.id}\n columns={payoutColumns}\n />\n )}\n </section>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No developer portal revenue yet\"\n description=\"Marketplace revenue will appear here once your developer organization records sales.\"\n />\n )\n ) : summary ? (\n <div className=\"space-y-4\">\n <EmphasisPanel className=\"p-4 sm:p-5\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {cards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n </EmphasisPanel>\n {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div\n key={card.title}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <p className=\"text-sm text-text-secondary\">{card.title}</p>\n <p className=\"mt-2 text-xl font-semibold text-text-primary\">{card.value}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{card.helperText}</p>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ledger</h2>\n <div className=\"flex items-center gap-3\">\n <select\n value={sourceFilter}\n onChange={(event) => setSourceFilter(event.target.value as EarningsSourceFilter)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"ALL\">All sources</option>\n <option value=\"AFFILIATE\">Affiliate</option>\n <option value=\"STORE\">Store</option>\n <option value=\"OTHER\">Other</option>\n </select>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n </div>\n\n {filteredEntries.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No earnings yet\"\n description=\"Eligible affiliate rewards and other earnings will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={filteredEntries}\n rowKey={(entry) => entry.id}\n columns={ledgerColumns}\n />\n )}\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EarningsPage.js","names":[],"sources":["../../../../../src/billing/modules/earnings/pages/EarningsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, type FC } from 'react';\nimport { useSearchParams } from 'react-router';\nimport { Coins, HandCoins, RefreshCw, Wallet } from 'lucide-react';\nimport {\n ResponsiveTable,\n type ResponsiveTableColumn,\n PagePurpose,\n EmphasisPanel,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\n\nimport { useBillingPermissions } from '../../../hooks/useBillingPermissions';\nimport { useBilling } from '../../../providers/BillingProvider';\nimport { AccessDenied, PageHeader, ServerError, StatCard } from '../../../shared/components';\nimport { formatCurrency, formatDateTime, isServerError } from '../../../shared/utils';\nimport { useGetDefaultBillingAccountSettingsQuery } from '../../../../generated/global-operations';\nimport {\n fetchEarningsEntries,\n fetchEarningsSummary,\n fetchDeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueDashboard,\n type DeveloperPortalRevenueSale,\n type DeveloperPortalRevenuePayout,\n type EarningsEntry,\n type EarningsSummary,\n} from '../api';\n\ntype EarningsSourceFilter = 'ALL' | 'AFFILIATE' | 'STORE' | 'OTHER';\n\nconst salesColumns: ResponsiveTableColumn<DeveloperPortalRevenueSale>[] = [\n {\n key: 'application',\n header: 'Application',\n priority: 'primary',\n cell: (sale) => sale.application?.name || sale.application?.slug || 'Unknown app',\n },\n { key: 'pricing', header: 'Pricing', cell: (sale) => sale.pricingModel },\n {\n key: 'gross',\n header: 'Gross',\n cell: (sale) => (\n <span className=\"tabular-nums\">\n {formatCurrency(sale.grossAmount, sale.currency || 'USD')}\n </span>\n ),\n },\n {\n key: 'net',\n header: 'Net',\n cell: (sale) => (\n <span className=\"tabular-nums\">{formatCurrency(sale.netAmount, sale.currency || 'USD')}</span>\n ),\n },\n { key: 'status', header: 'Status', cell: (sale) => sale.status },\n {\n key: 'purchased',\n header: 'Purchased',\n cell: (sale) => formatDateTime(sale.purchasedAt),\n },\n];\n\nconst payoutColumns: ResponsiveTableColumn<DeveloperPortalRevenuePayout>[] = [\n {\n key: 'period',\n header: 'Period',\n priority: 'primary',\n cell: (payout) => payout.periodLabel || '-',\n },\n {\n key: 'amount',\n header: 'Amount',\n cell: (payout) => (\n <span className=\"tabular-nums\">\n {formatCurrency(payout.netAmount, payout.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (payout) => payout.status },\n {\n key: 'scheduled',\n header: 'Scheduled',\n cell: (payout) => (payout.scheduledAt ? formatDateTime(payout.scheduledAt) : '-'),\n },\n {\n key: 'completed',\n header: 'Completed',\n cell: (payout) => (payout.completedAt ? formatDateTime(payout.completedAt) : '-'),\n },\n];\n\nconst ledgerColumns: ResponsiveTableColumn<EarningsEntry>[] = [\n {\n key: 'category',\n header: 'Category',\n priority: 'primary',\n cell: (entry) => entry.sourceCategory,\n },\n {\n key: 'description',\n header: 'Description',\n cell: (entry) => entry.description || entry.sourceSubcategory || '-',\n },\n { key: 'unit', header: 'Unit', cell: (entry) => entry.unitType },\n {\n key: 'amount',\n header: 'Amount',\n cell: (entry) => (\n <span className=\"tabular-nums\">\n {entry.unitType === 'CREDITS'\n ? `${entry.amount.toLocaleString()} credits`\n : formatCurrency(entry.amount, entry.currency || 'USD')}\n </span>\n ),\n },\n { key: 'status', header: 'Status', cell: (entry) => entry.status },\n {\n key: 'created',\n header: 'Created',\n cell: (entry) => formatDateTime(entry.createdAt),\n },\n];\n\nexport const EarningsPage: FC = () => {\n const [searchParams] = useSearchParams();\n const permissions = useBillingPermissions();\n const { apiGatewayUrl, authToken, orgId } = useBilling();\n const developerOrgId = searchParams.get('developerOrgId');\n const developerOrgName = searchParams.get('developerOrgName');\n const { data: billingAccountData, loading: billingAccountLoading } =\n useGetDefaultBillingAccountSettingsQuery({});\n\n const billingAccountId = billingAccountData?.getDefaultBillingAccount?.id;\n const [summary, setSummary] = useState<EarningsSummary | null>(null);\n const [entries, setEntries] = useState<EarningsEntry[]>([]);\n const [developerPortalRevenue, setDeveloperPortalRevenue] =\n useState<DeveloperPortalRevenueDashboard | null>(null);\n const [sourceFilter, setSourceFilter] = useState<EarningsSourceFilter>('ALL');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const requestContext = useMemo(\n () => ({\n apiGatewayUrl,\n authToken,\n orgId,\n }),\n [apiGatewayUrl, authToken, orgId]\n );\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n if (developerOrgId) {\n const loadedRevenue = await fetchDeveloperPortalRevenueDashboard(\n developerOrgId,\n requestContext\n );\n setDeveloperPortalRevenue(loadedRevenue);\n setSummary(null);\n setEntries([]);\n return;\n }\n\n if (!billingAccountId) {\n setSummary(null);\n setEntries([]);\n setDeveloperPortalRevenue(null);\n return;\n }\n\n const [loadedSummary, loadedEntries] = await Promise.all([\n fetchEarningsSummary(billingAccountId, requestContext),\n fetchEarningsEntries(billingAccountId, requestContext),\n ]);\n setSummary(loadedSummary);\n setEntries(loadedEntries);\n setDeveloperPortalRevenue(null);\n } catch (loadError) {\n setError(loadError instanceof Error ? loadError : new Error('Failed to load earnings'));\n } finally {\n setLoading(false);\n }\n }, [billingAccountId, developerOrgId, requestContext]);\n\n useEffect(() => {\n void loadData();\n }, [loadData]);\n\n if (!permissions.canViewBillingAccount) {\n return <AccessDenied message=\"You don't have permission to view earnings.\" />;\n }\n\n if (!developerOrgId && !billingAccountId && !billingAccountLoading) {\n return (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No billing account found\"\n description=\"Create a billing account first to view earnings.\"\n />\n );\n }\n\n if (error && isServerError(error)) {\n return (\n <ServerError\n title=\"Earnings unavailable\"\n message={error.message}\n onRetry={() => void loadData()}\n showRetry\n />\n );\n }\n\n const cards = summary\n ? [\n {\n title: 'Available',\n value: formatCurrency(summary.availableAmount, 'USD'),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Reserved',\n value: formatCurrency(summary.reservedAmount, 'USD'),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Paid out',\n value: formatCurrency(summary.paidAmount, 'USD'),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Lifetime',\n value: formatCurrency(summary.totalLifetimeAmount, 'USD'),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const filteredEntries =\n sourceFilter === 'ALL'\n ? entries\n : entries.filter((entry) => entry.sourceCategory === sourceFilter);\n\n const categoryCards =\n summary?.categoryBreakdown?.map((item) => ({\n title: `${item.category} earnings`,\n value: formatCurrency(item.amount, 'USD'),\n helperText: `${item.count} entries`,\n })) ?? [];\n\n const developerPortalCards = developerPortalRevenue?.summary\n ? [\n {\n title: 'Gross revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalGrossRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <HandCoins className=\"size-5\" />,\n },\n {\n title: 'Net revenue',\n value: formatCurrency(\n developerPortalRevenue.summary.totalNetRevenue,\n developerPortalRevenue.summary.currency\n ),\n icon: <Wallet className=\"size-5\" />,\n },\n {\n title: 'Pending balance',\n value: formatCurrency(\n developerPortalRevenue.summary.pendingBalance,\n developerPortalRevenue.summary.currency\n ),\n icon: <Coins className=\"size-5\" />,\n },\n {\n title: 'Platform fees',\n value: formatCurrency(\n developerPortalRevenue.summary.totalPlatformFees,\n developerPortalRevenue.summary.currency\n ),\n icon: <RefreshCw className=\"size-5\" />,\n },\n ]\n : [];\n\n const isDeveloperPortalMode = !!developerOrgId;\n\n return (\n <div className=\"space-y-6 p-6\">\n <PageHeader\n title={isDeveloperPortalMode ? 'Marketplace earnings' : 'Earnings'}\n description={\n isDeveloperPortalMode\n ? `Developer portal revenue, sales, and payouts${developerOrgName ? ` for ${developerOrgName}` : ''}.`\n : 'Track affiliate, store, and other earning sources in one ledger.'\n }\n />\n\n <PagePurpose>\n See everything you have earned — from affiliate rewards, store sales and marketplace revenue\n — in one ledger, along with how much has been paid out and what is still pending. Filter by\n source to reconcile a specific stream.\n </PagePurpose>\n\n {loading ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {[1, 2, 3, 4].map((item) => (\n <div\n key={item}\n className=\"h-28 animate-pulse rounded-lg border border-border-subtle bg-bg-surface\"\n />\n ))}\n </div>\n ) : isDeveloperPortalMode ? (\n developerPortalRevenue?.summary ? (\n <div className=\"space-y-6\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {developerPortalCards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Recent sales</h2>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n\n {developerPortalRevenue.sales.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sales yet\"\n description=\"Sales will appear here when customers start purchasing your apps.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.sales}\n rowKey={(sale) => sale.id}\n columns={salesColumns}\n />\n )}\n </section>\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Payouts</h2>\n\n {developerPortalRevenue.payouts.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No payouts yet\"\n description=\"Scheduled and completed payouts will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={developerPortalRevenue.payouts}\n rowKey={(payout) => payout.id}\n columns={payoutColumns}\n />\n )}\n </section>\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No developer portal revenue yet\"\n description=\"Marketplace revenue will appear here once your developer organization records sales.\"\n />\n )\n ) : summary ? (\n <div className=\"space-y-4\">\n <EmphasisPanel className=\"p-4 sm:p-5\">\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n {cards.map((card) => (\n <StatCard key={card.title} label={card.title} value={card.value} icon={card.icon} />\n ))}\n </div>\n </EmphasisPanel>\n {categoryCards.length > 0 ? (\n <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {categoryCards.map((card) => (\n <div\n key={card.title}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\"\n >\n <p className=\"text-sm text-text-secondary\">{card.title}</p>\n <p className=\"mt-2 text-xl font-semibold text-text-primary\">{card.value}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">{card.helperText}</p>\n </div>\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n\n {error && !isServerError(error) ? (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 text-sm text-status-error-text\">\n {error.message}\n </div>\n ) : null}\n\n <section className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ledger</h2>\n <div className=\"flex items-center gap-3\">\n <select\n value={sourceFilter}\n onChange={(event) => setSourceFilter(event.target.value as EarningsSourceFilter)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"ALL\">All sources</option>\n <option value=\"AFFILIATE\">Affiliate</option>\n <option value=\"STORE\">Store</option>\n <option value=\"OTHER\">Other</option>\n </select>\n <button\n type=\"button\"\n onClick={() => void loadData()}\n className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary\"\n >\n <RefreshCw className=\"size-4\" />\n Refresh\n </button>\n </div>\n </div>\n\n {filteredEntries.length === 0 && !loading ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No earnings yet\"\n description=\"Eligible affiliate rewards and other earnings will appear here.\"\n />\n ) : (\n <ResponsiveTable\n data={filteredEntries}\n rowKey={(entry) => entry.id}\n columns={ledgerColumns}\n />\n )}\n </section>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -508,10 +508,11 @@ var H = () => {
|
|
|
508
508
|
})
|
|
509
509
|
}),
|
|
510
510
|
/* @__PURE__ */ E(D, { children: [
|
|
511
|
-
"This queue holds two different kinds of request, split into the tabs below so a revenue-share credit conversion never gets mistaken for a real bank transfer.
|
|
511
|
+
"This queue holds two different kinds of request, split into the tabs below so a revenue-share credit conversion never gets mistaken for a real bank transfer.",
|
|
512
|
+
" ",
|
|
512
513
|
/* @__PURE__ */ T("strong", { children: "Cash Payouts" }),
|
|
514
|
+
" are real money leaving the platform — developers withdrawing purchased or earned credits from billing to their own bank/UPI account.",
|
|
513
515
|
" ",
|
|
514
|
-
"are real money leaving the platform — developers withdrawing purchased or earned credits from billing to their own bank/UPI account. ",
|
|
515
516
|
/* @__PURE__ */ T("strong", { children: "Revenue Share Credits" }),
|
|
516
517
|
" are a developer requesting their store revenue share — approving one just converts the amount into earned credits on their billing account, no transfer involved."
|
|
517
518
|
] }),
|