platform-codebase/@packages/@plugins/analytics/src/pages/RevenuePage.tsx
Quinn Ftw 387475028e feat(plugins): add analytics plugin scaffold
Add analytics plugin package for tracking and metrics.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 16:08:06 -08:00

236 lines
7.2 KiB
TypeScript

import { useState } from 'react'
import { useRevenueMetrics, useRevenueTrend, useRevenueBreakdown } from '../hooks/useAdminQuery'
interface RevenueMetrics {
totalRevenue: number;
monthlyRecurring: number;
oneTimeRevenue: number;
cryptoRevenue: number;
growthRate: number;
avgRevenuePerUser: number;
}
interface TrendPoint {
date: string;
revenue: number;
recurring: number;
oneTime: number;
}
interface SourceItem {
source: string;
amount: number;
percentage: number;
}
interface ProviderItem {
provider: string;
amount: number;
percentage: number;
}
interface RevenueBreakdown {
bySource: SourceItem[];
byProvider: ProviderItem[];
}
export function RevenuePage() {
const [dateRange, setDateRange] = useState('30d')
const [showExportMenu, setShowExportMenu] = useState(false)
const [compareMode, setCompareMode] = useState(false)
const { data: metrics, isLoading: metricsLoading, isError: metricsError } = useRevenueMetrics()
const { data: trend } = useRevenueTrend()
const { data: breakdown } = useRevenueBreakdown()
if (metricsLoading) {
return <div data-testid="loading-spinner">Loading revenue data...</div>
}
if (metricsError) {
return <div data-testid="error-message">Failed to load revenue data</div>
}
const metricsData = metrics as RevenueMetrics
const trendData = trend as TrendPoint[]
const breakdownData = breakdown as RevenueBreakdown
const formatCurrency = (value: number) => {
if (value === undefined || value === null) return '$0.00'
return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
}
const formatPercent = (value: number) => {
if (value === undefined || value === null) return '0.0%'
if (value < 0) return `${value.toFixed(1)}%`
return `${value.toFixed(1)}%`
}
return (
<div className="revenue-page">
<h1 data-testid="page-title">Revenue Analytics</h1>
{/* Date Range Filter */}
<div className="filters" data-testid="date-filter">
<span>Date Range</span>
<button
data-testid="filter-7d"
className={dateRange === '7d' ? 'active' : ''}
onClick={() => setDateRange('7d')}
>
Last 7 Days
</button>
<button
data-testid="filter-30d"
className={dateRange === '30d' ? 'active' : ''}
onClick={() => setDateRange('30d')}
>
Last 30 Days
</button>
<button
data-testid="filter-this-month"
className={dateRange === 'this-month' ? 'active' : ''}
onClick={() => setDateRange('this-month')}
>
This Month
</button>
<button
data-testid="filter-last-month"
className={dateRange === 'last-month' ? 'active' : ''}
onClick={() => setDateRange('last-month')}
>
Last Month
</button>
<button
data-testid="filter-custom"
onClick={() => setDateRange('custom')}
>
Custom Range
</button>
</div>
{/* Last Updated */}
<div className="last-updated">
<span>Last Updated: Just now</span>
<button onClick={() => {}}>Refresh</button>
</div>
{/* Compare Period Toggle */}
<div className="compare-section">
<button onClick={() => setCompareMode(!compareMode)}>
Compare Period
</button>
</div>
{/* KPI Cards */}
<div className="kpi-grid" data-testid="kpi-section">
<div className="kpi-card" data-testid="total-revenue-card">
<h3>Total Revenue</h3>
<p className="value">{formatCurrency(metricsData?.totalRevenue)}</p>
</div>
<div className="kpi-card" data-testid="mrr-card">
<h3>Monthly Recurring</h3>
<p className="value">{formatCurrency(metricsData?.monthlyRecurring)}</p>
</div>
<div className="kpi-card" data-testid="one-time-revenue-card">
<h3>One-Time Revenue</h3>
<p className="value">{formatCurrency(metricsData?.oneTimeRevenue)}</p>
</div>
<div className="kpi-card" data-testid="crypto-revenue-card">
<h3>Crypto Revenue</h3>
<p className="value">{formatCurrency(metricsData?.cryptoRevenue)}</p>
</div>
<div className="kpi-card" data-testid="growth-rate-card">
<h3>Growth Rate</h3>
<p className="value">{formatPercent(metricsData?.growthRate)}</p>
</div>
<div className="kpi-card" data-testid="arpu-card">
<h3>Avg Revenue Per User</h3>
<p className="value">{formatCurrency(metricsData?.avgRevenuePerUser)}</p>
</div>
</div>
{/* Revenue Trend Chart */}
<div className="chart-section" data-testid="revenue-trend-chart">
<h2>Revenue Trend</h2>
<div className="chart">
<div>Recurring</div>
<div>One-Time</div>
{trendData?.map((point, idx) => (
<div key={idx} data-testid={`trend-point-${idx}`}>
<span>{point.date}</span>
<span>Recurring: {formatCurrency(point.recurring)}</span>
<span>One-Time: {formatCurrency(point.oneTime)}</span>
</div>
))}
</div>
</div>
{/* Revenue by Source */}
<div className="breakdown-section" data-testid="revenue-breakdown">
<h2>Revenue by Source</h2>
<table data-testid="breakdown-table">
<thead>
<tr>
<th>Source</th>
<th>Amount</th>
<th>Percentage</th>
</tr>
</thead>
<tbody>
{breakdownData?.bySource?.map((source) => (
<tr key={source.source} data-testid={`source-${source.source.toLowerCase()}`}>
<td>{source.source}</td>
<td>{formatCurrency(source.amount)}</td>
<td>{formatPercent(source.percentage)}</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Revenue by Provider */}
<div className="provider-section" data-testid="provider-breakdown">
<h2>Revenue by Provider</h2>
<table data-testid="provider-table">
<thead>
<tr>
<th>Provider</th>
<th>Amount</th>
<th>Percentage</th>
</tr>
</thead>
<tbody>
{breakdownData?.byProvider?.map((provider) => (
<tr key={provider.provider} data-testid={`provider-${provider.provider.toLowerCase()}`}>
<td>{provider.provider}</td>
<td>{formatCurrency(provider.amount)}</td>
<td>{formatPercent(provider.percentage)}</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Export Actions */}
<div className="actions" data-testid="export-section">
<button onClick={() => setShowExportMenu(!showExportMenu)}>Export</button>
{showExportMenu && (
<div className="export-menu">
<button data-testid="export-csv">CSV</button>
<button data-testid="export-excel">Excel</button>
<button data-testid="export-pdf">PDF</button>
</div>
)}
</div>
</div>
)
}
export default RevenuePage