generated from muhtadeetaron/nextjs-template
123 lines
3.5 KiB
TypeScript
123 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import { useExam, useExamResults } from "@/context/ExamContext";
|
|
import { useEffect, useState } from "react";
|
|
import React from "react";
|
|
import { ArrowLeft } from "lucide-react";
|
|
import SlidingGallery from "@/components/SlidingGallery";
|
|
import QuestionItem from "@/components/QuestionItem";
|
|
import { getResultViews } from "@/lib/resultViews";
|
|
|
|
export default function ResultsPage() {
|
|
const router = useRouter();
|
|
const {
|
|
clearExam,
|
|
isExamCompleted,
|
|
getApiResponse,
|
|
currentAttempt,
|
|
isHydrated,
|
|
} = useExam();
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
// Wait for hydration first
|
|
if (!isHydrated) return;
|
|
|
|
// Check if exam is completed, redirect if not
|
|
if (!isExamCompleted() || !currentAttempt) {
|
|
router.push("/unit");
|
|
return;
|
|
}
|
|
|
|
// If we have exam results, we're ready to render
|
|
if (currentAttempt?.answers) {
|
|
setIsLoading(false);
|
|
}
|
|
}, [isExamCompleted, currentAttempt, isHydrated, router]);
|
|
|
|
const handleBackToHome = () => {
|
|
clearExam();
|
|
router.push("/unit");
|
|
};
|
|
|
|
// Show loading screen while initializing or if no exam results
|
|
if (isLoading || !currentAttempt) {
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
|
<div className="text-center">
|
|
<div className="mt-60 flex flex-col items-center">
|
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mb-4"></div>
|
|
<p className="text-xl font-medium text-center">Loading...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const apiResponse = getApiResponse();
|
|
|
|
const timeTaken =
|
|
currentAttempt.endTime && currentAttempt.startTime
|
|
? Math.round(
|
|
(currentAttempt.endTime.getTime() -
|
|
currentAttempt.startTime.getTime()) /
|
|
1000 /
|
|
60
|
|
)
|
|
: 0;
|
|
|
|
const views = getResultViews(currentAttempt);
|
|
|
|
// Get score-based message
|
|
const getScoreMessage = () => {
|
|
if (!currentAttempt.score || currentAttempt.score < 30)
|
|
return "Try harder!";
|
|
if (currentAttempt.score < 70) return "Getting Better";
|
|
return "You did great!";
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-white">
|
|
<button className="p-10" onClick={handleBackToHome}>
|
|
<ArrowLeft size={30} color="black" />
|
|
</button>
|
|
|
|
<div className="bg-white rounded-lg shadow-lg px-10 pb-20">
|
|
<h1 className="text-2xl font-bold text-[#113768] mb-4 text-center">
|
|
{getScoreMessage()}
|
|
</h1>
|
|
|
|
{/* Score Display */}
|
|
<SlidingGallery className="my-8" views={views} height="170px" />
|
|
|
|
{apiResponse?.questions && (
|
|
<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}
|
|
selectedAnswer={currentAttempt.answers[question.id - 1]}
|
|
mode="result"
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</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>
|
|
);
|
|
}
|