Smart Live Polling & Q&A Platform

Smart Live Polling & Q&A Platform

Engage your audience in real-time.

Active Poll

Waiting for the presenter to start a poll...

Ask a Question

Your User Information

Your anonymous User ID for this session is:

Loading...

Waiting for the presenter to start a poll...

`; return; } const hasVoted = localStorage.getItem(`voted_${poll.id}_${currentUserId}`); const optionsHTML = poll.options.map(option => ` `).join(''); activePollContainer.innerHTML = `

${poll.question}

${optionsHTML}
${hasVoted ? '

Thanks for voting!

' : ''} `; } function renderPollResults(poll) { const chartCanvas = document.getElementById('results-chart'); if (!poll) { pollResultsContainer.innerHTML = `

Start a poll to see live results.

`; chartCanvas.classList.add('hidden'); downloadPdfBtn.disabled = true; return; } chartCanvas.classList.remove('hidden'); downloadPdfBtn.disabled = false; const ctx = chartCanvas.getContext('2d'); const data = { labels: poll.options, datasets: [{ label: 'Votes', data: poll.options.map(opt => poll.votes[opt] || 0), backgroundColor: ['#60A5FA', '#34D399', '#FBBF24', '#A78BFA', '#F87171', '#fb923c'], borderColor: '#fff', borderWidth: 1 }] }; if (resultsChart) resultsChart.destroy(); resultsChart = new Chart(ctx, { type: 'bar', data: data, options: { indexAxis: 'y', responsive: true, plugins: { legend: { display: false } } } }); } function renderQuestionList(questions) { if (questions.length === 0) { questionList.innerHTML = `

No questions have been asked yet.

`; return; } questionList.innerHTML = questions.map(q => `

${q.text}

`).join(''); } // --- FIRESTORE ACTIONS --- async function createPoll(e) { e.preventDefault(); const question = document.getElementById('poll-question').value; const options = Array.from(document.querySelectorAll('input[name="poll-option"]')).map(el => el.value.trim()).filter(Boolean); if (question && options.length > 1) { const votes = options.reduce((acc, opt) => ({ ...acc, [opt]: 0 }), {}); await addDoc(collection(db, `/artifacts/${appId}/public/data/polls`), { question, options, votes, isActive: false, timestamp: serverTimestamp() }); createPollForm.reset(); document.getElementById('poll-options-container').innerHTML = ` `; } } async function startPoll(pollId) { const pollsRef = collection(db, `/artifacts/${appId}/public/data/polls`); const batch = writeBatch(db); const snapshot = await getDocs(pollsRef); snapshot.forEach(doc => { batch.update(doc.ref, { isActive: doc.id === pollId }); }); await batch.commit(); } async function submitVote(pollId, option) { if (localStorage.getItem(`voted_${pollId}_${currentUserId}`)) return; const pollRef = doc(db, `/artifacts/${appId}/public/data/polls`, pollId); await updateDoc(pollRef, { [`votes.${option}`]: increment(1) }); localStorage.setItem(`voted_${pollId}_${currentUserId}`, 'true'); } async function askQuestion(e) { e.preventDefault(); const input = document.getElementById('question-input'); const text = input.value.trim(); if (text) { await addDoc(collection(db, `/artifacts/${appId}/public/data/questions`), { text, submitterId: currentUserId, isAnswered: false, timestamp: serverTimestamp() }); input.value = ''; } } async function toggleAnswered(questionId, isAnswered) { const questionRef = doc(db, `/artifacts/${appId}/public/data/questions`, questionId); await updateDoc(questionRef, { isAnswered: !isAnswered }); } // --- EVENT HANDLERS & HELPERS --- addOptionBtn.addEventListener('click', () => { const container = document.getElementById('poll-options-container'); const newOption = document.createElement('input'); newOption.type = 'text'; newOption.name = 'poll-option'; newOption.placeholder = `Option ${container.children.length + 1}`; newOption.className = 'w-full p-2 border rounded-md'; container.appendChild(newOption); }); function generatePdf() { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); const pdfTitleEl = document.getElementById('pdf-title'); if (!pdfContent || downloadPdfBtn.disabled) return; pdfTitleEl.textContent = 'Live Poll Results Summary'; html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false }) .then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const ratio = canvas.width / canvas.height; const imgHeight = (pdfWidth - 20) / ratio; pdf.addImage(imgData, 'PNG', 10, 10, pdfWidth - 20, imgHeight); pdf.save('Poll-Results.pdf'); pdfTitleEl.textContent = ''; }); } function addEventListeners() { tabButtons.forEach(button => { button.addEventListener('click', () => { const tab = button.dataset.tab; tabButtons.forEach(btn => btn.classList.toggle('active', btn.dataset.tab === tab)); tabContents.forEach(content => content.classList.toggle('active', content.id.startsWith(tab))); }); }); viewToggles.forEach(toggle => { toggle.addEventListener('change', () => { audienceView.classList.toggle('hidden', toggle.id === 'presenter-view-toggle'); presenterView.classList.toggle('hidden', toggle.id === 'audience-view-toggle'); }); }); createPollForm.addEventListener('submit', createPoll); pollList.addEventListener('click', e => { if (e.target.classList.contains('start-poll-btn')) startPoll(e.target.dataset.id); }); activePollContainer.addEventListener('click', e => { if (e.target.classList.contains('vote-btn')) submitVote(e.target.dataset.pollId, e.target.dataset.option); }); askQuestionForm.addEventListener('submit', askQuestion); questionList.addEventListener('click', e => { if (e.target.classList.contains('toggle-answered-btn')) { toggleAnswered(e.target.dataset.id, e.target.dataset.answered === 'true'); } }); downloadPdfBtn.addEventListener('click', generatePdf); } initialize();
Scroll to Top