@burdenoff/microfe-devportal 2026.623.7 → 2026.623.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"RevenueDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/RevenueDashboardPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n Bar,\n BarChart,\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport {\n AlertCircle,\n ArrowDownToLine,\n Building2,\n Check,\n CreditCard,\n DollarSign,\n Link2,\n Loader2,\n Plus,\n Wallet,\n} from \"lucide-react\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n type GetBillingAccountsByOrgQuery,\n type GetMyOrganizationsQuery,\n type GetRevenueDashboardDataQuery,\n getErrorMessage,\n useCreateBillingAccountMutation,\n useGetBillingAccountsByOrgQuery,\n useGetMyOrganizationsQuery,\n useGetRevenueDashboardDataQuery,\n useLinkDevOrgBillingAccountMutation,\n} from \"../hooks\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\n\ntype TimeRange = \"30d\" | \"90d\" | \"12m\";\n\nconst chartColors = {\n primary: \"var(--color-chart-1)\",\n secondary: \"var(--color-chart-2)\",\n tertiary: \"var(--color-chart-4)\",\n};\n\ntype RevenueSale =\n GetRevenueDashboardDataQuery[\"developerOrgSales\"][\"edges\"][number][\"node\"];\ntype RevenuePayout =\n GetRevenueDashboardDataQuery[\"developerOrgPayouts\"][\"edges\"][number][\"node\"];\n\nconst daysByRange: Record<TimeRange, number> = {\n \"30d\": 30,\n \"90d\": 90,\n \"12m\": 365,\n};\n\nexport const RevenueDashboardPage: FC = () => {\n const tr = useTr();\n const { activeOrgId, currentUser } = useDevportal();\n const [timeRange, setTimeRange] = useState<TimeRange>(\"90d\");\n const [linkingBilling, setLinkingBilling] = useState(false);\n const [linkBillingError, setLinkBillingError] = useState<string | null>(null);\n\n const [createBillingAccount] = useCreateBillingAccountMutation();\n const [linkBillingAccount] = useLinkDevOrgBillingAccountMutation();\n const [showBillingPicker, setShowBillingPicker] = useState(false);\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<\n string | null\n >(null);\n const [searchParams] = useSearchParams();\n const now = useMemo(() => new Date(), []);\n\n const { data: billingAccountsData, loading: billingAccountsLoading } =\n useGetBillingAccountsByOrgQuery({\n fetchPolicy: \"cache-and-network\",\n skip: !activeOrgId,\n });\n // searchParams kept for deep-link compatibility (URL ?org= still works via OrgSwitcher auto-select)\n void searchParams;\n const startDate = useMemo(() => {\n const nextDate = new Date(now);\n nextDate.setDate(nextDate.getDate() - daysByRange[timeRange]);\n return nextDate.toISOString();\n }, [now, timeRange]);\n\n const {\n data: organizationsData,\n loading: organizationsLoading,\n error: organizationsError,\n } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n const { data, loading, error } = useGetRevenueDashboardDataQuery({\n variables: {\n organizationId: activeOrgId ?? \"\",\n period: \"monthly\",\n startDate,\n endDate: now.toISOString(),\n salesLimit: 10,\n salesOffset: 0,\n payoutsLimit: 10,\n payoutsOffset: 0,\n },\n skip: !activeOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations: DeveloperOrganization[] = useMemo(\n () =>\n organizationsData?.myDeveloperOrganizations?.map(\n (\n organization: GetMyOrganizationsQuery[\"myDeveloperOrganizations\"][number],\n ) => organization as unknown as DeveloperOrganization,\n ) ?? [],\n [organizationsData?.myDeveloperOrganizations],\n );\n\n const selectedOrganization = organizations.find(\n (organization) => organization.id === activeOrgId,\n );\n\n type BillingAccount =\n GetBillingAccountsByOrgQuery[\"getBillingAccountsByOrg\"][number];\n const existingBillingAccounts: BillingAccount[] =\n billingAccountsData?.getBillingAccountsByOrg ?? [];\n\n const linkedBillingAccount =\n existingBillingAccounts.find(\n (a) => a.id === selectedOrganization?.billingAccountId,\n ) ?? null;\n\n const handleOpenBillingPicker = () => {\n if (!billingAccountsLoading && existingBillingAccounts.length > 0) {\n // Pre-select the currently linked account; fall back to default or first\n setSelectedBillingAccountId(\n selectedOrganization?.billingAccountId ??\n existingBillingAccounts.find((a) => a.isDefault)?.id ??\n existingBillingAccounts[0]?.id ??\n null,\n );\n setShowBillingPicker(true);\n } else {\n void handleLinkWithNew();\n }\n };\n\n const handleLinkWithNew = async () => {\n if (!activeOrgId) return;\n setLinkingBilling(true);\n setLinkBillingError(null);\n try {\n const billingResult = await createBillingAccount({\n variables: {\n input: {\n name: selectedOrganization?.name ?? activeOrgId,\n email: currentUser?.email ?? \"\",\n },\n },\n });\n const billingAccountId = billingResult.data?.createBillingAccount?.id;\n if (billingAccountId) {\n await linkBillingAccount({\n variables: { organizationId: activeOrgId, billingAccountId },\n refetchQueries: [\"GetMyOrganizations\"],\n });\n }\n } catch (err) {\n setLinkBillingError(\n err instanceof Error ? err.message : \"Failed to link billing account\",\n );\n } finally {\n setLinkingBilling(false);\n setShowBillingPicker(false);\n }\n };\n\n const handleLinkExisting = async () => {\n if (!activeOrgId || !selectedBillingAccountId) return;\n setLinkingBilling(true);\n setLinkBillingError(null);\n try {\n await linkBillingAccount({\n variables: {\n organizationId: activeOrgId,\n billingAccountId: selectedBillingAccountId,\n },\n refetchQueries: [\"GetMyOrganizations\"],\n });\n setShowBillingPicker(false);\n } catch (err) {\n setLinkBillingError(\n err instanceof Error ? err.message : \"Failed to link billing account\",\n );\n } finally {\n setLinkingBilling(false);\n }\n };\n\n const summary = data?.developerOrgRevenueSummary;\n const analytics = [...(data?.developerOrgRevenueAnalytics ?? [])].sort(\n (left, right) =>\n new Date(left.date).getTime() - new Date(right.date).getTime(),\n );\n const sales: RevenueSale[] =\n data?.developerOrgSales?.edges?.map(\n (\n edge: GetRevenueDashboardDataQuery[\"developerOrgSales\"][\"edges\"][number],\n ) => edge.node,\n ) ?? [];\n const payouts: RevenuePayout[] =\n data?.developerOrgPayouts?.edges?.map(\n (\n edge: GetRevenueDashboardDataQuery[\"developerOrgPayouts\"][\"edges\"][number],\n ) => edge.node,\n ) ?? [];\n\n const chartData = analytics.map((entry) => ({\n date: new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n }),\n grossRevenue: entry.grossRevenue,\n netRevenue: entry.netRevenue,\n platformFees: entry.platformFees,\n refunds: entry.refunds,\n salesCount: entry.salesCount,\n }));\n\n if (organizationsLoading && !organizationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (organizationsError) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.revenue.errorLoadOrgs\",\n \"Unable to load organizations\",\n )}\n description={getErrorMessage(organizationsError)}\n />\n </PageLayout>\n );\n }\n\n if (!activeOrgId) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<Building2 size={32} className=\"text-muted-foreground\" />}\n title={tr(\n \"devportal.revenue.selectOrgTitle\",\n \"Select an organization\",\n )}\n description={tr(\n \"devportal.revenue.selectOrgHint\",\n \"Use the organization switcher in the nav bar above to choose which organization's revenue to view.\",\n )}\n />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.revenue.errorLoadData\",\n \"Unable to load revenue data\",\n )}\n description={getErrorMessage(error)}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={\n selectedOrganization\n ? `${tr(\"devportal.revenue.financialPerformanceFor\", \"Financial performance for\")} ${selectedOrganization.name}`\n : tr(\n \"devportal.revenue.shortDescription\",\n \"Track revenue, sales, and payouts\",\n )\n }\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <select\n value={timeRange}\n onChange={(event) => setTimeRange(event.target.value as TimeRange)}\n aria-label={tr(\n \"devportal.revenue.selectRangeAria\",\n \"Select time range\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"30d\">\n {tr(\"devportal.revenue.range.30d\", \"Last 30 days\")}\n </option>\n <option value=\"90d\">\n {tr(\"devportal.revenue.range.90d\", \"Last 90 days\")}\n </option>\n <option value=\"12m\">\n {tr(\"devportal.revenue.range.12m\", \"Last 12 months\")}\n </option>\n </select>\n </div>\n }\n >\n {/* Billing account link banner for orgs not yet linked */}\n {selectedOrganization && !selectedOrganization.billingAccountId && (\n <div className=\"mb-6 rounded-lg border border-border-subtle bg-status-info-bg-subtle p-4 flex flex-col gap-3\">\n <div className=\"flex items-start gap-3\">\n <Link2\n size={20}\n className=\"text-accent-blue flex-shrink-0 mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {tr(\n \"devportal.revenue.billingNotLinkedTitle\",\n \"Link a billing account to receive store revenue\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-status-info-text\">\n {tr(\n \"devportal.revenue.billingNotLinkedDesc\",\n \"Once linked, net earnings from app sales will appear in your billing credits — you can spend them on platform services or withdraw to your bank.\",\n )}\n </p>\n {linkBillingError && (\n <p className=\"mt-2 text-sm text-status-error-text\">\n {linkBillingError}\n </p>\n )}\n </div>\n <button\n type=\"button\"\n onClick={handleOpenBillingPicker}\n disabled={linkingBilling || billingAccountsLoading}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 flex-shrink-0\"\n >\n {linkingBilling || billingAccountsLoading ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Link2 size={14} />\n )}\n {linkingBilling\n ? tr(\"devportal.revenue.linking\", \"Linking...\")\n : tr(\n \"devportal.revenue.linkBillingAccount\",\n \"Link Billing Account\",\n )}\n </button>\n </div>\n\n {/* Billing account picker — shown when user has existing accounts */}\n {showBillingPicker && existingBillingAccounts.length > 0 && (\n <div className=\"rounded-lg border border-border bg-card p-4 ml-8 space-y-3\">\n <p className=\"text-sm font-medium\">\n {tr(\n \"devportal.revenue.chooseBillingAccount\",\n \"Choose a billing account to link\",\n )}\n </p>\n <div className=\"space-y-2\">\n {existingBillingAccounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n onClick={() =>\n setSelectedBillingAccountId(account.id ?? null)\n }\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === account.id\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === account.id\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{account.name}</p>\n {account.isDefault && (\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.revenue.defaultAccount\", \"Default\")}\n </p>\n )}\n </div>\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => setSelectedBillingAccountId(null)}\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === null\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === null\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1\">\n <p className=\"font-medium flex items-center gap-1.5\">\n <Plus size={13} />\n {tr(\n \"devportal.revenue.createNewBillingAccount\",\n \"Create a new billing account\",\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n \"devportal.revenue.createNewBillingAccountDesc\",\n \"A fresh billing account named after this organization\",\n )}\n </p>\n </div>\n </button>\n </div>\n <div className=\"flex items-center justify-end gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={() => {\n setShowBillingPicker(false);\n setLinkBillingError(null);\n }}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent transition-colors\"\n >\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n disabled={linkingBilling}\n onClick={() =>\n selectedBillingAccountId\n ? handleLinkExisting()\n : handleLinkWithNew()\n }\n className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {linkingBilling ? (\n <Loader2 size={13} className=\"animate-spin\" />\n ) : (\n <Link2 size={13} />\n )}\n {tr(\"devportal.revenue.confirm\", \"Confirm\")}\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Linked billing account info — shown when billing is already linked */}\n {selectedOrganization?.billingAccountId && (\n <div className=\"mb-6 rounded-lg border border-border bg-card p-3 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n <CreditCard\n size={16}\n className=\"text-muted-foreground flex-shrink-0\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">\n {linkedBillingAccount?.name ??\n tr(\"devportal.revenue.billingAccount\", \"Billing account\")}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">\n {linkedBillingAccount\n ? `${linkedBillingAccount.currency}${linkedBillingAccount.email ? ` · ${linkedBillingAccount.email}` : \"\"}`\n : selectedOrganization.billingAccountId}\n </p>\n </div>\n {!showBillingPicker && (\n <button\n type=\"button\"\n onClick={handleOpenBillingPicker}\n disabled={billingAccountsLoading}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors flex-shrink-0 disabled:opacity-50\"\n >\n {tr(\"devportal.revenue.changeBillingAccount\", \"Change\")}\n </button>\n )}\n </div>\n {/* Picker for changing the linked account */}\n {showBillingPicker && existingBillingAccounts.length > 0 && (\n <div className=\"rounded-lg border border-border bg-background p-4 space-y-3\">\n <p className=\"text-sm font-medium\">\n {tr(\n \"devportal.revenue.chooseBillingAccount\",\n \"Choose a billing account to link\",\n )}\n </p>\n <div className=\"space-y-2\">\n {existingBillingAccounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n onClick={() =>\n setSelectedBillingAccountId(account.id ?? null)\n }\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === account.id\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === account.id\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{account.name}</p>\n {account.isDefault && (\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.revenue.defaultAccount\", \"Default\")}\n </p>\n )}\n </div>\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => setSelectedBillingAccountId(null)}\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === null\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === null\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1\">\n <p className=\"font-medium flex items-center gap-1.5\">\n <Plus size={13} />\n {tr(\n \"devportal.revenue.createNewBillingAccount\",\n \"Create a new billing account\",\n )}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {tr(\n \"devportal.revenue.createNewBillingAccountDesc\",\n \"A fresh billing account named after this organization\",\n )}\n </p>\n </div>\n </button>\n </div>\n <div className=\"flex items-center justify-end gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={() => {\n setShowBillingPicker(false);\n setLinkBillingError(null);\n }}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent transition-colors\"\n >\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n disabled={linkingBilling}\n onClick={() =>\n selectedBillingAccountId\n ? void handleLinkExisting()\n : void handleLinkWithNew()\n }\n className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {linkingBilling ? (\n <Loader2 size={13} className=\"animate-spin\" />\n ) : (\n <Link2 size={13} />\n )}\n {tr(\"devportal.revenue.confirm\", \"Confirm\")}\n </button>\n </div>\n {linkBillingError && (\n <p className=\"text-xs text-status-error-text\">\n {linkBillingError}\n </p>\n )}\n </div>\n )}\n </div>\n )}\n\n {loading && !summary ? (\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n ) : summary ? (\n <>\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.revenue.grossRevenue\", \"Gross Revenue\")}\n value={`$${summary.totalGrossRevenue.toLocaleString()}`}\n icon={<DollarSign size={20} />}\n />\n <StatCard\n title={tr(\"devportal.revenue.netRevenue\", \"Net Revenue\")}\n value={`$${summary.totalNetRevenue.toLocaleString()}`}\n icon={<Wallet size={20} />}\n />\n <StatCard\n title={tr(\"devportal.revenue.pendingBalance\", \"Pending Balance\")}\n value={`$${summary.pendingBalance.toLocaleString()}`}\n icon={<CreditCard size={20} />}\n description={\n summary.nextPayoutDate\n ? `${tr(\"devportal.revenue.nextPayout\", \"Next payout\")} ${new Date(summary.nextPayoutDate).toLocaleDateString()}`\n : tr(\n \"devportal.revenue.noPayoutScheduled\",\n \"No payout scheduled\",\n )\n }\n />\n <StatCard\n title={tr(\"devportal.revenue.platformFees\", \"Platform Fees\")}\n value={`$${summary.totalPlatformFees.toLocaleString()}`}\n icon={<ArrowDownToLine size={20} />}\n description={`${summary.totalRefundsCount} ${tr(\"devportal.revenue.refunds\", \"refunds\")}`}\n />\n </StatCardGrid>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.revenue.revenueTrend\", \"Revenue trend\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"grossRevenue\"\n stroke={chartColors.primary}\n strokeWidth={2}\n dot={false}\n />\n <Line\n type=\"monotone\"\n dataKey=\"netRevenue\"\n stroke={chartColors.secondary}\n strokeWidth={2}\n dot={false}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.revenue.topApps\",\n \"Top applications by revenue\",\n )}\n >\n {summary.topApps.length > 0 ? (\n <div className=\"space-y-2\">\n {summary.topApps.map(\n (\n application: GetRevenueDashboardDataQuery[\"developerOrgRevenueSummary\"][\"topApps\"][number],\n ) => (\n <div\n key={application.applicationId}\n className=\"rounded-lg border bg-card p-4\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"font-medium\">\n {application.applicationName}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {application.salesCount}{\" \"}\n {tr(\"devportal.revenue.sales\", \"sales\")}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"font-semibold\">\n ${application.grossRevenue.toLocaleString()}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\"devportal.revenue.net\", \"Net\")} $\n {application.netRevenue.toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n ),\n )}\n </div>\n ) : (\n <EmptyState\n icon={<Building2 size={24} />}\n title={tr(\n \"devportal.revenue.noLeadersTitle\",\n \"No revenue leaders yet\",\n )}\n description={tr(\n \"devportal.revenue.noLeadersDescription\",\n \"Top-performing applications will appear here once revenue is recorded.\",\n )}\n />\n )}\n </PageSection>\n </div>\n\n <PageSection\n title={tr(\"devportal.revenue.salesVolume\", \"Sales volume\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={280}>\n <BarChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Bar\n dataKey=\"salesCount\"\n fill={chartColors.tertiary}\n radius={[6, 6, 0, 0]}\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.revenue.recentSales\", \"Recent sales\")}\n >\n <DataTable\n data={sales}\n keyField=\"id\"\n columns={[\n {\n key: \"application\",\n header: tr(\"devportal.revenue.application\", \"Application\"),\n render: (sale) =>\n sale.application?.name ||\n sale.planName ||\n tr(\"devportal.common.unknown\", \"Unknown\"),\n },\n {\n key: \"grossAmount\",\n header: tr(\"devportal.revenue.gross\", \"Gross\"),\n render: (sale) => `$${sale.grossAmount.toLocaleString()}`,\n },\n {\n key: \"netAmount\",\n header: tr(\"devportal.revenue.net\", \"Net\"),\n render: (sale) => `$${sale.netAmount.toLocaleString()}`,\n },\n {\n key: \"status\",\n header: tr(\"devportal.revenue.status\", \"Status\"),\n render: (sale) => (\n <StatusBadge status={sale.status} type=\"app\" />\n ),\n },\n ]}\n />\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.revenue.payoutHistory\", \"Payout history\")}\n >\n <DataTable\n data={payouts}\n keyField=\"id\"\n columns={[\n {\n key: \"periodLabel\",\n header: tr(\"devportal.revenue.period\", \"Period\"),\n render: (payout) => payout.periodLabel,\n },\n {\n key: \"netAmount\",\n header: tr(\"devportal.revenue.netPayout\", \"Net payout\"),\n render: (payout) => `$${payout.netAmount.toLocaleString()}`,\n },\n {\n key: \"status\",\n header: tr(\"devportal.revenue.status\", \"Status\"),\n render: (payout) => (\n <StatusBadge status={payout.status} type=\"app\" />\n ),\n },\n ]}\n />\n </PageSection>\n </div>\n </>\n ) : (\n <EmptyState\n icon={<DollarSign size={32} />}\n title={tr(\"devportal.revenue.noDataTitle\", \"No revenue data yet\")}\n description={tr(\n \"devportal.revenue.noDataDescription\",\n \"Revenue metrics will appear after this organization starts recording marketplace sales.\",\n )}\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"RevenueDashboardPage.js","names":[],"sources":["../../../src/devportal/pages/RevenueDashboardPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useMemo, useState } from \"react\";\nimport { useSearchParams } from \"react-router-dom\";\nimport {\n Bar,\n BarChart,\n CartesianGrid,\n Line,\n LineChart,\n ResponsiveContainer,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\nimport {\n AlertCircle,\n ArrowDownToLine,\n Building2,\n Check,\n CreditCard,\n DollarSign,\n Link2,\n Loader2,\n Wallet,\n} from \"lucide-react\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { PageLayout, PageSection } from \"../components/PageLayout\";\nimport { DataTable } from \"../components/DataTable\";\nimport { EmptyState } from \"../components/EmptyState\";\nimport { StatCard, StatCardGrid } from \"../components/StatCard\";\nimport { StatusBadge } from \"../components/StatusBadge\";\nimport type { DeveloperOrganization } from \"../types\";\nimport {\n type GetMyOrganizationsQuery,\n type GetRevenueDashboardDataQuery,\n getErrorMessage,\n useGetBillingAccountsByOrgQuery,\n useGetMyOrganizationsQuery,\n useGetRevenueDashboardDataQuery,\n useLinkDevOrgBillingAccountMutation,\n} from \"../hooks\";\nimport { cn } from \"../utils/cn\";\nimport { useTr } from \"../utils/i18n\";\n\ntype TimeRange = \"30d\" | \"90d\" | \"12m\";\n\nconst chartColors = {\n primary: \"var(--color-chart-1)\",\n secondary: \"var(--color-chart-2)\",\n tertiary: \"var(--color-chart-4)\",\n};\n\ntype RevenueSale =\n GetRevenueDashboardDataQuery[\"developerOrgSales\"][\"edges\"][number][\"node\"];\ntype RevenuePayout =\n GetRevenueDashboardDataQuery[\"developerOrgPayouts\"][\"edges\"][number][\"node\"];\n\nconst daysByRange: Record<TimeRange, number> = {\n \"30d\": 30,\n \"90d\": 90,\n \"12m\": 365,\n};\n\nexport const RevenueDashboardPage: FC = () => {\n const tr = useTr();\n const { activeOrgId, tenantId } = useDevportal();\n const [timeRange, setTimeRange] = useState<TimeRange>(\"90d\");\n const [linkingBilling, setLinkingBilling] = useState(false);\n const [linkBillingError, setLinkBillingError] = useState<string | null>(null);\n\n const [linkBillingAccount] = useLinkDevOrgBillingAccountMutation();\n const [showBillingPicker, setShowBillingPicker] = useState(false);\n const [selectedBillingAccountId, setSelectedBillingAccountId] = useState<\n string | null\n >(null);\n const [searchParams] = useSearchParams();\n const now = useMemo(() => new Date(), []);\n\n const { data: billingAccountsData, loading: billingAccountsLoading } =\n useGetBillingAccountsByOrgQuery({\n fetchPolicy: \"cache-and-network\",\n context: { headers: { \"x-org-id\": tenantId ?? \"\" } },\n });\n // searchParams kept for deep-link compatibility (URL ?org= still works via OrgSwitcher auto-select)\n void searchParams;\n const startDate = useMemo(() => {\n const nextDate = new Date(now);\n nextDate.setDate(nextDate.getDate() - daysByRange[timeRange]);\n return nextDate.toISOString();\n }, [now, timeRange]);\n\n const {\n data: organizationsData,\n loading: organizationsLoading,\n error: organizationsError,\n } = useGetMyOrganizationsQuery({\n fetchPolicy: \"cache-and-network\",\n });\n const { data, loading, error } = useGetRevenueDashboardDataQuery({\n variables: {\n organizationId: activeOrgId ?? \"\",\n period: \"monthly\",\n startDate,\n endDate: now.toISOString(),\n salesLimit: 10,\n salesOffset: 0,\n payoutsLimit: 10,\n payoutsOffset: 0,\n },\n skip: !activeOrgId,\n fetchPolicy: \"cache-and-network\",\n });\n\n const organizations: DeveloperOrganization[] = useMemo(\n () =>\n organizationsData?.myDeveloperOrganizations?.map(\n (\n organization: GetMyOrganizationsQuery[\"myDeveloperOrganizations\"][number],\n ) => organization as unknown as DeveloperOrganization,\n ) ?? [],\n [organizationsData?.myDeveloperOrganizations],\n );\n\n const selectedOrganization = organizations.find(\n (organization) => organization.id === activeOrgId,\n );\n\n type BillingAccount = NonNullable<\n typeof billingAccountsData\n >[\"getBillingAccountsByOrg\"][number];\n const existingBillingAccounts: BillingAccount[] =\n billingAccountsData?.getBillingAccountsByOrg ?? [];\n\n const linkedBillingAccount =\n existingBillingAccounts.find(\n (a) => a.id === selectedOrganization?.billingAccountId,\n ) ?? null;\n\n const handleOpenBillingPicker = () => {\n // Pre-select the currently linked account; fall back to default or first\n setSelectedBillingAccountId(\n selectedOrganization?.billingAccountId ??\n existingBillingAccounts.find((a) => a.isDefault)?.id ??\n existingBillingAccounts[0]?.id ??\n null,\n );\n setShowBillingPicker(true);\n };\n\n const handleLinkExisting = async () => {\n if (!activeOrgId || !selectedBillingAccountId) return;\n setLinkingBilling(true);\n setLinkBillingError(null);\n try {\n await linkBillingAccount({\n variables: {\n organizationId: activeOrgId,\n billingAccountId: selectedBillingAccountId,\n },\n refetchQueries: [\"GetMyOrganizations\"],\n });\n setShowBillingPicker(false);\n } catch (err) {\n setLinkBillingError(\n err instanceof Error ? err.message : \"Failed to link billing account\",\n );\n } finally {\n setLinkingBilling(false);\n }\n };\n\n const summary = data?.developerOrgRevenueSummary;\n const analytics = [...(data?.developerOrgRevenueAnalytics ?? [])].sort(\n (left, right) =>\n new Date(left.date).getTime() - new Date(right.date).getTime(),\n );\n const sales: RevenueSale[] =\n data?.developerOrgSales?.edges?.map(\n (\n edge: GetRevenueDashboardDataQuery[\"developerOrgSales\"][\"edges\"][number],\n ) => edge.node,\n ) ?? [];\n const payouts: RevenuePayout[] =\n data?.developerOrgPayouts?.edges?.map(\n (\n edge: GetRevenueDashboardDataQuery[\"developerOrgPayouts\"][\"edges\"][number],\n ) => edge.node,\n ) ?? [];\n\n const chartData = analytics.map((entry) => ({\n date: new Date(entry.date).toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n }),\n grossRevenue: entry.grossRevenue,\n netRevenue: entry.netRevenue,\n platformFees: entry.platformFees,\n refunds: entry.refunds,\n salesCount: entry.salesCount,\n }));\n\n if (organizationsLoading && !organizationsData) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n </PageLayout>\n );\n }\n\n if (organizationsError) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.revenue.errorLoadOrgs\",\n \"Unable to load organizations\",\n )}\n description={getErrorMessage(organizationsError)}\n />\n </PageLayout>\n );\n }\n\n if (!activeOrgId) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<Building2 size={32} className=\"text-muted-foreground\" />}\n title={tr(\n \"devportal.revenue.selectOrgTitle\",\n \"Select an organization\",\n )}\n description={tr(\n \"devportal.revenue.selectOrgHint\",\n \"Use the organization switcher in the nav bar above to choose which organization's revenue to view.\",\n )}\n />\n </PageLayout>\n );\n }\n\n if (error) {\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={tr(\n \"devportal.revenue.description\",\n \"Track real revenue, sales, and payout activity for your developer organizations\",\n )}\n >\n <EmptyState\n icon={<AlertCircle size={32} className=\"text-status-error-text\" />}\n title={tr(\n \"devportal.revenue.errorLoadData\",\n \"Unable to load revenue data\",\n )}\n description={getErrorMessage(error)}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={tr(\"devportal.revenue.title\", \"Revenue\")}\n description={\n selectedOrganization\n ? `${tr(\"devportal.revenue.financialPerformanceFor\", \"Financial performance for\")} ${selectedOrganization.name}`\n : tr(\n \"devportal.revenue.shortDescription\",\n \"Track revenue, sales, and payouts\",\n )\n }\n actions={\n <div className=\"flex flex-wrap gap-2\">\n <select\n value={timeRange}\n onChange={(event) => setTimeRange(event.target.value as TimeRange)}\n aria-label={tr(\n \"devportal.revenue.selectRangeAria\",\n \"Select time range\",\n )}\n className=\"rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary\"\n >\n <option value=\"30d\">\n {tr(\"devportal.revenue.range.30d\", \"Last 30 days\")}\n </option>\n <option value=\"90d\">\n {tr(\"devportal.revenue.range.90d\", \"Last 90 days\")}\n </option>\n <option value=\"12m\">\n {tr(\"devportal.revenue.range.12m\", \"Last 12 months\")}\n </option>\n </select>\n </div>\n }\n >\n {/* Billing account link banner for orgs not yet linked */}\n {selectedOrganization && !selectedOrganization.billingAccountId && (\n <div className=\"mb-6 rounded-lg border border-border-subtle bg-status-info-bg-subtle p-4 flex flex-col gap-3\">\n <div className=\"flex items-start gap-3\">\n <Link2\n size={20}\n className=\"text-accent-blue flex-shrink-0 mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {tr(\n \"devportal.revenue.billingNotLinkedTitle\",\n \"Link a billing account to receive store revenue\",\n )}\n </p>\n <p className=\"mt-1 text-sm text-status-info-text\">\n {tr(\n \"devportal.revenue.billingNotLinkedDesc\",\n \"Once linked, net earnings from app sales will appear in your billing credits — you can spend them on platform services or withdraw to your bank.\",\n )}\n </p>\n {linkBillingError && (\n <p className=\"mt-2 text-sm text-status-error-text\">\n {linkBillingError}\n </p>\n )}\n </div>\n <button\n type=\"button\"\n onClick={handleOpenBillingPicker}\n disabled={linkingBilling || billingAccountsLoading}\n className=\"inline-flex items-center gap-2 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 flex-shrink-0\"\n >\n {linkingBilling || billingAccountsLoading ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : (\n <Link2 size={14} />\n )}\n {linkingBilling\n ? tr(\"devportal.revenue.linking\", \"Linking...\")\n : tr(\n \"devportal.revenue.linkBillingAccount\",\n \"Link Billing Account\",\n )}\n </button>\n </div>\n\n {/* No billing accounts message */}\n {showBillingPicker && existingBillingAccounts.length === 0 && (\n <div className=\"rounded-lg border border-border bg-card p-4 ml-8 text-sm text-muted-foreground\">\n {tr(\n \"devportal.revenue.noBillingAccounts\",\n \"You don't have any billing accounts yet. Create one from your account billing settings first.\",\n )}\n </div>\n )}\n\n {/* Billing account picker — shown when user has existing accounts */}\n {showBillingPicker && existingBillingAccounts.length > 0 && (\n <div className=\"rounded-lg border border-border bg-card p-4 ml-8 space-y-3\">\n <p className=\"text-sm font-medium\">\n {tr(\n \"devportal.revenue.chooseBillingAccount\",\n \"Choose a billing account to link\",\n )}\n </p>\n <div className=\"space-y-2\">\n {existingBillingAccounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n onClick={() =>\n setSelectedBillingAccountId(account.id ?? null)\n }\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === account.id\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === account.id\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{account.name}</p>\n {account.isDefault && (\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.revenue.defaultAccount\", \"Default\")}\n </p>\n )}\n </div>\n </button>\n ))}\n </div>\n <div className=\"flex items-center justify-end gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={() => {\n setShowBillingPicker(false);\n setLinkBillingError(null);\n }}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent transition-colors\"\n >\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n disabled={linkingBilling || !selectedBillingAccountId}\n onClick={() => void handleLinkExisting()}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {linkingBilling ? (\n <Loader2 size={13} className=\"animate-spin\" />\n ) : (\n <Link2 size={13} />\n )}\n {tr(\"devportal.revenue.confirm\", \"Confirm\")}\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n\n {/* Linked billing account info — shown when billing is already linked */}\n {selectedOrganization?.billingAccountId && (\n <div className=\"mb-6 rounded-lg border border-border bg-card p-3 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n <CreditCard\n size={16}\n className=\"text-muted-foreground flex-shrink-0\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">\n {linkedBillingAccount?.name ??\n tr(\"devportal.revenue.billingAccount\", \"Billing account\")}\n </p>\n <p className=\"text-xs text-muted-foreground truncate\">\n {linkedBillingAccount\n ? `${linkedBillingAccount.currency}${linkedBillingAccount.email ? ` · ${linkedBillingAccount.email}` : \"\"}`\n : selectedOrganization.billingAccountId}\n </p>\n </div>\n {!showBillingPicker && (\n <button\n type=\"button\"\n onClick={handleOpenBillingPicker}\n disabled={billingAccountsLoading}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors flex-shrink-0 disabled:opacity-50\"\n >\n {tr(\"devportal.revenue.changeBillingAccount\", \"Change\")}\n </button>\n )}\n </div>\n {/* Picker for changing the linked account */}\n {showBillingPicker && existingBillingAccounts.length > 0 && (\n <div className=\"rounded-lg border border-border bg-background p-4 space-y-3\">\n <p className=\"text-sm font-medium\">\n {tr(\n \"devportal.revenue.chooseBillingAccount\",\n \"Choose a billing account to link\",\n )}\n </p>\n <div className=\"space-y-2\">\n {existingBillingAccounts.map((account) => (\n <button\n key={account.id}\n type=\"button\"\n onClick={() =>\n setSelectedBillingAccountId(account.id ?? null)\n }\n className={cn(\n \"flex w-full items-center gap-3 rounded-md border px-3 py-2.5 text-sm text-left transition-colors\",\n selectedBillingAccountId === account.id\n ? \"border-primary bg-primary/5 text-foreground\"\n : \"border-border hover:bg-accent text-foreground\",\n )}\n >\n <Check\n size={14}\n className={cn(\n \"flex-shrink-0\",\n selectedBillingAccountId === account.id\n ? \"opacity-100 text-primary\"\n : \"opacity-0\",\n )}\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"font-medium truncate\">{account.name}</p>\n {account.isDefault && (\n <p className=\"text-xs text-muted-foreground\">\n {tr(\"devportal.revenue.defaultAccount\", \"Default\")}\n </p>\n )}\n </div>\n </button>\n ))}\n </div>\n <div className=\"flex items-center justify-end gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={() => {\n setShowBillingPicker(false);\n setLinkBillingError(null);\n }}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent transition-colors\"\n >\n {tr(\"devportal.cancel\", \"Cancel\")}\n </button>\n <button\n type=\"button\"\n disabled={linkingBilling || !selectedBillingAccountId}\n onClick={() => void handleLinkExisting()}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50\"\n >\n {linkingBilling ? (\n <Loader2 size={13} className=\"animate-spin\" />\n ) : (\n <Link2 size={13} />\n )}\n {tr(\"devportal.revenue.confirm\", \"Confirm\")}\n </button>\n </div>\n {linkBillingError && (\n <p className=\"text-xs text-status-error-text\">\n {linkBillingError}\n </p>\n )}\n </div>\n )}\n </div>\n )}\n\n {loading && !summary ? (\n <div className=\"flex items-center justify-center py-16 text-muted-foreground\">\n <Loader2 className=\"h-8 w-8 animate-spin\" />\n </div>\n ) : summary ? (\n <>\n <StatCardGrid columns={4}>\n <StatCard\n title={tr(\"devportal.revenue.grossRevenue\", \"Gross Revenue\")}\n value={`$${summary.totalGrossRevenue.toLocaleString()}`}\n icon={<DollarSign size={20} />}\n />\n <StatCard\n title={tr(\"devportal.revenue.netRevenue\", \"Net Revenue\")}\n value={`$${summary.totalNetRevenue.toLocaleString()}`}\n icon={<Wallet size={20} />}\n />\n <StatCard\n title={tr(\"devportal.revenue.pendingBalance\", \"Pending Balance\")}\n value={`$${summary.pendingBalance.toLocaleString()}`}\n icon={<CreditCard size={20} />}\n description={\n summary.nextPayoutDate\n ? `${tr(\"devportal.revenue.nextPayout\", \"Next payout\")} ${new Date(summary.nextPayoutDate).toLocaleDateString()}`\n : tr(\n \"devportal.revenue.noPayoutScheduled\",\n \"No payout scheduled\",\n )\n }\n />\n <StatCard\n title={tr(\"devportal.revenue.platformFees\", \"Platform Fees\")}\n value={`$${summary.totalPlatformFees.toLocaleString()}`}\n icon={<ArrowDownToLine size={20} />}\n description={`${summary.totalRefundsCount} ${tr(\"devportal.revenue.refunds\", \"refunds\")}`}\n />\n </StatCardGrid>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.revenue.revenueTrend\", \"Revenue trend\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={300}>\n <LineChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"grossRevenue\"\n stroke={chartColors.primary}\n strokeWidth={2}\n dot={false}\n />\n <Line\n type=\"monotone\"\n dataKey=\"netRevenue\"\n stroke={chartColors.secondary}\n strokeWidth={2}\n dot={false}\n />\n </LineChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <PageSection\n title={tr(\n \"devportal.revenue.topApps\",\n \"Top applications by revenue\",\n )}\n >\n {summary.topApps.length > 0 ? (\n <div className=\"space-y-2\">\n {summary.topApps.map(\n (\n application: GetRevenueDashboardDataQuery[\"developerOrgRevenueSummary\"][\"topApps\"][number],\n ) => (\n <div\n key={application.applicationId}\n className=\"rounded-lg border bg-card p-4\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"font-medium\">\n {application.applicationName}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {application.salesCount}{\" \"}\n {tr(\"devportal.revenue.sales\", \"sales\")}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"font-semibold\">\n ${application.grossRevenue.toLocaleString()}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {tr(\"devportal.revenue.net\", \"Net\")} $\n {application.netRevenue.toLocaleString()}\n </p>\n </div>\n </div>\n </div>\n ),\n )}\n </div>\n ) : (\n <EmptyState\n icon={<Building2 size={24} />}\n title={tr(\n \"devportal.revenue.noLeadersTitle\",\n \"No revenue leaders yet\",\n )}\n description={tr(\n \"devportal.revenue.noLeadersDescription\",\n \"Top-performing applications will appear here once revenue is recorded.\",\n )}\n />\n )}\n </PageSection>\n </div>\n\n <PageSection\n title={tr(\"devportal.revenue.salesVolume\", \"Sales volume\")}\n >\n <div className=\"rounded-lg border bg-card p-4\">\n <ResponsiveContainer width=\"100%\" height={280}>\n <BarChart data={chartData}>\n <CartesianGrid\n strokeDasharray=\"3 3\"\n stroke=\"var(--color-chart-grid)\"\n />\n <XAxis\n dataKey=\"date\"\n stroke=\"var(--color-chart-axis)\"\n fontSize={12}\n />\n <YAxis stroke=\"var(--color-chart-axis)\" fontSize={12} />\n <Tooltip\n contentStyle={{\n backgroundColor: \"var(--color-card)\",\n border: \"1px solid var(--color-border-default)\",\n borderRadius: 12,\n }}\n />\n <Bar\n dataKey=\"salesCount\"\n fill={chartColors.tertiary}\n radius={[6, 6, 0, 0]}\n />\n </BarChart>\n </ResponsiveContainer>\n </div>\n </PageSection>\n\n <div className=\"grid gap-6 xl:grid-cols-2\">\n <PageSection\n title={tr(\"devportal.revenue.recentSales\", \"Recent sales\")}\n >\n <DataTable\n data={sales}\n keyField=\"id\"\n columns={[\n {\n key: \"application\",\n header: tr(\"devportal.revenue.application\", \"Application\"),\n render: (sale) =>\n sale.application?.name ||\n sale.planName ||\n tr(\"devportal.common.unknown\", \"Unknown\"),\n },\n {\n key: \"grossAmount\",\n header: tr(\"devportal.revenue.gross\", \"Gross\"),\n render: (sale) => `$${sale.grossAmount.toLocaleString()}`,\n },\n {\n key: \"netAmount\",\n header: tr(\"devportal.revenue.net\", \"Net\"),\n render: (sale) => `$${sale.netAmount.toLocaleString()}`,\n },\n {\n key: \"status\",\n header: tr(\"devportal.revenue.status\", \"Status\"),\n render: (sale) => (\n <StatusBadge status={sale.status} type=\"app\" />\n ),\n },\n ]}\n />\n </PageSection>\n\n <PageSection\n title={tr(\"devportal.revenue.payoutHistory\", \"Payout history\")}\n >\n <DataTable\n data={payouts}\n keyField=\"id\"\n columns={[\n {\n key: \"periodLabel\",\n header: tr(\"devportal.revenue.period\", \"Period\"),\n render: (payout) => payout.periodLabel,\n },\n {\n key: \"netAmount\",\n header: tr(\"devportal.revenue.netPayout\", \"Net payout\"),\n render: (payout) => `$${payout.netAmount.toLocaleString()}`,\n },\n {\n key: \"status\",\n header: tr(\"devportal.revenue.status\", \"Status\"),\n render: (payout) => (\n <StatusBadge status={payout.status} type=\"app\" />\n ),\n },\n ]}\n />\n </PageSection>\n </div>\n </>\n ) : (\n <EmptyState\n icon={<DollarSign size={32} />}\n title={tr(\"devportal.revenue.noDataTitle\", \"No revenue data yet\")}\n description={tr(\n \"devportal.revenue.noDataDescription\",\n \"Revenue metrics will appear after this organization starts recording marketplace sales.\",\n )}\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -1600,6 +1600,13 @@ function xt(e) {
1600
1600
  };
1601
1601
  return t.useQuery(bt, r);
1602
1602
  }
1603
+ e`
1604
+ query MyBillingAccounts {
1605
+ myBillingAccounts {
1606
+ ...BillingAccountFields
1607
+ }
1608
+ }
1609
+ ${d}`;
1603
1610
  var St = e`
1604
1611
  query GetMyDeveloperProfile {
1605
1612
  myDeveloperProfile {