fix(dashboard): DPP tags properly dynamic based on user target exam
This commit is contained in:
@@ -83,7 +83,7 @@ export default function AnalyticsPage() {
|
||||
<Tooltip
|
||||
cursor={{fill: 'transparent'}}
|
||||
contentStyle={{ backgroundColor: '#1f2937', borderColor: '#374151', borderRadius: '8px', color: '#fff' }}
|
||||
formatter={(value: number) => [`${value}% Accuracy`, 'Accuracy']}
|
||||
formatter={(value: any) => [`${value}% Accuracy`, 'Accuracy']}
|
||||
/>
|
||||
<Bar dataKey="accuracy" radius={[0, 4, 4, 0]} barSize={12}>
|
||||
{heatmapData.map((entry, index) => (
|
||||
|
||||
@@ -123,7 +123,7 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
|
||||
{idx + 1}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium text-lg leading-relaxed">{q.text}</h3>
|
||||
<h3 className="font-medium text-lg leading-relaxed">{q.question_text || q.text_en || q.text}</h3>
|
||||
<div className="flex gap-2 mt-2">
|
||||
<Badge variant="outline" className="text-xs">{q.topic}</Badge>
|
||||
<Badge variant="outline" className="text-xs">{q.difficulty}</Badge>
|
||||
@@ -141,13 +141,19 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-bold text-muted-foreground uppercase">Your Answer</p>
|
||||
<div className={`p-3 rounded-lg border ${ans.is_correct ? 'bg-green-500/10 border-green-500/30 text-green-500' : 'bg-red-500/10 border-red-500/30 text-red-500'}`}>
|
||||
{q.options[ans.selected_answer] ? `${ans.selected_answer}) ${q.options[ans.selected_answer]}` : 'Not Attempted'}
|
||||
{ans.is_subjective || q.type === 'Subjective' || q.type === 'Numerical'
|
||||
? (ans.selected_answer || 'Not Attempted')
|
||||
: (q.options && q.options[ans.selected_answer] ? `${ans.selected_answer}) ${q.options[ans.selected_answer]}` : ans.selected_answer || 'Not Attempted')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-bold text-muted-foreground uppercase">Correct Answer</p>
|
||||
<div className="p-3 rounded-lg border bg-green-500/10 border-green-500/30 text-green-500">
|
||||
{q.correct_answer?.correct}) {q.options[q.correct_answer?.correct]}
|
||||
{ans.is_subjective || q.type === 'Subjective' || q.type === 'Numerical'
|
||||
? (q.correct_answer?.value || q.correct_answer?.correct || 'Subjective text')
|
||||
: (q.options && q.options[q.correct_answer?.correct || q.correct_answer?.value]
|
||||
? `${q.correct_answer?.correct || q.correct_answer?.value}) ${q.options[q.correct_answer?.correct || q.correct_answer?.value]}`
|
||||
: (q.correct_answer?.correct || q.correct_answer?.value || 'N/A'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function CBTPage() {
|
||||
if (!userRes.ok) throw new Error("Failed to load user target exam");
|
||||
const userData = await userRes.json();
|
||||
const pattern = userData.target_exam;
|
||||
setTargetExam(pattern === "NEET" ? "NEET" : "JEE Main");
|
||||
setTargetExam(pattern === "NEET" ? "NEET" : pattern === "JEE_Advanced" ? "JEE Advanced" : "JEE Main");
|
||||
|
||||
// 2. Fetch tests filtered by exam
|
||||
const testRes = await fetch(`/api/tests?exam_pattern=${pattern}&user_id=${userId}`);
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import { useState } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"
|
||||
import { MessageSquare, ThumbsUp, ChevronUp, Search, Image as ImageIcon, CheckCircle } from "lucide-react"
|
||||
import { MessageSquare, ThumbsUp, ChevronUp, Search, Image as ImageIcon, CheckCircle, Lock } from "lucide-react"
|
||||
import { useActiveUser } from "@/hooks/useActiveUser"
|
||||
|
||||
interface Doubt {
|
||||
id: string
|
||||
@@ -20,6 +21,7 @@ interface Doubt {
|
||||
}
|
||||
|
||||
export default function CommunityPage() {
|
||||
const { hasAccessTo } = useActiveUser()
|
||||
const [activeFilter, setActiveFilter] = useState<'all' | 'my-doubts' | 'solved' | 'unsolved'>('all')
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
|
||||
@@ -87,9 +89,16 @@ export default function CommunityPage() {
|
||||
<p className="text-muted-foreground mt-2 font-medium">Ask questions, share knowledge, and learn together with the community.</p>
|
||||
</div>
|
||||
|
||||
<button className="px-5 py-2.5 bg-[#00F0FF] text-black font-bold rounded-xl shadow-[0_0_15px_-3px_rgba(0,240,255,0.4)] hover:bg-[#00d0dd] transition-colors">
|
||||
Ask a Doubt
|
||||
</button>
|
||||
{hasAccessTo("ask-doubts-from-tutors") ? (
|
||||
<button className="px-5 py-2.5 bg-[#00F0FF] text-black font-bold rounded-xl shadow-[0_0_15px_-3px_rgba(0,240,255,0.4)] hover:bg-[#00d0dd] transition-colors">
|
||||
Ask a Doubt
|
||||
</button>
|
||||
) : (
|
||||
<button disabled className="px-5 py-2.5 bg-secondary text-muted-foreground font-bold rounded-xl flex items-center gap-2 cursor-not-allowed">
|
||||
<Lock size={16} />
|
||||
Pro Feature
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
|
||||
@@ -6,15 +6,21 @@ import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock } from "lucide
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
import { useActiveUser } from "@/hooks/useActiveUser"
|
||||
|
||||
export default function DPPPage() {
|
||||
const { user } = useActiveUser()
|
||||
const [dpps, setDpps] = useState<any[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchDpps() {
|
||||
if (!user) return; // Wait for user to be available
|
||||
|
||||
try {
|
||||
const res = await fetch("http://localhost:8000/api/tests?type=DPS")
|
||||
const pattern = user.target_exam || "JEE_Main";
|
||||
// Also fetch from the correct Next.js proxied route instead of localhost:8000
|
||||
const res = await fetch(`/api/tests?type=DPS&exam_pattern=${pattern}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setDpps(data)
|
||||
@@ -26,7 +32,7 @@ export default function DPPPage() {
|
||||
}
|
||||
}
|
||||
fetchDpps()
|
||||
}, [])
|
||||
}, [user])
|
||||
|
||||
const getDifficultyColor = (diff: string) => {
|
||||
switch(diff) {
|
||||
@@ -80,7 +86,7 @@ export default function DPPPage() {
|
||||
Object.values(dpp.sections).forEach((s: any) => { count += (s.questions?.length || 0) });
|
||||
}
|
||||
// Temporary mock for status
|
||||
const status = "Pending"
|
||||
let status: string = "Pending"
|
||||
|
||||
return (
|
||||
<Card key={dpp.id} className={`group cursor-pointer transition-all hover:shadow-md ${status === 'Completed' ? 'opacity-70 hover:opacity-100 bg-secondary/10' : 'hover:border-[#00F0FF]/50 bg-background'}`}>
|
||||
@@ -91,7 +97,9 @@ export default function DPPPage() {
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF]">{dpp.exam_pattern?.replace("_", " ") || "JEE/NEET"}</span>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-[#00F0FF]">
|
||||
{user?.target_exam?.replace("_", " ") || "JEE/NEET"}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-xs font-bold">•</span>
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-muted-foreground">{dpp.difficulty} Level</span>
|
||||
</div>
|
||||
@@ -113,7 +121,7 @@ export default function DPPPage() {
|
||||
</Link>
|
||||
) : (
|
||||
<Link href={`/cbt/${dpp.id}`}>
|
||||
<Button variant="secondary" size="icon" className="rounded-full group-hover:bg-[#00F0FF] group-hover:text-black dark:group-hover:text-black hover:bg-[#00F0FF] hover:text-black dark:hover:text-black shadow-sm transition-all duration-300">
|
||||
<Button variant="secondary" size="icon" className="rounded-full group-hover:bg-primary group-hover:text-primary-foreground hover:bg-primary hover:text-primary-foreground shadow-sm transition-all duration-300">
|
||||
<Play size={16} className="ml-1" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -59,7 +59,13 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
</div>
|
||||
<NavItem href="/dashboard/leaderboard" icon={<Trophy size={18} />} label="Leaderboard" active={pathname.startsWith("/dashboard/leaderboard")} />
|
||||
<NavItem href="/dashboard/progress" icon={<Activity size={18} />} label="Syllabus Tracker" active={pathname.startsWith("/dashboard/progress")} />
|
||||
<NavItem href="/dashboard/community" icon={<BookOpen size={18} />} label="Doubt Forum" active={pathname.startsWith("/dashboard/community")} />
|
||||
<NavItem
|
||||
href="/dashboard/community"
|
||||
icon={<BookOpen size={18} />}
|
||||
label="Doubt Forum"
|
||||
active={pathname.startsWith("/dashboard/community")}
|
||||
isLocked={!hasAccessTo("ask-doubts-from-tutors")}
|
||||
/>
|
||||
|
||||
<div className="pt-4 pb-2">
|
||||
<p className="px-3 text-xs font-bold uppercase tracking-widest text-muted-foreground">AI Intelligence</p>
|
||||
@@ -159,7 +165,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Streak count moved to top header */}
|
||||
{user && (
|
||||
<Link href="/dashboard/streaks" className="hover:opacity-85 transition-opacity flex items-center gap-1.5 bg-secondary/50 border border-border px-3 py-1 rounded-xl">
|
||||
<Link href="/dashboard/streaks" className="hover:opacity-85 transition-opacity">
|
||||
<StreakCounter streak={user.streak_count} />
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -30,12 +30,7 @@ export default function DashboardPage() {
|
||||
|
||||
return (
|
||||
<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">
|
||||
<Button size="lg" className="gap-2 shadow-sm bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-bold">
|
||||
<BrainCircuit size={18} />
|
||||
Generate AI Plan
|
||||
</Button>
|
||||
</header>
|
||||
|
||||
|
||||
{/* Free Tier Upgrade CTA Banner */}
|
||||
<Card className="bg-primary/5 border-primary/20 relative overflow-hidden">
|
||||
@@ -47,7 +42,7 @@ export default function DashboardPage() {
|
||||
<Badge className="bg-primary text-primary-foreground font-bold tracking-widest uppercase mb-2">Upgrade to Pro</Badge>
|
||||
<h2 className="text-2xl font-bold tracking-tight">Unlock Unlimited DPS & Mocks</h2>
|
||||
<p className="text-muted-foreground max-w-xl font-medium">
|
||||
You're currently on the Free Tier. Upgrade to Pro for ₹299/mo to access unlimited Daily Practice Sheets, weekly CBT tests, and advanced analytics.
|
||||
You're currently on the Free Tier. Upgrade to Pro for ₹2499/yr to access unlimited Daily Practice Sheets, weekly CBT tests, and advanced analytics.
|
||||
</p>
|
||||
</div>
|
||||
<Button size="lg" className="shrink-0 rounded-xl shadow-[0_0_20px_-5px_var(--color-primary)] font-bold">
|
||||
|
||||
Reference in New Issue
Block a user