Redesign college predictor, swap DPP contents, reorder sidebar, fix imports, add sql dump
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
"use client"
|
||||
"use client"
|
||||
|
||||
import { fetchWithAuth } from "@/lib/apiClient";
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles, Share2, Maximize2, Minimize2 } from "lucide-react"
|
||||
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles, Share2, Maximize2, Minimize2, Zap } from "lucide-react"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
import { useActiveUser } from "@/hooks/useActiveUser"
|
||||
|
||||
export default function DPPPage() {
|
||||
export default function AIDailyPracticePage() {
|
||||
const { user, userId } = useActiveUser()
|
||||
const [dpps, setDpps] = useState<any[]>([])
|
||||
const [attempts, setAttempts] = useState<any[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [dateFilter, setDateFilter] = useState("")
|
||||
|
||||
const [selectedPdfDpp, setSelectedPdfDpp] = useState<any | null>(null)
|
||||
const [isFullScreen, setIsFullScreen] = useState(false)
|
||||
const [copiedShare, setCopiedShare] = useState(false)
|
||||
@@ -73,10 +74,7 @@ export default function DPPPage() {
|
||||
const scheduledDate = new Date(dpp.scheduled_date).toISOString().split('T')[0];
|
||||
if (scheduledDate !== dateFilter) return false;
|
||||
}
|
||||
const isNeet = user?.target_exam === "NEET";
|
||||
const title = dpp.title.toLowerCase();
|
||||
if (isNeet && (title.includes("math") || title.includes("mth"))) return false;
|
||||
if (!isNeet && title.includes("bio")) return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -97,13 +95,21 @@ export default function DPPPage() {
|
||||
const cleanTitle = (title: string) => title.replace(/\s*\(ExamEnum\.[^)]+\)/, '');
|
||||
|
||||
return (
|
||||
<div className="p-8 space-y-8 animate-in fade-in zoom-in-95 origin-top duration-500 max-w-7xl mx-auto">
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between p-8 bg-gradient-to-r from-secondary/50 to-background border border-border rounded-2xl shadow-sm gap-6">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold tracking-tight mb-2">Daily Practice Problems (DPP)</h1>
|
||||
<p className="text-muted-foreground font-medium max-w-xl">
|
||||
Hyper-personalized problem sets generated daily by our AI Evaluator to target your specific weak areas based on past exam performance.
|
||||
</p>
|
||||
<div className="p-6 md:p-8 space-y-6 animate-in fade-in zoom-in-95 origin-top duration-500 max-w-7xl mx-auto">
|
||||
{/* Page Header */}
|
||||
<div className="border-b border-border/50 pb-6">
|
||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||
<div>
|
||||
<h1 className="text-3xl md:text-4xl font-black tracking-tight flex items-center gap-3 mb-1">
|
||||
<span className="p-2.5 rounded-xl bg-cyan-50 dark:bg-[var(--cyan-ai-10)] border border-cyan-300/60 dark:border-[var(--cyan-ai-20)]">
|
||||
<FileText className="text-primary" size={28} /></span>
|
||||
Daily Practice (DPP)
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-base font-medium max-w-2xl pl-1">
|
||||
Launch Daily Practice Problems (DPPs) tailored to your exam pattern.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -115,27 +121,10 @@ export default function DPPPage() {
|
||||
onChange={(e) => setDateFilter(e.target.value)}
|
||||
className="px-3 py-1.5 bg-background border border-border rounded-lg text-xs font-bold focus:ring-2 focus:ring-[var(--cyan-ai)] outline-none text-muted-foreground mr-2"
|
||||
/>
|
||||
<span className="text-sm font-bold text-muted-foreground mr-2"><Filter size={16} className="inline mr-1"/> Difficulty:</span>
|
||||
{['Mixed', 'Easy', 'Medium', 'Hard'].map((diff) => (
|
||||
<button key={diff} className={`px-3 py-1.5 rounded-lg text-xs font-bold border transition-colors ${diff === 'Mixed' ? 'bg-primary text-primary-foreground border-primary' : 'bg-background text-muted-foreground border-border hover:border-primary/50'}`}>
|
||||
{diff}
|
||||
</button>
|
||||
))}
|
||||
<div className="flex items-center gap-1 ml-2 text-xs text-muted-foreground bg-secondary/50 px-2 py-1 rounded-md">
|
||||
<Lock size={12}/> Pro
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(window.location.origin + '/dashboard/dpp');
|
||||
setCopiedShare(true);
|
||||
setTimeout(() => setCopiedShare(false), 2000);
|
||||
}}
|
||||
className="gap-2 rounded-xl text-sm font-bold border-primary/30 hover:bg-primary/10 text-primary transition-all shadow-sm"
|
||||
>
|
||||
{copiedShare ? <CheckCircle2 size={16} className="text-green-500" /> : <Share2 size={16} />}
|
||||
{copiedShare ? "Share Link Copied!" : "Share DPPs Link"}
|
||||
<Button variant="outline" className="gap-2 rounded-xl text-sm font-bold">
|
||||
<Download size={16} /> Export as PDF
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -189,10 +178,12 @@ export default function DPPPage() {
|
||||
</div>
|
||||
<h3 className="font-bold text-lg leading-tight group-hover:text-[var(--cyan-ai)] transition-colors">
|
||||
{cleanTitle(dpp.title)}
|
||||
<span className={`ml-2 text-[10px] uppercase px-2 py-0.5 rounded-md border font-bold tracking-wider ${getDifficultyColor(dpp.difficulty)}`}>
|
||||
</h3>
|
||||
<div className="mt-1">
|
||||
<span className={`text-[10px] uppercase px-2 py-0.5 rounded-md border font-bold tracking-wider ${getDifficultyColor(dpp.difficulty)}`}>
|
||||
{dpp.difficulty}
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="text-sm text-muted-foreground mt-2 font-medium">
|
||||
{count} Questions • {dpp.total_time} mins
|
||||
{dpp.scheduled_date && (
|
||||
@@ -214,15 +205,19 @@ export default function DPPPage() {
|
||||
<Button variant="outline" size="sm" className="font-bold border-border">Result</Button>
|
||||
</Link>
|
||||
{!isExpired && (
|
||||
<Button onClick={() => setSelectedPdfDpp(dpp)} variant="secondary" size="sm" className="font-bold bg-[var(--cyan-ai-10)] text-[var(--cyan-ai)] hover:bg-[var(--cyan-ai-20)] gap-2">
|
||||
<Eye size={14} /> Read PDF
|
||||
</Button>
|
||||
<Link href={`/cbt/${dpp.id}`}>
|
||||
<Button variant="secondary" size="sm" className="font-bold bg-[var(--cyan-ai-10)] text-[var(--cyan-ai)] hover:bg-[var(--cyan-ai-20)] gap-2">
|
||||
<Play size={14} className="fill-current" /> Retake Test
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Button onClick={() => setSelectedPdfDpp(dpp)} variant="secondary" className="rounded-xl bg-primary/10 text-primary hover:bg-primary/20 font-bold gap-2 text-xs">
|
||||
<Eye size={14} /> Open PDF
|
||||
</Button>
|
||||
<Link href={`/cbt/${dpp.id}`}>
|
||||
<Button variant="secondary" size="sm" className="rounded-xl bg-[var(--cyan-ai)] text-black hover:bg-[var(--cyan-ai-80)] font-extrabold gap-2 text-xs shadow-[0_0_12px_rgba(12,96,96,0.2)]">
|
||||
<Play size={14} className="fill-black" /> Launch Practice Test
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -242,7 +237,7 @@ export default function DPPPage() {
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-black text-base sm:text-lg flex items-center gap-2">
|
||||
{cleanTitle(selectedPdfDpp.title)}
|
||||
{selectedPdfDpp.title}
|
||||
<span className="text-[10px] bg-yellow-500/10 text-yellow-500 border border-yellow-500/20 px-2 py-0.5 rounded-full uppercase tracking-wider font-extrabold hidden md:inline-block">
|
||||
Protected In-App PDF View
|
||||
</span>
|
||||
@@ -257,7 +252,7 @@ export default function DPPPage() {
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(window.location.origin + '/dashboard/dpp');
|
||||
navigator.clipboard.writeText(window.location.origin + '/dashboard/ai-coach/cbt-dpp');
|
||||
setCopiedShare(true);
|
||||
setTimeout(() => setCopiedShare(false), 2000);
|
||||
}}
|
||||
@@ -291,7 +286,7 @@ export default function DPPPage() {
|
||||
</span>
|
||||
<Link href="/upgrade" className="hidden sm:block shrink-0 ml-2">
|
||||
<Button size="sm" className="bg-amber-500 text-black hover:bg-amber-400 font-extrabold h-7 text-[11px] rounded-lg">
|
||||
Upgrade for Interactive CBT Mode →
|
||||
Upgrade for Interactive Practice Mode →
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -325,7 +320,7 @@ export default function DPPPage() {
|
||||
</Button>
|
||||
<Link href="/upgrade">
|
||||
<Button className="bg-[var(--cyan-ai)] text-black hover:bg-[var(--cyan-ai-80)] font-extrabold rounded-xl shadow-[0_0_15px_rgba(12,96,96,0.2)] text-xs h-9">
|
||||
<Sparkles size={14} className="mr-1.5" /> Upgrade to AI Coach for CBT
|
||||
<Sparkles size={14} className="mr-1.5" /> Upgrade to AI Coach
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user