Fix UI bugs, admin bulk upload limits, test ingestion bugs, and reset demo users

This commit is contained in:
2026-09-25 14:21:48 +05:30
parent 08e54ac055
commit eefcb12ffc
9 changed files with 5911 additions and 146 deletions

View File

@@ -1,6 +1,7 @@
"use client"
import { fetchWithAuth } from "@/lib/apiClient";
import Link from "next/link";
import { useRef, useState, useEffect } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
@@ -14,6 +15,8 @@ export default function DashboardPage() {
const { user, userId, loading: userLoading, hasAccessTo, trialInfo } = useActiveUser()
const [userStats, setUserStats] = useState<any>(null)
const [loading, setLoading] = useState(true)
const [dpps, setDpps] = useState<any[]>([])
const [cbts, setCbts] = useState<any[]>([])
const [downloading, setDownloading] = useState(false)
const [shareMenuOpen, setShareMenuOpen] = useState(false)
const progressRef = useRef<HTMLDivElement>(null)
@@ -25,20 +28,26 @@ export default function DashboardPage() {
setLoading(false)
return
}
async function fetchStats() {
async function fetchStatsAndTests() {
try {
const res = await fetchWithAuth(`/api/users/${currentUserId}/stats`)
if (res.ok) {
const data = await res.json()
setUserStats(data)
}
const pattern = user?.target_exam || "JEE_Main";
const [statsRes, dppRes, cbtRes] = await Promise.all([
fetchWithAuth(`/api/users/${currentUserId}/stats`),
fetchWithAuth(`/api/tests?type=DPS&exam_pattern=${pattern}`),
fetchWithAuth(`/api/tests?type=Mock&exam_pattern=${pattern}`)
]);
if (statsRes.ok) setUserStats(await statsRes.json());
if (dppRes.ok) setDpps((await dppRes.json()).slice(0, 2));
if (cbtRes.ok) setCbts((await cbtRes.json()).slice(0, 2));
} catch (e) {
console.error("Failed to load user stats", e)
console.error("Failed to load user data", e)
} finally {
setLoading(false)
}
}
fetchStats()
fetchStatsAndTests()
}, [userLoading, user?.id, userId])
const getShareUrl = () => {
@@ -227,61 +236,29 @@ export default function DashboardPage() {
<Button variant="ghost" size="sm" className="text-muted-foreground font-medium">View All</Button>
</div>
<div className="space-y-4">
<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">Physics: Rotational Dynamics</h3>
<p className="text-sm text-muted-foreground mt-0.5">20 Questions • High 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>
{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} />
{dpps.length > 0 ? (
dpps.map((dpp) => (
<Card key={dpp.id} 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">{dpp.title}</h3>
<p className="text-sm text-muted-foreground mt-0.5">{dpp.total_time} Minutes • {dpp.difficulty || "Medium"} Priority</p>
</div>
</div>
<div>
<h3 className="font-medium text-base group-hover:text-primary transition-colors">
{isNeet ? "Biology: Human Physiology" : "Maths: Integral Calculus"}
</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>
<Link href={`/dashboard/dpp`}>
<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>
</Link>
</CardContent>
</Card>
))
) : (
<Card className="relative opacity-60 cursor-not-allowed border-dashed">
<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-muted-foreground">
<Lock size={20} />
</div>
<div>
<h3 className="font-medium text-base text-muted-foreground">
{isNeet ? "Biology: Human Physiology" : "Maths: Integral Calculus"}
</h3>
<p className="text-sm text-muted-foreground mt-0.5 flex items-center gap-1"><Lock size={12}/> Pro Feature</p>
</div>
</div>
<Button variant="outline" size="sm" disabled className="gap-2 rounded-xl">
Locked
</Button>
</CardContent>
</Card>
<p className="text-muted-foreground text-sm py-4">No DPPs scheduled for today.</p>
)}
</div>
</section>
@@ -293,38 +270,33 @@ export default function DashboardPage() {
Upcoming CBTs
</h2>
</div>
<Card className="overflow-hidden">
<div className="p-6 border-b border-border flex items-center justify-between bg-background">
<div>
<div className="flex items-center gap-3 mb-2">
<Badge variant="outline" className="border-primary/20 bg-primary/5 text-primary">Mock Test</Badge>
<span className="text-xs text-muted-foreground font-semibold uppercase tracking-wider">Tomorrow, 10:00 AM</span>
</div>
<h3 className="font-semibold text-lg tracking-tight">{isNeet ? 'NEET Mock Test 4' : 'JEE Mock Test 4'}</h3>
<p className="text-sm text-muted-foreground flex items-center gap-1.5 mt-1.5">
<Clock size={14} /> 180 Minutes • 720 Marks
</p>
</div>
<Button variant="secondary" className="rounded-xl font-medium">Remind Me</Button>
</div>
{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="space-y-4">
{cbts.length > 0 ? (
cbts.map((cbt, idx) => (
<Card key={cbt.id} className="overflow-hidden">
<div className="p-6 border-b border-border flex items-center justify-between bg-background">
<div>
<div className="flex items-center gap-3 mb-2">
<Badge variant="outline" className="border-primary/20 bg-primary/5 text-primary">{cbt.exam_pattern}</Badge>
<span className="text-xs text-muted-foreground font-semibold uppercase tracking-wider">{cbt.scheduled_date ? new Date(cbt.scheduled_date).toLocaleDateString() : 'Available Now'}</span>
</div>
<h3 className="font-semibold text-lg tracking-tight">{cbt.title}</h3>
<p className="text-sm text-muted-foreground flex items-center gap-1.5 mt-1.5">
<Clock size={14} /> {cbt.total_time} Minutes • {cbt.difficulty || 'Medium'}
</p>
</div>
<Link href={`/dashboard/cbt`}>
<Button variant={idx === 0 ? "secondary" : "outline"} className="rounded-xl font-medium">Start</Button>
</Link>
</div>
</Card>
))
) : (
<div className="p-5 bg-secondary/50 flex items-center justify-between transition-colors hover:bg-secondary/70 opacity-75">
<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>
<p className="text-xs text-muted-foreground mt-0.5 font-medium ml-6">Oct 24, 2026</p>
</div>
<Badge variant="secondary" className="text-xs">Pro Only</Badge>
</div>
<Card className="overflow-hidden p-6 border-dashed opacity-70">
<p className="text-muted-foreground text-sm">No upcoming CBTs at the moment.</p>
</Card>
)}
</Card>
</div>
</section>
</div>
@@ -340,3 +312,4 @@ export default function DashboardPage() {
</div>
)
}