SchiriTrainer2/frontend/src/pages/QuizPage.jsx
2025-07-25 14:34:29 +02:00

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>
);
}