// ────────────────────────────── static/quiz.js ────────────────────────────── (function() { // Quiz state let currentQuiz = null; let currentQuestionIndex = 0; let quizAnswers = {}; let quizTimer = null; let timeRemaining = 0; let quizSetupStep = 1; // DOM elements const quizLink = document.getElementById('quiz-link'); const quizSetupModal = document.getElementById('quiz-setup-modal'); const quizModal = document.getElementById('quiz-modal'); const quizResultsModal = document.getElementById('quiz-results-modal'); const quizSetupForm = document.getElementById('quiz-setup-form'); const quizQuestionsInput = document.getElementById('quiz-questions-input'); const quizTimeLimit = document.getElementById('quiz-time-limit'); const quizDocumentList = document.getElementById('quiz-document-list'); const quizPrevStep = document.getElementById('quiz-prev-step'); const quizNextStep = document.getElementById('quiz-next-step'); const quizCancel = document.getElementById('quiz-cancel'); const quizSubmit = document.getElementById('quiz-submit'); const quizTimerElement = document.getElementById('quiz-timer'); const quizProgressFill = document.getElementById('quiz-progress-fill'); const quizProgressText = document.getElementById('quiz-progress-text'); const quizQuestion = document.getElementById('quiz-question'); const quizAnswers = document.getElementById('quiz-answers'); const quizPrev = document.getElementById('quiz-prev'); const quizNext = document.getElementById('quiz-next'); const quizSubmitBtn = document.getElementById('quiz-submit'); const quizResultsContent = document.getElementById('quiz-results-content'); const quizResultsClose = document.getElementById('quiz-results-close'); // Initialize init(); function init() { setupEventListeners(); } function setupEventListeners() { // Quiz link if (quizLink) { quizLink.addEventListener('click', (e) => { e.preventDefault(); openQuizSetup(); }); } // Quiz setup form if (quizSetupForm) { quizSetupForm.addEventListener('submit', handleQuizSetupSubmit); } // Quiz setup navigation if (quizNextStep) { quizNextStep.addEventListener('click', nextQuizStep); } if (quizPrevStep) { quizPrevStep.addEventListener('click', prevQuizStep); } if (quizCancel) { quizCancel.addEventListener('click', closeQuizSetup); } // Quiz navigation if (quizPrev) { quizPrev.addEventListener('click', prevQuestion); } if (quizNext) { quizNext.addEventListener('click', nextQuestion); } if (quizSubmitBtn) { quizSubmitBtn.addEventListener('click', submitQuiz); } // Quiz results if (quizResultsClose) { quizResultsClose.addEventListener('click', closeQuizResults); } // Close modals on outside click document.addEventListener('click', (e) => { if (e.target.classList.contains('modal')) { closeAllQuizModals(); } }); } async function openQuizSetup() { const user = window.__sb_get_user(); if (!user) { alert('Please sign in to create a quiz'); window.__sb_show_auth_modal(); return; } const currentProject = window.__sb_get_current_project && window.__sb_get_current_project(); if (!currentProject) { alert('Please select a project first'); return; } // Load available documents await loadQuizDocuments(); // Reset form quizSetupStep = 1; updateQuizSetupStep(); // Show modal quizSetupModal.classList.remove('hidden'); } async function loadQuizDocuments() { const user = window.__sb_get_user(); const currentProject = window.__sb_get_current_project && window.__sb_get_current_project(); if (!user || !currentProject) return; try { const res = await fetch(`/files?user_id=${encodeURIComponent(user.user_id)}&project_id=${encodeURIComponent(currentProject.project_id)}`); if (!res.ok) return; const data = await res.json(); const files = data.files || []; // Clear existing documents quizDocumentList.innerHTML = ''; if (files.length === 0) { quizDocumentList.innerHTML = '
${question.question}
`; // Show answers if (question.type === 'mcq') { showMCQAnswers(question); } else if (question.type === 'self_reflect') { showSelfReflectAnswer(question); } // Update navigation quizPrev.disabled = index === 0; quizNext.style.display = index < currentQuiz.questions.length - 1 ? 'inline-flex' : 'none'; quizSubmitBtn.style.display = index === currentQuiz.questions.length - 1 ? 'inline-flex' : 'none'; } function showMCQAnswers(question) { quizAnswers.innerHTML = ''; question.options.forEach((option, index) => { const optionDiv = document.createElement('div'); optionDiv.className = 'quiz-answer-option'; optionDiv.innerHTML = ` `; // Check if already answered if (quizAnswers[currentQuestionIndex] !== undefined) { const radio = optionDiv.querySelector('input[type="radio"]'); radio.checked = quizAnswers[currentQuestionIndex] === index; if (radio.checked) { optionDiv.classList.add('selected'); } } // Add click handler optionDiv.addEventListener('click', () => { // Remove selection from other options quizAnswers.querySelectorAll('.quiz-answer-option').forEach(opt => { opt.classList.remove('selected'); }); // Select this option optionDiv.classList.add('selected'); const radio = optionDiv.querySelector('input[type="radio"]'); radio.checked = true; // Save answer quizAnswers[currentQuestionIndex] = index; }); quizAnswers.appendChild(optionDiv); }); } function showSelfReflectAnswer(question) { quizAnswers.innerHTML = ` `; const textarea = quizAnswers.querySelector('textarea'); textarea.addEventListener('input', (e) => { quizAnswers[currentQuestionIndex] = e.target.value; }); } function prevQuestion() { if (currentQuestionIndex > 0) { showQuestion(currentQuestionIndex - 1); } } function nextQuestion() { if (currentQuestionIndex < currentQuiz.questions.length - 1) { showQuestion(currentQuestionIndex + 1); } } async function submitQuiz() { if (quizTimer) { clearInterval(quizTimer); } // Validate that all questions are answered const unansweredQuestions = []; for (let i = 0; i < currentQuiz.questions.length; i++) { if (quizAnswers[i] === undefined || quizAnswers[i] === null || quizAnswers[i] === '') { unansweredQuestions.push(i + 1); } } if (unansweredQuestions.length > 0) { const confirmSubmit = confirm(`You have ${unansweredQuestions.length} unanswered questions (${unansweredQuestions.join(', ')}). Do you want to submit anyway?`); if (!confirmSubmit) { return; } } // Show loading with progress showLoading('Submitting quiz...'); updateLoadingProgress('Processing your answers...', 30); try { const user = window.__sb_get_user(); const currentProject = window.__sb_get_current_project && window.__sb_get_current_project(); updateLoadingProgress('Marking your answers...', 60); const formData = new FormData(); formData.append('user_id', user.user_id); formData.append('project_id', currentProject.project_id); formData.append('quiz_id', currentQuiz.quiz_id); formData.append('answers', JSON.stringify(quizAnswers)); const response = await fetch('/quiz/submit', { method: 'POST', body: formData }); const data = await response.json(); if (response.ok) { updateLoadingProgress('Generating feedback...', 90); // Simulate processing time for better UX await new Promise(resolve => setTimeout(resolve, 1500)); hideLoading(); closeQuizModal(); showQuizResults(data.results); } else { hideLoading(); showNotification(data.detail || 'Failed to submit quiz', 'error'); } } catch (error) { hideLoading(); console.error('Quiz submission failed:', error); showNotification('Failed to submit quiz. Please try again.', 'error'); } } function showQuizResults(results) { // Show results summary const totalQuestions = results.questions.length; const correctAnswers = results.questions.filter(q => q.status === 'correct').length; const partialAnswers = results.questions.filter(q => q.status === 'partial').length; const incorrectAnswers = results.questions.filter(q => q.status === 'incorrect').length; const score = Math.round((correctAnswers + partialAnswers * 0.5) / totalQuestions * 100); // Determine performance level let performanceLevel = 'Needs Improvement'; let performanceColor = 'var(--error)'; if (score >= 90) { performanceLevel = 'Excellent'; performanceColor = 'var(--success)'; } else if (score >= 80) { performanceLevel = 'Good'; performanceColor = 'var(--accent)'; } else if (score >= 70) { performanceLevel = 'Satisfactory'; performanceColor = 'var(--warning)'; } quizResultsContent.innerHTML = `