chore: Secure routes with auth middleware, update text and fix minor bugs
This commit is contained in:
@@ -115,7 +115,7 @@ export default function AIComCBTDPPPage() {
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-xs font-black uppercase tracking-widest text-[#00F0FF] bg-[#00F0FF]/10 px-2.5 py-0.5 rounded-full border border-[#00F0FF]/30">
|
||||
AI CBT DPP Simulator
|
||||
PrepPilot AI
|
||||
</span>
|
||||
<span className="text-xs font-bold text-muted-foreground">• {user?.target_exam?.replace("_", " ") || "JEE/NEET"}</span>
|
||||
</div>
|
||||
@@ -180,7 +180,7 @@ export default function AIComCBTDPPPage() {
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<p className="text-lg font-bold leading-relaxed text-foreground">
|
||||
<p className="text-xl md:text-2xl font-black leading-relaxed text-foreground">
|
||||
{sampleQuestions[activeQuestion].question}
|
||||
</p>
|
||||
|
||||
@@ -203,13 +203,13 @@ export default function AIComCBTDPPPage() {
|
||||
<div
|
||||
key={optIdx}
|
||||
onClick={() => handleOptionSelect(activeQuestion, optIdx)}
|
||||
className={`flex items-center gap-4 p-4 rounded-2xl border cursor-pointer transition-all ${btnStyle}`}
|
||||
className={`flex items-center gap-4 p-4.5 rounded-2xl border cursor-pointer transition-all ${btnStyle}`}
|
||||
>
|
||||
<span className="w-8 h-8 rounded-xl bg-background/80 border border-border flex items-center justify-center font-bold text-sm shrink-0">
|
||||
<span className="w-10 h-10 rounded-xl bg-background/80 border border-border flex items-center justify-center font-black text-base shrink-0">
|
||||
{letter}
|
||||
</span>
|
||||
<span className="text-base font-medium flex-1">{opt}</span>
|
||||
{submitted && isCorrect && <CheckCircle2 size={20} className="text-emerald-400" />}
|
||||
<span className="text-lg md:text-xl font-bold flex-1">{opt}</span>
|
||||
{submitted && isCorrect && <CheckCircle2 size={22} className="text-emerald-400" />}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import AttemptHistoryPage from "@/app/dashboard/cbt/history/[attemptId]/page";
|
||||
|
||||
export default function AIHistoryPage({ params }: { params: Promise<{ attemptId: string }> }) {
|
||||
return <AttemptHistoryPage params={params} />;
|
||||
}
|
||||
@@ -2,19 +2,21 @@
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles } from "lucide-react"
|
||||
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles, Share2, Maximize2, Minimize2 } from "lucide-react"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
import { useActiveUser } from "@/hooks/useActiveUser"
|
||||
|
||||
export default function PrepPilotAIPage() {
|
||||
export default function AIDailyPracticePage() {
|
||||
const { user, userId } = useActiveUser()
|
||||
const [dpps, setDpps] = useState<any[]>([])
|
||||
const [attempts, setAttempts] = useState<any[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [dateFilter, setDateFilter] = useState("")
|
||||
const [selectedPdfDpp, setSelectedPdfDpp] = useState<any | null>(null)
|
||||
const [isFullScreen, setIsFullScreen] = useState(false)
|
||||
const [copiedShare, setCopiedShare] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchDpps() {
|
||||
@@ -90,13 +92,26 @@ export default function PrepPilotAIPage() {
|
||||
const cleanTitle = (title: string) => title.replace(/\s*\(ExamEnum\.[^)]+\)/, '');
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500 max-w-5xl mx-auto">
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between p-8 bg-gradient-to-r from-secondary/50 to-background border border-border rounded-2xl shadow-sm gap-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight mb-2">PrepPilot AI <span className="text-[#00F0FF] text-xl">&</span> CBT Simulator</h1>
|
||||
<p className="text-muted-foreground font-medium max-w-xl">
|
||||
Select an interactive Target DPP to launch the AI-powered CBT examination simulator.
|
||||
</p>
|
||||
<div className="p-6 md:p-8 space-y-6 animate-in fade-in slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-1">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Sparkles className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
AI Daily Practice (DPP)
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Launch AI-generated Daily Practice Problems (DPPs) tailored to your exam pattern and weak areas.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5">
|
||||
<BrainCircuit size={12} /> AI Powered
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -114,12 +129,9 @@ export default function PrepPilotAIPage() {
|
||||
{diff}
|
||||
</button>
|
||||
))}
|
||||
<div className="flex items-center gap-1 ml-2 text-xs text-muted-foreground bg-secondary/50 px-2 py-1 rounded-md">
|
||||
<Lock size={12}/> Pro
|
||||
</div>
|
||||
</div>
|
||||
<Button variant="outline" className="gap-2 rounded-xl text-sm font-bold">
|
||||
<Download size={16} /> Export as PDF <span className="ml-1 text-[10px] uppercase tracking-wider bg-primary/10 text-primary px-1.5 py-0.5 rounded-md">Pro</span>
|
||||
<Download size={16} /> Export as PDF
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -200,7 +212,7 @@ export default function PrepPilotAIPage() {
|
||||
{!isExpired && (
|
||||
<Link href={`/cbt/${dpp.id}`}>
|
||||
<Button variant="secondary" size="sm" className="font-bold bg-[#00F0FF]/10 text-[#00F0FF] hover:bg-[#00F0FF]/20 gap-2">
|
||||
<Play size={14} className="fill-current" /> Retake CBT
|
||||
<Play size={14} className="fill-current" /> Retake Test
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
@@ -208,7 +220,7 @@ export default function PrepPilotAIPage() {
|
||||
) : (
|
||||
<Link href={`/cbt/${dpp.id}`}>
|
||||
<Button variant="secondary" size="sm" className="rounded-xl bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-extrabold gap-2 text-xs shadow-[0_0_12px_rgba(0,240,255,0.2)]">
|
||||
<Play size={14} className="fill-black" /> Launch CBT DPP
|
||||
<Play size={14} className="fill-black" /> Launch Practice Test
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
@@ -220,18 +232,18 @@ export default function PrepPilotAIPage() {
|
||||
|
||||
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
|
||||
{selectedPdfDpp && (
|
||||
<div className="fixed inset-0 z-50 bg-black/80 backdrop-blur-md flex items-center justify-center p-4 animate-in fade-in duration-300">
|
||||
<div className="bg-background border border-border rounded-3xl w-full max-w-4xl max-h-[90vh] flex flex-col overflow-hidden shadow-2xl">
|
||||
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'} animate-in fade-in duration-300`}>
|
||||
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
||||
{/* Modal Header */}
|
||||
<div className="p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
||||
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-2.5 bg-primary/10 rounded-xl border border-primary/20 text-primary">
|
||||
<div className="p-2.5 bg-primary/10 rounded-xl border border-primary/20 text-primary hidden sm:flex">
|
||||
<FileText size={22} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-black text-lg flex items-center gap-2">
|
||||
<h3 className="font-black text-base sm:text-lg flex items-center gap-2">
|
||||
{selectedPdfDpp.title}
|
||||
<span className="text-[10px] bg-yellow-500/10 text-yellow-500 border border-yellow-500/20 px-2 py-0.5 rounded-full uppercase tracking-wider font-extrabold">
|
||||
<span className="text-[10px] bg-yellow-500/10 text-yellow-500 border border-yellow-500/20 px-2 py-0.5 rounded-full uppercase tracking-wider font-extrabold hidden md:inline-block">
|
||||
Protected In-App PDF View
|
||||
</span>
|
||||
</h3>
|
||||
@@ -240,24 +252,46 @@ export default function PrepPilotAIPage() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => setSelectedPdfDpp(null)}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="rounded-full border-border hover:bg-secondary"
|
||||
>
|
||||
<X size={18} />
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(window.location.origin + '/dashboard/ai-coach/cbt-dpp');
|
||||
setCopiedShare(true);
|
||||
setTimeout(() => setCopiedShare(false), 2000);
|
||||
}}
|
||||
className="rounded-xl font-bold text-xs gap-1.5 h-9 px-3"
|
||||
>
|
||||
{copiedShare ? <CheckCircle2 size={14} className="text-green-500" /> : <Share2 size={14} />}
|
||||
<span>{copiedShare ? "Copied" : "Share PDF"}</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => setIsFullScreen(!isFullScreen)}
|
||||
className="rounded-xl font-bold text-xs gap-1.5 h-9 px-3 bg-primary/10 text-primary border-primary/20 hover:bg-primary/20"
|
||||
>
|
||||
{isFullScreen ? <Minimize2 size={14} /> : <Maximize2 size={14} />}
|
||||
<span>{isFullScreen ? "Exit Fullscreen" : "Fullscreen"}</span>
|
||||
</Button>
|
||||
<button
|
||||
onClick={() => { setSelectedPdfDpp(null); setIsFullScreen(false); }}
|
||||
className="ml-1 flex-shrink-0 w-9 h-9 rounded-full border border-border bg-secondary flex items-center justify-center text-foreground hover:bg-destructive hover:border-destructive hover:text-white transition-all"
|
||||
>
|
||||
<X size={18} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Security Notice Banner */}
|
||||
<div className="bg-amber-500/10 border-b border-amber-500/20 px-6 py-2.5 flex items-center justify-between text-xs text-amber-400 font-bold">
|
||||
<span className="flex items-center gap-2">
|
||||
<ShieldAlert size={16} /> Read-Only Mode (Free Tier) — Downloads, text copying, and sharing are restricted.
|
||||
<div className="bg-amber-500/10 border-b border-amber-500/20 px-4 sm:px-6 py-2 flex items-center justify-between text-xs text-amber-400 font-bold">
|
||||
<span className="flex items-center gap-2 truncate">
|
||||
<ShieldAlert size={16} className="shrink-0" /> Read-Only Mode (Free Tier) — Downloads & direct copying are restricted.
|
||||
</span>
|
||||
<Link href="/upgrade">
|
||||
<Link href="/upgrade" className="hidden sm:block shrink-0 ml-2">
|
||||
<Button size="sm" className="bg-amber-500 text-black hover:bg-amber-400 font-extrabold h-7 text-[11px] rounded-lg">
|
||||
Upgrade for Interactive CBT Mode →
|
||||
Upgrade for Interactive Practice Mode →
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -265,27 +299,33 @@ export default function PrepPilotAIPage() {
|
||||
{/* Protected PDF Document Sheet Content (select-none) */}
|
||||
<div
|
||||
onContextMenu={(e) => e.preventDefault()}
|
||||
className="flex-1 w-full h-full min-h-[60vh] select-none bg-[#525659]"
|
||||
className="flex-1 w-full select-none bg-[#525659] overflow-hidden"
|
||||
style={{minHeight: isFullScreen ? 'calc(100vh - 120px)' : '75vh'}}
|
||||
>
|
||||
<embed
|
||||
src={getPdfUrl(selectedPdfDpp.title)}
|
||||
type="application/pdf"
|
||||
className="w-full h-full rounded-b-lg"
|
||||
className="w-full h-full"
|
||||
style={{height: isFullScreen ? 'calc(100vh - 120px)' : '75vh'}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Modal Footer */}
|
||||
<div className="p-4 border-t border-border bg-secondary/30 flex items-center justify-between">
|
||||
<span className="text-xs text-muted-foreground font-medium">
|
||||
<div className="p-3.5 sm:p-4 border-t border-border bg-secondary/30 flex items-center justify-between flex-wrap gap-2">
|
||||
<span className="text-xs text-muted-foreground font-medium flex items-center gap-2">
|
||||
📄 PragatiVeer Protected PDF Reader v2.0
|
||||
</span>
|
||||
<div className="flex gap-3">
|
||||
<Button onClick={() => setSelectedPdfDpp(null)} variant="outline" className="rounded-xl font-bold">
|
||||
Close PDF Reader
|
||||
<div className="flex gap-2 items-center">
|
||||
<Button onClick={() => setIsFullScreen(!isFullScreen)} variant="secondary" className="rounded-xl font-bold text-xs h-9 bg-primary/10 text-primary hover:bg-primary/20 flex items-center gap-1.5">
|
||||
{isFullScreen ? <Minimize2 size={14} /> : <Maximize2 size={14} />}
|
||||
<span>{isFullScreen ? "Exit Fullscreen" : "Fullscreen"}</span>
|
||||
</Button>
|
||||
<Button onClick={() => { setSelectedPdfDpp(null); setIsFullScreen(false); }} variant="outline" className="rounded-xl font-bold text-xs h-9">
|
||||
Close Reader
|
||||
</Button>
|
||||
<Link href="/upgrade">
|
||||
<Button className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-extrabold rounded-xl shadow-[0_0_15px_rgba(0,240,255,0.2)]">
|
||||
<Sparkles size={16} className="mr-2" /> Upgrade to AI Coach for Interactive CBT
|
||||
<Button className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-extrabold rounded-xl shadow-[0_0_15px_rgba(0,240,255,0.2)] text-xs h-9">
|
||||
<Sparkles size={14} className="mr-1.5" /> Upgrade to AI Coach
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -2,51 +2,131 @@
|
||||
|
||||
import { CollegePredictorCard } from "@/components/AI/CollegePredictorCard"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { GraduationCap, ArrowLeft, Building2, MapPin, Award, CheckCircle2 } from "lucide-react"
|
||||
import { GraduationCap, Building2, Award, CheckCircle2, TrendingUp, MapPin, Users, BarChart2 } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
const CUTOFF_TRENDS = [
|
||||
{ year: "2021", rank: 3800 },
|
||||
{ year: "2022", rank: 3500 },
|
||||
{ year: "2023", rank: 3200 },
|
||||
{ year: "2024", rank: 2950 },
|
||||
{ year: "2025", rank: 2750 },
|
||||
]
|
||||
|
||||
export default function CollegePredictorPage() {
|
||||
const maxRank = Math.max(...CUTOFF_TRENDS.map(d => d.rank))
|
||||
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Navigation Header */}
|
||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<GraduationCap className="text-[#00F0FF]" size={36} />
|
||||
AI College & Cutoff Predictor
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Discover your probable target medical & engineering colleges based on current mock exam scores and historical cutoffs.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<GraduationCap className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
AI College & Cutoff Predictor
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Discover your probable target medical & engineering colleges based on current mock exam scores and historical cutoffs.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<GraduationCap size={12} /> AI Powered
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Summary KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Predicted Rank", value: "~4,200", icon: <TrendingUp size={18} className="text-[#00F0FF]" />, color: "border-[#00F0FF]/20 bg-[#00F0FF]/5" },
|
||||
{ label: "Target Colleges", value: "12", icon: <Building2 size={18} className="text-amber-400" />, color: "border-amber-400/20 bg-amber-400/5" },
|
||||
{ label: "Reach Colleges", value: "5", icon: <MapPin size={18} className="text-purple-400" />, color: "border-purple-400/20 bg-purple-400/5" },
|
||||
{ label: "Safe Colleges", value: "18", icon: <CheckCircle2 size={18} className="text-green-400" />, color: "border-green-400/20 bg-green-400/5" },
|
||||
].map((kpi) => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color} hover:scale-[1.02] transition-transform`}>
|
||||
<CardContent className="p-5 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">{kpi.label}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
<Card className="p-8 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-6 flex items-center gap-2">
|
||||
<Building2 className="text-[#00F0FF]" size={24} /> Target College Analytics
|
||||
</h2>
|
||||
<CollegePredictorCard />
|
||||
{/* College Predictor */}
|
||||
<CollegePredictorCard />
|
||||
|
||||
{/* Cutoff Trend Chart */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<BarChart2 size={20} className="text-[#00F0FF]" />
|
||||
<h3 className="text-lg font-extrabold tracking-tight">NIT Trichy CSE — Closing Rank Trend</h3>
|
||||
<span className="ml-auto text-xs font-bold text-green-400 bg-green-400/10 border border-green-400/20 px-2.5 py-1 rounded-full flex items-center gap-1">
|
||||
<TrendingUp size={11} /> Improving Cutoffs
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-end gap-4 h-32 px-2">
|
||||
{CUTOFF_TRENDS.map((d, i) => (
|
||||
<div key={d.year} className="flex flex-col items-center gap-1.5 flex-1">
|
||||
<span className="text-xs font-black text-muted-foreground">{d.rank.toLocaleString()}</span>
|
||||
<div
|
||||
className={`w-full rounded-t-md transition-all duration-700 ${i === CUTOFF_TRENDS.length - 1 ? "bg-gradient-to-t from-[#00F0FF]/60 to-[#00F0FF]" : "bg-gradient-to-t from-white/10 to-white/25"}`}
|
||||
style={{ height: `${(d.rank / maxRank) * 80}px` }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground font-semibold">{d.year}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-4 pl-1">Closing rank trend: cutoffs are improving, meaning competition is easing. Your predicted rank of ~4,200 is within Target range.</p>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
<Card className="p-6 bg-gradient-to-br from-[#00F0FF]/10 via-secondary/20 to-background border border-[#00F0FF]/30 rounded-3xl space-y-4">
|
||||
<h3 className="text-xl font-black tracking-tight text-[#00F0FF] flex items-center gap-2">
|
||||
<Award size={20} /> Cutoff Modeling Parameters
|
||||
<h3 className="text-base font-black tracking-tight text-[#00F0FF] flex items-center gap-2">
|
||||
<Award size={18} /> Cutoff Modelling Parameters
|
||||
</h3>
|
||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span>Includes 100,000+ candidate rank trends across 2021-2025 rounds.</span>
|
||||
<span>Trained on <strong className="text-foreground">100,000+ candidate rank trends</strong> across 2021–2025 counselling rounds.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span>Supports All India Quota (AIQ) & State Quota adjustments.</span>
|
||||
<span>Supports <strong className="text-foreground">All India Quota (AIQ)</strong> & State Quota seat adjustments.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span>Simulates category reservation cutoffs (General, OBC, SC, ST, EWS).</span>
|
||||
<span>Simulates <strong className="text-foreground">category reservation cutoffs</strong>: General, OBC, SC, ST, EWS.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span>Score updated daily as you complete more mock tests.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl space-y-3">
|
||||
<h3 className="text-base font-black text-muted-foreground uppercase tracking-wider flex items-center gap-2">
|
||||
<Users size={16} className="text-amber-400" /> Improve Your Rank
|
||||
</h3>
|
||||
<ul className="space-y-2.5 text-sm text-muted-foreground font-medium">
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-amber-400 font-black shrink-0">+15 marks</span>
|
||||
<span>in Maths → upgrades you from NIT Trichy to <strong className="text-foreground">IIT Roorkee</strong></span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-[#00F0FF] font-black shrink-0">Fix Optics</span>
|
||||
<span>errors to recover ~8 marks in Physics alone</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<span className="text-green-400 font-black shrink-0">Boost Speed</span>
|
||||
<span>from 45s → 38s/Q gives you ~12 extra attempt opportunities</span>
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
@@ -1,24 +1,156 @@
|
||||
"use client"
|
||||
|
||||
import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap"
|
||||
import { ArrowLeft, Flame } from "lucide-react"
|
||||
import { Flame, AlertTriangle, TrendingDown, BookOpen, ArrowRight, BarChart2, Target } from "lucide-react"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import Link from "next/link"
|
||||
|
||||
const CRITICAL_TOPICS = [
|
||||
{ name: "Rotational Dynamics", rate: "80%", rateNum: 80, subject: "Physics" },
|
||||
{ name: "Optics", rate: "60%", rateNum: 60, subject: "Physics" },
|
||||
{ name: "Electromagnetism", rate: "30%", rateNum: 30, subject: "Physics" },
|
||||
{ name: "GOC — Reaction Mechanisms", rate: "55%", rateNum: 55, subject: "Chemistry" },
|
||||
{ name: "Thermodynamics", rate: "25%", rateNum: 25, subject: "Physics" },
|
||||
]
|
||||
|
||||
const SUMMARY_STATS = [
|
||||
{ label: "Total Errors (Last 5 Tests)", value: "87", icon: <AlertTriangle size={18} className="text-red-400" />, color: "border-red-400/20 bg-red-400/5" },
|
||||
{ label: "Critical Topics", value: "4", icon: <Flame size={18} className="text-orange-400" />, color: "border-orange-400/20 bg-orange-400/5" },
|
||||
{ label: "Improving Topics", value: "3", icon: <TrendingDown size={18} className="text-green-400" />, color: "border-green-400/20 bg-green-400/5" },
|
||||
{ label: "Avg Error Rate", value: "38%", icon: <Target size={18} className="text-amber-400" />, color: "border-amber-400/20 bg-amber-400/5" },
|
||||
]
|
||||
|
||||
export default function HeatmapPage() {
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Flame className="text-yellow-500" size={36} />
|
||||
Mistake Heatmap Vault
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Visual representation of your error density across subjects and topics.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-amber-500/10 border border-amber-500/20">
|
||||
<Flame className="text-amber-500" size={28} />
|
||||
</span>
|
||||
Mistake Heatmap Vault
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Visual density map of your errors across subjects and topics — pinpoint your weakest areas instantly.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-amber-500 bg-amber-500/10 border border-amber-500/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<AlertTriangle size={12} /> Error Density Analysis
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<MistakeHeatmap />
|
||||
{/* KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{SUMMARY_STATS.map((kpi) => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color} hover:scale-[1.02] transition-transform`}>
|
||||
<CardContent className="p-5 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">{kpi.label}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Legend / Guidance Row */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Critical (> 50%)", color: "bg-red-500/20 border-red-500/30 text-red-400", dot: "bg-red-500", desc: "Immediate revision needed" },
|
||||
{ label: "Warning (30–50%)", color: "bg-amber-500/20 border-amber-500/30 text-amber-400", dot: "bg-amber-500", desc: "Focus on these next" },
|
||||
{ label: "Moderate (10–30%)", color: "bg-yellow-500/20 border-yellow-500/30 text-yellow-400", dot: "bg-yellow-500", desc: "Review periodically" },
|
||||
{ label: "Good (< 10%)", color: "bg-green-500/20 border-green-500/30 text-green-400", dot: "bg-green-500", desc: "Mostly understood" },
|
||||
].map((item) => (
|
||||
<Card key={item.label} className={`rounded-2xl border ${item.color.split(" ").slice(0, 2).join(" ")}`}>
|
||||
<CardContent className="p-4">
|
||||
<div className={`inline-flex items-center gap-1.5 text-xs font-black uppercase tracking-wider mb-1 ${item.color.split(" ")[2]}`}>
|
||||
<span className={`w-2.5 h-2.5 rounded-sm ${item.dot}`} />
|
||||
{item.label}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground font-medium">{item.desc}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main 2-col layout */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Heatmap — takes 2/3 */}
|
||||
<div className="lg:col-span-2 space-y-3">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<TrendingDown size={16} className="text-red-400" />
|
||||
Topic Error Rate — Last 5 Tests
|
||||
</div>
|
||||
<MistakeHeatmap />
|
||||
</div>
|
||||
|
||||
{/* Side panel */}
|
||||
<div className="space-y-6">
|
||||
{/* Error frequency chart */}
|
||||
<Card className="bg-secondary/10 border-border/60 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-4">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-foreground flex items-center gap-2">
|
||||
<BarChart2 size={15} className="text-red-400" /> Priority Topics by Error Rate
|
||||
</h3>
|
||||
<div className="space-y-3">
|
||||
{CRITICAL_TOPICS.map((t) => (
|
||||
<div key={t.name}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div>
|
||||
<p className="text-xs font-bold leading-tight">{t.name}</p>
|
||||
<p className="text-[11px] text-muted-foreground">{t.subject}</p>
|
||||
</div>
|
||||
<span className={`text-xs font-black px-2 py-0.5 rounded-md ${t.rateNum >= 50 ? "text-red-400 bg-red-400/10" : t.rateNum >= 30 ? "text-amber-400 bg-amber-400/10" : "text-yellow-400 bg-yellow-400/10"}`}>
|
||||
{t.rate}
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-1.5 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full rounded-full ${t.rateNum >= 50 ? "bg-red-500" : t.rateNum >= 30 ? "bg-amber-500" : "bg-yellow-500"}`}
|
||||
style={{ width: `${t.rateNum}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Action card */}
|
||||
<Card className="bg-gradient-to-br from-[#00F0FF]/10 via-secondary/20 to-background border border-[#00F0FF]/20 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-3">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-[#00F0FF]">What To Do Next</h3>
|
||||
<div className="space-y-2">
|
||||
{[
|
||||
{ label: "Start Mistake Review Session", href: "/dashboard/ai-coach/mistakes" },
|
||||
{ label: "Take a Physics DPP", href: "/dashboard/ai-coach/cbt-dpp" },
|
||||
{ label: "Check Exam Readiness Score", href: "/dashboard/ai-coach/readiness" },
|
||||
].map((link) => (
|
||||
<Link key={link.href} href={link.href}
|
||||
className="flex items-center justify-between text-sm font-bold text-muted-foreground hover:text-foreground py-2 border-b border-border/30 last:border-0 transition-colors group">
|
||||
{link.label}
|
||||
<ArrowRight size={14} className="group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Tip */}
|
||||
<Card className="bg-secondary/20 border-border/40 rounded-2xl">
|
||||
<CardContent className="p-4">
|
||||
<div className="flex items-start gap-2.5">
|
||||
<BookOpen size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<p className="text-xs text-muted-foreground font-medium">
|
||||
<span className="font-black text-foreground">Pro Tip:</span> Focus the next 3 days entirely on Rotational Dynamics — it alone is worth 8–12 marks in JEE and shows an 80% error rate across your last 5 tests.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,9 +5,8 @@ import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap"
|
||||
import { MistakeReviewCard, MistakePayload } from "@/components/AI/MistakeReviewCard"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { BrainCircuit, RefreshCw, CheckCircle2, ArrowLeft, Flame, Sparkles, AlertTriangle } from "lucide-react"
|
||||
import { BrainCircuit, RefreshCw, CheckCircle2, Flame, Sparkles, AlertTriangle, Target, Clock, TrendingDown } from "lucide-react"
|
||||
import { useActiveUser } from "@/hooks/useActiveUser"
|
||||
import Link from "next/link"
|
||||
|
||||
export default function MistakeTrackingPage() {
|
||||
const [mistakes, setMistakes] = useState<MistakePayload[]>([])
|
||||
@@ -23,8 +22,7 @@ export default function MistakeTrackingPage() {
|
||||
if (!res.ok) throw new Error("Failed to fetch")
|
||||
const data = await res.json()
|
||||
setMistakes(data)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} catch {
|
||||
setMistakes([])
|
||||
} finally {
|
||||
setLoading(false)
|
||||
@@ -32,9 +30,7 @@ export default function MistakeTrackingPage() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!userLoading && userId) {
|
||||
fetchMistakes()
|
||||
}
|
||||
if (!userLoading && userId) fetchMistakes()
|
||||
}, [userId, userLoading])
|
||||
|
||||
const submitReview = async (mistakeId: string, selectedAnswer: string) => {
|
||||
@@ -55,51 +51,97 @@ export default function MistakeTrackingPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const completedCount = Math.min(currentIndex, mistakes.length)
|
||||
const progressPct = mistakes.length > 0 ? Math.round((completedCount / mistakes.length) * 100) : 0
|
||||
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Navigation Header */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 border-b border-border/50 pb-6">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<BrainCircuit className="text-[#00F0FF]" size={36} />
|
||||
AI Mistake Vault & SM-2 Engine
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium">
|
||||
Review logged errors, practice spaced-repetition cards, and observe subject heatmap trends.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 shrink-0">
|
||||
<div className="bg-[#00F0FF]/10 text-[#00F0FF] border border-[#00F0FF]/30 px-4 py-2 rounded-2xl font-bold text-sm flex items-center gap-2">
|
||||
<Sparkles size={16} /> SM-2 Adaptive Algorithm Active
|
||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<BrainCircuit className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Mistake Review & Spaced Repetition
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Review logged errors using our SM-2 spaced repetition engine. Questions resurface at optimal intervals to cement long-term retention.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<Sparkles size={12} /> SM-2 Engine
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main Review Workspace */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
{/* KPI Strip */}
|
||||
{!loading && (
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "In Today's Queue", value: mistakes.length.toString(), icon: <Flame size={18} className="text-amber-400" />, color: "border-amber-400/20 bg-amber-400/5" },
|
||||
{ label: "Reviewed This Session", value: completedCount.toString(), icon: <CheckCircle2 size={18} className="text-green-400" />, color: "border-green-400/20 bg-green-400/5" },
|
||||
{ label: "Session Progress", value: `${progressPct}%`, icon: <Target size={18} className="text-[#00F0FF]" />, color: "border-[#00F0FF]/20 bg-[#00F0FF]/5" },
|
||||
{ label: "Avg Error Rate", value: "38%", icon: <TrendingDown size={18} className="text-red-400" />, color: "border-red-400/20 bg-red-400/5" },
|
||||
].map(kpi => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color}`}>
|
||||
<CardContent className="p-4 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">{kpi.label}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Progress bar */}
|
||||
{!loading && mistakes.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<div className="flex justify-between text-xs font-bold text-muted-foreground">
|
||||
<span>Session Progress</span>
|
||||
<span className="text-[#00F0FF]">{completedCount} of {mistakes.length} reviewed</span>
|
||||
</div>
|
||||
<div className="h-2 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-[#00F0FF] to-teal-400 rounded-full transition-all duration-500"
|
||||
style={{ width: `${progressPct}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Main 2-col layout */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 lg:gap-8 items-start">
|
||||
<div className="lg:col-span-7 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight flex items-center gap-2">
|
||||
<Flame className="text-amber-500" size={24} /> Today's Active Review Queue
|
||||
<h2 className="text-lg font-extrabold tracking-tight flex items-center gap-2 text-muted-foreground uppercase tracking-wider text-sm">
|
||||
<Clock size={16} className="text-amber-400" />
|
||||
Active Review Queue
|
||||
</h2>
|
||||
<span className="text-sm font-bold text-[#00F0FF] bg-[#00F0FF]/10 px-4 py-1.5 rounded-full border border-[#00F0FF]/20">
|
||||
{currentIndex < mistakes.length ? `Question ${currentIndex + 1} of ${mistakes.length}` : "Completed"}
|
||||
</span>
|
||||
{mistakes.length > 0 && (
|
||||
<span className="text-sm font-bold text-[#00F0FF] bg-[#00F0FF]/10 px-4 py-1.5 rounded-full border border-[#00F0FF]/20">
|
||||
{currentIndex < mistakes.length ? `${currentIndex + 1} / ${mistakes.length}` : "Complete"}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<Card className="p-16 flex items-center justify-center border-dashed">
|
||||
<RefreshCw className="animate-spin text-[#00F0FF] mr-3" size={24} />
|
||||
<span className="text-lg font-bold">Loading your active error queue...</span>
|
||||
<Card className="min-h-[480px] h-full flex flex-col items-center justify-center border-dashed p-8 gap-4">
|
||||
<RefreshCw className="animate-spin text-[#00F0FF]" size={28} />
|
||||
<span className="text-base font-semibold text-muted-foreground">Loading your review queue...</span>
|
||||
</Card>
|
||||
) : mistakes.length === 0 ? (
|
||||
<Card className="p-16 text-center border-dashed bg-secondary/10 rounded-3xl">
|
||||
<CheckCircle2 size={56} className="mx-auto text-green-400 mb-4 opacity-80" />
|
||||
<h3 className="text-2xl font-extrabold mb-2">Zero Mistakes Pending!</h3>
|
||||
<p className="text-muted-foreground text-base max-w-md mx-auto mb-6">
|
||||
All scheduled errors have been reviewed. Solve more mock tests to automatically surface weak questions here.
|
||||
</p>
|
||||
<Button onClick={() => window.location.reload()} variant="outline" className="rounded-xl font-bold">
|
||||
<Card className="min-h-[480px] h-full flex flex-col items-center justify-center text-center border-dashed bg-secondary/10 rounded-3xl p-8 gap-4">
|
||||
<CheckCircle2 size={56} className="text-green-400 opacity-80" />
|
||||
<div>
|
||||
<h3 className="text-xl font-extrabold mb-2">Queue Complete</h3>
|
||||
<p className="text-muted-foreground text-sm max-w-md mx-auto font-medium">
|
||||
All scheduled reviews for today are done. Solve more practice tests to surface new questions here.
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={() => window.location.reload()} variant="outline" className="rounded-xl font-bold h-10 px-6">
|
||||
Refresh Queue
|
||||
</Button>
|
||||
</Card>
|
||||
@@ -110,21 +152,27 @@ export default function MistakeTrackingPage() {
|
||||
onSubmitReview={submitReview}
|
||||
/>
|
||||
) : (
|
||||
<Card className="p-16 text-center border-dashed bg-[#00F0FF]/5 border-[#00F0FF]/30 rounded-3xl">
|
||||
<BrainCircuit size={56} className="mx-auto text-[#00F0FF] mb-4" />
|
||||
<h3 className="text-2xl font-extrabold mb-2 text-[#00F0FF]">Review Session Mastered 🎉</h3>
|
||||
<p className="text-muted-foreground text-base max-w-md mx-auto mb-6">
|
||||
Fantastic focus! Your memory decay intervals have been updated in the database.
|
||||
</p>
|
||||
<Button onClick={() => window.location.reload()} className="bg-[#00F0FF] text-black font-bold rounded-xl px-6">
|
||||
Check Additional Pending Queues
|
||||
<Card className="min-h-[480px] h-full flex flex-col items-center justify-center text-center border-dashed bg-[#00F0FF]/5 border-[#00F0FF]/30 rounded-3xl p-8 gap-4">
|
||||
<BrainCircuit size={56} className="text-[#00F0FF]" />
|
||||
<div>
|
||||
<h3 className="text-xl font-extrabold mb-2 text-[#00F0FF]">Session Complete 🎉</h3>
|
||||
<p className="text-muted-foreground text-sm max-w-md mx-auto font-medium">
|
||||
All {mistakes.length} questions reviewed. The SM-2 engine has scheduled your next review intervals.
|
||||
</p>
|
||||
</div>
|
||||
<Button onClick={() => window.location.reload()} className="bg-[#00F0FF] text-black font-bold rounded-xl px-6 h-10 text-sm">
|
||||
Check for New Errors
|
||||
</Button>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Heatmap & Info Column */}
|
||||
<div className="space-y-6">
|
||||
{/* Heatmap Column */}
|
||||
<div className="lg:col-span-5 space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<AlertTriangle size={16} className="text-amber-400" />
|
||||
Error Density by Topic
|
||||
</div>
|
||||
<MistakeHeatmap />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,75 +3,169 @@
|
||||
import { ReadinessGauge } from "@/components/AI/ReadinessGauge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Gauge, ArrowLeft, Target, Award, ShieldAlert, CheckCircle2 } from "lucide-react"
|
||||
import { Gauge, TrendingUp, Target, Award, ShieldAlert, CheckCircle2, BookOpen, Zap, BarChart2, Clock } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
|
||||
const SCORE_HISTORY = [
|
||||
{ week: "Wk 1", score: 54 },
|
||||
{ week: "Wk 2", score: 60 },
|
||||
{ week: "Wk 3", score: 63 },
|
||||
{ week: "Wk 4", score: 68 },
|
||||
{ week: "Wk 5", score: 72 },
|
||||
{ week: "Wk 6", score: 78 },
|
||||
]
|
||||
|
||||
export default function ReadinessPage() {
|
||||
const maxScore = Math.max(...SCORE_HISTORY.map(d => d.score))
|
||||
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Navigation Header */}
|
||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Gauge className="text-[#00F0FF]" size={36} />
|
||||
Exam Readiness Analytics
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Real-time algorithmic prediction of your readiness percentage for JEE & NEET based on speed, accuracy, and test history.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Gauge className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Exam Readiness Analytics
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Real-time algorithmic prediction of your exam readiness — based on speed, accuracy, syllabus coverage, and test history.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<Gauge size={12} /> AI Powered
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Overall Score", value: "72 / 100", trend: "+5 this week", trendUp: true, icon: <Gauge size={20} className="text-[#00F0FF]" /> },
|
||||
{ label: "Accuracy Rate", value: "88%", trend: "+3% vs last week", trendUp: true, icon: <Target size={20} className="text-amber-400" /> },
|
||||
{ label: "Avg Speed / Q", value: "45 sec", trend: "↓ Needs work", trendUp: false, icon: <Clock size={20} className="text-red-400" /> },
|
||||
{ label: "Syllabus Covered", value: "64%", trend: "+8% this month", trendUp: true, icon: <BookOpen size={20} className="text-emerald-400" /> },
|
||||
].map((kpi) => (
|
||||
<Card key={kpi.label} className="border-border/60 bg-secondary/10 rounded-2xl hover:border-[#00F0FF]/30 transition-colors">
|
||||
<CardContent className="p-5">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
{kpi.icon}
|
||||
<span className={`text-xs font-bold px-2 py-0.5 rounded-full ${kpi.trendUp ? "bg-green-500/10 text-green-400" : "bg-red-500/10 text-red-400"}`}>
|
||||
{kpi.trend}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-2xl font-black mb-0.5">{kpi.value}</div>
|
||||
<div className="text-xs text-muted-foreground font-semibold uppercase tracking-wider">{kpi.label}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
<Card className="p-8 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-6 flex items-center gap-2">
|
||||
<Award className="text-amber-400" size={24} /> Overall Readiness Index
|
||||
</h2>
|
||||
{/* Readiness Score Card */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-5">
|
||||
<Award className="text-amber-400" size={22} />
|
||||
<h2 className="text-xl font-extrabold tracking-tight">Composite Readiness Index</h2>
|
||||
<span className="ml-auto text-xs font-bold text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-2.5 py-1 rounded-full">Updated Daily</span>
|
||||
</div>
|
||||
<ReadinessGauge />
|
||||
</Card>
|
||||
|
||||
{/* Subject Confidence Breakdown */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl space-y-6">
|
||||
<h3 className="text-xl font-extrabold tracking-tight">Subject Confidence Matrix</h3>
|
||||
{/* Subject Confidence Matrix */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl space-y-5">
|
||||
<div className="flex items-center gap-2">
|
||||
<BarChart2 size={20} className="text-[#00F0FF]" />
|
||||
<h3 className="text-lg font-extrabold tracking-tight">Subject Confidence Matrix</h3>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ subject: "Biology / Maths", score: 82, color: "bg-[#00F0FF]", status: "High Readiness" },
|
||||
{ subject: "Chemistry", score: 74, color: "bg-amber-400", status: "Moderate Readiness" },
|
||||
{ subject: "Physics", score: 61, color: "bg-red-400", status: "Needs Intensive Drill" },
|
||||
{ subject: "Biology / Maths", score: 82, color: "bg-[#00F0FF]", status: "High Readiness", statusColor: "text-[#00F0FF]" },
|
||||
{ subject: "Chemistry", score: 74, color: "bg-amber-400", status: "Moderate Readiness", statusColor: "text-amber-400" },
|
||||
{ subject: "Physics", score: 61, color: "bg-red-400", status: "Needs Intensive Drill", statusColor: "text-red-400" },
|
||||
].map((sub) => (
|
||||
<div key={sub.subject} className="space-y-2">
|
||||
<div className="flex justify-between items-center text-sm font-bold">
|
||||
<span>{sub.subject}</span>
|
||||
<span className="text-muted-foreground">{sub.score}% • {sub.status}</span>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-sm font-black">{sub.subject}</span>
|
||||
<span className={`text-xs font-bold ${sub.statusColor}`}>{sub.score}% · {sub.status}</span>
|
||||
</div>
|
||||
<div className="h-3 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div className={`h-full ${sub.color}`} style={{ width: `${sub.score}%` }} />
|
||||
<div className="h-2.5 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div className={`h-full ${sub.color} rounded-full transition-all duration-700`} style={{ width: `${sub.score}%` }} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Score History Chart */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-6">
|
||||
<TrendingUp size={20} className="text-green-400" />
|
||||
<h3 className="text-lg font-extrabold tracking-tight">6-Week Readiness Trend</h3>
|
||||
</div>
|
||||
<div className="flex items-end gap-3 h-28">
|
||||
{SCORE_HISTORY.map((d, i) => (
|
||||
<div key={d.week} className="flex flex-col items-center gap-1 flex-1">
|
||||
<span className="text-xs font-black text-muted-foreground">{d.score}</span>
|
||||
<div
|
||||
className={`w-full rounded-t-md transition-all duration-700 ${i === SCORE_HISTORY.length - 1 ? "bg-gradient-to-t from-[#00F0FF]/60 to-[#00F0FF]" : "bg-gradient-to-t from-white/10 to-white/25"}`}
|
||||
style={{ height: `${(d.score / maxScore) * 80}px` }}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground font-semibold">{d.week}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="space-y-6">
|
||||
<Card className="p-6 bg-gradient-to-br from-amber-500/10 via-secondary/20 to-background border border-amber-500/30 rounded-3xl space-y-4">
|
||||
<h3 className="text-xl font-black tracking-tight text-amber-400 flex items-center gap-2">
|
||||
<ShieldAlert size={20} /> Readiness Boosters
|
||||
<h3 className="text-base font-black tracking-tight text-amber-400 flex items-center gap-2">
|
||||
<ShieldAlert size={18} /> Readiness Boosters
|
||||
</h3>
|
||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
||||
<li className="flex items-start gap-2">
|
||||
<ul className="space-y-3.5 text-sm font-semibold text-muted-foreground">
|
||||
<li className="flex items-start gap-2.5">
|
||||
<CheckCircle2 size={16} className="text-amber-400 shrink-0 mt-0.5" />
|
||||
<span>Complete 2 Full-Length Mock Tests this week.</span>
|
||||
<span>Complete 2 full-length mock tests this week to boost consistency score.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-amber-400 shrink-0 mt-0.5" />
|
||||
<span>Clear 15 pending errors in Physics error queue.</span>
|
||||
<span>Clear 15 pending errors in your Physics queue to gain ~4 readiness points.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-amber-400 shrink-0 mt-0.5" />
|
||||
<span>Maintain a 7+ day study streak.</span>
|
||||
<span>Maintain a 7+ day streak — consistency adds 6% to your readiness index.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-amber-400 shrink-0 mt-0.5" />
|
||||
<span>Reduce avg time-per-question below 40s with daily timed DPP sessions.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl space-y-4">
|
||||
<h3 className="text-base font-black text-muted-foreground uppercase tracking-wider flex items-center gap-2">
|
||||
<Zap size={16} className="text-[#00F0FF]" /> Quick Actions
|
||||
</h3>
|
||||
<div className="space-y-2.5">
|
||||
{[
|
||||
{ label: "Practice Physics DPP", href: "/dashboard/ai-coach/cbt-dpp", color: "text-[#00F0FF]" },
|
||||
{ label: "Review Mistake Queue", href: "/dashboard/ai-coach/mistakes", color: "text-red-400" },
|
||||
{ label: "View Exam Strategy", href: "/dashboard/ai-coach/strategy", color: "text-amber-400" },
|
||||
{ label: "College Predictor", href: "/dashboard/ai-coach/college-predictor", color: "text-emerald-400" },
|
||||
].map((a) => (
|
||||
<Link key={a.href} href={a.href}
|
||||
className="flex items-center justify-between p-2.5 rounded-xl border border-border/40 hover:border-[#00F0FF]/30 hover:bg-white/5 transition-all group text-sm font-bold">
|
||||
<span className={a.color}>{a.label}</span>
|
||||
<span className="text-muted-foreground group-hover:translate-x-1 transition-transform">→</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,39 +3,133 @@
|
||||
import { ExamStrategyCard } from "@/components/AI/ExamStrategyCard"
|
||||
import { StudyTimeOptimizationCard } from "@/components/AI/StudyTimeOptimizationCard"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Zap, ArrowLeft, Clock, Target, Lightbulb, CheckCircle2 } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { Zap, Clock, Target, Lightbulb, CheckCircle2, AlertTriangle, TrendingUp } from "lucide-react"
|
||||
|
||||
const NEG_MARKING_DATA = [
|
||||
{ subject: "Physics", attempts: 30, negMarks: 12, accuracy: 60 },
|
||||
{ subject: "Chemistry", attempts: 35, negMarks: 7, accuracy: 80 },
|
||||
{ subject: "Maths", attempts: 28, negMarks: 10, accuracy: 64 },
|
||||
]
|
||||
|
||||
export default function StrategyPage() {
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Navigation Header */}
|
||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Zap className="text-[#00F0FF]" size={36} />
|
||||
Exam Strategy & Time Optimization
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Master time allocation per question, eliminate negative marking traps, and fine-tune your subject sequence for maximum score yield.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Zap className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Exam Strategy & Time Optimization
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Master time allocation per question, eliminate negative marking traps, and fine-tune your subject sequence for maximum score yield.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<Zap size={12} /> AI Powered
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-4 flex items-center gap-2">
|
||||
<Target className="text-[#00F0FF]" size={24} /> Exam Day Time Strategy
|
||||
</h2>
|
||||
{/* KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Time Per Question", value: "45 sec", note: "Target: 38 sec", icon: <Clock size={18} className="text-red-400" />, color: "border-red-400/20 bg-red-400/5" },
|
||||
{ label: "Negative Marks Lost", value: "−29", note: "Last mock test", icon: <AlertTriangle size={18} className="text-amber-400" />, color: "border-amber-400/20 bg-amber-400/5" },
|
||||
{ label: "Attempted Questions", value: "93 / 120", note: "+7 vs last test", icon: <Target size={18} className="text-[#00F0FF]" />, color: "border-[#00F0FF]/20 bg-[#00F0FF]/5" },
|
||||
{ label: "Score Yield", value: "214", note: "Predicted score", icon: <TrendingUp size={18} className="text-green-400" />, color: "border-green-400/20 bg-green-400/5" },
|
||||
].map((kpi) => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color} hover:scale-[1.02] transition-transform`}>
|
||||
<CardContent className="p-5 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground">{kpi.label}</div>
|
||||
<div className="text-[11px] font-bold text-muted-foreground/60">{kpi.note}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main Cards Row */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<Target size={16} className="text-[#00F0FF]" />
|
||||
Subject Sequence Strategy
|
||||
</div>
|
||||
<ExamStrategyCard />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-4 flex items-center gap-2">
|
||||
<Clock className="text-amber-400" size={24} /> Study Time Optimization
|
||||
</h2>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<Clock size={16} className="text-amber-400" />
|
||||
Daily Peak Hours Analysis
|
||||
</div>
|
||||
<StudyTimeOptimizationCard />
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Negative Marking Analysis */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-5">
|
||||
<AlertTriangle size={20} className="text-amber-400" />
|
||||
<h3 className="text-lg font-extrabold tracking-tight">Negative Marking Analysis</h3>
|
||||
<span className="ml-auto text-xs text-muted-foreground font-semibold">Last Mock Test · Aug 1</span>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{NEG_MARKING_DATA.map((row) => (
|
||||
<div key={row.subject} className="grid grid-cols-4 gap-4 items-center p-3 rounded-xl bg-white/5 border border-border/40">
|
||||
<div className="font-black text-sm">{row.subject}</div>
|
||||
<div className="text-center">
|
||||
<div className="text-sm font-black text-foreground">{row.attempts}</div>
|
||||
<div className="text-[11px] text-muted-foreground font-semibold">Attempted</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-sm font-black text-red-400">−{row.negMarks}</div>
|
||||
<div className="text-[11px] text-muted-foreground font-semibold">Neg. Marks</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-xs font-bold mb-1">
|
||||
<span className="text-muted-foreground">Accuracy</span>
|
||||
<span className={row.accuracy >= 75 ? "text-green-400" : row.accuracy >= 60 ? "text-amber-400" : "text-red-400"}>{row.accuracy}%</span>
|
||||
</div>
|
||||
<div className="h-2 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full rounded-full ${row.accuracy >= 75 ? "bg-green-400" : row.accuracy >= 60 ? "bg-amber-400" : "bg-red-400"}`}
|
||||
style={{ width: `${row.accuracy}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-4 font-medium pl-1">
|
||||
<span className="font-black text-amber-400">Insight:</span> You're losing ~29 marks to wrong answers. Switching to "skip and revisit" for uncertain Physics questions could recover 15–20 marks.
|
||||
</p>
|
||||
</Card>
|
||||
|
||||
{/* Strategy Tips */}
|
||||
<Card className="p-6 bg-gradient-to-br from-[#00F0FF]/5 via-secondary/10 to-background border border-[#00F0FF]/20 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<Lightbulb size={20} className="text-yellow-400" />
|
||||
<h3 className="text-base font-black tracking-tight">AI Strategy Recommendations</h3>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{[
|
||||
{ tip: "Start with Chemistry (highest accuracy) to build momentum and bank easy marks in the first 40 minutes.", color: "text-green-400", label: "Opening Strategy" },
|
||||
{ tip: "Attempt Physics only if you are 80%+ confident per question. Otherwise, mark and skip — recover in last 10 min buffer.", color: "text-red-400", label: "Physics Guard" },
|
||||
{ tip: "Reserve 10–15 minutes at the end to revisit starred questions. Your review accuracy is historically 20% higher than first-attempt.", color: "text-[#00F0FF]", label: "Review Window" },
|
||||
].map((s) => (
|
||||
<div key={s.label} className="p-4 rounded-xl bg-white/5 border border-border/30 space-y-2">
|
||||
<div className={`text-xs font-black uppercase tracking-wider ${s.color}`}>{s.label}</div>
|
||||
<p className="text-sm text-muted-foreground font-medium leading-relaxed">{s.tip}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,62 +3,152 @@
|
||||
import { StudyPlanCard } from "@/components/AI/StudyPlanCard"
|
||||
import { WeeklyProgressReport } from "@/components/AI/WeeklyProgressReport"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Calendar, ArrowLeft, BookOpen, Clock, Target, CheckCircle2 } from "lucide-react"
|
||||
import Link from "next/link"
|
||||
import { Calendar, BookOpen, Clock, Target, CheckCircle2, TrendingUp, Flame } from "lucide-react"
|
||||
|
||||
export default function StudyPlanPage() {
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Navigation Header */}
|
||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Calendar className="text-[#00F0FF]" size={36} />
|
||||
Personalized Daily & Weekly Study Plan
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
AI-generated task schedule dynamically tailored to fix your weak areas and maintain optimal syllabus coverage.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Calendar className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Personalized Daily & Weekly Study Plan
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
AI-generated task schedule dynamically tailored to fix your weak areas and maintain optimal syllabus coverage.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<Calendar size={12} /> AI Powered
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Tasks Today", value: "5", sub: "2 completed", icon: <CheckCircle2 size={18} className="text-green-400" />, color: "border-green-400/20 bg-green-400/5" },
|
||||
{ label: "Study Hours Today", value: "3.8 hrs", sub: "Target: 5 hrs", icon: <Clock size={18} className="text-[#00F0FF]" />, color: "border-[#00F0FF]/20 bg-[#00F0FF]/5" },
|
||||
{ label: "Syllabus Coverage", value: "64%", sub: "+8% this week", icon: <Target size={18} className="text-amber-400" />, color: "border-amber-400/20 bg-amber-400/5" },
|
||||
{ label: "Current Streak", value: "12 Days", sub: "Keep it up!", icon: <Flame size={18} className="text-orange-400" />, color: "border-orange-400/20 bg-orange-400/5" },
|
||||
].map((kpi) => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color} hover:scale-[1.02] transition-transform`}>
|
||||
<CardContent className="p-5 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">{kpi.label}</div>
|
||||
<div className="text-[11px] font-bold text-muted-foreground/60">{kpi.sub}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-8">
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-4 flex items-center gap-2">
|
||||
<Clock className="text-[#00F0FF]" size={24} /> Today's Action Plan
|
||||
</h2>
|
||||
{/* Today's Schedule */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<Clock size={16} className="text-[#00F0FF]" />
|
||||
Today's Schedule
|
||||
</div>
|
||||
<span className="text-xs font-bold text-[#00F0FF]">
|
||||
{new Date().toLocaleDateString("en-IN", { weekday: "long", day: "numeric", month: "long" })}
|
||||
</span>
|
||||
</div>
|
||||
<StudyPlanCard />
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<h2 className="text-2xl font-extrabold tracking-tight mb-4 flex items-center gap-2">
|
||||
<Target className="text-emerald-400" size={24} /> Weekly Syllabus Target
|
||||
</h2>
|
||||
{/* Weekly Overview */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<TrendingUp size={16} className="text-emerald-400" />
|
||||
Weekly Syllabus Progress
|
||||
</div>
|
||||
<WeeklyProgressReport />
|
||||
</div>
|
||||
|
||||
{/* Syllabus Coverage */}
|
||||
<Card className="p-6 bg-secondary/10 border-border/60 rounded-3xl">
|
||||
<div className="flex items-center gap-2 mb-5">
|
||||
<BookOpen size={20} className="text-[#00F0FF]" />
|
||||
<h3 className="text-lg font-extrabold tracking-tight">Subject Coverage Breakdown</h3>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{ subject: "Physics", covered: 58, total: 100, chapters: "21 / 29 chapters" },
|
||||
{ subject: "Chemistry", covered: 71, total: 100, chapters: "19 / 26 chapters" },
|
||||
{ subject: "Biology / Maths", covered: 64, total: 100, chapters: "32 / 52 topics" },
|
||||
].map((sub) => (
|
||||
<div key={sub.subject}>
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<span className="text-sm font-black">{sub.subject}</span>
|
||||
<div className="flex items-center gap-3 text-xs font-semibold text-muted-foreground">
|
||||
<span>{sub.chapters}</span>
|
||||
<span className={`font-black ${sub.covered >= 70 ? "text-green-400" : sub.covered >= 55 ? "text-amber-400" : "text-red-400"}`}>{sub.covered}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-2.5 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full rounded-full transition-all duration-700 ${sub.covered >= 70 ? "bg-green-400" : sub.covered >= 55 ? "bg-amber-400" : "bg-red-400"}`}
|
||||
style={{ width: `${sub.covered}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Sidebar Info */}
|
||||
{/* Sidebar */}
|
||||
<div className="space-y-6">
|
||||
<Card className="p-6 bg-gradient-to-br from-[#00F0FF]/10 via-secondary/20 to-background border border-[#00F0FF]/30 rounded-3xl space-y-4">
|
||||
<h3 className="text-xl font-black tracking-tight text-[#00F0FF] flex items-center gap-2">
|
||||
<BookOpen size={20} /> AI Scheduler Rules
|
||||
<h3 className="text-base font-black tracking-tight text-[#00F0FF] flex items-center gap-2">
|
||||
<BookOpen size={18} /> AI Scheduler Rules
|
||||
</h3>
|
||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span><strong>High-Yield Prioritization:</strong> Focuses extra time on topics with heavy exam weightage.</span>
|
||||
<span><strong className="text-foreground">High-Yield Prioritization:</strong> Extra time on topics with heavy exam weightage.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span><strong>Error Interleaving:</strong> Integrates recent incorrect questions directly into study blocks.</span>
|
||||
<span><strong className="text-foreground">Error Interleaving:</strong> Recent incorrect questions are integrated directly into study blocks.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span><strong>Burnout Prevention:</strong> Recommends 10-minute micro-breaks between intensive problem sets.</span>
|
||||
<span><strong className="text-foreground">Burnout Prevention:</strong> 10-minute micro-breaks recommended between intensive problem sets.</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<CheckCircle2 size={16} className="text-[#00F0FF] shrink-0 mt-0.5" />
|
||||
<span><strong className="text-foreground">Spaced Repetition:</strong> SM-2 algorithm reschedules mistake reviews at optimal intervals.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<Card className="p-5 bg-secondary/10 border-border/60 rounded-3xl space-y-3">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-muted-foreground">Upcoming This Week</h3>
|
||||
<div className="space-y-2">
|
||||
{[
|
||||
{ day: "Tue, Aug 5", task: "Full-Length Mock — JEE Mains Pattern", type: "Test", color: "text-purple-400 bg-purple-400/10" },
|
||||
{ day: "Wed, Aug 6", task: "Rotational Dynamics Intensive Drill", type: "Practice", color: "text-[#00F0FF] bg-[#00F0FF]/10" },
|
||||
{ day: "Thu, Aug 7", task: "Chemistry Organic — Mistake Review", type: "Review", color: "text-red-400 bg-red-400/10" },
|
||||
{ day: "Fri, Aug 8", task: "Optics + Wave Optics Revision", type: "Revision", color: "text-yellow-400 bg-yellow-400/10" },
|
||||
].map((item) => (
|
||||
<div key={item.day} className="flex items-center gap-2 p-2.5 rounded-lg bg-white/5 border border-border/30">
|
||||
<span className={`text-[10px] font-black px-2 py-0.5 rounded-md shrink-0 ${item.color}`}>{item.type}</span>
|
||||
<div className="min-w-0">
|
||||
<div className="text-xs font-bold truncate">{item.task}</div>
|
||||
<div className="text-[11px] text-muted-foreground">{item.day}</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,152 @@
|
||||
"use client"
|
||||
|
||||
import { StudyTimeOptimizationCard } from "@/components/AI/StudyTimeOptimizationCard"
|
||||
import { ArrowLeft, Clock } from "lucide-react"
|
||||
import { Clock, Zap, Moon, Sun, AlertCircle, ArrowRight, BarChart2 } from "lucide-react"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import Link from "next/link"
|
||||
|
||||
const INSIGHTS = [
|
||||
{
|
||||
icon: <Sun size={16} className="text-yellow-400" />,
|
||||
title: "Peak Cognitive Window",
|
||||
desc: "2 PM – 5 PM is your highest-efficiency block. Reserve this for new concepts, hard problems, and mock tests.",
|
||||
color: "border-yellow-400/20 bg-yellow-400/5",
|
||||
},
|
||||
{
|
||||
icon: <Moon size={16} className="text-indigo-400" />,
|
||||
title: "Evening Consolidation",
|
||||
desc: "9–10 PM is ideal for light revision and flashcard review — this window solidifies short-term to long-term memory.",
|
||||
color: "border-indigo-400/20 bg-indigo-400/5",
|
||||
},
|
||||
{
|
||||
icon: <AlertCircle size={16} className="text-red-400" />,
|
||||
title: "Avoid After 11 PM",
|
||||
desc: "Cognitive fatigue significantly increases error rate. Solving new concepts late at night is counterproductive.",
|
||||
color: "border-red-400/20 bg-red-400/5",
|
||||
},
|
||||
]
|
||||
|
||||
const HOURLY_EFFICIENCY = [
|
||||
{ slot: "6–9 AM", pct: 60, label: "Morning" },
|
||||
{ slot: "9–12 PM", pct: 72, label: "Mid-Morning" },
|
||||
{ slot: "12–2 PM", pct: 55, label: "Post-Lunch dip" },
|
||||
{ slot: "2–5 PM", pct: 95, label: "Peak ★", highlight: true },
|
||||
{ slot: "5–7 PM", pct: 82, label: "Afternoon" },
|
||||
{ slot: "7–9 PM", pct: 74, label: "Evening" },
|
||||
{ slot: "9–11 PM", pct: 60, label: "Night Revision" },
|
||||
{ slot: "11 PM+", pct: 32, label: "Avoid" },
|
||||
]
|
||||
|
||||
export default function TimeOptimizationPage() {
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Clock className="text-[#00F0FF]" size={36} />
|
||||
Study Time Optimization
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Detailed metrics on your productive hours and stamina blocks.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Clock className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Study Time Optimization
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Understand your peak productive hours and schedule your hardest topics in your highest-efficiency windows.
|
||||
</p>
|
||||
</div>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5 shrink-0 self-start">
|
||||
<Zap size={12} /> Chronobiology Analytics
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<StudyTimeOptimizationCard />
|
||||
{/* KPI Strip */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "Peak Efficiency", value: "95%", sub: "2–5 PM window", color: "border-yellow-400/20 bg-yellow-400/5", icon: <Sun size={18} className="text-yellow-400" /> },
|
||||
{ label: "Study Hrs Today", value: "3.8 h", sub: "Target: 6 h", color: "border-[#00F0FF]/20 bg-[#00F0FF]/5", icon: <Clock size={18} className="text-[#00F0FF]" /> },
|
||||
{ label: "Morning Block", value: "60%", sub: "6–9 AM", color: "border-indigo-400/20 bg-indigo-400/5", icon: <Moon size={18} className="text-indigo-400" /> },
|
||||
{ label: "Evening Block", value: "74%", sub: "7–9 PM", color: "border-green-400/20 bg-green-400/5", icon: <BarChart2 size={18} className="text-green-400" /> },
|
||||
].map(kpi => (
|
||||
<Card key={kpi.label} className={`rounded-2xl border ${kpi.color}`}>
|
||||
<CardContent className="p-4 flex flex-col gap-2">
|
||||
{kpi.icon}
|
||||
<div className="text-2xl font-black">{kpi.value}</div>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">{kpi.label}</div>
|
||||
<div className="text-[11px] font-bold text-muted-foreground/60">{kpi.sub}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Chart — 2/3 */}
|
||||
<div className="lg:col-span-2 space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm font-black uppercase tracking-wider text-muted-foreground">
|
||||
<BarChart2 size={16} className="text-[#00F0FF]" />
|
||||
Hourly Efficiency Profile
|
||||
</div>
|
||||
<StudyTimeOptimizationCard />
|
||||
</div>
|
||||
|
||||
{/* Right Panel */}
|
||||
<div className="space-y-5">
|
||||
{/* Slot breakdown table */}
|
||||
<Card className="bg-secondary/10 border-border/60 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-3">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-muted-foreground">Time Slot Breakdown</h3>
|
||||
<div className="space-y-2">
|
||||
{HOURLY_EFFICIENCY.map(slot => (
|
||||
<div key={slot.slot} className={`flex items-center gap-3 p-2 rounded-lg ${slot.highlight ? "bg-yellow-400/10 border border-yellow-400/20" : "bg-white/5"}`}>
|
||||
<div className="w-16 text-xs font-bold text-muted-foreground shrink-0">{slot.slot}</div>
|
||||
<div className="flex-1 h-1.5 bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full rounded-full ${slot.pct >= 80 ? (slot.highlight ? "bg-yellow-400" : "bg-green-400") : slot.pct >= 60 ? "bg-[#00F0FF]" : "bg-red-400"}`}
|
||||
style={{ width: `${slot.pct}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className={`text-xs font-black w-8 text-right shrink-0 ${slot.highlight ? "text-yellow-400" : "text-muted-foreground"}`}>{slot.pct}%</div>
|
||||
{slot.highlight && <span className="text-[10px] font-black text-yellow-400 shrink-0">PEAK</span>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* AI Insights */}
|
||||
<div className="space-y-3">
|
||||
{INSIGHTS.map(insight => (
|
||||
<Card key={insight.title} className={`rounded-2xl border ${insight.color}`}>
|
||||
<CardContent className="p-4 flex items-start gap-3">
|
||||
<div className="mt-0.5 shrink-0">{insight.icon}</div>
|
||||
<div>
|
||||
<p className="text-sm font-black">{insight.title}</p>
|
||||
<p className="text-xs text-muted-foreground font-medium mt-0.5">{insight.desc}</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Card className="bg-gradient-to-br from-[#00F0FF]/10 via-secondary/20 to-background border border-[#00F0FF]/20 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-3">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-[#00F0FF]">Apply Insights</h3>
|
||||
<div className="space-y-2">
|
||||
{[
|
||||
{ label: "Schedule Today's Study Plan", href: "/dashboard/ai-coach/study-plan" },
|
||||
{ label: "Check Exam Readiness", href: "/dashboard/ai-coach/readiness" },
|
||||
{ label: "Launch a Practice Test Now", href: "/dashboard/ai-coach/cbt-dpp" },
|
||||
].map(link => (
|
||||
<Link key={link.href} href={link.href}
|
||||
className="flex items-center justify-between text-sm font-bold text-muted-foreground hover:text-foreground py-2 border-b border-border/30 last:border-0 transition-colors group">
|
||||
{link.label}
|
||||
<ArrowRight size={14} className="group-hover:translate-x-1 transition-transform" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,11 +1,52 @@
|
||||
"use client"
|
||||
|
||||
import { TutorChat } from "@/components/AI/TutorChat"
|
||||
import { BrainCircuit, Sparkles, MessageSquare, Lightbulb } from "lucide-react"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
|
||||
const CAPABILITIES = [
|
||||
{ icon: <Lightbulb size={16} className="text-yellow-400" />, label: "Concept Explanations", desc: "Step-by-step breakdown of Physics, Chemistry, Maths & Biology topics" },
|
||||
{ icon: <Sparkles size={16} className="text-[#00F0FF]" />, label: "Problem Solving", desc: "Full worked solutions with formulas, derivations and shortcuts" },
|
||||
{ icon: <MessageSquare size={16} className="text-green-400" />, label: "Doubt Clearing", desc: "Ask follow-up questions — the AI remembers context within the session" },
|
||||
]
|
||||
|
||||
export default function TutorChatPage() {
|
||||
return (
|
||||
<div className="h-[calc(100vh-80px)] w-full flex flex-col p-4 md:p-6 animate-in fade-in duration-500">
|
||||
<div className="flex-1 rounded-3xl overflow-hidden border border-border/50 shadow-xl bg-background">
|
||||
<div className="p-6 md:p-8 space-y-6 max-w-7xl mx-auto animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-2">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<BrainCircuit className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
AI Tutor — 24/7 Doubt Solver
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Ask any JEE or NEET concept, get step-by-step explanations, formula derivations, and solved examples — instantly.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Capabilities Strip */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{CAPABILITIES.map(c => (
|
||||
<Card key={c.label} className="border-border/50 bg-secondary/10 rounded-2xl">
|
||||
<CardContent className="p-4 flex items-start gap-3">
|
||||
<div className="mt-0.5 shrink-0">{c.icon}</div>
|
||||
<div>
|
||||
<div className="text-sm font-black">{c.label}</div>
|
||||
<div className="text-xs text-muted-foreground font-medium mt-0.5">{c.desc}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Chat — full height */}
|
||||
<div className="flex-1 rounded-3xl overflow-hidden border border-border/50 shadow-xl bg-background" style={{ minHeight: "560px" }}>
|
||||
<TutorChat />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,129 @@
|
||||
"use client"
|
||||
|
||||
import { WeeklyProgressReport } from "@/components/AI/WeeklyProgressReport"
|
||||
import { ArrowLeft, Target } from "lucide-react"
|
||||
import { Target, TrendingUp, Calendar, Zap, ArrowRight, BookOpen, CheckCircle2 } from "lucide-react"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import Link from "next/link"
|
||||
|
||||
const STATS = [
|
||||
{ label: "Avg. Accuracy", value: "85%", delta: "+6%", positive: true },
|
||||
{ label: "Days Active", value: "7 / 7", delta: "Perfect week", positive: true },
|
||||
{ label: "Questions Solved", value: "214", delta: "+38 vs last week", positive: true },
|
||||
{ label: "Topics Covered", value: "12", delta: "3 remaining", positive: false },
|
||||
]
|
||||
|
||||
const SYLLABUS_PROGRESS = [
|
||||
{ subject: "Physics", completed: 42, total: 60, percentage: 70, color: "bg-blue-500", text: "text-blue-500" },
|
||||
{ subject: "Chemistry", completed: 35, total: 55, percentage: 63, color: "bg-amber-500", text: "text-amber-500" },
|
||||
{ subject: "Mathematics", completed: 50, total: 65, percentage: 76, color: "bg-purple-500", text: "text-purple-500" },
|
||||
{ subject: "Biology", completed: 20, total: 40, percentage: 50, color: "bg-emerald-500", text: "text-emerald-500" },
|
||||
]
|
||||
|
||||
export default function WeeklyProgressPage() {
|
||||
return (
|
||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in duration-500 min-h-screen">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<h1 className="text-3xl md:text-5xl font-black tracking-tight flex items-center gap-3">
|
||||
<Target className="text-[#00F0FF]" size={36} />
|
||||
Weekly Progress Overview
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base md:text-lg mt-1 font-medium max-w-3xl">
|
||||
Track your syllabus completion goals and weekly milestones.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-1">
|
||||
<span className="p-2.5 rounded-xl bg-[#00F0FF]/10 border border-[#00F0FF]/20">
|
||||
<Target className="text-[#00F0FF]" size={28} />
|
||||
</span>
|
||||
Weekly Progress Overview
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Track your syllabus completion goals, study streaks, and weekly milestones at a glance.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF] bg-[#00F0FF]/10 border border-[#00F0FF]/20 px-3 py-1.5 rounded-full flex items-center gap-1.5">
|
||||
<Zap size={12} /> Live Analytics
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<WeeklyProgressReport />
|
||||
{/* KPI Stats Row */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{STATS.map((stat) => (
|
||||
<Card key={stat.label} className="bg-secondary/20 border-border/60 rounded-2xl">
|
||||
<CardContent className="p-4">
|
||||
<p className="text-xs font-bold uppercase tracking-wider text-muted-foreground mb-1">{stat.label}</p>
|
||||
<p className="text-2xl font-black tracking-tight">{stat.value}</p>
|
||||
<p className={`text-xs font-bold mt-1 ${stat.positive ? "text-emerald-400" : "text-amber-400"}`}>
|
||||
{stat.delta}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main Content Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Weekly Bar Chart */}
|
||||
<div className="lg:col-span-2 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-extrabold tracking-tight flex items-center gap-2">
|
||||
<Calendar size={20} className="text-[#00F0FF]" /> This Week at a Glance
|
||||
</h2>
|
||||
</div>
|
||||
<WeeklyProgressReport />
|
||||
</div>
|
||||
|
||||
{/* Side Panel */}
|
||||
<div className="space-y-6">
|
||||
{/* Syllabus Progress */}
|
||||
<div className="space-y-3">
|
||||
<h2 className="text-xl font-extrabold tracking-tight flex items-center gap-2">
|
||||
<BookOpen size={20} className="text-purple-400" /> Syllabus Progress
|
||||
</h2>
|
||||
<Card className="bg-secondary/10 border-border/60 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-4">
|
||||
{SYLLABUS_PROGRESS.map((item) => (
|
||||
<div key={item.subject} className="space-y-1.5">
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="font-bold">{item.subject}</span>
|
||||
<span className={`font-black ${item.text}`}>{item.percentage}%</span>
|
||||
</div>
|
||||
<div className="h-2 w-full bg-secondary rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full ${item.color} rounded-full transition-all duration-500`}
|
||||
style={{ width: `${item.percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground font-semibold text-right">
|
||||
{item.completed} / {item.total} chapters
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Weekly Goals */}
|
||||
<Card className="bg-gradient-to-br from-[#00F0FF]/10 via-secondary/20 to-background border border-[#00F0FF]/20 rounded-2xl">
|
||||
<CardContent className="p-5 space-y-3">
|
||||
<h3 className="text-sm font-black uppercase tracking-wider text-[#00F0FF]">Weekly Goals</h3>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-start gap-2 p-2 rounded-lg bg-white/5">
|
||||
<CheckCircle2 size={16} className="text-green-400 mt-0.5 shrink-0" />
|
||||
<div>
|
||||
<div className="text-xs font-bold">Complete 200 Questions</div>
|
||||
<div className="text-[10px] text-muted-foreground">Goal Met (214/200)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-2 p-2 rounded-lg bg-white/5 opacity-70">
|
||||
<div className="w-4 h-4 rounded-full border-2 border-muted-foreground mt-0.5 shrink-0" />
|
||||
<div>
|
||||
<div className="text-xs font-bold">Take 1 Full Mock Test</div>
|
||||
<div className="text-[10px] text-muted-foreground">Scheduled for Sunday</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user