feat: setup admin JSON generation and pdf viewer for free plan DPPs

This commit is contained in:
2026-07-27 14:56:25 +05:30
parent c214ca41b6
commit a5bb2d867c
74 changed files with 8546 additions and 915 deletions

View File

@@ -2,7 +2,7 @@
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock } from "lucide-react"
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles } from "lucide-react"
import { useEffect, useState } from "react"
import Link from "next/link"
@@ -14,6 +14,7 @@ export default function DPPPage() {
const [attempts, setAttempts] = useState<any[]>([])
const [loading, setLoading] = useState(true)
const [dateFilter, setDateFilter] = useState("")
const [selectedPdfDpp, setSelectedPdfDpp] = useState<any | null>(null)
useEffect(() => {
async function fetchDpps() {
@@ -76,6 +77,16 @@ export default function DPPPage() {
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';
// Default fallback
return '/dpps/dps-phy-ch4-20260707.pdf#toolbar=0&navpanes=0&scrollbar=0';
};
return (
<div className="p-8 space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500 max-w-5xl 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">
@@ -181,27 +192,111 @@ export default function DPPPage() {
<Button disabled variant="outline" size="sm" className="font-bold bg-secondary/50">Expired</Button>
) : isAttempted ? (
<>
<Link href={`/cbt/${dpp.id}/result`}>
<Button variant="outline" size="sm" className="font-bold border-border">Result</Button>
<Link href={user?.tier === "Free" ? "#" : `/cbt/${dpp.id}/result`}>
<Button onClick={() => user?.tier === "Free" && setSelectedPdfDpp(dpp)} variant="outline" size="sm" className="font-bold border-border">Result</Button>
</Link>
{!isExpired && (
<Link href={`/cbt/${dpp.id}`}>
<Button variant="secondary" size="sm" className="font-bold bg-[#00F0FF]/10 text-[#00F0FF] hover:bg-[#00F0FF]/20">Retake</Button>
<Link href={user?.tier === "Free" ? "#" : `/dashboard/ai-coach/cbt-dpp/${dpp.id}`}>
<Button onClick={() => user?.tier === "Free" && setSelectedPdfDpp(dpp)} variant="secondary" size="sm" className="font-bold bg-[#00F0FF]/10 text-[#00F0FF] hover:bg-[#00F0FF]/20">
{user?.tier === "Free" ? "Read PDF" : "Retake CBT"}
</Button>
</Link>
)}
</>
) : (
<Link href={`/cbt/${dpp.id}`}>
<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" />
user?.tier === "Free" ? (
<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>
) : (
<Link href={`/dashboard/ai-coach/cbt-dpp/${dpp.id}`}>
<Button variant="secondary" size="sm" className="rounded-xl bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-extrabold gap-2 text-xs shadow-[0_0_12px_rgba(0,240,255,0.2)]">
<Play size={14} className="fill-black" /> Launch CBT DPP
</Button>
</Link>
)
)}
</div>
</CardContent>
</Card>
)})}
</div>
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
{selectedPdfDpp && (
<div className="fixed inset-0 z-50 bg-black/80 backdrop-blur-md flex items-center justify-center p-4 animate-in fade-in duration-300">
<div className="bg-background border border-border rounded-3xl w-full max-w-4xl max-h-[90vh] flex flex-col overflow-hidden shadow-2xl">
{/* Modal Header */}
<div className="p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="p-2.5 bg-primary/10 rounded-xl border border-primary/20 text-primary">
<FileText size={22} />
</div>
<div>
<h3 className="font-black text-lg flex items-center gap-2">
{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">
Protected In-App PDF View
</span>
</h3>
<p className="text-xs text-muted-foreground font-medium">
{selectedPdfDpp.difficulty} Level • {user?.target_exam?.replace("_", " ") || "JEE/NEET"} Practice Sheet
</p>
</div>
</div>
<Button
onClick={() => setSelectedPdfDpp(null)}
variant="outline"
size="icon"
className="rounded-full border-border hover:bg-secondary"
>
<X size={18} />
</Button>
</div>
{/* Security Notice Banner */}
<div className="bg-amber-500/10 border-b border-amber-500/20 px-6 py-2.5 flex items-center justify-between text-xs text-amber-400 font-bold">
<span className="flex items-center gap-2">
<ShieldAlert size={16} /> Read-Only Mode (Free Tier) — Downloads, text copying, and sharing are restricted.
</span>
<Link href="/upgrade">
<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 →
</Button>
</Link>
</div>
{/* Protected PDF Document Sheet Content (select-none) */}
<div
onContextMenu={(e) => e.preventDefault()}
className="flex-1 w-full h-full min-h-[60vh] select-none bg-[#525659]"
>
<embed
src={getPdfUrl(selectedPdfDpp.title)}
type="application/pdf"
className="w-full h-full rounded-b-lg"
/>
</div>
{/* Modal Footer */}
<div className="p-4 border-t border-border bg-secondary/30 flex items-center justify-between">
<span className="text-xs text-muted-foreground font-medium">
📄 PragatiVeer Protected PDF Reader v2.0
</span>
<div className="flex gap-3">
<Button onClick={() => setSelectedPdfDpp(null)} variant="outline" className="rounded-xl font-bold">
Close PDF Reader
</Button>
<Link href="/upgrade">
<Button className="bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 font-extrabold rounded-xl shadow-[0_0_15px_rgba(0,240,255,0.2)]">
<Sparkles size={16} className="mr-2" /> Upgrade to AI Coach for Interactive CBT
</Button>
</Link>
</div>
</div>
</div>
</div>
)}
</div>
)
}