213 lines
10 KiB
TypeScript
213 lines
10 KiB
TypeScript
"use client";
|
|
|
|
import { fetchWithAuth } from "@/lib/apiClient";
|
|
import { useEffect, useState } from "react"
|
|
import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap"
|
|
import { StudyPlanCard } from "@/components/AI/StudyPlanCard"
|
|
import { ReadinessGauge } from "@/components/AI/ReadinessGauge"
|
|
import { CollegePredictorCard } from "@/components/AI/CollegePredictorCard"
|
|
import { ExamStrategyCard } from "@/components/AI/ExamStrategyCard"
|
|
import { StudyTimeOptimizationCard } from "@/components/AI/StudyTimeOptimizationCard"
|
|
import { TutorChat } from "@/components/AI/TutorChat"
|
|
import { ReferralCard } from "@/components/AI/ReferralCard"
|
|
import { ProgressShare } from "@/components/AI/ProgressShare"
|
|
import { DailyChallengeBanner } from "@/components/AI/DailyChallengeBanner"
|
|
import { WeeklyProgressReport } from "@/components/AI/WeeklyProgressReport"
|
|
import { Card, CardContent } from "@/components/ui/card"
|
|
import { Button } from "@/components/ui/button"
|
|
import { BrainCircuit, RefreshCw, CheckCircle2, Flame, Trophy, Target, Zap, BookOpen, Bot, FileText } from "lucide-react"
|
|
import { useActiveUser, isDemoUser } from "@/hooks/useActiveUser"
|
|
import Link from "next/link"
|
|
|
|
|
|
// Days until NEET 2026 (May 3, 2026)
|
|
function getDaysToExam(exam: string) {
|
|
const targets: Record<string, Date> = {
|
|
"NEET": new Date("2026-05-03"),
|
|
"JEE_Main": new Date("2026-01-22"),
|
|
"JEE_Advanced": new Date("2026-05-24"),
|
|
}
|
|
const t = targets[exam] || targets["NEET"]
|
|
const diff = Math.ceil((t.getTime() - Date.now()) / 86400000)
|
|
return diff > 0 ? diff : 0
|
|
}
|
|
|
|
export default function AICoachDashboard() {
|
|
const [stats, setStats] = useState<any>(null)
|
|
|
|
const { userId, user, hasAccessTo, loading: userLoading } = useActiveUser();
|
|
const isDemo = isDemoUser(userId);
|
|
|
|
useEffect(() => {
|
|
if (!userLoading && userId) {
|
|
fetchWithAuth(`/api/users/${userId}/stats`)
|
|
.then(res => res.ok ? res.json() : null)
|
|
.then(data => setStats(data))
|
|
.catch(() => setStats(null))
|
|
}
|
|
}, [userId, userLoading])
|
|
|
|
if (userLoading) {
|
|
return (
|
|
<div className="h-screen flex items-center justify-center">
|
|
<div className="flex flex-col items-center gap-3 text-muted-foreground">
|
|
<BrainCircuit size={32} className="animate-pulse text-[var(--cyan-ai)]" />
|
|
<span className="text-sm font-medium">Loading AI Coach...</span>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!hasAccessTo("ai-mistake-tracking")) {
|
|
return (
|
|
<div className="max-w-3xl mx-auto text-center py-20 px-8 space-y-8">
|
|
<div className="size-20 rounded-full bg-[var(--cyan-ai-10)] flex items-center justify-center mx-auto text-[var(--cyan-ai)] border border-[var(--cyan-ai-20)] shadow-[0_0_20px_rgba(12,96,96,0.1)]">
|
|
<BrainCircuit size={40} />
|
|
</div>
|
|
<div className="space-y-4">
|
|
<h1 className="text-4xl font-extrabold tracking-tight">AI Coach Workspace</h1>
|
|
<p className="text-muted-foreground text-lg max-w-xl mx-auto leading-relaxed">
|
|
Mistake tracking, Spaced Repetition (SM-2), AI Tutor Chats, and Readiness scores are premium features reserved for <strong>AI Coach</strong> subscribers.
|
|
</p>
|
|
</div>
|
|
<div className="pt-4">
|
|
<Link href="/upgrade">
|
|
<Button size="lg" className="rounded-xl px-8 font-bold bg-[var(--cyan-ai)] text-background hover:bg-[var(--cyan-ai-80)] shadow-[0_0_25px_-5px_var(--cyan-ai)]">
|
|
Upgrade to AI Coach Plan
|
|
</Button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const daysLeft = getDaysToExam(user?.target_exam || "NEET")
|
|
const questionsSolved = isDemo ? "1,247" : (stats?.total_questions_attempted ?? 0).toLocaleString()
|
|
const overallAccuracy = isDemo ? "74%" : `${stats?.overall_accuracy ?? 0}%`
|
|
const mistakesMastered = isDemo ? 38 : 0
|
|
const aiSessions = isDemo ? 124 : 0
|
|
const currentStreakDays = `${user?.streak_count || (isDemo ? 12 : 1)} d`
|
|
|
|
return (
|
|
<div className="p-6 max-w-6xl mx-auto space-y-8">
|
|
|
|
{/* ── METRICS BAR ── */}
|
|
<div className="flex flex-wrap items-center justify-end gap-2 pt-2">
|
|
<div className="inline-flex items-center gap-1.5 bg-yellow-500/10 text-yellow-500 px-3 py-1.5 rounded-xl text-xs font-bold border border-yellow-500/20">
|
|
<Flame size={14} className="fill-yellow-500" />
|
|
{user?.streak_count || 1}-Day Streak
|
|
</div>
|
|
<div className="inline-flex items-center gap-1.5 bg-red-500/10 text-red-400 px-3 py-1.5 rounded-xl text-xs font-bold border border-red-500/20">
|
|
<Target size={13} />
|
|
{daysLeft} days to {user?.target_exam?.replace("_", " ") || "Exam"}
|
|
</div>
|
|
<div className="inline-flex items-center gap-1.5 bg-purple-500/10 text-purple-400 px-3 py-1.5 rounded-xl text-xs font-bold border border-purple-500/20">
|
|
<Trophy size={13} />
|
|
AI Coach
|
|
</div>
|
|
</div>
|
|
|
|
{/* ── DAILY CHALLENGE BANNER ── */}
|
|
<div className=""><DailyChallengeBanner /></div>
|
|
|
|
{/* ── QUICK STATS ── */}
|
|
<section className="grid grid-cols-2 md:grid-cols-5 gap-4">
|
|
{[
|
|
{ label: "Questions Solved", value: questionsSolved, color: "text-[var(--cyan-ai)]", bg: "bg-[var(--cyan-ai-10)]", border: "border-[var(--cyan-ai-20)]", icon: <FileText size={32} /> },
|
|
{ label: "Overall Accuracy", value: overallAccuracy, color: "text-amber-500", bg: "bg-amber-500/5", border: "border-amber-500/20", icon: <Target size={32} /> },
|
|
{ label: "Current Streak", value: currentStreakDays, color: "text-yellow-400", bg: "bg-yellow-400/5", border: "border-yellow-400/20", icon: <Flame size={32} className="fill-yellow-400" /> },
|
|
{ label: "Mistakes Mastered", value: mistakesMastered, color: "text-green-400", bg: "bg-green-400/5", border: "border-green-400/20", icon: <CheckCircle2 size={32} /> },
|
|
{ label: "AI Sessions", value: aiSessions, color: "text-purple-400", bg: "bg-purple-400/5", border: "border-purple-400/20", icon: <Bot size={32} /> },
|
|
].map((stat) => (
|
|
<Card key={stat.label} className={`border ${stat.border} ${stat.bg} backdrop-blur-sm rounded-2xl`}>
|
|
<CardContent className="p-6 flex flex-col items-center justify-center text-center">
|
|
<div className="text-3xl mb-2 filter drop-shadow-md">{stat.icon}</div>
|
|
<div className={`text-4xl font-black ${stat.color} leading-none tracking-tight mb-2 filter drop-shadow-sm`}>{stat.value}</div>
|
|
<div className="text-xs font-extrabold text-muted-foreground uppercase tracking-wider">{stat.label}</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</section>
|
|
|
|
{/* ── PREDICTIVE INTELLIGENCE ROW ── */}
|
|
<section className="mt-10">
|
|
<div className="flex items-center justify-between gap-3 mb-6">
|
|
<div className="flex items-center gap-2 text-base md:text-lg font-black uppercase tracking-widest text-[var(--cyan-ai)]">
|
|
<Zap size={20} />
|
|
Predictive Intelligence & Strategy
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<Link href="/dashboard/ai-coach/readiness" className="text-xs font-bold text-[var(--cyan-ai)] hover:underline flex items-center gap-1">
|
|
Full Analytics →
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<ReadinessGauge />
|
|
<CollegePredictorCard />
|
|
<ExamStrategyCard />
|
|
<StudyTimeOptimizationCard />
|
|
</div>
|
|
</section>
|
|
|
|
|
|
{/* ── HEATMAP / STUDY PLAN / WEEKLY REPORT ── */}
|
|
<section className="grid grid-cols-1 lg:grid-cols-2 gap-8 pt-10 border-t border-border">
|
|
<div>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-2 text-base font-extrabold">
|
|
<BookOpen size={18} className="text-[var(--cyan-ai)]" /> Study Plan
|
|
</div>
|
|
<Link href="/dashboard/ai-coach/study-plan" className="text-xs font-bold text-[var(--cyan-ai)] hover:underline">
|
|
Full Schedule →
|
|
</Link>
|
|
</div>
|
|
<StudyPlanCard />
|
|
</div>
|
|
<div>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-2 text-base font-extrabold">
|
|
<Flame size={18} className="text-yellow-500" /> Mastery Map
|
|
</div>
|
|
<Link href="/dashboard/ai-coach/heatmap" className="text-xs font-bold text-[var(--cyan-ai)] hover:underline">
|
|
Mastery Map Vault →
|
|
</Link>
|
|
</div>
|
|
<MistakeHeatmap />
|
|
</div>
|
|
</section>
|
|
|
|
<section className="pt-8 border-t border-border">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-2 text-base font-extrabold">
|
|
<Target size={18} className="text-[var(--cyan-ai)]" /> Weekly Progress Overview
|
|
</div>
|
|
<Link href="/dashboard/ai-coach/study-plan" className="text-xs font-bold text-[var(--cyan-ai)] hover:underline">
|
|
View Details →
|
|
</Link>
|
|
</div>
|
|
<WeeklyProgressReport />
|
|
</section>
|
|
|
|
{/* ── TUTOR CHAT ── */}
|
|
<section className="pt-8 border-t border-border">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h2 className="text-2xl font-extrabold tracking-tight">24/7 AI Tutor Chat Assistant</h2>
|
|
<Link href="/dashboard/ai-coach/tutor" className="text-xs font-extrabold text-[var(--cyan-ai)] bg-[var(--cyan-ai-10)] px-3.5 py-1.5 rounded-xl border border-[var(--cyan-ai-30)] hover:bg-[var(--cyan-ai)] hover:text-black transition-all">
|
|
Full Desk Mode →
|
|
</Link>
|
|
</div>
|
|
<TutorChat />
|
|
</section>
|
|
|
|
{/* ── GROWTH HUB ── */}
|
|
<section className="grid grid-cols-1 lg:grid-cols-2 gap-6 pt-6 border-t border-border">
|
|
<ReferralCard />
|
|
<ProgressShare />
|
|
</section>
|
|
|
|
</div>
|
|
)
|
|
}
|
|
|