feat: setup admin JSON generation and pdf viewer for free plan DPPs
This commit is contained in:
@@ -5,16 +5,33 @@ 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 { MistakeReviewCard, MistakePayload } from "@/components/AI/MistakeReviewCard"
|
||||
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, BookOpen, Calculator, Target, RefreshCw, CheckCircle2, Lock } from "lucide-react"
|
||||
import { BrainCircuit, RefreshCw, CheckCircle2, Flame, Trophy, Target, Zap, BookOpen, Bot, FileText } from "lucide-react"
|
||||
import { useActiveUser } 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 [mistakes, setMistakes] = useState<MistakePayload[]>([])
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
@@ -32,7 +49,6 @@ export default function AICoachDashboard() {
|
||||
setMistakes(data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
// If backend fails, fallback to empty array
|
||||
setMistakes([])
|
||||
} finally {
|
||||
setLoading(false)
|
||||
@@ -51,7 +67,6 @@ export default function AICoachDashboard() {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ mistake_id: mistakeId, selected_answer: selectedAnswer })
|
||||
})
|
||||
|
||||
if (!res.ok) throw new Error("Failed to submit review")
|
||||
return await res.json()
|
||||
}
|
||||
@@ -60,13 +75,19 @@ export default function AICoachDashboard() {
|
||||
if (currentIndex < mistakes.length - 1) {
|
||||
setCurrentIndex(prev => prev + 1)
|
||||
} else {
|
||||
// Session finished
|
||||
setCurrentIndex(mistakes.length) // Push out of bounds to trigger complete state
|
||||
setCurrentIndex(mistakes.length)
|
||||
}
|
||||
}
|
||||
|
||||
if (userLoading) {
|
||||
return <div className="p-8 text-center text-muted-foreground animate-pulse">Loading AI Coach...</div>
|
||||
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-[#00F0FF]" />
|
||||
<span className="text-sm font-medium">Loading AI Coach...</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!hasAccessTo("ai-mistake-tracking")) {
|
||||
@@ -78,7 +99,7 @@ export default function AICoachDashboard() {
|
||||
<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 **AI Coach** subscribers.
|
||||
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">
|
||||
@@ -92,81 +113,113 @@ export default function AICoachDashboard() {
|
||||
)
|
||||
}
|
||||
|
||||
const daysLeft = getDaysToExam(user?.target_exam || "NEET")
|
||||
const physicsErrors = mistakes.filter(m => m.question.subject === "Physics").length
|
||||
const chemErrors = mistakes.filter(m => m.question.subject === "Chemistry").length
|
||||
const mathErrors = mistakes.filter(m => m.question.subject === "Maths" || m.question.subject === "Mathematics").length
|
||||
|
||||
return (
|
||||
<div className="p-8 max-w-6xl mx-auto space-y-10 animate-in fade-in duration-500">
|
||||
<header className="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight flex items-center gap-3">
|
||||
<BrainCircuit className="text-primary" size={32}/> AI Coach
|
||||
</h1>
|
||||
<p className="text-muted-foreground mt-1 font-medium">Your personalized SM-2 spaced repetition and analytics engine.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div className="p-6 max-w-6xl mx-auto space-y-8 animate-in fade-in duration-500">
|
||||
|
||||
{/* Summary Metrics */}
|
||||
<section className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Card className="border-border shadow-sm">
|
||||
<CardContent className="p-5 flex items-center gap-4">
|
||||
<div className="p-3 bg-secondary rounded-xl text-primary"><Calculator size={20}/></div>
|
||||
<div>
|
||||
<p className="text-sm font-bold text-muted-foreground uppercase tracking-wider">Physics Errors</p>
|
||||
<h3 className="text-2xl font-bold">{mistakes.filter(m => m.question.subject === 'Physics').length}</h3>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border shadow-sm">
|
||||
<CardContent className="p-5 flex items-center gap-4">
|
||||
<div className="p-3 bg-secondary rounded-xl text-emerald-500"><BookOpen size={20}/></div>
|
||||
<div>
|
||||
<p className="text-sm font-bold text-muted-foreground uppercase tracking-wider">Chemistry Errors</p>
|
||||
<h3 className="text-2xl font-bold">{mistakes.filter(m => m.question.subject === 'Chemistry').length}</h3>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-border shadow-sm">
|
||||
<CardContent className="p-5 flex items-center gap-4">
|
||||
<div className="p-3 bg-secondary rounded-xl text-blue-500"><Target size={20}/></div>
|
||||
<div>
|
||||
<p className="text-sm font-bold text-muted-foreground uppercase tracking-wider">Maths Errors</p>
|
||||
<h3 className="text-2xl font-bold">{mistakes.filter(m => m.question.subject === 'Maths').length}</h3>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* ── 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 || 0}-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 ── */}
|
||||
<DailyChallengeBanner />
|
||||
|
||||
{/* ── QUICK STATS ── */}
|
||||
<section className="grid grid-cols-2 md:grid-cols-5 gap-4">
|
||||
{[
|
||||
{ label: "Questions Solved", value: "1,247", color: "text-[#00F0FF]", bg: "bg-[#00F0FF]/5", border: "border-[#00F0FF]/20", icon: <FileText size={32} /> },
|
||||
{ label: "Overall Accuracy", value: "74%", color: "text-amber-500", bg: "bg-amber-500/5", border: "border-amber-500/20", icon: <Target size={32} /> },
|
||||
{ label: "Current Streak", value: `${user?.streak_count || 0} d`, 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: 38, color: "text-green-400", bg: "bg-green-400/5", border: "border-green-400/20", icon: <CheckCircle2 size={32} /> },
|
||||
{ label: "AI Sessions", value: 124, 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 shadow-sm hover:shadow-[0_0_20px_rgba(0,240,255,0.2)] transition-all duration-300 transform hover:-translate-y-1 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 */}
|
||||
<section className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
|
||||
<ReadinessGauge />
|
||||
<CollegePredictorCard />
|
||||
{/* ── 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-[#00F0FF]">
|
||||
<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-[#00F0FF] 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>
|
||||
|
||||
{/* Mistake Review Workspace */}
|
||||
<section>
|
||||
<div className="flex items-center justify-between mb-5">
|
||||
<h2 className="text-xl font-semibold tracking-tight">Daily Mistake Review Queue</h2>
|
||||
<span className="text-sm font-bold text-muted-foreground bg-secondary px-3 py-1 rounded-full">
|
||||
{currentIndex < mistakes.length ? `${currentIndex + 1} / ${mistakes.length}` : "Finished"}
|
||||
</span>
|
||||
{/* ── MISTAKE REVIEW WORKSPACE ── */}
|
||||
<section className="mt-12">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2.5 bg-[#00F0FF]/10 rounded-xl border border-[#00F0FF]/20">
|
||||
<BrainCircuit size={24} className="text-[#00F0FF]" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-black tracking-tight">Daily Mistake Review Queue</h2>
|
||||
<p className="text-sm text-muted-foreground font-medium">SM-2 Spaced Repetition Flashcard Engine</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/dashboard/ai-coach/mistakes" className="hidden sm:inline-flex text-xs font-extrabold text-[#00F0FF] bg-[#00F0FF]/10 px-4 py-2 rounded-xl border border-[#00F0FF]/30 hover:bg-[#00F0FF] hover:text-black transition-all">
|
||||
Open Full Mistake Vault Page →
|
||||
</Link>
|
||||
<span className="text-sm font-extrabold text-[#00F0FF] bg-[#00F0FF]/10 px-4 py-1.5 rounded-full border border-[#00F0FF]/30 shadow-[0_0_10px_rgba(0,240,255,0.15)]">
|
||||
{currentIndex < mistakes.length ? `${currentIndex + 1} / ${mistakes.length}` : "Finished"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{loading ? (
|
||||
<Card className="p-12 flex items-center justify-center border-dashed">
|
||||
<RefreshCw className="animate-spin text-muted-foreground mr-3" /> Loading queue...
|
||||
</Card>
|
||||
) : mistakes.length === 0 ? (
|
||||
<Card className="p-12 text-center border-dashed bg-secondary/20">
|
||||
<Card className="p-12 text-center border-dashed bg-secondary/20 rounded-3xl">
|
||||
<CheckCircle2 size={48} className="mx-auto text-green-500 mb-4 opacity-50" />
|
||||
<h3 className="text-xl font-bold mb-2">You're all caught up!</h3>
|
||||
<p className="text-muted-foreground">No mistakes scheduled for review today. Go take a test!</p>
|
||||
</Card>
|
||||
) : currentIndex < mistakes.length ? (
|
||||
<MistakeReviewCard
|
||||
data={mistakes[currentIndex]}
|
||||
<MistakeReviewCard
|
||||
data={mistakes[currentIndex]}
|
||||
onNext={handleNext}
|
||||
onSubmitReview={submitReview}
|
||||
/>
|
||||
) : (
|
||||
<Card className="p-12 text-center border-dashed bg-primary/5 border-primary/20">
|
||||
<Card className="p-12 text-center border-dashed bg-primary/5 border-primary/20 rounded-3xl">
|
||||
<BrainCircuit size={48} className="mx-auto text-primary mb-4 opacity-80" />
|
||||
<h3 className="text-xl font-bold mb-2 text-primary">Session Complete</h3>
|
||||
<p className="text-muted-foreground mb-6">Great job clearing your error queue! The SM-2 engine has scheduled your next reviews.</p>
|
||||
@@ -175,23 +228,57 @@ export default function AICoachDashboard() {
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Heatmap & Timeline */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8 pt-8 border-t border-border">
|
||||
<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-[#00F0FF]" /> Study Plan
|
||||
</div>
|
||||
<Link href="/dashboard/ai-coach/study-plan" className="text-xs font-bold text-[#00F0FF] hover:underline">
|
||||
Full Schedule →
|
||||
</Link>
|
||||
</div>
|
||||
<StudyPlanCard />
|
||||
</section>
|
||||
<section>
|
||||
</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" /> Mistake Heatmap
|
||||
</div>
|
||||
<Link href="/dashboard/ai-coach/mistakes" className="text-xs font-bold text-[#00F0FF] hover:underline">
|
||||
Heatmap Vault →
|
||||
</Link>
|
||||
</div>
|
||||
<MistakeHeatmap />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Tutor Chat Workspace */}
|
||||
<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-[#00F0FF]" /> Weekly Progress Overview
|
||||
</div>
|
||||
<Link href="/dashboard/ai-coach/study-plan" className="text-xs font-bold text-[#00F0FF] 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-[#00F0FF] bg-[#00F0FF]/10 px-3.5 py-1.5 rounded-xl border border-[#00F0FF]/30 hover:bg-[#00F0FF] hover:text-black transition-all">
|
||||
Full Desk Mode →
|
||||
</Link>
|
||||
</div>
|
||||
<TutorChat />
|
||||
</section>
|
||||
|
||||
{/* Growth & Sharing Hub */}
|
||||
<section className="grid grid-cols-1 lg:grid-cols-2 gap-8 pt-8 border-t border-border mt-8">
|
||||
{/* ── GROWTH HUB ── */}
|
||||
<section className="grid grid-cols-1 lg:grid-cols-2 gap-6 pt-6 border-t border-border">
|
||||
<ReferralCard />
|
||||
<ProgressShare />
|
||||
</section>
|
||||
@@ -199,3 +286,4 @@ export default function AICoachDashboard() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user