'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: () => (
),
}
);
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) => (
))}
}
>
}
>
}
>
);
}