// Practice Mode Module
class PracticeMode extends BaseModule {
constructor() {
super();
this.sessionStats = {
correct: 0,
incorrect: 0,
total: 0
};
this.answered = false;
this.init();
}
init() {
this.setupEventListeners();
}
setupEventListeners() {
document.getElementById('start-practice')?.addEventListener('click', () => {
this.startPractice();
});
document.getElementById('new-session')?.addEventListener('click', () => {
this.resetSession();
});
document.getElementById('skip-question')?.addEventListener('click', () => {
this.nextQuestion();
});
document.getElementById('next-question')?.addEventListener('click', () => {
this.nextQuestion();
});
document.getElementById('practice-again')?.addEventListener('click', () => {
this.resetSession();
this.startPractice();
});
}
async startPractice() {
const count = parseInt(document.getElementById('question-count').value);
this.showLoading();
BaseModule.hide('welcome-message');
BaseModule.hide('practice-content');
BaseModule.hide('practice-complete');
try {
const data = await this.fetchQuestions({
mode: 'random',
count: count
});
this.questions = data;
this.currentIndex = 0;
this.resetSession();
this.displayQuestion();
this.hideLoading();
BaseModule.show('practice-content');
} catch (error) {
this.hideLoading();
console.error('Error in startPractice:', error);
}
}
displayQuestion() {
if (this.currentIndex >= this.questions.length) {
this.showResults();
return;
}
const question = this.questions[this.currentIndex];
this.answered = false;
let html = `
Pregunta ${question.id}
${this.currentIndex + 1} de ${this.questions.length}
`;
if (question.has_image && question.image) {
html += `

`;
}
html += `
${question.question}
`;
html += '
';
question.options.forEach((option, index) => {
const letter = String.fromCharCode(97 + index); // a, b, c, d
html += `
`;
});
html += '
';
html += '
';
html += '
';
document.getElementById('question-container').innerHTML = html;
document.getElementById('question-counter').textContent = `${this.currentIndex + 1} de ${this.questions.length}`;
// Setup option click handlers
this.setupOptionHandlers(question);
BaseModule.show('skip-question');
BaseModule.hide('next-question');
// Setup keyboard shortcuts
this.setupKeyboardHandlers();
}
setupOptionHandlers(question) {
const optionButtons = document.querySelectorAll('.option-enhanced');
optionButtons.forEach(button => {
button.addEventListener('click', () => {
if (this.answered) return;
this.playSound('click');
button.classList.add('selected');
const selectedAnswer = button.getAttribute('data-answer');
this.checkAnswer(selectedAnswer, question);
});
});
}
setupKeyboardHandlers() {
document.removeEventListener('keydown', this.practiceKeyHandler);
document.addEventListener('keydown', this.practiceKeyHandler.bind(this));
}
practiceKeyHandler(e) {
if (this.answered) return;
const key = e.key.toLowerCase();
if (['a', 'b', 'c', 'd'].includes(key)) {
e.preventDefault();
const optionButton = document.querySelector(`.option-enhanced[data-answer="${key}"]`);
if (optionButton) {
optionButton.click();
}
}
}
checkAnswer(selectedAnswer, question) {
if (this.answered) return;
this.answered = true;
const isCorrect = selectedAnswer === question.correct;
// Update session stats
this.sessionStats.total++;
if (isCorrect) {
this.sessionStats.correct++;
this.playSound('correct');
} else {
this.sessionStats.incorrect++;
this.playSound('incorrect');
}
this.updateSessionStats();
// Update global stats
if (window.statsManager) {
window.statsManager.updateStats(isCorrect);
}
// Show feedback
this.showFeedback(isCorrect, question);
BaseModule.hide('skip-question');
BaseModule.show('next-question');
}
showFeedback(isCorrect, question) {
const optionButtons = document.querySelectorAll('.option-enhanced');
optionButtons.forEach(button => {
const answer = button.getAttribute('data-answer');
if (answer === question.correct) {
button.classList.add('correct');
} else if (button.classList.contains('selected') && !isCorrect) {
button.classList.add('incorrect');
}
button.style.pointerEvents = 'none';
});
let feedbackHtml = '';
if (isCorrect) {
feedbackHtml = `
¡Excelente!
Has seleccionado la respuesta correcta.
`;
} else {
feedbackHtml = `
Respuesta incorrecta
La respuesta correcta es: ${question.correct.toUpperCase()})
`;
}
const feedbackElement = document.getElementById('feedback');
feedbackElement.innerHTML = feedbackHtml;
feedbackElement.style.display = 'none';
feedbackElement.style.opacity = '0';
feedbackElement.style.display = 'block';
// Fade in effect
setTimeout(() => {
feedbackElement.style.transition = 'opacity 0.3s ease';
feedbackElement.style.opacity = '1';
}, 10);
}
nextQuestion() {
document.removeEventListener('keydown', this.practiceKeyHandler);
this.currentIndex++;
this.displayQuestion();
}
updateSessionStats() {
document.getElementById('session-correct').textContent = this.sessionStats.correct;
document.getElementById('session-incorrect').textContent = this.sessionStats.incorrect;
const accuracy = this.sessionStats.total > 0 ?
Math.round((this.sessionStats.correct / this.sessionStats.total) * 100) : 0;
document.getElementById('session-accuracy').textContent = accuracy + '%';
// Update progress bar
const progressBar = document.getElementById('session-progress');
progressBar.style.width = accuracy + '%';
// Change bar color based on accuracy
progressBar.classList.remove('bg-danger', 'bg-warning', 'bg-success', 'bg-light');
if (accuracy >= 80) {
progressBar.classList.add('bg-success');
} else if (accuracy >= 60) {
progressBar.classList.add('bg-warning');
} else if (accuracy > 0) {
progressBar.classList.add('bg-danger');
} else {
progressBar.classList.add('bg-light');
}
}
resetSession() {
this.sessionStats = {
correct: 0,
incorrect: 0,
total: 0
};
this.updateSessionStats();
}
showResults() {
const accuracy = this.sessionStats.total > 0 ?
Math.round((this.sessionStats.correct / this.sessionStats.total) * 100) : 0;
document.getElementById('final-correct').textContent = this.sessionStats.correct;
document.getElementById('final-incorrect').textContent = this.sessionStats.incorrect;
document.getElementById('final-accuracy').textContent = accuracy + '%';
const finalProgress = document.getElementById('final-progress');
finalProgress.style.width = accuracy + '%';
// Change final progress bar color
finalProgress.classList.remove('bg-danger', 'bg-warning', 'bg-success');
if (accuracy >= 80) {
finalProgress.classList.add('bg-success');
if (window.Utils) {
Utils.createConfetti();
Utils.playSound('complete');
Utils.showNotification('¡Excelente trabajo! Has obtenido una puntuación sobresaliente.', 'success');
}
} else if (accuracy >= 60) {
finalProgress.classList.add('bg-warning');
if (window.Utils) {
Utils.playSound('complete');
Utils.showNotification('¡Buen trabajo! Sigue practicando para mejorar.', 'warning');
}
} else {
finalProgress.classList.add('bg-danger');
if (window.Utils) {
Utils.showNotification('Sigue estudiando. La práctica hace al maestro.', 'info');
}
}
BaseModule.hide('practice-content');
BaseModule.show('practice-complete');
}
}
// Auto-initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
if (document.getElementById('practice-content')) {
window.practiceMode = new PracticeMode();
}
});
// Export for global use
window.PracticeMode = PracticeMode;