// /public/js/quiz.js // State variables for managing the quiz lifecycle let questions = []; let currentQuestionIndex = 0; let score = 0; let isAnswered = false; // Initializes the quiz by fetching data from the internal API. // Behavior: // - Detects mode (standard vs all) from the window path // - Toggles visibility between loading, error, and quiz states async function initQuiz() { const loadingState = document.getElementById('loading-state'); const quizInterface = document.getElementById('quiz-interface'); const errorState = document.getElementById('error-state'); // Determine if we are in "All Questions" mode based on the current URL const isAllMode = window.location.pathname.includes('/all'); const apiUrl = isAllMode ? '/api/quiz/questions?mode=all' : '/api/quiz/questions'; try { const response = await fetch(apiUrl); if (!response.ok) { throw new Error('Failed to fetch questions'); } questions = await response.json(); loadingState.style.display = 'none'; if (questions.length > 0) { quizInterface.style.display = 'block'; startQuiz(); } else { throw new Error('No questions received'); } } catch (error) { console.error(error); loadingState.style.display = 'none'; errorState.style.display = 'block'; } } // Resets game state and triggers the first question render. function startQuiz() { currentQuestionIndex = 0; score = 0; document.getElementById('total-q').textContent = questions.length; renderQuestion(); } // Handles DOM construction for the current question and answers. // Behavior: // - Randomizes answer order visually for every question // - Attaches correctness data to buttons for validation function renderQuestion() { isAnswered = false; const currentQ = questions[currentQuestionIndex]; // Reset UI and navigation states document.getElementById('next-btn').disabled = true; document.getElementById('feedback-container').style.display = 'none'; document.getElementById('feedback-container').className = 'feedback-box'; // Update progress markers and score display document.getElementById('current-q').textContent = currentQuestionIndex + 1; document.getElementById('score-tracker').textContent = `Score: ${score}`; const progressPercent = ((currentQuestionIndex) / questions.length) * 100; document.getElementById('progress-fill').style.width = `${progressPercent}%`; // Populate question text (English, Phonetic, and Thai) document.getElementById('question-text-en').textContent = currentQ.question; document.getElementById('question-text-ph').textContent = currentQ.question_ph; document.getElementById('question-text-th').textContent = currentQ.question_th; const answersContainer = document.getElementById('answers-container'); answersContainer.innerHTML = ''; // Shuffle answer array to prevent position-based guessing const shuffledAnswers = [...currentQ.answers].sort(() => Math.random() - 0.5); shuffledAnswers.forEach(answer => { const btn = document.createElement('button'); btn.className = 'answer-btn'; // Tag the button for validation during the handleAnswer phase btn.dataset.correct = answer.is_correct; btn.innerHTML = `
${answer.text}
${answer.ph}
${answer.th}
`; btn.onclick = () => handleAnswer(btn, answer.is_correct); answersContainer.appendChild(btn); }); } // Validates the user selection and provides immediate feedback. // Parameters: // selectedBtn : The DOM element clicked // isCorrect : Boolean result from the data source // Behavior: // - Highlights correct/incorrect choices // - Automatically scrolls to the bottom to show the Next button function handleAnswer(selectedBtn, isCorrect) { if (isAnswered) return; isAnswered = true; const allBtns = document.querySelectorAll('.answer-btn'); const feedbackContainer = document.getElementById('feedback-container'); const feedbackIcon = document.getElementById('feedback-icon'); const feedbackEn = document.getElementById('feedback-msg-en'); const feedbackTh = document.getElementById('feedback-msg-th'); const nextBtn = document.getElementById('next-btn'); allBtns.forEach(btn => btn.disabled = true); if (isCorrect) { score++; selectedBtn.classList.add('btn-success'); feedbackContainer.className = 'feedback-box alert-success'; feedbackIcon.textContent = '✅'; feedbackEn.textContent = 'Correct!'; feedbackTh.textContent = 'ถูกต้อง'; } else { selectedBtn.classList.add('btn-danger'); // Reveal the correct answer visually if the user was wrong const correctBtn = document.querySelector('.answer-btn[data-correct="true"]'); if (correctBtn) { correctBtn.classList.add('btn-success'); } feedbackContainer.className = 'feedback-box alert-danger'; feedbackIcon.textContent = '❌'; feedbackEn.textContent = 'Incorrect'; feedbackTh.textContent = 'ไม่ถูกต้อง'; } feedbackContainer.style.display = 'flex'; nextBtn.disabled = false; document.getElementById('score-tracker').textContent = `Score: ${score}`; // Ensure user sees the feedback and navigation button window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); } // Advances the question index and resets the viewport. // Targets multiple scroll containers to ensure cross-browser/mobile compatibility. function nextQuestion() { currentQuestionIndex++; const scrollTargets = [ document.documentElement, document.body, document.querySelector('.quiz-container') ]; scrollTargets.forEach(target => { if (target) target.scrollTop = 0; }); window.scrollTo({ top: 0, left: 0, behavior: 'instant' }); if (currentQuestionIndex < questions.length) { renderQuestion(); } else { finishQuiz(); } } // Renders the final score and results panel. function finishQuiz() { document.getElementById('quiz-interface').style.display = 'none'; document.getElementById('results-interface').style.display = 'block'; const percentage = Math.round((score / questions.length) * 100); const scoreDisplay = document.getElementById('final-score-display'); const resultMsg = document.getElementById('result-message'); scoreDisplay.textContent = `${percentage}%`; if (percentage >= 75) { scoreDisplay.style.color = 'var(--aus-green)'; resultMsg.innerHTML = `

Congratulations!

You passed the practice test.

ขอแสดงความยินดี! คุณสอบผ่านแบบทดสอบฝึกหัด

`; } else { scoreDisplay.style.color = 'var(--danger-red)'; resultMsg.innerHTML = `

Keep Practicing

You need 75% to pass.

ฝึกฝนต่อไป คุณต้องได้คะแนน 75% เพื่อสอบผ่าน

`; } } // Main event loop initialization document.addEventListener('DOMContentLoaded', function() { initQuiz(); document.getElementById('next-btn').addEventListener('click', nextQuestion); document.getElementById('restart-btn').addEventListener('click', function() { document.getElementById('results-interface').style.display = 'none'; document.getElementById('loading-state').style.display = 'block'; initQuiz(); }); });