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>
468 lines
13 KiB
TypeScript
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,
|
|
};
|