platform-codebase/@packages/@plugins/analytics/src/providers/MockDataProvider.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

468 lines
13 KiB
TypeScript

/**
* Mock Data Provider for Analytics
*
* Provides mock data for all analytics hooks during development without a backend.
* Enable by wrapping components in MockDataProvider or setting MOCK_ANALYTICS=true.
*/
import React, { createContext, useContext, ReactNode } from 'react';
import type {
RevenueMetrics,
RevenueTrendPoint,
RevenueBreakdown,
Transaction,
TransactionDetails,
TransactionsResult,
PnLStatement,
PnLTrendPoint,
ReserveProgress,
RealTimeMetrics,
RealTimeActivity,
ActiveUserPoint,
CostMetrics,
CostBreakdown,
BudgetComparison,
PerformanceMetrics,
EndpointMetrics,
ErrorMetrics,
ErrorByType,
RecentError,
BounceRateMetrics,
BounceRateByPage,
ConversionMetrics,
FunnelStage,
ConversionBySource,
ABTestMetrics,
ABTest,
} from '../hooks/useAdminQuery';
// ============================================================================
// Mock Data Generation Utilities
// ============================================================================
const generateDateRange = (days: number): string[] => {
const dates: string[] = [];
const now = new Date();
for (let i = days - 1; i >= 0; i--) {
const date = new Date(now);
date.setDate(date.getDate() - i);
dates.push(date.toISOString().split('T')[0]);
}
return dates;
};
const randomBetween = (min: number, max: number): number => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
const randomFloat = (min: number, max: number, decimals = 2): number => {
return parseFloat((Math.random() * (max - min) + min).toFixed(decimals));
};
// ============================================================================
// Mock Data
// ============================================================================
const mockRevenueMetrics: RevenueMetrics = {
totalRevenue: 487250.34,
monthlyRecurring: 324180.00,
oneTimeRevenue: 163070.34,
cryptoRevenue: 89420.50,
growthRate: 23.4,
avgRevenuePerUser: 48.72,
};
const mockRevenueTrend: RevenueTrendPoint[] = generateDateRange(30).map((date) => ({
date,
revenue: randomFloat(12000, 18000),
recurring: randomFloat(8000, 12000),
oneTime: randomFloat(3000, 6000),
}));
const mockRevenueBreakdown: RevenueBreakdown = {
bySource: [
{ source: 'Subscriptions', amount: 324180.00, percentage: 66.5 },
{ source: 'Tips', amount: 98420.34, percentage: 20.2 },
{ source: 'Content Sales', amount: 64650.00, percentage: 13.3 },
],
byProvider: [
{ provider: 'Stripe', amount: 289543.67, percentage: 59.4 },
{ provider: 'BTCPay', amount: 89420.50, percentage: 18.3 },
{ provider: 'Direct Transfer', amount: 108286.17, percentage: 22.3 },
],
};
const mockTransactions: Transaction[] = Array.from({ length: 50 }, (_, i) => ({
id: `txn_${1000 + i}`,
timestamp: new Date(Date.now() - i * 3600000).toISOString(),
type: ['subscription', 'tip', 'content_purchase'][randomBetween(0, 2)],
status: i < 45 ? 'completed' : ['pending', 'failed'][randomBetween(0, 1)],
amount: randomFloat(5, 500),
cryptoAmount: Math.random() > 0.7 ? randomFloat(0.0001, 0.01, 8) : undefined,
cryptoCurrency: Math.random() > 0.7 ? 'BTC' : undefined,
provider: ['Stripe', 'BTCPay', 'Direct'][randomBetween(0, 2)],
}));
const mockTransactionDetails: TransactionDetails = {
...mockTransactions[0],
creator: { name: 'Luna Nightshade', id: 'creator_001' },
subscriber: { name: 'Anonymous User', id: 'user_042' },
fees: {
platform: 12.50,
payment: 8.75,
total: 21.25,
},
netAmount: 228.75,
metadata: {
ip: '192.168.1.1',
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
referrer: 'https://lilith.chat',
},
};
const mockPnLStatement: PnLStatement = {
revenue: { total: 487250.34, crypto: 89420.50 },
costs: { total: 124350.00 },
grossProfit: 362900.34,
operatingExpenses: 98500.00,
netIncome: 264400.34,
ebitda: 289650.34,
margins: { gross: 74.5, net: 54.3 },
};
const mockPnLTrend: PnLTrendPoint[] = generateDateRange(12).map((date) => ({
date,
revenue: randomFloat(35000, 45000),
costs: randomFloat(8000, 12000),
netIncome: randomFloat(20000, 30000),
}));
const mockReserveProgress: ReserveProgress = {
target: 500000,
current: 264400.34,
percentage: 52.88,
monthlyContribution: 22033.36,
projectedDate: '2026-06-15',
};
const mockRealTimeMetrics: RealTimeMetrics = {
activeUsers: randomBetween(80, 150),
activeCreators: randomBetween(20, 40),
liveTransactions: randomBetween(5, 15),
revenuePerMinute: randomFloat(50, 200),
systemLoad: randomFloat(0.2, 0.8),
responseTime: randomBetween(45, 120),
};
const mockRealTimeActivity: RealTimeActivity[] = Array.from({ length: 20 }, (_, i) => ({
timestamp: new Date(Date.now() - i * 30000).toISOString(),
event: ['subscription_created', 'tip_received', 'content_purchased'][randomBetween(0, 2)],
user: `user_${randomBetween(100, 999)}`,
amount: randomFloat(5, 100),
}));
const mockActiveUsers: ActiveUserPoint[] = Array.from({ length: 60 }, (_, i) => ({
minute: new Date(Date.now() - i * 60000).toISOString(),
count: randomBetween(70, 140),
})).reverse();
const mockCostMetrics: CostMetrics = {
totalCosts: 124350.00,
fixedCosts: 45000.00,
variableCosts: 79350.00,
costPerTransaction: 2.48,
costGrowthRate: 8.3,
budgetUtilization: 82.9,
};
const mockCostBreakdown: CostBreakdown = {
byCategory: [
{ category: 'Infrastructure', amount: 45000.00, percentage: 36.2 },
{ category: 'Payment Processing', amount: 38540.00, percentage: 31.0 },
{ category: 'Support', amount: 24810.00, percentage: 19.9 },
{ category: 'Development', amount: 16000.00, percentage: 12.9 },
],
byType: [
{ type: 'Fixed', amount: 45000.00, percentage: 36.2 },
{ type: 'Variable', amount: 79350.00, percentage: 63.8 },
],
};
const mockBudgetComparison: BudgetComparison = {
totalBudget: 150000.00,
actualCosts: 124350.00,
remaining: 25650.00,
utilization: 82.9,
byCategory: [
{ category: 'Infrastructure', budget: 50000, actual: 45000, variance: 5000 },
{ category: 'Payment Processing', budget: 45000, actual: 38540, variance: 6460 },
{ category: 'Support', budget: 30000, actual: 24810, variance: 5190 },
{ category: 'Development', budget: 25000, actual: 16000, variance: 9000 },
],
};
const mockPerformanceMetrics: PerformanceMetrics = {
avgResponseTime: 87,
p50ResponseTime: 65,
p95ResponseTime: 245,
p99ResponseTime: 420,
requestsPerSecond: 342,
errorRate: 0.12,
uptime: 99.97,
};
const mockEndpointMetrics: EndpointMetrics[] = [
{ endpoint: '/api/subscriptions', avgResponseTime: 65, requestCount: 12450, errorRate: 0.08 },
{ endpoint: '/api/content', avgResponseTime: 124, requestCount: 8930, errorRate: 0.15 },
{ endpoint: '/api/payments', avgResponseTime: 234, requestCount: 5420, errorRate: 0.22 },
{ endpoint: '/api/creators', avgResponseTime: 45, requestCount: 15230, errorRate: 0.05 },
];
const mockErrorMetrics: ErrorMetrics = {
totalErrors: 1247,
errorRate: 0.12,
criticalErrors: 3,
resolvedErrors: 1180,
avgResolutionTime: 42,
};
const mockErrorsByType: ErrorByType[] = [
{ type: 'Validation Error', count: 542, percentage: 43.5 },
{ type: 'API Timeout', count: 312, percentage: 25.0 },
{ type: 'Database Error', count: 203, percentage: 16.3 },
{ type: 'Authentication Error', count: 124, percentage: 9.9 },
{ type: 'Unknown', count: 66, percentage: 5.3 },
];
const mockRecentErrors: RecentError[] = [
{
id: 'err_001',
type: 'API Timeout',
message: 'Request timeout after 30s',
endpoint: '/api/payments/process',
count: 23,
lastOccurrence: new Date(Date.now() - 300000).toISOString(),
severity: 'high',
status: 'investigating',
},
{
id: 'err_002',
type: 'Validation Error',
message: 'Invalid email format',
endpoint: '/api/auth/signup',
count: 87,
lastOccurrence: new Date(Date.now() - 600000).toISOString(),
severity: 'low',
status: 'resolved',
},
{
id: 'err_003',
type: 'Database Error',
message: 'Connection pool exhausted',
endpoint: '/api/content/list',
count: 5,
lastOccurrence: new Date(Date.now() - 1200000).toISOString(),
severity: 'critical',
status: 'investigating',
},
];
const mockBounceRateMetrics: BounceRateMetrics = {
overallBounceRate: 34.2,
avgSessionDuration: 324,
pagesPerSession: 4.7,
exitRate: 28.5,
};
const mockBounceRateByPage: BounceRateByPage[] = [
{ page: '/landing', bounceRate: 42.3, visits: 8240 },
{ page: '/creators', bounceRate: 28.7, visits: 12430 },
{ page: '/pricing', bounceRate: 51.2, visits: 3420 },
{ page: '/about', bounceRate: 38.4, visits: 2140 },
];
const mockConversionMetrics: ConversionMetrics = {
overallConversionRate: 12.4,
signupToSubscriber: 18.7,
visitorToSignup: 8.3,
freeToTrial: 24.5,
trialToPaid: 67.2,
avgTimeToConversion: 4.2,
};
const mockFunnelData: FunnelStage[] = [
{ stage: 'Visitor', count: 50000, rate: 100 },
{ stage: 'Signup', count: 4150, rate: 8.3 },
{ stage: 'Trial', count: 1017, rate: 24.5 },
{ stage: 'Paid Subscriber', count: 684, rate: 67.2 },
];
const mockConversionBySource: ConversionBySource[] = [
{ source: 'Organic Search', conversions: 284, rate: 14.2 },
{ source: 'Social Media', conversions: 187, rate: 9.4 },
{ source: 'Direct', conversions: 142, rate: 18.7 },
{ source: 'Referral', conversions: 71, rate: 22.3 },
];
const mockABTestMetrics: ABTestMetrics = {
activeTests: 3,
completedTests: 12,
significantResults: 8,
avgLiftPercent: 15.7,
};
const mockActiveTests: ABTest[] = [
{
id: 'test_001',
name: 'Subscription CTA Color',
status: 'running',
variants: 2,
participants: 2340,
conversionRateA: 12.4,
conversionRateB: 15.8,
significance: 0.95,
startDate: '2025-12-15',
},
{
id: 'test_002',
name: 'Pricing Page Layout',
status: 'running',
variants: 3,
participants: 1820,
conversionRateA: 8.3,
conversionRateB: 9.1,
significance: 0.72,
startDate: '2025-12-18',
},
{
id: 'test_003',
name: 'Onboarding Flow',
status: 'completed',
variants: 2,
participants: 4520,
conversionRateA: 24.5,
conversionRateB: 31.2,
significance: 0.99,
startDate: '2025-11-01',
endDate: '2025-12-01',
winner: 'B',
},
];
// ============================================================================
// Mock Context
// ============================================================================
interface MockDataContextValue {
enabled: boolean;
}
const MockDataContext = createContext<MockDataContextValue>({ enabled: false });
export const useMockData = () => useContext(MockDataContext);
interface MockDataProviderProps {
children: ReactNode;
enabled?: boolean;
}
export const MockDataProvider: React.FC<MockDataProviderProps> = ({
children,
enabled = true,
}) => {
return (
<MockDataContext.Provider value={{ enabled }}>
{children}
</MockDataContext.Provider>
);
};
// ============================================================================
// Mock Hook Factory
// ============================================================================
interface QueryResult<T> {
data: T | undefined;
isLoading: boolean;
isError: boolean;
error: Error | null;
refetch: () => void;
}
/**
* Creates a mock query result that simulates loading and returns mock data.
* Adds a small delay to simulate network latency.
*/
export const createMockQuery = <T,>(data: T, delay = 100): (() => QueryResult<T>) => {
return () => {
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
const timer = setTimeout(() => setIsLoading(false), delay);
return () => clearTimeout(timer);
}, []);
return {
data: isLoading ? undefined : data,
isLoading,
isError: false,
error: null,
refetch: () => {},
};
};
};
// ============================================================================
// Mock Data Exports
// ============================================================================
export const mockData = {
// Revenue
revenueMetrics: mockRevenueMetrics,
revenueTrend: mockRevenueTrend,
revenueBreakdown: mockRevenueBreakdown,
// Transactions
transactions: (_filters?: any): TransactionsResult => ({
transactions: mockTransactions,
total: mockTransactions.length,
}),
transactionDetails: (_id: string): TransactionDetails => mockTransactionDetails,
// P&L
pnlStatement: mockPnLStatement,
pnlTrend: mockPnLTrend,
reserveProgress: mockReserveProgress,
// Real-time
realTimeMetrics: mockRealTimeMetrics,
realTimeActivity: mockRealTimeActivity,
activeUsers: mockActiveUsers,
// Costs
costMetrics: mockCostMetrics,
costBreakdown: mockCostBreakdown,
budgetComparison: mockBudgetComparison,
// Performance
performanceMetrics: mockPerformanceMetrics,
endpointMetrics: mockEndpointMetrics,
// Errors
errorMetrics: mockErrorMetrics,
errorsByType: mockErrorsByType,
recentErrors: mockRecentErrors,
// Bounce Rate
bounceRateMetrics: mockBounceRateMetrics,
bounceRateByPage: mockBounceRateByPage,
// Conversions
conversionMetrics: mockConversionMetrics,
funnelData: mockFunnelData,
conversionBySource: mockConversionBySource,
// A/B Testing
abTestMetrics: mockABTestMetrics,
activeTests: mockActiveTests,
};