177 lines
5.6 KiB
JavaScript
177 lines
5.6 KiB
JavaScript
import { useEffect, useState } from "react";
|
|
import QuestionCard from "../components/QuestionCard";
|
|
import ResultPage from "./ResultPage";
|
|
import {useNavigate} from "react-router-dom";
|
|
|
|
export default function QuizPage({ mode, onBack, customQuestions }) {
|
|
const [questions, setQuestions] = useState([]);
|
|
const [currentIdx, setCurrentIdx] = useState(0);
|
|
const [score, setScore] = useState(0);
|
|
const [wrongQuestions, setWrongQuestions] = useState([]);
|
|
const [showResult, setShowResult] = useState(false);
|
|
const [refreshKey, setRefreshKey] = useState(0);
|
|
const [answerStatus, setAnswerStatus] = useState([]); // "correct" | "wrong" | undefined
|
|
const navigate = useNavigate();
|
|
|
|
|
|
useEffect(() => {
|
|
const savedQuestions = sessionStorage.getItem("quiz_questions");
|
|
const savedIndex = sessionStorage.getItem("quiz_current_idx");
|
|
const savedScore = sessionStorage.getItem("quiz_score");
|
|
const savedWrong = sessionStorage.getItem("quiz_wrong_questions");
|
|
const savedStatus = sessionStorage.getItem("quiz_answer_status");
|
|
|
|
|
|
|
|
if (savedQuestions) {
|
|
setQuestions(JSON.parse(savedQuestions));
|
|
setCurrentIdx(parseInt(savedIndex) || 0);
|
|
setScore(parseInt(savedScore) || 0);
|
|
setWrongQuestions(JSON.parse(savedWrong) || []);
|
|
setAnswerStatus(JSON.parse(savedStatus) || []);
|
|
return;
|
|
}
|
|
|
|
if (customQuestions) {
|
|
setQuestions(customQuestions);
|
|
sessionStorage.setItem("quiz_questions", JSON.stringify(customQuestions));
|
|
} else {
|
|
fetch(`/api/questions/${mode}`)
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
const shuffled = data.sort(() => 0.5 - Math.random()).slice(0, 30);
|
|
setQuestions(shuffled);
|
|
sessionStorage.setItem("quiz_questions", JSON.stringify(shuffled));
|
|
});
|
|
}
|
|
}, [mode, customQuestions, refreshKey]);
|
|
|
|
const handleAnswer = (isCorrect, currentQuestion) => {
|
|
const index = currentIdx;
|
|
|
|
if (isCorrect) {
|
|
setScore((prev) => {
|
|
const newScore = prev + 1;
|
|
sessionStorage.setItem("quiz_score", newScore);
|
|
return newScore;
|
|
});
|
|
} else {
|
|
setWrongQuestions((prev) => {
|
|
const updated = [...prev, currentQuestion];
|
|
sessionStorage.setItem("quiz_wrong_questions", JSON.stringify(updated));
|
|
return updated;
|
|
});
|
|
}
|
|
|
|
// Update and persist answer status
|
|
setAnswerStatus((prev) => {
|
|
const updated = [...prev];
|
|
updated[index] = isCorrect ? "correct" : "wrong";
|
|
sessionStorage.setItem("quiz_answer_status", JSON.stringify(updated));
|
|
return updated;
|
|
});
|
|
};
|
|
|
|
const handleNext = () => {
|
|
const nextIndex = currentIdx + 1;
|
|
if (nextIndex < questions.length) {
|
|
setCurrentIdx(nextIndex);
|
|
sessionStorage.setItem("quiz_current_idx", nextIndex);
|
|
} else {
|
|
setShowResult(true);
|
|
}
|
|
};
|
|
|
|
const handleReset = () => {
|
|
sessionStorage.removeItem("quiz_questions");
|
|
sessionStorage.removeItem("quiz_current_idx");
|
|
sessionStorage.removeItem("quiz_score");
|
|
sessionStorage.removeItem("quiz_wrong_questions");
|
|
sessionStorage.removeItem("quiz_answer_status");
|
|
};
|
|
|
|
if (showResult) {
|
|
return (
|
|
<ResultPage
|
|
score={score}
|
|
total={questions.length}
|
|
wrongQuestions={wrongQuestions}
|
|
onRestart={() => {
|
|
handleReset();
|
|
setScore(0);
|
|
setWrongQuestions([]);
|
|
setCurrentIdx(0);
|
|
setShowResult(false);
|
|
setQuestions([]);
|
|
setAnswerStatus([]);
|
|
setRefreshKey((prev) => prev + 1);
|
|
}}
|
|
onRepeatWrong={() => {
|
|
handleReset();
|
|
setScore(0);
|
|
setCurrentIdx(0);
|
|
setShowResult(false);
|
|
setQuestions(wrongQuestions);
|
|
setAnswerStatus([]);
|
|
setWrongQuestions([]);
|
|
}}
|
|
onBack={onBack}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const currentQuestion = questions[currentIdx];
|
|
if (!currentQuestion) return <p className="p-6">Fragen werden geladen...</p>;
|
|
|
|
return (
|
|
<div className="min-h-screen flex flex-col justify-center max-w-3xl mx-auto p-4">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
Frage {currentIdx + 1} / {questions.length}
|
|
</p>
|
|
<div className="flex items-center gap-3">
|
|
<button
|
|
onClick={() => navigate("/solutions")}
|
|
className="text-sm text-gray-700 dark:text-gray-300 hover:text-blue-600 hover:underline transition"
|
|
title="Lösungen durchsuchen"
|
|
>
|
|
Lösungen anzeigen
|
|
</button>
|
|
<span className="text-gray-300">|</span>
|
|
<button
|
|
onClick={onBack}
|
|
className="text-sm text-blue-600 dark:text-blue-400 underline hover:text-blue-800 transition"
|
|
>
|
|
Modus wechseln
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Segmentierter Balken */}
|
|
<div className="w-full flex gap-[1px] mb-4">
|
|
{questions.map((_, idx) => {
|
|
let bg = "bg-gray-300";
|
|
if (answerStatus[idx] === "correct") bg = "bg-green-500";
|
|
else if (answerStatus[idx] === "wrong") bg = "bg-red-500";
|
|
|
|
return (
|
|
<div
|
|
key={idx}
|
|
className={`flex-1 h-2 ${bg} rounded-sm`}
|
|
title={`Frage ${idx + 1}`}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<QuestionCard
|
|
frage={currentQuestion.frage}
|
|
antworten={currentQuestion.antworten}
|
|
onNext={handleNext}
|
|
onCheck={(correct) => handleAnswer(correct, currentQuestion)}
|
|
isLast={currentIdx === questions.length - 1}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|