/** * Crowd Pulse Quiz Panel */ import { escapeHTML, setHTML } from '../utils/dom.js'; export class CrowdPulsePanel { constructor(containerEl, crowdPulseService) { this.containerEl = containerEl; this.crowdPulseService = crowdPulseService; } render() { if (!this.containerEl) return; setHTML(this.containerEl, `
🧠

Waiting for match events...

AI-generated prediction questions will appear here

🏆 Match Leaderboard
#FanScoreStreak
`); this.updateLeaderboard(); } showQuestion(question) { const quizArea = this.containerEl?.querySelector('#active-quiz-area'); if (!quizArea) return; const safeQuestion = escapeHTML(question?.question || question?.text || 'Who will score next?'); const safeOptions = Array.isArray(question?.options) && question.options.length ? question.options.map((opt) => escapeHTML(opt)) : ['Yes', 'No']; setHTML(quizArea, `
LIVE PREDICTION
${safeQuestion}
${safeOptions.map((opt, idx) => ` `).join('')}
`); // Update an offscreen announcer to ensure screen readers detect the new question const announcer = this.containerEl?.querySelector('#active-quiz-announcer'); if (announcer) { // set textContent separately to trigger live region announcements announcer.textContent = safeQuestion; } quizArea.querySelectorAll('.quiz-opt-btn').forEach(btn => { btn.addEventListener('click', (e) => { const idx = parseInt(e.currentTarget.dataset.idx, 10); this.submitVote(question.id, idx); }); }); } submitVote(questionId, idx) { if (!this.crowdPulseService) return; const res = this.crowdPulseService.submitAnswer(questionId, idx); const quizArea = this.containerEl?.querySelector('#active-quiz-area'); const percentage = 40 + Math.round((String(questionId || '').charCodeAt(0) || 0) % 35) + (idx * 3) % 15; const pct = Math.min(95, Math.max(15, percentage)); if (quizArea) { const isCorrect = res.isCorrect; const resultText = isCorrect ? 'Correct! +10 pts' : 'Wrong prediction'; setHTML(quizArea, `
${isCorrect ? '✅' : '❌'}
${isCorrect ? 'Correct! +10 pts' : 'Wrong prediction'}
${pct}% of fans voted similarly
`); // Announce the result through the offscreen announcer for assistive tech const announcer = this.containerEl?.querySelector('#active-quiz-announcer'); if (announcer) announcer.textContent = resultText; } this.updateLeaderboard(); } updateLeaderboard() { if (!this.crowdPulseService) return; const tbody = this.containerEl?.querySelector('#leaderboard-body'); if (!tbody) return; const data = this.crowdPulseService.getLeaderboard(); setHTML(tbody, data.map((p, idx) => { const rank = Number.isFinite(Number(idx)) ? idx + 1 : ''; const name = escapeHTML(p?.name || 'Fan'); const score = Number.isFinite(Number(p?.score)) ? Number(p.score) : 0; const streak = Number.isFinite(Number(p?.streak)) ? Number(p.streak) : 0; const isUser = p?.id === 'p5'; return ` ${rank} ${name} ${score} 🔥 ${streak} `; }).join('')); } }