"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, Zap } from "lucide-react" import { useEffect, useState } from "react" import Link from "next/link" import { useActiveUser } from "@/hooks/useActiveUser" export default function AIDailyPracticePage() { const { user, userId, hasAccessTo } = useActiveUser() const [dpps, setDpps] = useState([]) const [attempts, setAttempts] = useState([]) const [loading, setLoading] = useState(true) const [dateFilter, setDateFilter] = useState("") const [selectedPdfDpp, setSelectedPdfDpp] = useState(null) const [isFullScreen, setIsFullScreen] = useState(false) const [copiedShare, setCopiedShare] = useState(false) useEffect(() => { async function fetchDpps() { if (!user) return; // Wait for user to be available try { const pattern = user.target_exam || "JEE_Main"; // Also fetch from the correct Next.js proxied route instead of localhost:8000 const res = await fetchWithAuth(`/api/tests?type=DPS`); if (res.ok) { let data = await res.json() // Filter by subject based on target exam const target = user.target_exam || "JEE_Main"; data = data.filter((dpp: any) => { const title = dpp.title.toLowerCase(); const isMath = title.includes("math"); const isBio = title.includes("bio") || title.includes("botany") || title.includes("zoology"); if (target === "NEET" && isMath) return false; if (target.startsWith("JEE") && target !== "JEE_NEET" && isBio) return false; return true; }); setDpps(data) } if (userId) { const attemptsRes = await fetchWithAuth(`/api/users/${userId}/attempts`); if (attemptsRes.ok) { const attemptsData = await attemptsRes.json(); setAttempts(attemptsData); } } } catch (err) { console.error("Failed to fetch DPPs", err) } finally { setLoading(false) } } fetchDpps() }, [user]) const getDifficultyColor = (diff: string) => { switch(diff) { case 'Easy': return 'text-emerald-500 bg-emerald-500/10 border-emerald-500/20'; case 'Medium': return 'text-amber-500 bg-amber-500/10 border-amber-500/20'; case 'Hard': return 'text-destructive bg-destructive/10 border-destructive/20'; default: return 'text-primary bg-primary/10 border-primary/20'; } } const attemptsByTest = attempts.reduce((acc, curr) => { // Isolate analytics to first attempt only - ignore retakes if (curr.is_retake) return acc; if (!acc[curr.source_id] || acc[curr.source_id].score < curr.score) { acc[curr.source_id] = curr; } return acc; }, {} as Record); const filteredDpps = dpps.filter(dpp => { // Only show PDF DPPs here if (!dpp.pdf_url) return false; if (dateFilter) { if (!dpp.scheduled_date) return false; const scheduledDate = new Date(dpp.scheduled_date).toISOString().split('T')[0]; if (scheduledDate !== dateFilter) return false; } return true; }); const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString("en-US", { year: 'numeric', month: 'short', day: 'numeric' }); } const getPdfUrl = (title: string) => { const t = title.toLowerCase(); if (t.includes('phys')) return '/dpps/dps-phy-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0'; if (t.includes('chem')) return '/dpps/dps-che-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0'; if (t.includes('math')) return '/dpps/dps-mth-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0'; if (t.includes('bio')) return '/dpps/dps-bio-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0'; return '/dpps/dps-phy-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0'; }; // Strip ugly ExamEnum. prefix from seeded test titles const cleanTitle = (title: string) => title.replace(/\s*\(ExamEnum\.[^)]+\)/, ''); return (
{/* Page Header */}

Daily Practice (DPP)

Launch Daily Practice Problems (DPPs) tailored to your exam pattern.

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" />
{loading ? (
Loading AI-generated DPPs...
) : filteredDpps.length === 0 ? (
No DPPs available for the selected criteria.
) : filteredDpps.map((dpp, i) => { // Calculate total questions dynamically from sections let count = 0; if (dpp.sections) { Object.values(dpp.sections).forEach((s: any) => { count += (s.questions?.length || 0) }); } const attempt = attemptsByTest[dpp.id]; const isAttempted = !!attempt; // Date logic const now = new Date(); const scheduledTime = dpp.scheduled_date ? new Date(dpp.scheduled_date) : now; const endTime = dpp.end_date ? new Date(dpp.end_date) : null; const isUpcoming = scheduledTime > now; const isExpired = endTime ? now > endTime : false; return (
{isAttempted ? :
}
{user?.target_exam?.replace("_", " ") || "JEE/NEET"} • {dpp.difficulty} Level {isUpcoming ? ( <> • Upcoming ) : isExpired ? ( <> • Expired ) : null}

{cleanTitle(dpp.title)}

{dpp.difficulty}
{count} Questions • {dpp.total_time} mins {dpp.scheduled_date && ( {isUpcoming ? `Available on ${formatDate(dpp.scheduled_date)}` : isExpired ? `Expired on ${formatDate(dpp.end_date!)}` : 'Available Now'} )}
{isUpcoming ? ( ) : isExpired && !isAttempted ? ( ) : ( hasAccessTo('PRO') ? ( ) : ( ) )}
)})}
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */} {selectedPdfDpp && (
{/* Modal Header */}

{selectedPdfDpp.title} Protected In-App PDF View

{selectedPdfDpp.difficulty} Level • {user?.target_exam?.replace("_", " ") || "JEE/NEET"} Practice Sheet

{/* Security Notice Banner */}
Read-Only Mode (Free Tier) — Downloads & direct copying are restricted.
{/* Protected PDF Document Sheet Content (select-none) */}
e.preventDefault()} className="flex-1 w-full select-none bg-[#525659] overflow-hidden" style={{minHeight: isFullScreen ? 'calc(100vh - 120px)' : '75vh'}} >
{/* Modal Footer */}
📄 PragatiVeer Protected PDF Reader v2.0
)}
) }