UI: Fix streak modal, light mode contrast, state datalist, and plan mapping

This commit is contained in:
2026-07-07 14:41:04 +05:30
parent 22549edcdb
commit 8536196ac0
5 changed files with 102 additions and 32 deletions

View File

@@ -32,15 +32,15 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
return () => document.removeEventListener("mousedown", handleClickOutside) return () => document.removeEventListener("mousedown", handleClickOutside)
}, []) }, [])
const userInitials = user ? user.name.split(" ").map(n => n[0]).join("").toUpperCase() : "DS" const userInitials = user ? user.name.split(" ").filter(n => /^[a-zA-Z]/.test(n)).slice(0, 2).map(n => n[0]).join("").toUpperCase() : "DS"
const targetExamLabel = user?.target_exam === "JEE_Main" ? "JEE Main" : user?.target_exam === "JEE_Advanced" ? "JEE Advanced" : user?.target_exam === "NEET" ? "NEET" : "NEET/JEE" const targetExamLabel = user?.target_exam === "JEE_Main" ? "JEE Main" : user?.target_exam === "JEE_Advanced" ? "JEE Advanced" : user?.target_exam === "NEET" ? "NEET" : "NEET/JEE"
return ( return (
<div className="flex h-screen bg-background overflow-hidden text-foreground selection:bg-primary/20"> <div className="flex h-screen bg-background overflow-hidden text-foreground selection:bg-primary/20">
{/* Sidebar */} {/* Sidebar */}
<aside className="w-64 border-r border-border bg-background flex flex-col hidden md:flex"> <aside className="w-64 border-r border-border bg-background flex flex-col hidden md:flex">
<div className="p-6"> <div className="px-5 py-4">
<Link href="/dashboard" className="block relative h-16 w-full hover:opacity-90 transition-opacity"> <Link href="/dashboard" className="block relative h-10 w-full hover:opacity-90 transition-opacity">
<div className="absolute inset-0 dark:hidden"> <div className="absolute inset-0 dark:hidden">
<Image <Image
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg" src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
@@ -88,21 +88,21 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
icon={<LineChart size={18} />} icon={<LineChart size={18} />}
label="Performance Analytics" label="Performance Analytics"
active={pathname.startsWith("/dashboard/analytics")} active={pathname.startsWith("/dashboard/analytics")}
isLocked={!hasAccessTo("ai-mistake-tracking")} isLocked={!hasAccessTo("detailed-performance-analytics")}
/> />
<NavItem <NavItem
href="/dashboard/rank-predictor" href="/dashboard/rank-predictor"
icon={<Trophy size={18} />} icon={<Trophy size={18} />}
label="Rank Predictor" label="Rank Predictor"
active={pathname.startsWith("/dashboard/rank-predictor")} active={pathname.startsWith("/dashboard/rank-predictor")}
isLocked={!hasAccessTo("ai-mistake-tracking")} isLocked={!hasAccessTo("college-predictor")}
/> />
<NavItem <NavItem
href="/dashboard/ai-coach" href="/dashboard/ai-coach"
icon={<BrainCircuitIcon />} icon={<BrainCircuitIcon />}
label="AI Coach" label="AI Coach"
active={pathname.startsWith("/dashboard/ai-coach")} active={pathname.startsWith("/dashboard/ai-coach")}
isLocked={!hasAccessTo("ai-mistake-tracking")} isLocked={!hasAccessTo("ai-tutor-chat")}
/> />
</nav> </nav>

View File

@@ -8,8 +8,10 @@ import { Activity, BrainCircuit, ArrowRight, Clock, Target, CheckCircle2, Trendi
import * as htmlToImage from 'html-to-image' import * as htmlToImage from 'html-to-image'
import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap" import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap"
import { AdaptiveStudyPlan } from "@/components/AI/AdaptiveStudyPlan" import { AdaptiveStudyPlan } from "@/components/AI/AdaptiveStudyPlan"
import { useActiveUser } from "@/hooks/useActiveUser"
export default function DashboardPage() { export default function DashboardPage() {
const { user, hasAccessTo } = useActiveUser()
const progressRef = useRef<HTMLDivElement>(null) const progressRef = useRef<HTMLDivElement>(null)
const handleExport = async () => { const handleExport = async () => {
@@ -29,7 +31,7 @@ export default function DashboardPage() {
return ( return (
<div className="p-8 max-w-6xl mx-auto space-y-10 animate-in fade-in duration-500 slide-in-from-bottom-4"> <div className="p-8 max-w-6xl mx-auto space-y-10 animate-in fade-in duration-500 slide-in-from-bottom-4">
<header className="flex justify-end mb-2"> <header className="flex justify-end mb-2">
<Button size="lg" className="gap-2 shadow-sm bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 font-bold"> <Button size="lg" className="gap-2 shadow-sm bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-bold">
<BrainCircuit size={18} /> <BrainCircuit size={18} />
Generate AI Plan Generate AI Plan
</Button> </Button>
@@ -133,6 +135,24 @@ export default function DashboardPage() {
</CardContent> </CardContent>
</Card> </Card>
{hasAccessTo("topic-wise-microtests-unlimited") ? (
<Card className="hover:border-primary/30 hover:shadow-md cursor-pointer transition-all duration-300 group">
<CardContent className="p-5 flex items-center justify-between">
<div className="flex gap-4 items-center">
<div className="p-3 bg-secondary rounded-xl text-foreground">
<BrainCircuit size={20} />
</div>
<div>
<h3 className="font-medium text-base group-hover:text-primary transition-colors">Biology: Human Physiology</h3>
<p className="text-sm text-muted-foreground mt-0.5">30 Questions • Medium Priority</p>
</div>
</div>
<Button variant="outline" size="sm" className="gap-2 rounded-xl group-hover:bg-primary group-hover:text-primary-foreground group-hover:border-primary transition-all">
Start <ArrowRight size={14} />
</Button>
</CardContent>
</Card>
) : (
<Card className="relative opacity-60 cursor-not-allowed border-dashed"> <Card className="relative opacity-60 cursor-not-allowed border-dashed">
<CardContent className="p-5 flex items-center justify-between"> <CardContent className="p-5 flex items-center justify-between">
<div className="flex gap-4 items-center"> <div className="flex gap-4 items-center">
@@ -149,6 +169,7 @@ export default function DashboardPage() {
</Button> </Button>
</CardContent> </CardContent>
</Card> </Card>
)}
</div> </div>
</section> </section>
@@ -171,13 +192,23 @@ export default function DashboardPage() {
</div> </div>
<Button variant="secondary" className="rounded-xl font-medium">Remind Me</Button> <Button variant="secondary" className="rounded-xl font-medium">Remind Me</Button>
</div> </div>
<div className="p-5 bg-secondary/50 flex items-center justify-between transition-colors hover:bg-secondary/70"> {hasAccessTo("weekly-test-series") ? (
<div className="p-5 bg-secondary/50 flex items-center justify-between transition-colors hover:bg-secondary/70 cursor-pointer group">
<div>
<h3 className="font-medium text-sm text-foreground flex items-center gap-2"><Activity size={14} className="text-primary group-hover:animate-pulse"/> Part Test 3: Mechanics</h3>
<p className="text-xs text-muted-foreground mt-0.5 font-medium ml-6">Oct 24, 2026</p>
</div>
<Button variant="outline" size="sm" className="h-7 text-xs rounded-lg group-hover:bg-primary group-hover:text-primary-foreground group-hover:border-primary">Start <ArrowRight size={12} className="ml-1" /></Button>
</div>
) : (
<div className="p-5 bg-secondary/50 flex items-center justify-between transition-colors hover:bg-secondary/70 opacity-75">
<div> <div>
<h3 className="font-medium text-sm text-foreground flex items-center gap-2"><Lock size={14} className="text-muted-foreground"/> Part Test 3: Mechanics</h3> <h3 className="font-medium text-sm text-foreground flex items-center gap-2"><Lock size={14} className="text-muted-foreground"/> Part Test 3: Mechanics</h3>
<p className="text-xs text-muted-foreground mt-0.5 font-medium ml-6">Oct 24, 2026</p> <p className="text-xs text-muted-foreground mt-0.5 font-medium ml-6">Oct 24, 2026</p>
</div> </div>
<Badge variant="secondary" className="text-xs">Pro Only</Badge> <Badge variant="secondary" className="text-xs">Pro Only</Badge>
</div> </div>
)}
</Card> </Card>
</section> </section>
</div> </div>

View File

@@ -134,7 +134,7 @@ export default function SettingsPage() {
className="hidden" className="hidden"
disabled={uploading} disabled={uploading}
/> />
<Button type="button" variant="outline" className="w-full gap-2 rounded-xl border-dashed" asChild> <Button type="button" variant="outline" className="w-full gap-2 rounded-xl border-dashed">
<span> <span>
<Upload size={16} /> {avatarUrl ? "Change Photo" : "Upload Photo"} <Upload size={16} /> {avatarUrl ? "Change Photo" : "Upload Photo"}
</span> </span>
@@ -182,14 +182,53 @@ export default function SettingsPage() {
/> />
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-bold">State</label> <label className="text-sm font-bold">State / Union Territory</label>
<input <input
type="text" type="text"
value={state} value={state}
placeholder="Enter your state (e.g. Rajasthan, Delhi)" list="indian-states"
placeholder="Enter or select your state"
onChange={(e) => setState(e.target.value)} onChange={(e) => setState(e.target.value)}
className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#00F0FF]" className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#00F0FF]"
/> />
<datalist id="indian-states">
<option value="Andhra Pradesh" />
<option value="Arunachal Pradesh" />
<option value="Assam" />
<option value="Bihar" />
<option value="Chhattisgarh" />
<option value="Goa" />
<option value="Gujarat" />
<option value="Haryana" />
<option value="Himachal Pradesh" />
<option value="Jharkhand" />
<option value="Karnataka" />
<option value="Kerala" />
<option value="Madhya Pradesh" />
<option value="Maharashtra" />
<option value="Manipur" />
<option value="Meghalaya" />
<option value="Mizoram" />
<option value="Nagaland" />
<option value="Odisha" />
<option value="Punjab" />
<option value="Rajasthan" />
<option value="Sikkim" />
<option value="Tamil Nadu" />
<option value="Telangana" />
<option value="Tripura" />
<option value="Uttar Pradesh" />
<option value="Uttarakhand" />
<option value="West Bengal" />
<option value="Andaman and Nicobar Islands" />
<option value="Chandigarh" />
<option value="Dadra and Nagar Haveli and Daman and Diu" />
<option value="Delhi" />
<option value="Jammu and Kashmir" />
<option value="Ladakh" />
<option value="Lakshadweep" />
<option value="Puducherry" />
</datalist>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-bold">Email Address</label> <label className="text-sm font-bold">Email Address</label>

View File

@@ -81,7 +81,7 @@ export function StreakOnboardingModal() {
<div className="pt-4"> <div className="pt-4">
<Button <Button
onClick={handleEnter} onClick={handleEnter}
className="w-full size-12 rounded-xl text-base font-black bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 shadow-[0_0_20px_-3px_#00F0FF] hover:shadow-[0_0_30px_#00F0FF] transition-all duration-300" className="w-full h-14 rounded-xl text-lg font-black bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 shadow-[0_0_20px_-3px_#00F0FF] hover:shadow-[0_0_30px_#00F0FF] hover:-translate-y-1 transition-all duration-300"
> >
Enter Workspace Enter Workspace
</Button> </Button>

View File

@@ -8,7 +8,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
} }
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => { ({ className, variant = "default", size = "default", asChild, ...props }, ref) => {
return ( return (
<button <button
ref={ref} ref={ref}