'use client'; import { useEffect, useState, Suspense } from 'react'; import { TrendingUp, Target, Clock, Flame, BarChart3, PieChart as PieChartIcon, } from 'lucide-react'; import dynamic from 'next/dynamic'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Tabs, TabsContent, TabsList, TabsTrigger, } from '@/components/ui/tabs'; // Lazy load recharts (~180KB) const AnalyticsCharts = dynamic( () => import('@/components/analytics/analytics-charts').then((m) => m.AnalyticsCharts), { ssr: false, loading: () => (
{[1, 2].map((i) => (
))}
), } ); interface AnalyticsData { taskCompletionRate: number; habitConsistency: number; totalTimeMinutes: number; activeStreaks: number; bestStreak: number; period: number; } interface TimeData { date: string; tasks: number; habits: number; time: number; } interface DomainData { name: string; value: number; color: string; } interface HabitData { name: string; streak: number; score: number; consistency: number; } export default function AnalyticsPage() { const [analytics, setAnalytics] = useState(null); const [timeData, setTimeData] = useState([]); const [domainData, setDomainData] = useState([]); const [habitData, setHabitData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { fetchAnalytics(); }, []); async function fetchAnalytics() { try { // Fetch overall analytics const analyticsResponse = await fetch('/api/analytics?period=30'); if (analyticsResponse.ok) { const analyticsData = await analyticsResponse.json(); setAnalytics(analyticsData); } // Fetch time summary const timeResponse = await fetch('/api/time-summary?period=30'); if (timeResponse.ok) { const timeSummary = await timeResponse.json(); // Transform to domain data for pie chart const COLORS = ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', '#ef4444', '#06b6d4']; const domains: DomainData[] = Object.entries( timeSummary.byDomain || {} ).map(([name, value], index) => ({ name, value: value as number, color: COLORS[index % COLORS.length], })); setDomainData(domains); } // Fetch habit streaks const habitsResponse = await fetch('/api/habits/streaks'); if (habitsResponse.ok) { const habitsData = await habitsResponse.json(); const habits: HabitData[] = (habitsData.streaks || []).map( (s: { habit: { name: string; score?: number }; current_streak: number; best_streak: number; }) => ({ name: s.habit.name, streak: s.current_streak, score: s.habit.score || 0, consistency: 0, // Would need to calculate from logs }) ); setHabitData(habits); } // Generate sample time data (would come from API in production) const sampleTimeData: TimeData[] = Array.from({ length: 30 }, (_, i) => { const date = new Date(); date.setDate(date.getDate() - (29 - i)); return { date: date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', }), tasks: Math.floor(Math.random() * 10) + 2, habits: Math.floor(Math.random() * 5) + 1, time: Math.floor(Math.random() * 180) + 30, }; }); setTimeData(sampleTimeData); } catch (error) { console.error('Failed to fetch analytics:', error); } finally { setLoading(false); } } if (loading || !analytics) { return

Loading analytics...

; } return (

Analytics

Patterns behind your progress.

{/* Summary cards */}
Task Completion
{analytics.taskCompletionRate}%

Last {analytics.period} days

Habit Consistency
{analytics.habitConsistency}%

Last {analytics.period} days

Time Tracked
{Math.round(analytics.totalTimeMinutes / 60)}h

Last {analytics.period} days

Active Streaks
{analytics.activeStreaks}

Best: {analytics.bestStreak} days

{/* Charts */} Trends Habits Time {[1, 2].map((i) => (
))}
} >
} > } >
); }