feat: complete comprehensive zero-state metrics across all dashboard pages for new accounts
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user