Feat: Complete CBT PDF upload, AI parsing, and MinIO storage integration

This commit is contained in:
2026-07-07 15:56:44 +05:30
parent c5260eec2e
commit b6ebb9d9c3
8 changed files with 476 additions and 8 deletions

View File

@@ -15,6 +15,7 @@ interface TestData {
exam_pattern: string;
total_time: number;
difficulty: string;
scheduled_date?: string;
}
export default function CBTPage() {
@@ -116,6 +117,11 @@ export default function CBTPage() {
const isAttempted = !!attempt;
const isLocked = !hasAccessTo("weekly-test-series");
// Date logic
const now = new Date();
const scheduledTime = exam.scheduled_date ? new Date(exam.scheduled_date) : now;
const isUpcoming = scheduledTime > now;
return (
<Card key={exam.id} className={`hover:border-[#00F0FF]/50 hover:shadow-[0_0_15px_-5px_#00F0FF] transition-all group ${isAttempted ? 'border-primary/20' : ''} ${isLocked ? 'opacity-80' : ''}`}>
<CardContent className="p-6">
@@ -123,7 +129,11 @@ export default function CBTPage() {
<Badge variant="outline" className="bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20">
{exam.type} Test
</Badge>
{isLocked ? (
{isUpcoming ? (
<Badge variant="secondary" className="bg-yellow-500/10 text-yellow-500 border-yellow-500/20">
Upcoming
</Badge>
) : isLocked ? (
<Badge variant="outline" className="bg-red-500/10 text-red-500 border-red-500/20 flex items-center gap-1">
<Lock size={12} /> Premium
</Badge>
@@ -137,10 +147,17 @@ export default function CBTPage() {
{exam.title}
</h3>
<div className="text-sm text-muted-foreground space-y-1 mb-6">
<div className="font-medium text-foreground">Available Now</div>
<div className="font-medium text-foreground">
{isUpcoming ? `Available on ${formatDate(exam.scheduled_date!)}` : 'Available Now'}
</div>
<div>{exam.total_time} Min • {exam.difficulty} Difficulty</div>
</div>
{isLocked ? (
{isUpcoming ? (
<Button disabled className="w-full gap-2 rounded-xl bg-secondary text-muted-foreground font-bold">
<Clock size={16} /> Starts Soon
</Button>
) : isLocked ? (
<Button
onClick={() => setShowUpgradeModal(true)}
className="w-full gap-2 rounded-xl bg-secondary text-muted-foreground border border-dashed border-border hover:border-[#00F0FF]/50 hover:text-foreground font-bold"