Fix UI bugs: history page fallback, admin page typescript type, cbt page math rendering

This commit is contained in:
2026-07-09 09:47:10 +05:30
parent 8f9bef9744
commit bc444ea737
4 changed files with 66 additions and 39 deletions

View File

@@ -153,7 +153,7 @@ export default function AdminTestsPage() {
<label className="text-sm font-medium">Scheduled Start (Optional)</label>
<DatePicker
selected={scheduledDate}
onChange={(date) => setScheduledDate(date)}
onChange={(date: Date | null) => setScheduledDate(date)}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}
@@ -167,7 +167,7 @@ export default function AdminTestsPage() {
<label className="text-sm font-medium">Scheduled End (Optional)</label>
<DatePicker
selected={endDate}
onChange={(date) => setEndDate(date)}
onChange={(date: Date | null) => setEndDate(date)}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}

View File

@@ -6,6 +6,10 @@ import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { ArrowLeft, CheckCircle2, XCircle, Clock, Award } from "lucide-react";
import ReactMarkdown from "react-markdown";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import "katex/dist/katex.min.css";
export default function AttemptHistoryPage({ params }: { params: Promise<{ attemptId: string }> }) {
const { attemptId } = use(params);
@@ -123,7 +127,11 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
{idx + 1}
</div>
<div>
<h3 className="font-medium text-lg leading-relaxed">{q.question_text || q.text_en || q.text}</h3>
<div className="font-medium text-lg leading-relaxed prose prose-sm dark:prose-invert">
<ReactMarkdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{q.question_text || q.text_en || q.text || ""}
</ReactMarkdown>
</div>
<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>
@@ -140,28 +148,39 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6 ml-12">
<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'}`}>
{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 className={`p-3 rounded-lg border prose prose-sm dark:prose-invert ${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'}`}>
<ReactMarkdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{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')}
</ReactMarkdown>
</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">
{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 className="p-3 rounded-lg border bg-green-500/10 border-green-500/30 text-green-500 prose prose-sm dark:prose-invert">
<ReactMarkdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{ans.is_subjective || q.type === 'Subjective' || q.type === 'Numerical'
? (q.correct_answer?.value || q.correct_answer?.correct || q.correct_answer?.selected || 'Subjective text')
: (q.options && q.options[q.correct_answer?.correct || q.correct_answer?.value || q.correct_answer?.selected]
? `${q.correct_answer?.correct || q.correct_answer?.value || q.correct_answer?.selected}) ${q.options[q.correct_answer?.correct || q.correct_answer?.value || q.correct_answer?.selected]}`
: (q.correct_answer?.correct || q.correct_answer?.value || q.correct_answer?.selected || 'N/A'))}
</ReactMarkdown>
</div>
</div>
</div>
{q.correct_answer?.explanation && (
{(q.solution_text || q.correct_answer?.explanation) && (
<div className="mt-6 ml-12 p-4 bg-secondary/30 rounded-xl border border-border">
<p className="text-sm font-bold mb-2">Explanation:</p>
<p className="text-muted-foreground">{q.correct_answer.explanation}</p>
<p className="text-sm font-bold mb-2 flex items-center gap-2">
<Award className="w-4 h-4 text-primary" />
Detailed Solution:
</p>
<div className="text-muted-foreground prose prose-sm dark:prose-invert max-w-none">
<ReactMarkdown remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]}>
{q.solution_text || q.correct_answer?.explanation || ""}
</ReactMarkdown>
</div>
</div>
)}
</CardContent>

View File

@@ -126,9 +126,16 @@ export default function CBTPage() {
<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">
<div className="flex justify-between items-start mb-4">
<Badge variant="outline" className="bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20">
{exam.type} Test
</Badge>
<div className="flex gap-2 flex-wrap">
<Badge variant="outline" className="bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20">
{exam.type} Test
</Badge>
{exam.exam_pattern && (
<Badge variant="outline" className="bg-primary/20 text-primary border-primary/30 uppercase tracking-wider text-[10px]">
{exam.exam_pattern}
</Badge>
)}
</div>
{isUpcoming ? (
<Badge variant="secondary" className="bg-yellow-500/10 text-yellow-500 border-yellow-500/20">
Upcoming
@@ -211,7 +218,7 @@ export default function CBTPage() {
<div className="font-bold text-base md:text-lg text-[#00F0FF]">{Math.round(attempt.accuracy)}%</div>
</div>
<Link href={`/dashboard/cbt/history/${attempt.id}`}>
<Button variant="outline" className="rounded-xl border-border hover:bg-secondary">
<Button variant="outline" className="rounded-xl border-border hover:bg-secondary hover:text-foreground">
View Solutions
</Button>
</Link>