245 lines
12 KiB
TypeScript
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>
|
|
)
|
|
}
|