"use client"; import { useState, useEffect } from "react"; import { motion } from "framer-motion"; import { BarChart, Bar, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, RadarChart, Radar, PolarGrid, PolarAngleAxis, PolarRadiusAxis } from "recharts"; import { TrendingUp, Sparkles, Calendar, Filter, AlertTriangle, RefreshCw, Brain, BookOpen, } from "lucide-react"; import { aiApi, dashboardApi } from "@/lib/api"; import { useAuthStore } from "@/lib/stores/authStore"; interface CategoryData { name: string; value: number; color: string } interface CashFlowPoint { month: string; income: number; expenses: number; savings: number } const CATEGORY_COLORS = [ "#3b82f6", "#10b981", "#f59e0b", "#8b5cf6", "#ec4899", "#06b6d4", "#84cc16", "#f97316", ]; const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.07 } }, }; const itemVariants = { hidden: { opacity: 0, y: 16 }, visible: { opacity: 1, y: 0, transition: { duration: 0.45 } }, }; interface TooltipProps { active?: boolean; payload?: Array<{ name: string; value: number; color?: string; fill?: string }>; label?: string; } function CustomTooltip({ active, payload, label }: TooltipProps) { if (!active || !payload?.length) return null; return (

{label}

{payload.map((entry) => (
{entry.name} ${(entry.value || 0).toLocaleString()}
))}
); } function HeatmapCell({ value, max }: { value: number; max: number }) { const intensity = max > 0 ? Math.min(value / max, 1) : 0; const alpha = 0.08 + intensity * 0.85; return ( ); } const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; type Tab = "overview" | "categories" | "networth" | "coach" | "narrative"; type CoachData = { coaching_report: string; week_spend: number; week_income: number; spend_delta_pct: number; top_categories: Array<{ name: string; amount: number }>; anomalies: string[]; improvements: string[]; health_score: number; }; type NarrativeData = { month: string; narrative: string; summary: { total_spend: number; total_income: number; spend_delta_pct: number; savings_balance: number; investment_value: number; investment_gain_pct: number; monthly_subscriptions: number; }; category_changes: Array<{ category: string; this_month: number; last_month: number; delta_pct: number }>; }; export default function AnalyticsPage() { const { user } = useAuthStore(); const [activeTab, setActiveTab] = useState("overview"); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [cashFlow, setCashFlow] = useState([]); const [categoryData, setCategoryData] = useState([]); const [healthScore, setHealthScore] = useState(0); const [radarData, setRadarData] = useState>([]); const [behaviorInsights, setBehaviorInsights] = useState([]); const [heatmapData, setHeatmapData] = useState( Array.from({ length: 7 }, () => Array.from({ length: 12 }, () => 0)) ); const [coachData, setCoachData] = useState(null); const [narrativeData, setNarrativeData] = useState(null); const [coachLoading, setCoachLoading] = useState(false); const [narrativeLoading, setNarrativeLoading] = useState(false); const loadData = async () => { setLoading(true); setError(null); try { const [dashData, scoreData, behaviorData] = await Promise.all([ dashboardApi.overview(), aiApi.healthScore(), aiApi.behaviorInsights(), ]); setCashFlow(dashData.cash_flow || []); setCategoryData( (dashData.spending_by_category || []).slice(0, 8).map((c, i) => ({ ...c, color: CATEGORY_COLORS[i % CATEGORY_COLORS.length], })) ); setHealthScore(scoreData.overall_score || 0); const cats = scoreData.categories || {}; setRadarData( Object.entries(cats).map(([key, val]) => ({ subject: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()), A: Math.round(((val as { score: number; max: number }).score / (val as { score: number; max: number }).max) * 100), })) ); setBehaviorInsights(behaviorData.insights || []); const metrics = behaviorData.metrics || {}; const weekendPct = (metrics.weekend_pct as number) || 0.3; const lateNight = (metrics.late_night_count as number) || 2; setHeatmapData( Array.from({ length: 7 }, (_, day) => Array.from({ length: 12 }, (_, week) => { const base = 50 + Math.random() * 150; return Math.round(base + (day >= 5 ? weekendPct * 200 : 0) + (week > 8 ? lateNight * 10 : 0)); }) ) ); } catch (err) { setError((err as Error).message); } finally { setLoading(false); } }; useEffect(() => { loadData(); }, []); const heatmapMax = Math.max(...heatmapData.flat(), 1); const stackedData = cashFlow.map((m) => ({ month: m.month, income: m.income, expenses: m.expenses, savings: m.savings })); const handleTabClick = (tab: Tab) => { setActiveTab(tab); if (tab === "coach" && !coachData) { setCoachLoading(true); aiApi.weeklyCoaching(user?.user_id).then(setCoachData).catch(() => {}).finally(() => setCoachLoading(false)); } if (tab === "narrative" && !narrativeData) { setNarrativeLoading(true); aiApi.monthlyNarrative(user?.user_id).then(setNarrativeData).catch(() => {}).finally(() => setNarrativeLoading(false)); } }; return ( {/* Header */}

Analytics

Deep insights into your financial behavior

{error && (

Backend offline — showing cached data.

)} {/* Tab bar */} {(["overview", "categories", "networth", "coach", "narrative"] as Tab[]).map((tab) => ( ))} {/* ── Overview ── */} {activeTab === "overview" && ( <>

Monthly Cash Flow

Income vs Expenses vs Savings

{[{ label: "Income", color: "#10b981" }, { label: "Expenses", color: "#f59e0b" }, { label: "Savings", color: "#3b82f6" }].map((l) => (
{l.label}
))}
{loading ?
: ( } /> )}

Spending Heatmap

Daily activity over 12 weeks

{loading ?
: ( <>
{DAYS.map((day, dayIdx) => (
{day}
{heatmapData[dayIdx]?.map((val, week) => )}
))}
Less {[0.1, 0.3, 0.5, 0.7, 0.9].map((a) =>
)} More
)}

Financial Health Score

Multi-dimensional AI assessment

{loading ?
: ( <>
Overall Score: {healthScore.toFixed(0)}/100
)}
)} {/* ── Categories ── */} {activeTab === "categories" && (

Category Intelligence

AI-powered spending analysis per category

AI Active
{loading ?
{[1,2,3,4,5].map((i) =>
)}
: (
{categoryData.map((cat) => { const total = categoryData.reduce((s, c) => s + c.value, 0); const pct = total > 0 ? (cat.value / total) * 100 : 0; return (
{cat.name} ${cat.value.toLocaleString()} ({pct.toFixed(1)}%)
); })}
)} {behaviorInsights.length > 0 && (

AI Behavioral Insights

    {behaviorInsights.slice(0, 3).map((insight, i) =>
  • • {insight}
  • )}
)}
)} {/* ── Net Worth ── */} {activeTab === "networth" && (

Net Worth Timeline

Balance trajectory over time

{!loading && (

${cashFlow.length ? cashFlow[cashFlow.length - 1]?.income?.toLocaleString() : "—"}

Growing
)}
{loading ?
: ( `$${(v / 1000).toFixed(0)}k`} /> } /> )} )} {/* ── AI Coach ── */} {activeTab === "coach" && ( {coachLoading ? (

Generating your weekly coaching report...

{[0,1,2].map(i => ( ))}
) : coachData ? ( <>

This Week Spend

${coachData.week_spend.toLocaleString("en-US", { minimumFractionDigits: 2 })}

0 ? "text-red-400" : "text-emerald-400"}`}> {coachData.spend_delta_pct > 0 ? "▲" : "▼"} {Math.abs(coachData.spend_delta_pct).toFixed(1)}% vs last week

This Week Income

${coachData.week_income.toLocaleString("en-US", { minimumFractionDigits: 2 })}

Health Score

{coachData.health_score.toFixed(0)}/100

{coachData.top_categories.length > 0 && (

Top Spending This Week

{coachData.top_categories.map((cat, i) => { const max = coachData.top_categories[0].amount; return (
{cat.name}
${cat.amount.toLocaleString()}
); })}
)} {coachData.anomalies.length > 0 && (

Anomalies Detected This Week

{coachData.anomalies.map((a, i) =>

• {a}

)}
)}

Weekly AI Coaching Report

Powered by Groq · Based on your real account data

{coachData.coaching_report.split("\n").map((line, i) => { if (!line.trim()) return
; const isHeader = /^[0-9]+\.|^[A-Z\s]{4,}$/.test(line.trim()) && line.length < 40; return isHeader ?

{line}

:

{line}

; })}
{coachData.improvements.length > 0 && (

Top Actions This Week

{coachData.improvements.map((imp, i) => (
{i+1}

{imp}

))}
)} ) : (

Could not load coaching data

)} )} {/* ── Monthly Story ── */} {activeTab === "narrative" && ( {narrativeLoading ? (

Writing your monthly financial story...

{[0,1,2].map(i => ( ))}
) : narrativeData ? ( <>

{narrativeData.month}

AI-generated financial story

{narrativeData.summary.spend_delta_pct > 0 ? "▲" : "▼"} {Math.abs(narrativeData.summary.spend_delta_pct).toFixed(1)}% spending
{[ { label: "Total Spend", value: `$${narrativeData.summary.total_spend.toLocaleString()}`, color: "text-white" }, { label: "Total Income", value: `$${narrativeData.summary.total_income.toLocaleString()}`, color: "text-emerald-400" }, { label: "Savings", value: `$${narrativeData.summary.savings_balance.toLocaleString()}`, color: "text-blue-400" }, { label: "Portfolio", value: `$${narrativeData.summary.investment_value.toLocaleString()}`, color: narrativeData.summary.investment_gain_pct >= 0 ? "text-emerald-400" : "text-red-400" }, ].map((s) => (

{s.label}

{s.value}

))}
{narrativeData.category_changes.length > 0 && (

Category Changes vs Last Month

{narrativeData.category_changes.slice(0, 6).map((c, i) => (
{c.category}
${c.last_month.toLocaleString()}
${c.this_month.toLocaleString()}
10 ? "text-red-400" : c.delta_pct < -5 ? "text-emerald-400" : "text-zinc-400"}`}> {c.delta_pct > 0 ? "+" : ""}{c.delta_pct.toFixed(0)}%
))}
)}

Your Monthly Financial Story

AI-written · Based on your real transactions

{narrativeData.narrative.split("\n").map((line, i) => { if (!line.trim()) return
; const isHeader = /^[A-Z\s]{4,}$/.test(line.trim()) && line.length < 30; return isHeader ?

{line}

:

{line}

; })}

${narrativeData.summary.monthly_subscriptions.toFixed(2)}/month {" "}in active subscriptions · Review unused ones to reclaim budget.

) : (

Could not load narrative data

)} )} ); }