"use client"; import { useEffect } from "react"; import { motion } from "framer-motion"; import { TrendingUp, TrendingDown, DollarSign, CreditCard, ArrowUpRight, ArrowDownRight, Sparkles, Shield, ChevronRight, Activity, AlertTriangle } from "lucide-react"; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from "recharts"; import { useDashboardStore } from "@/lib/stores/dashboardStore"; import { useAuthStore } from "@/lib/stores/authStore"; import { useLanguageStore } from "@/lib/stores/languageStore"; import { useThemeStore } from "@/lib/stores/themeStore"; import Link from "next/link"; // ─── Category colors ────────────────────────────────────────────────────────── const CATEGORY_COLORS = [ "#3b82f6", "#10b981", "#f59e0b", "#8b5cf6", "#ec4899", "#06b6d4", "#84cc16", "#f97316", "#6b7280", ]; // ─── Animation variants ─────────────────────────────────────────────────────── const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.08 } }, }; const itemVariants = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: "easeOut" as const } }, }; // ─── Skeleton loader ────────────────────────────────────────────────────────── function Skeleton({ className }: { className?: string }) { return
; } // ─── Custom Tooltip ─────────────────────────────────────────────────────────── interface TooltipProps { active?: boolean; payload?: Array<{ name: string; value: number; color?: string }>; label?: string; } function CustomTooltip({ active, payload, label }: TooltipProps) { if (!active || !payload?.length) return null; return (

{label}

{payload.map((entry) => (
{entry.name} ${entry.value.toLocaleString()}
))}
); } // ─── Stat Card ──────────────────────────────────────────────────────────────── interface StatCardProps { title: string; value: string; change?: string; positive?: boolean; icon: React.ElementType; gradient: string; lightGradient: string; iconColor: string; borderColor: string; lightBorderColor: string; loading?: boolean; isLight: boolean; } function StatCard({ title, value, change, positive, icon: Icon, gradient, lightGradient, iconColor, borderColor, lightBorderColor, loading, isLight }: StatCardProps) { return (

{title}

{loading ? ( ) : (

{value}

)}
{change && !loading && (
{positive ? ( ) : ( )} {change} vs last month
)} ); } // ─── Main Page ──────────────────────────────────────────────────────────────── export default function Home() { const { data, isLoading, error, fetch } = useDashboardStore(); const { user } = useAuthStore(); const { t } = useLanguageStore(); const { theme } = useThemeStore(); const isLight = theme === "light"; // Recharts axis tick color const tickColor = isLight ? "#64748b" : "#71717a"; const gridColor = isLight ? "rgba(15,23,42,0.07)" : "rgba(255,255,255,0.05)"; useEffect(() => { fetch(); }, [fetch]); const firstName = user?.name?.split(" ")[0] || "there"; const greeting = () => { const h = new Date().getHours(); if (h < 12) return t("good_morning"); if (h < 17) return t("good_afternoon"); return t("good_evening"); }; const briefingText = data?.ai_briefing ? (typeof data.ai_briefing === "string" ? data.ai_briefing : data.ai_briefing.summary || data.ai_briefing.briefing || "Your financial health looks good today.") : null; const categoryData = (data?.spending_by_category || []).slice(0, 6).map((c, i) => ({ ...c, color: CATEGORY_COLORS[i % CATEGORY_COLORS.length], })); const totalCategorySpend = categoryData.reduce((s, c) => s + c.value, 0); return ( {/* Header */}

{greeting()}, {firstName} 👋

{t("financial_overview")}

{/* Error banner */} {error && (

{t("backend_offline")} — {t("showing_cached")}{" "}

)} {/* AI Briefing */}
{isLoading ? ( <> ) : ( <>

{t("ai_daily_briefing")}{" "} {briefingText?.slice(0, 100) || "Your financial health looks good today."}

{t("health_score")} {data?.health_score ?? "—"}/100 {data?.fraud_alert_count ? ` · ${data.fraud_alert_count} fraud alert(s)` : ` · ${t("no_fraud_alerts")}`}

)}
Ask AI
{/* Stat Cards */}
20 ? "+" : ""}${(data.savings_rate - 20).toFixed(1)}% vs target` : undefined} positive={data ? data.savings_rate >= 20 : true} icon={Activity} gradient="from-purple-500/20 to-violet-500/20" lightGradient="from-purple-50 to-violet-50" iconColor="text-purple-500" borderColor="border-purple-500/20" lightBorderColor="border-purple-200/70" loading={isLoading} isLight={isLight} />
{/* Charts Row */}
{/* Cash Flow Chart */}

{t("cash_flow")}

{t("income_vs_expenses")}

{[ { label: t("income"), color: "#10b981" }, { label: t("expenses"), color: "#f59e0b" }, { label: t("savings"), color: "#3b82f6" }, ].map((l) => (
{l.label}
))}
{isLoading ? ( ) : ( {[ { id: "incomeGrad", color: "#10b981" }, { id: "expenseGrad", color: "#f59e0b" }, { id: "savingsGrad", color: "#3b82f6" }, ].map(({ id, color }) => ( ))} } /> )} {/* Spending Breakdown */}

{t("spending_breakdown")}

{t("this_month_by_category")}

{isLoading ? ( ) : (
{categoryData.map((entry, index) => ( ))} active && payload?.length ? (
{payload[0].name} ${(payload[0].value as number).toLocaleString()}
) : null } />
)}
{isLoading ? [1, 2, 3, 4].map((i) => ) : categoryData.map((cat) => (
{cat.name}
0 ? (cat.value / totalCategorySpend) * 100 : 0}%`, background: cat.color, }} />
${cat.value.toLocaleString()}
))}
{/* Recent Transactions */}

{t("recent_transactions")}

{t("latest_activity")}

{t("view_all")}
{isLoading ? [1, 2, 3, 4, 5].map((i) => ) : (data?.recent_transactions || []).map((tx, i) => (
{tx.merchant.charAt(0).toUpperCase()}

{tx.merchant}

{tx.category} · {tx.timestamp ? new Date(tx.timestamp).toLocaleDateString() : ""}

0 ? "text-emerald-500" : ""}`} style={tx.amount <= 0 ? { color: "var(--fg)" } : undefined} > {tx.amount > 0 ? "+" : ""}${Math.abs(tx.amount).toFixed(2)} {tx.amount > 0 ? ( ) : ( )}
))}
{/* Fraud Shield */}

{t("fraud_shield_active")} {data?.fraud_alert_count ? ` — ${data.fraud_alert_count} ${t("alerts_require_attention")}` : ` — ${t("all_monitored")}`}

{data?.fraud_alert_count ? ( {t("review")} ) : null}
); }