Files
pragativeer-v2/src/app/dashboard/ai-coach/cbt-dpp/[id]/page.tsx

290 lines
13 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { BrainCircuit, Clock, CheckCircle2, AlertTriangle, ArrowLeft, ArrowRight, ShieldAlert, Sparkles, Send } from "lucide-react"
import Link from "next/link"
import { useActiveUser } from "@/hooks/useActiveUser"
import { useRouter } from "next/navigation"
export default function AIComCBTDPPPage() {
const { user, hasAccessTo, loading } = useActiveUser()
const router = useRouter()
const [activeQuestion, setActiveQuestion] = useState(0)
const [selectedAnswers, setSelectedAnswers] = useState<Record<number, string>>({})
const [timeLeft, setTimeLeft] = useState(1800) // 30 minutes
const [submitted, setSubmitted] = useState(false)
// Mock AI CBT DPP questions
const sampleQuestions = [
{
id: 1,
subject: "Physics",
topic: "Rotational Dynamics & Torque",
question: "A uniform disc of mass M and radius R rotates about an axis passing through its center and perpendicular to its plane. Its moment of inertia about a tangent parallel to its plane is:",
options: ["(1/2) M R²", "(5/4) M R²", "(3/2) M R²", "(7/4) M R²"],
correct: 1,
explanation: "Using parallel axis theorem: I_tangent = I_cm + M R^2 = (1/4 M R^2) + M R^2 = 5/4 M R^2."
},
{
id: 2,
subject: "Chemistry",
topic: "Chemical Equilibrium & Kp/Kc",
question: "For the reaction N2(g) + 3H2(g) ⇌ 2NH3(g), the value of Kp / Kc at temperature T Kelvin is given by:",
options: ["(RT)⁻²", "(RT)⁻¹", "(RT)", "(RT)²"],
correct: 0,
explanation: "Δn_g = 2 - (1 + 3) = -2. Therefore, Kp = Kc (RT)^(-2), so Kp / Kc = (RT)^(-2)."
},
{
id: 3,
subject: "Biology / Maths",
topic: "Calculus / Cell Biology",
question: "Which organelle is responsible for the synthesis of lipids and steroidal hormones in eukaryotic cells?",
options: ["Rough Endoplasmic Reticulum", "Smooth Endoplasmic Reticulum", "Golgi Apparatus", "Lysosome"],
correct: 1,
explanation: "Smooth Endoplasmic Reticulum (SER) is the primary site for synthesis of lipids and steroid hormones."
},
{
id: 4,
subject: "Physics",
topic: "Electrostatics & Potential",
question: "Two point charges +q and -q are placed at distance 2a. The electric potential at the midpoint of the line joining them is:",
options: ["Zero", "q / (4πε₀a)", "2q / (4πε₀a)", "Infinity"],
correct: 0,
explanation: "V_total = V_+q + V_-q = (q / 4πε₀a) + (-q / 4πε₀a) = 0."
},
{
id: 5,
subject: "Chemistry",
topic: "Organic Mechanism & Nucleophiles",
question: "Which of the following undergoes SN1 reaction at the fastest rate?",
options: ["Methyl chloride", "Ethyl chloride", "Isopropyl chloride", "Tert-butyl chloride"],
correct: 3,
explanation: "SN1 rate depends on carbocation stability. Tert-butyl carbocation (3°) is the most stable."
}
]
useEffect(() => {
if (submitted || timeLeft <= 0) return
const timer = setInterval(() => {
setTimeLeft(prev => Math.max(0, prev - 1))
}, 1000)
return () => clearInterval(timer)
}, [submitted, timeLeft])
const formatTime = (secs: number) => {
const m = Math.floor(secs / 60)
const s = secs % 60
return `${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`
}
const handleOptionSelect = (qIdx: number, optIdx: number) => {
if (submitted) return
setSelectedAnswers(prev => ({ ...prev, [qIdx]: String.fromCharCode(65 + optIdx) }))
}
const calculateScore = () => {
let score = 0
sampleQuestions.forEach((q, idx) => {
const selected = selectedAnswers[idx]
if (selected) {
const selectedOptIdx = selected.charCodeAt(0) - 65
if (selectedOptIdx === q.correct) score += 4
else score -= 1
}
})
return score
}
if (loading) {
return <div className="p-8 text-center text-muted-foreground">Loading AI Coach CBT Engine...</div>
}
return (
<div className="p-6 md:p-8 space-y-6 max-w-6xl mx-auto min-h-screen animate-in fade-in duration-500">
{/* Top Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-secondary/20 border border-border p-6 rounded-3xl backdrop-blur-xl">
<div className="flex items-center gap-4">
<Link href="/dashboard/dpp">
<Button variant="outline" size="icon" className="rounded-xl border-border hover:bg-secondary">
<ArrowLeft size={18} />
</Button>
</Link>
<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">
PrepPilot AI
</span>
<span className="text-xs font-bold text-muted-foreground">• {user?.target_exam?.replace("_", " ") || "JEE/NEET"}</span>
</div>
<h1 className="text-2xl font-black tracking-tight">Interactive Target DPP #14</h1>
</div>
</div>
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 px-4 py-2 bg-background border border-border rounded-2xl font-mono text-lg font-bold text-[#00F0FF] shadow-inner">
<Clock size={18} className="text-[#00F0FF] animate-pulse" />
{formatTime(timeLeft)}
</div>
{!submitted ? (
<Button
onClick={() => setSubmitted(true)}
className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-bold px-6 rounded-xl shadow-[0_0_15px_rgba(0,240,255,0.2)]"
>
Submit Test <Send size={16} className="ml-2" />
</Button>
) : (
<Button
onClick={() => { setSubmitted(false); setSelectedAnswers({}); setTimeLeft(1800); setActiveQuestion(0) }}
variant="outline"
className="font-bold rounded-xl border-border"
>
Retake CBT DPP
</Button>
)}
</div>
</div>
{submitted && (
<Card className="border-emerald-500/30 bg-emerald-500/10 p-6 rounded-3xl space-y-4 animate-in zoom-in-95">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<CheckCircle2 size={32} className="text-emerald-400" />
<div>
<h3 className="text-xl font-black text-emerald-400">CBT DPP Completed!</h3>
<p className="text-xs text-muted-foreground">Your performance analysis has been evaluated by the AI Evaluator.</p>
</div>
</div>
<div className="text-right">
<span className="text-3xl font-black text-emerald-400">{calculateScore()} / 20</span>
<p className="text-xs text-muted-foreground font-bold">Total Marks</p>
</div>
</div>
</Card>
)}
{/* Main CBT Grid */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Question Area */}
<div className="lg:col-span-3">
<Card className="border-border bg-background/80 backdrop-blur-xl p-6 rounded-3xl shadow-xl space-y-6">
<div className="flex justify-between items-center border-b border-border pb-4">
<span className="text-sm font-bold text-[#00F0FF] uppercase tracking-wider">
Question {activeQuestion + 1} of {sampleQuestions.length}
</span>
<span className="text-xs font-bold bg-secondary px-3 py-1 rounded-full text-muted-foreground">
{sampleQuestions[activeQuestion].topic}
</span>
</div>
<div className="space-y-4">
<p className="text-xl md:text-2xl font-black leading-relaxed text-foreground">
{sampleQuestions[activeQuestion].question}
</p>
<div className="space-y-3 pt-2">
{sampleQuestions[activeQuestion].options.map((opt, optIdx) => {
const letter = String.fromCharCode(65 + optIdx)
const isSelected = selectedAnswers[activeQuestion] === letter
const isCorrect = sampleQuestions[activeQuestion].correct === optIdx
let btnStyle = "border-border bg-secondary/20 hover:border-primary/50 text-foreground"
if (isSelected) {
btnStyle = "border-[#00F0FF] bg-[#00F0FF]/15 text-[#00F0FF] font-bold shadow-[0_0_12px_rgba(0,240,255,0.15)]"
}
if (submitted) {
if (isCorrect) btnStyle = "border-emerald-500 bg-emerald-500/20 text-emerald-400 font-bold"
else if (isSelected && !isCorrect) btnStyle = "border-red-500 bg-red-500/20 text-red-400 font-bold"
}
return (
<div
key={optIdx}
onClick={() => handleOptionSelect(activeQuestion, optIdx)}
className={`flex items-center gap-4 p-4.5 rounded-2xl border cursor-pointer transition-all ${btnStyle}`}
>
<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-lg md:text-xl font-bold flex-1">{opt}</span>
{submitted && isCorrect && <CheckCircle2 size={22} className="text-emerald-400" />}
</div>
)
})}
</div>
{submitted && (
<div className="mt-6 p-4 rounded-2xl bg-[#00F0FF]/10 border border-[#00F0FF]/30 text-sm text-[#00F0FF] space-y-1 animate-in fade-in">
<span className="font-extrabold uppercase text-xs tracking-wider block">AI Solution & Explanation:</span>
<p>{sampleQuestions[activeQuestion].explanation}</p>
</div>
)}
</div>
{/* Navigation buttons */}
<div className="flex justify-between items-center pt-4 border-t border-border">
<Button
variant="outline"
disabled={activeQuestion === 0}
onClick={() => setActiveQuestion(prev => Math.max(0, prev - 1))}
className="rounded-xl font-bold border-border"
>
<ArrowLeft size={16} className="mr-2" /> Previous
</Button>
<Button
disabled={activeQuestion === sampleQuestions.length - 1}
onClick={() => setActiveQuestion(prev => Math.min(sampleQuestions.length - 1, prev + 1))}
className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-bold rounded-xl"
>
Next Question <ArrowRight size={16} className="ml-2" />
</Button>
</div>
</Card>
</div>
{/* Question Palette Sidebar */}
<div className="space-y-4">
<Card className="border-border bg-background/80 backdrop-blur-xl p-5 rounded-3xl shadow-xl space-y-4">
<h3 className="text-sm font-bold uppercase tracking-wider text-muted-foreground">Question Palette</h3>
<div className="grid grid-cols-5 gap-2">
{sampleQuestions.map((q, idx) => {
const isAns = !!selectedAnswers[idx]
const isCurr = activeQuestion === idx
return (
<button
key={q.id}
onClick={() => setActiveQuestion(idx)}
className={`h-10 rounded-xl text-xs font-extrabold transition-all border ${
isCurr
? "border-[#00F0FF] bg-[#00F0FF] text-black ring-2 ring-[#00F0FF]/50"
: isAns
? "bg-[#00F0FF]/20 border-[#00F0FF]/40 text-[#00F0FF]"
: "bg-secondary/40 border-border text-muted-foreground hover:border-primary"
}`}
>
{idx + 1}
</button>
)
})}
</div>
<div className="pt-4 border-t border-border space-y-2 text-xs font-semibold text-muted-foreground">
<div className="flex items-center gap-2">
<span className="w-3 h-3 rounded-md bg-[#00F0FF]" /> Current Question
</div>
<div className="flex items-center gap-2">
<span className="w-3 h-3 rounded-md bg-[#00F0FF]/20 border border-[#00F0FF]/40" /> Answered
</div>
<div className="flex items-center gap-2">
<span className="w-3 h-3 rounded-md bg-secondary/40 border border-border" /> Unattempted
</div>
</div>
</Card>
</div>
</div>
</div>
)
}