Files
pragativeer-v2/src/app/dashboard/rank-predictor/page.tsx

245 lines
12 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import { Card, CardContent } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Trophy, TrendingUp, AlertTriangle, Sparkles, Building2, Target, Sliders, CheckCircle2, ChevronRight, UserCheck } from "lucide-react"
import { useActiveUser } from "@/hooks/useActiveUser"
export default function RankPredictorPage() {
const { user } = useActiveUser()
const [exam, setExam] = useState<"NEET" | "JEE">("NEET")
const [physics, setPhysics] = useState(135)
const [chemistry, setChemistry] = useState(155)
const [bioOrMath, setBioOrMath] = useState(330) // Bio out of 360 or Math out of 100
const [saved, setSaved] = useState(false)
useEffect(() => {
if (user?.target_exam) {
if (user.target_exam.includes("NEET")) {
setExam("NEET")
setPhysics(140)
setChemistry(150)
setBioOrMath(320)
} else {
setExam("JEE")
setPhysics(65)
setChemistry(70)
setBioOrMath(75)
}
}
}, [user])
const maxTotal = exam === "NEET" ? 720 : 300
const maxPhysics = exam === "NEET" ? 180 : 100
const maxChem = exam === "NEET" ? 180 : 100
const maxThird = exam === "NEET" ? 360 : 100
const totalScore = physics + chemistry + bioOrMath
// Calculate predicted rank based on total score percentage
const calculateRank = (score: number, max: number) => {
const pct = score / max
if (pct >= 0.95) return Math.max(12, Math.round((1 - pct) * 2000))
if (pct >= 0.90) return Math.round(1500 + (0.95 - pct) * 50000)
if (pct >= 0.80) return Math.round(4000 + (0.90 - pct) * 80000)
if (pct >= 0.70) return Math.round(12000 + (0.80 - pct) * 120000)
if (pct >= 0.60) return Math.round(25000 + (0.70 - pct) * 200000)
return Math.round(60000 + (0.60 - pct) * 400000)
}
const predictedRank = calculateRank(totalScore, maxTotal)
const colleges = exam === "NEET" ? [
{ name: "AIIMS New Delhi", category: "Top Tier Medical", minScore: 690, color: "text-[#00F0FF]", border: "border-[#00F0FF]/30", bg: "bg-[#00F0FF]/10" },
{ name: "MAMC New Delhi", category: "Central GMC", minScore: 665, color: "text-amber-400", border: "border-amber-400/30", bg: "bg-amber-400/10" },
{ name: "KGMU Lucknow / VMMCH", category: "Premier State GMC", minScore: 635, color: "text-emerald-400", border: "border-emerald-400/30", bg: "bg-emerald-400/10" },
{ name: "Top State Govt Medical College", category: "State Quota", minScore: 590, color: "text-purple-400", border: "border-purple-400/30", bg: "bg-purple-400/10" },
] : [
{ name: "IIT Bombay / IIT Delhi (CS)", category: "Top 5 IITs", minScore: 260, color: "text-[#00F0FF]", border: "border-[#00F0FF]/30", bg: "bg-[#00F0FF]/10" },
{ name: "IIT Madras / Kharagpur", category: "Core Engineering", minScore: 220, color: "text-amber-400", border: "border-amber-400/30", bg: "bg-amber-400/10" },
{ name: "NIT Trichy / Surathkal", category: "Top NITs", minScore: 180, color: "text-emerald-400", border: "border-emerald-400/30", bg: "bg-emerald-400/10" },
{ name: "Top State Engineering Colleges", category: "State Govt", minScore: 140, color: "text-purple-400", border: "border-purple-400/30", bg: "bg-purple-400/10" },
]
return (
<div className="p-6 md:p-8 space-y-8 animate-in fade-in duration-500 max-w-7xl mx-auto min-h-screen">
{/* Header */}
<div className="text-center max-w-3xl mx-auto space-y-3">
<div className="inline-flex items-center gap-2 px-4 py-1.5 bg-[#00F0FF]/10 text-[#00F0FF] rounded-full border border-[#00F0FF]/30 text-xs font-black tracking-widest uppercase shadow-[0_0_15px_rgba(0,240,255,0.15)]">
<Sparkles size={14} /> AI Neural Prediction Engine
</div>
<h1 className="text-4xl md:text-5xl font-black tracking-tight">AI Rank & College Predictor</h1>
<p className="text-muted-foreground text-base md:text-lg font-medium">
Simulate your subject marks to dynamically calculate your All India Rank (AIR) and college admission chances.
</p>
{user && (
<div className="inline-flex items-center gap-2 px-3 py-1 bg-emerald-500/10 text-emerald-400 border border-emerald-500/30 rounded-xl text-xs font-bold mt-1">
<UserCheck size={14} /> Profile Connected: {user.name} ({user.target_exam?.replace("_", " ")})
</div>
)}
{/* Exam Switcher */}
<div className="inline-flex p-1.5 bg-secondary/40 border border-border rounded-2xl gap-2 mt-4">
<button
onClick={() => { setExam("NEET"); setPhysics(135); setChemistry(155); setBioOrMath(330) }}
className={`px-6 py-2 rounded-xl text-sm font-extrabold transition-all ${
exam === "NEET" ? "bg-[#00F0FF] text-black shadow-[0_0_15px_#00F0FF]" : "text-muted-foreground hover:text-foreground"
}`}
>
NEET (UG) 720 Marks
</button>
<button
onClick={() => { setExam("JEE"); setPhysics(65); setChemistry(70); setBioOrMath(75) }}
className={`px-6 py-2 rounded-xl text-sm font-extrabold transition-all ${
exam === "JEE" ? "bg-[#00F0FF] text-black shadow-[0_0_15px_#00F0FF]" : "text-muted-foreground hover:text-foreground"
}`}
>
JEE (Main) 300 Marks
</button>
</div>
</div>
{/* Main Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Left Interactive Simulator */}
<div className="lg:col-span-2 space-y-6">
<Card className="border-border/60 bg-secondary/10 backdrop-blur-xl rounded-3xl p-6 space-y-6 shadow-xl">
<div className="flex items-center justify-between border-b border-border/40 pb-4">
<h2 className="text-xl font-extrabold flex items-center gap-2">
<Sliders className="text-[#00F0FF]" size={20} /> Mark Simulator
</h2>
<span className="text-xs font-bold text-muted-foreground uppercase tracking-wider">Drag Sliders to Adjust</span>
</div>
{/* Physics Slider */}
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-extrabold">
<span>Physics Score</span>
<span className="text-[#00F0FF] text-base">{physics} / {maxPhysics}</span>
</div>
<input
type="range"
min={0}
max={maxPhysics}
value={physics}
onChange={(e) => setPhysics(Number(e.target.value))}
className="w-full h-2.5 bg-secondary rounded-lg appearance-none cursor-pointer accent-[#00F0FF]"
/>
</div>
{/* Chemistry Slider */}
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-extrabold">
<span>Chemistry Score</span>
<span className="text-amber-400 text-base">{chemistry} / {maxChem}</span>
</div>
<input
type="range"
min={0}
max={maxChem}
value={chemistry}
onChange={(e) => setChemistry(Number(e.target.value))}
className="w-full h-2.5 bg-secondary rounded-lg appearance-none cursor-pointer accent-amber-400"
/>
</div>
{/* Bio / Math Slider */}
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-extrabold">
<span>{exam === "NEET" ? "Biology Score (Botany + Zoology)" : "Mathematics Score"}</span>
<span className="text-emerald-400 text-base">{bioOrMath} / {maxThird}</span>
</div>
<input
type="range"
min={0}
max={maxThird}
value={bioOrMath}
onChange={(e) => setBioOrMath(Number(e.target.value))}
className="w-full h-2.5 bg-secondary rounded-lg appearance-none cursor-pointer accent-emerald-400"
/>
</div>
<div className="p-4 bg-background/50 border border-border/50 rounded-2xl flex items-center justify-between">
<span className="text-sm font-bold">Simulated Total Score</span>
<span className="text-3xl font-black text-foreground">{totalScore} <span className="text-sm text-muted-foreground font-semibold">/ {maxTotal}</span></span>
</div>
</Card>
{/* AI Strategy Insights based on Score */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card className="p-5 bg-emerald-500/10 border-emerald-500/30 rounded-2xl flex items-start gap-3">
<TrendingUp className="text-emerald-400 shrink-0 mt-0.5" size={22} />
<div>
<h4 className="font-extrabold text-emerald-400">Strongest Domain</h4>
<p className="text-xs text-muted-foreground font-medium mt-1">
Your Biology/Math score ({bioOrMath}) provides solid rank leverage. Keep maintaining your revision momentum.
</p>
</div>
</Card>
<Card className="p-5 bg-amber-500/10 border-amber-500/30 rounded-2xl flex items-start gap-3">
<AlertTriangle className="text-amber-400 shrink-0 mt-0.5" size={22} />
<div>
<h4 className="font-extrabold text-amber-400">High-Yield Growth Zone</h4>
<p className="text-xs text-muted-foreground font-medium mt-1">
Increasing Physics by just 25 marks will boost your rank by approximately ~4,800 positions.
</p>
</div>
</Card>
</div>
</div>
{/* Right Output Dashboard */}
<div className="space-y-6">
{/* AIR Display Card */}
<Card className="border-2 border-[#00F0FF] bg-gradient-to-br from-[#00F0FF]/15 via-secondary/30 to-background rounded-3xl p-6 text-center shadow-[0_0_30px_rgba(0,240,255,0.15)] relative overflow-hidden">
<div className="absolute top-0 right-0 p-4 opacity-10">
<Trophy size={120} className="text-[#00F0FF]" />
</div>
<div className="text-xs font-black uppercase tracking-widest text-[#00F0FF] mb-2">Estimated All India Rank</div>
<div className="text-5xl md:text-6xl font-black tracking-tighter text-foreground my-3 filter drop-shadow-md">
AIR ~{predictedRank.toLocaleString()}
</div>
<div className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-[#00F0FF]/20 text-[#00F0FF] text-xs font-bold border border-[#00F0FF]/40">
<CheckCircle2 size={13} /> High Accuracy Confidence
</div>
</Card>
{/* College Admission Probability Table */}
<Card className="border-border/60 bg-secondary/10 backdrop-blur-xl rounded-3xl p-6 space-y-4">
<h3 className="text-lg font-extrabold flex items-center gap-2">
<Building2 className="text-[#00F0FF]" size={20} /> College Admission Chances
</h3>
<div className="space-y-3">
{colleges.map((c) => {
const isLikely = totalScore >= c.minScore
const chancePct = Math.min(99, Math.max(10, Math.round((totalScore / c.minScore) * 85)))
return (
<div key={c.name} className={`p-3.5 rounded-2xl border ${c.border} ${c.bg} space-y-1.5`}>
<div className="flex justify-between items-center">
<span className="font-extrabold text-sm text-foreground">{c.name}</span>
<span className={`text-xs font-black ${isLikely ? "text-green-400" : "text-amber-400"}`}>
{isLikely ? `${chancePct}% Likely` : "Reach Target"}
</span>
</div>
<div className="flex justify-between text-xs text-muted-foreground font-medium">
<span>{c.category}</span>
<span>Cutoff Score: {c.minScore}+</span>
</div>
</div>
)
})}
</div>
</Card>
</div>
</div>
</div>
)
}