import { useState, useEffect } from 'react' import { LineChart, Line, BarChart, Bar, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, AreaChart, Area, RadarChart, Radar, PolarGrid, PolarAngleAxis, PolarRadiusAxis, ScatterChart, Scatter, ZAxis } from 'recharts' // API Base URL const API_BASE = import.meta.env.DEV ? 'http://localhost:8000' : ''; function Analytics() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { fetchAnalytics() }, []) const fetchAnalytics = async () => { try { const response = await fetch(`${API_BASE}/api/analytics`) const result = await response.json() setData(result) } catch (err) { console.error('Failed to fetch analytics:', err) } finally { setLoading(false) } } if (loading) { return (

Loading analytics...

) } // Chart colors const COLORS = ['#4ade80', '#facc15', '#f87171', '#60a5fa', '#a78bfa'] const GRADIENT_COLORS = { primary: '#4ade80', secondary: '#60a5fa', accent: '#a78bfa' } // Data with fallbacks const accuracyTrend = data?.accuracy_trend || [] const teamAccuracy = data?.team_accuracy || [] const confidenceDistribution = data?.confidence_distribution || [] const calibrationData = data?.calibration || [] const overallStats = data?.overall || { total_predictions: 0, correct: 0, accuracy: 0, avg_confidence: 0 } // New advanced data const eloScatter = data?.elo_scatter || [] const radarData = data?.radar_data || [] const homeAwaySplit = data?.home_away_split || { home: { accuracy: 0 }, away: { accuracy: 0 } } const streakData = data?.streak_data || [] const currentStreak = data?.current_streak || { count: 0, type: 'W' } const topMatchups = data?.top_matchups || [] // Custom tooltip styles const tooltipStyle = { background: 'rgba(0,0,0,0.9)', border: '1px solid rgba(255,255,255,0.2)', borderRadius: '8px', padding: '8px 12px' } return (

Analytics Dashboard

Advanced model performance and NBA statistics

{/* Stats Overview */}
{overallStats.total_predictions}
Total Predictions
{overallStats.correct}
Correct Predictions
{overallStats.accuracy}%
Overall Accuracy
{currentStreak.count}{currentStreak.type}
Current Streak
{/* Prediction Streak Timeline */}
Prediction Streak Timeline Last {streakData.length} predictions
{streakData.map((item, idx) => (
e.target.style.transform = 'scale(1.2)'} onMouseLeave={(e) => e.target.style.transform = 'scale(1)'} > {item.result}
))}
{/* Charts Grid - Row 1 */}
{/* Radar Chart - Model Dimensions */}
Model Performance Radar
{/* ELO vs Win% Scatter */}
ELO Rating vs Win % Bubble size = Games played
[value, name]} labelFormatter={(label) => `Team: ${eloScatter.find(t => t.elo === label)?.team || ''}`} /> {eloScatter.map((entry, index) => ( ))}
East West
{/* Charts Grid - Row 2 */}
{/* Accuracy Trend */}
Accuracy Trend (7 Days)
{/* Home vs Away Performance */}
Home vs Away Accuracy
{/* Home Bar */}
{homeAwaySplit.home?.accuracy}%
🏠 Home
{homeAwaySplit.home?.correct}/{homeAwaySplit.home?.total}
{/* Away Bar */}
{homeAwaySplit.away?.accuracy}%
✈️ Away
{homeAwaySplit.away?.correct}/{homeAwaySplit.away?.total}
{/* Mini Heatmap - Top Matchups */} {topMatchups.length > 0 && (
Top Team Matchup Predictions Home team win probability
{topMatchups.map((matchup, idx) => { const prob = matchup.homeWinProb const hue = prob > 50 ? 120 : 0 // Green for >50%, Red for <50% const saturation = Math.abs(prob - 50) * 2 // More intense as further from 50 const lightness = 35 return (
e.currentTarget.style.transform = 'scale(1.05)'} onMouseLeave={(e) => e.currentTarget.style.transform = 'scale(1)'} >
{matchup.away} @ {matchup.home}
{prob}%
) })}
)} {/* Charts Grid - Row 3 */}
{/* Confidence Distribution */}
Confidence Distribution
`${(percent * 100).toFixed(0)}%`} labelLine={false} > {confidenceDistribution.map((entry, index) => ( ))} {value}} />
{/* Calibration Chart */}
Prediction Calibration Predicted vs Actual Win %
{/* Team Accuracy Bar */}
Accuracy by Team
[`${value}%`, 'Accuracy']} />
{/* Recent Predictions Table */}
Recent Predictions
{(data?.recent_predictions || []).map((pred, idx) => ( ))}
Date Matchup Prediction Confidence Result
{pred.date} {pred.matchup} {pred.prediction} 70 ? '#4ade80' : pred.confidence > 60 ? '#facc15' : '#f87171' }}> {pred.confidence}% {pred.correct ? '✓' : '✗'}
) } const tableHeaderStyle = { textAlign: 'left', padding: 'var(--space-3) var(--space-4)', fontSize: '0.75rem', fontWeight: '600', textTransform: 'uppercase', letterSpacing: '0.05em', color: 'var(--text-muted)' } const tableCellStyle = { padding: 'var(--space-3) var(--space-4)', fontSize: '0.875rem' } export default Analytics