import React, { useEffect, useState, useMemo } from 'react'; import { StorageService } from '../services/storageService'; import { Task, TaskStatus, StudySession, Priority, UserProfile } from '../types'; import { useNavigate } from 'react-router-dom'; import { BarChart, Bar, XAxis, YAxis, Tooltip as RechartsTooltip, ResponsiveContainer, Cell, PieChart, Pie } from 'recharts'; import { TrendingUp, Zap, Target, Brain, Info, ArrowUpRight, Loader2, GraduationCap, Activity, CheckCircle2, Clock, Sparkles, PieChart as PieIcon, Zap as ZapIcon, Layout, ArrowUp, ArrowDown, Minus, AlertCircle } from 'lucide-react'; import { Button } from '../components/ui/Button'; import { useLanguage } from '../contexts/LanguageContext'; const CountUp = ({ end, duration = 1500 }: { end: number, duration?: number }) => { const [count, setCount] = useState(0); useEffect(() => { let startTime: number; let animationFrame: number; const update = (currentTime: number) => { if (!startTime) startTime = currentTime; const progress = Math.min((currentTime - startTime) / duration, 1); const ease = 1 - Math.pow(1 - progress, 4); setCount(Math.floor(ease * end)); if (progress < 1) animationFrame = requestAnimationFrame(update); }; animationFrame = requestAnimationFrame(update); return () => cancelAnimationFrame(animationFrame); }, [end, duration]); return <>{count}; }; const EmptyMetricState = ({ title, message, cta, onCtaClick, icon: Icon }: { title: string, message: string, cta: string, onCtaClick: () => void, icon: any }) => (

{title}

"{message}"

); const Analytics: React.FC = () => { const navigate = useNavigate(); const { t } = useLanguage(); const [tasks, setTasks] = useState([]); const [sessions, setSessions] = useState([]); const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { setLoading(true); const [tasksData, sessionsData, profileData] = await Promise.all([ StorageService.getTasks(), StorageService.getStudySessions(), StorageService.getProfile() ]); setTasks(tasksData); setSessions(sessionsData); setProfile(profileData); setLoading(false); }; fetchData(); }, []); const stats = useMemo(() => { if (tasks.length === 0 && sessions.length === 0) { return { score: 0, trend: 'stable', focus: 0, deepWork: 0, curriculum: 0, consistency: 0, difficulty: 0 }; } // 1. Focus Grade (30%): Completion percentage const completedTasks = tasks.filter(t => t.status === TaskStatus.COMPLETED).length; const focusGrade = tasks.length > 0 ? (completedTasks / tasks.length) * 100 : 0; // 2. Deep Work Hours (25%): Target 15 hours / week as 100% const totalFocusMinutes = sessions.filter(s => s.isFocusMode).reduce((sum, s) => sum + s.durationMinutes, 0); const deepWorkHours = totalFocusMinutes / 60; const deepWorkScore = Math.min(100, (deepWorkHours / 15) * 100); // 3. Curriculum Load Completion (20%): Percentage of tasks completed const curriculumScore = tasks.length > 0 ? (completedTasks / tasks.length) * 100 : 0; // 4. Consistency/Streaks (15%): Days active in the last 7 days const uniqueDays = new Set(sessions.map(s => new Date(s.timestamp).toLocaleDateString())).size; const consistencyScore = (uniqueDays / 7) * 100; // 5. Task Difficulty Handling (10%): Completion of High Priority tasks const highPriorityTasks = tasks.filter(t => t.priority === Priority.HIGH); const completedHighPriority = highPriorityTasks.filter(t => t.status === TaskStatus.COMPLETED).length; const difficultyScore = highPriorityTasks.length > 0 ? (completedHighPriority / highPriorityTasks.length) * 100 : 50; const compositeScore = Math.round( (focusGrade * 0.30) + (deepWorkScore * 0.25) + (curriculumScore * 0.20) + (consistencyScore * 0.15) + (difficultyScore * 0.10) ); let trend: 'up' | 'down' | 'stable' = 'stable'; if (sessions.length > 2) { const mid = Math.floor(sessions.length / 2); const recent = sessions.slice(mid).reduce((a, b) => a + b.durationMinutes, 0); const older = sessions.slice(0, mid).reduce((a, b) => a + b.durationMinutes, 0); if (recent > older * 1.1) trend = 'up'; else if (recent < older * 0.9) trend = 'down'; } return { score: compositeScore, trend, focus: Math.round(focusGrade), deepWork: Math.round(deepWorkHours * 10) / 10, curriculum: Math.round(curriculumScore), consistency: Math.round(consistencyScore), difficulty: Math.round(difficultyScore) }; }, [tasks, sessions]); const intensityMapping = useMemo(() => { const days = 7; const result = []; for (let i = days - 1; i >= 0; i--) { const d = new Date(); d.setDate(d.getDate() - i); const dateStr = d.toLocaleDateString(); const mins = sessions .filter(s => new Date(s.timestamp).toLocaleDateString() === dateStr) .reduce((sum, s) => sum + s.durationMinutes, 0); result.push({ name: d.toLocaleDateString(undefined, {weekday: 'short'}), mins }); } return result; }, [sessions]); const velocityByDiscipline = useMemo(() => { const subs = Array.from(new Set(tasks.map(t => t.subject))); return subs.map(sub => { const subTasks = tasks.filter(t => t.subject === sub); const completed = subTasks.filter(t => t.status === TaskStatus.COMPLETED).length; const subSessions = sessions.filter(s => s.subject === sub); const totalMins = subSessions.reduce((sum, s) => sum + s.durationMinutes, 0); return { subject: sub, percent: Math.round((completed / subTasks.length) * 100), time: totalMins, tasks: subTasks.length }; }).sort((a, b) => b.percent - a.percent); }, [tasks, sessions]); const curriculumLoad = useMemo(() => { const subjects = Array.from(new Set(tasks.map(t => t.subject))); return subjects.map((sub, i) => ({ name: sub, value: tasks.filter(t => t.subject === sub).length, fill: ['#ef4444', '#3b82f6', '#10b981', '#f59e0b', '#6366f1', '#ec4899'][i % 6] })); }, [tasks]); const stateAnalysisData = useMemo(() => { const deepWork = sessions.filter(s => s.isFocusMode).reduce((sum, s) => sum + s.durationMinutes, 0); const standardWork = sessions.filter(s => !s.isFocusMode).reduce((sum, s) => sum + s.durationMinutes, 0); return [ { name: 'Deep Work', value: deepWork, fill: '#4f46e5' }, { name: 'Standard', value: standardWork, fill: '#94a3b8' } ].filter(v => v.value > 0); }, [sessions]); const nextBestAction = useMemo(() => { const pending = tasks.filter(t => t.status !== TaskStatus.COMPLETED); if (pending.length === 0) return { title: "Set New Goals", desc: "Your queue is empty. Ready for the next challenge?", subject: "General" }; const highPriority = pending.find(t => t.priority === Priority.HIGH); if (highPriority) return { title: "High Priority Mission", desc: `Focus on ${highPriority.title}. It's critical for your curriculum progress.`, subject: highPriority.subject }; return { title: "Momentum Builder", desc: `Keep the streak alive by finishing "${pending[0].title}".`, subject: pending[0].subject }; }, [tasks]); if (loading) return (

Processing Intelligence Command...

); return (
{/* HEADER & COMPOSITE SCORE */}
{stats.trend === 'up' && } {stats.trend === 'down' && } {stats.trend === 'stable' && }
Intelligence Score

Cognitive Profile

This score reflects learning quality, not IQ. Breakdown: Focus (30%), Deep Work (25%), Completion (20%), Consistency (15%), Difficulty (10%).

Efficiency at {stats.focus}%. Deep work sessions are {stats.trend === 'up' ? 'increasing' : 'stabilizing'}.

{stats.score > 70 ? 'Scholar Class' : 'Active Growth'}
Level {Math.floor((profile?.xp || 0)/500)+1}

Recommendation

{nextBestAction.title}

"{nextBestAction.desc}"

{/* INTENSITY MAPPING (STUDY PULSE) */}

Intensity Pulse

Concentration Peaks (Last 7 Days)

{sessions.length > 0 && (

{(sessions.reduce((a,b) => a+b.durationMinutes,0)/60).toFixed(1)}h

Total Energy Invested

)}
{sessions.length === 0 ? ( navigate('/study-buddy')} icon={ZapIcon} /> ) : (
{ if (active && payload) return
{payload[0].value} Minutes
; return null; }} /> {intensityMapping.map((entry, index) => ( 60 ? '#dc2626' : entry.mins > 0 ? '#4f46e5' : '#e2e8f0'} /> ))}
)}
{/* CURRICULUM LOAD BREAKDOWN */}

Equilibrium Index

{tasks.length === 0 ? ( navigate('/planner')} icon={Layout} /> ) : (
{curriculumLoad.map((entry, index) => ( ))}
{curriculumLoad.map((item, i) => (
{item.name}
{item.value} Units
))}
)}
{/* STATE ANALYSIS */}

Flow Ratio

{sessions.length === 0 ? ( navigate('/study-buddy')} icon={ZapIcon} /> ) : (
{stateAnalysisData.map((item, i) => { const total = stateAnalysisData.reduce((a,b) => a+b.value, 0); const percent = Math.round((item.value / total) * 100); return (
{item.name} {percent}%
); })}

Focus sessions yield 2x faster mastery conversion.

)}
{/* VELOCITY BY DISCIPLINE */}

Subject Velocity

{velocityByDiscipline.length === 0 ? ( navigate('/planner')} icon={TrendingUp} /> ) : (
{velocityByDiscipline.map((sub, i) => (

{sub.subject}

{sub.time} Minutes Invested • {sub.tasks} Units

{sub.percent}%
))}
)}
); }; export default Analytics;