feat: complete comprehensive zero-state metrics across all dashboard pages for new accounts

This commit is contained in:
2026-09-13 22:17:40 +05:30
parent d9bd142e6a
commit afab06d33c
22 changed files with 771 additions and 299 deletions

View File

@@ -4,31 +4,40 @@ 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"
import { useActiveUser, isDemoUser } from "@/hooks/useActiveUser"
export default function RankPredictorPage() {
const { user } = useActiveUser()
const isDemo = isDemoUser(user?.id)
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 [physics, setPhysics] = useState(0)
const [chemistry, setChemistry] = useState(0)
const [bioOrMath, setBioOrMath] = useState(0)
const [saved, setSaved] = useState(false)
const [initialized, setInitialized] = useState(false)
useEffect(() => {
if (user?.target_exam) {
if (user.target_exam.includes("NEET")) {
setExam("NEET")
if (!user || initialized) return
const isNeet = user.target_exam ? user.target_exam.includes("NEET") : true
setExam(isNeet ? "NEET" : "JEE")
if (isDemo) {
if (isNeet) {
setPhysics(140)
setChemistry(150)
setBioOrMath(320)
} else {
setExam("JEE")
setPhysics(65)
setChemistry(70)
setBioOrMath(75)
}
} else {
setPhysics(0)
setChemistry(0)
setBioOrMath(0)
}
}, [user])
setInitialized(true)
}, [user, isDemo, initialized])
const maxTotal = exam === "NEET" ? 720 : 300
const maxPhysics = exam === "NEET" ? 180 : 100
@@ -83,7 +92,18 @@ export default function RankPredictorPage() {
{/* 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) }}
onClick={() => {
setExam("NEET")
if (isDemo) {
setPhysics(135)
setChemistry(155)
setBioOrMath(330)
} else {
setPhysics(0)
setChemistry(0)
setBioOrMath(0)
}
}}
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"
}`}
@@ -91,7 +111,18 @@ export default function RankPredictorPage() {
NEET (UG) 720 Marks
</button>
<button
onClick={() => { setExam("JEE"); setPhysics(65); setChemistry(70); setBioOrMath(75) }}
onClick={() => {
setExam("JEE")
if (isDemo) {
setPhysics(65)
setChemistry(70)
setBioOrMath(75)
} else {
setPhysics(0)
setChemistry(0)
setBioOrMath(0)
}
}}
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"
}`}
@@ -175,7 +206,9 @@ export default function RankPredictorPage() {
<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.
{totalScore === 0
? "Baseline Calibrating: Solve your first DPP or CBT to benchmark your subject strengths."
: `Your Biology/Math score (${bioOrMath}) provides solid rank leverage. Keep maintaining your revision momentum.`}
</p>
</div>
</Card>
@@ -185,7 +218,9 @@ export default function RankPredictorPage() {
<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.
{totalScore === 0
? "Zero Baseline: Adjust the sliders above or take practice tests to see rank impact in real time."
: "Increasing Physics by just 25 marks will boost your rank by approximately ~4,800 positions."}
</p>
</div>
</Card>
@@ -202,10 +237,10 @@ export default function RankPredictorPage() {
</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()}
{totalScore === 0 ? "AIR --" : `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
<CheckCircle2 size={13} /> {totalScore === 0 ? "Calibrating · Adjust Sliders" : "High Accuracy Confidence"}
</div>
</Card>
@@ -215,26 +250,33 @@ export default function RankPredictorPage() {
<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>
{totalScore === 0 ? (
<div className="p-4 rounded-2xl bg-secondary/20 border border-dashed border-border text-center text-xs text-muted-foreground space-y-1">
<p className="font-bold text-foreground">No Marks Simulated</p>
<p>Drag the subject sliders on the left or complete mock tests to view college probability predictions.</p>
</div>
) : (
<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 className="flex justify-between text-xs text-muted-foreground font-medium">
<span>{c.category}</span>
<span>Cutoff Score: {c.minScore}+</span>
</div>
</div>
)
})}
</div>
)
})}
</div>
)}
</Card>
</div>