generated from muhtadeetaron/nextjs-template
142 lines
4.1 KiB
TypeScript
142 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import { useExam, useExamResults } from "@/context/ExamContext";
|
|
import { useEffect } from "react";
|
|
import React from "react";
|
|
|
|
interface Question {
|
|
solution: string;
|
|
id: number;
|
|
question: string;
|
|
options: Record<string, string>;
|
|
}
|
|
|
|
interface QuestionItemProps {
|
|
question: Question;
|
|
selectedAnswer: string | undefined;
|
|
}
|
|
|
|
const QuestionItem = React.memo<QuestionItemProps>(
|
|
({ question, selectedAnswer }) => (
|
|
<div className="border border-[#8abdff]/50 rounded-2xl p-4 flex flex-col gap-7">
|
|
<h3 className="text-xl font-medium">
|
|
{question.id}. {question.question}
|
|
</h3>
|
|
<div className="flex flex-col gap-4 items-start">
|
|
{Object.entries(question.options).map(([key, value]) => (
|
|
<button key={key} className="flex items-center gap-3">
|
|
<span
|
|
className={`flex items-center rounded-full border px-1.5 ${
|
|
selectedAnswer === key
|
|
? "text-white bg-[#113768] border-[#113768]"
|
|
: ""
|
|
}`}
|
|
>
|
|
{key.toUpperCase()}
|
|
</span>
|
|
<span className="option-description">{value}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
<div className="flex flex-col gap-4">
|
|
<h3 className="text-xl font-bold text-black/40">Solution:</h3>
|
|
<p className="text-lg font-medium">{question.solution}</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
);
|
|
|
|
export default function ResultsPage() {
|
|
const router = useRouter();
|
|
const { clearExam, isExamCompleted, getApiResponse } = useExam();
|
|
|
|
useEffect(() => {
|
|
// Redirect if no completed exam
|
|
if (!isExamCompleted()) {
|
|
router.push("/exam/select");
|
|
return;
|
|
}
|
|
}, [isExamCompleted, router]);
|
|
|
|
let examResults;
|
|
try {
|
|
examResults = useExamResults();
|
|
} catch (error) {
|
|
// Handle case where there's no completed exam
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
<div className="text-center">
|
|
<h1 className="text-2xl font-bold text-gray-900 mb-4">
|
|
No exam results found
|
|
</h1>
|
|
<button
|
|
onClick={() => router.push("/exam/select")}
|
|
className="bg-blue-900 text-white px-6 py-3 rounded-lg hover:bg-blue-800"
|
|
>
|
|
Take an Exam
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Get API response data
|
|
const apiResponse = getApiResponse();
|
|
|
|
const handleBackToHome = () => {
|
|
router.push("/unit");
|
|
clearExam();
|
|
};
|
|
|
|
const timeTaken =
|
|
examResults.endTime && examResults.startTime
|
|
? Math.round(
|
|
(examResults.endTime.getTime() - examResults.startTime.getTime()) /
|
|
1000 /
|
|
60
|
|
)
|
|
: 0;
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
<div className="bg-white rounded-lg shadow-lg px-10 py-20">
|
|
<h1 className="text-2xl font-bold text-gray-900 mb-2 text-center">
|
|
Keep up the good work!
|
|
</h1>
|
|
|
|
{/* Score Display */}
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
|
<div className="bg-blue-50 rounded-lg p-6 text-center">
|
|
<div className="text-3xl font-bold text-blue-900 mb-2">
|
|
{examResults.score}%
|
|
</div>
|
|
<div className="text-sm text-gray-600">Final Score</div>
|
|
</div>
|
|
</div>
|
|
|
|
{apiResponse && (
|
|
<div className="mb-8">
|
|
<h3 className="text-2xl font-bold text-[#113768] mb-4">
|
|
Solutions
|
|
</h3>
|
|
<div className="flex flex-col gap-7">
|
|
{apiResponse.questions?.map((question) => (
|
|
<QuestionItem key={question.id} question={question} />
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Action Buttons */}
|
|
</div>
|
|
<button
|
|
onClick={handleBackToHome}
|
|
className="fixed bottom-0 w-full bg-blue-900 text-white h-[74px] font-bold text-lg disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
>
|
|
Finish
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|