generated from muhtadeetaron/nextjs-template
fix(func): fix issues in results page
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useExam, useExamResults } from "@/context/ExamContext";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import React from "react";
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
@ -83,48 +83,92 @@ const QuestionItem = ({ question, selectedAnswer }: QuestionItemProps) => (
|
||||
);
|
||||
|
||||
export default function ResultsPage() {
|
||||
// All hooks at the top - no conditional calls
|
||||
const router = useRouter();
|
||||
const { clearExam, isExamCompleted, getApiResponse } = useExam();
|
||||
let examResults;
|
||||
|
||||
// Add a ref to track if we're in cleanup mode
|
||||
const isCleaningUp = useRef(false);
|
||||
|
||||
// Conditionally call useExamResults based on cleanup state
|
||||
const examResults = !isCleaningUp.current ? useExamResults() : null;
|
||||
|
||||
// State to control component behavior
|
||||
const [componentState, setComponentState] = useState<
|
||||
"loading" | "redirecting" | "ready"
|
||||
>("loading");
|
||||
|
||||
// Single useEffect to handle all initialization logic
|
||||
useEffect(() => {
|
||||
if (!isExamCompleted()) {
|
||||
router.push("/unit");
|
||||
return;
|
||||
}
|
||||
}, [isExamCompleted, router]);
|
||||
let mounted = true;
|
||||
|
||||
const initializeComponent = async () => {
|
||||
// Allow time for all hooks to initialize
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
// Check if exam is completed
|
||||
if (!isExamCompleted()) {
|
||||
setComponentState("redirecting");
|
||||
// Small delay before redirect to prevent hook order issues
|
||||
setTimeout(() => {
|
||||
if (mounted) {
|
||||
router.push("/unit");
|
||||
}
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we have exam results
|
||||
if (!examResults || !examResults.answers) {
|
||||
// Keep loading state
|
||||
return;
|
||||
}
|
||||
|
||||
// Everything is ready
|
||||
setComponentState("ready");
|
||||
};
|
||||
|
||||
initializeComponent();
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [isExamCompleted, router, examResults]);
|
||||
|
||||
// Always render loading screen for non-ready states
|
||||
if (componentState !== "ready") {
|
||||
const loadingText =
|
||||
componentState === "redirecting" ? "Redirecting..." : "Loading...";
|
||||
|
||||
try {
|
||||
examResults = useExamResults();
|
||||
console.log(examResults);
|
||||
} 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">
|
||||
<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>
|
||||
<p className="text-xl font-medium text-center">{loadingText}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Get API response data
|
||||
// At this point, we know examResults exists and component is ready
|
||||
const apiResponse = getApiResponse();
|
||||
|
||||
const handleBackToHome = () => {
|
||||
clearExam();
|
||||
// Set cleanup flag to prevent useExamResults from running
|
||||
isCleaningUp.current = true;
|
||||
|
||||
// Give time for state to fully reset before pushing new route
|
||||
clearExam();
|
||||
setTimeout(() => {
|
||||
router.push("/unit");
|
||||
}, 400); // 50–100ms is usually enough
|
||||
}, 400);
|
||||
};
|
||||
|
||||
const timeTaken =
|
||||
examResults.endTime && examResults.startTime
|
||||
examResults?.endTime && examResults?.startTime
|
||||
? Math.round(
|
||||
(examResults.endTime.getTime() - examResults.startTime.getTime()) /
|
||||
1000 /
|
||||
@ -149,10 +193,12 @@ export default function ResultsPage() {
|
||||
height={60}
|
||||
/>
|
||||
<h2 className="text-6xl font-bold text-[#113678]">
|
||||
{(
|
||||
(examResults.score / examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)}
|
||||
{examResults
|
||||
? (
|
||||
(examResults.score / examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)
|
||||
: "0"}
|
||||
%
|
||||
</h2>
|
||||
</div>
|
||||
@ -177,11 +223,13 @@ export default function ResultsPage() {
|
||||
height={60}
|
||||
/>
|
||||
<h2 className="text-6xl font-bold text-[#113678]">
|
||||
{(
|
||||
((examResults.totalQuestions - examResults.score) /
|
||||
examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)}
|
||||
{examResults
|
||||
? (
|
||||
((examResults.totalQuestions - examResults.score) /
|
||||
examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)
|
||||
: "0"}
|
||||
%
|
||||
</h2>
|
||||
</div>
|
||||
@ -206,10 +254,13 @@ export default function ResultsPage() {
|
||||
height={60}
|
||||
/>
|
||||
<h2 className="text-6xl font-bold text-[#113678]">
|
||||
{(
|
||||
(examResults.answers.length / examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)}
|
||||
{examResults
|
||||
? (
|
||||
(examResults.answers.length /
|
||||
examResults.totalQuestions) *
|
||||
100
|
||||
).toFixed(1)
|
||||
: "0"}
|
||||
%
|
||||
</h2>
|
||||
</div>
|
||||
@ -227,7 +278,7 @@ export default function ResultsPage() {
|
||||
</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">
|
||||
{examResults?.score < 30
|
||||
{!examResults?.score || examResults?.score < 30
|
||||
? "Try harder!"
|
||||
: examResults?.score < 70
|
||||
? "Getting Better"
|
||||
@ -247,14 +298,12 @@ export default function ResultsPage() {
|
||||
<QuestionItem
|
||||
key={question.id}
|
||||
question={question}
|
||||
selectedAnswer={examResults.answers?.[question.id]}
|
||||
selectedAnswer={examResults?.answers?.[question.id]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Action Buttons */}
|
||||
</div>
|
||||
<button
|
||||
onClick={handleBackToHome}
|
||||
|
||||
Reference in New Issue
Block a user