class UIController { constructor(peerManager, pollManager) { this.peerManager = peerManager; this.pollManager = pollManager; this.initializeEventListeners(); } initializeEventListeners() { // Connection controls document.getElementById('join-btn').addEventListener('click', () => this.handleJoinRoom()); document.getElementById('copy-id-btn').addEventListener('click', () => this.copyPeerId()); // Poll creation document.getElementById('create-poll-btn').addEventListener('click', () => this.handleCreatePoll()); document.getElementById('add-option-btn').addEventListener('click', () => this.addOptionInput()); // Active poll document.getElementById('add-poll-option-btn').addEventListener('click', () => this.showAddOptionModal()); document.getElementById('reset-poll-btn').addEventListener('click', () => this.handleResetPoll()); document.getElementById('new-poll-btn').addEventListener('click', () => this.handleNewPoll()); // Modal controls document.getElementById('close-modal-btn').addEventListener('click', () => this.hideAddOptionModal()); document.getElementById('cancel-modal-btn').addEventListener('click', () => this.hideAddOptionModal()); document.getElementById('save-option-btn').addEventListener('click', () => this.handleAddOptionFromModal()); // Enter key handlers document.getElementById('room-id').addEventListener('keypress', (e) => { if (e.key === 'Enter') this.handleJoinRoom(); }); document.getElementById('poll-question').addEventListener('keypress', (e) => { if (e.key === 'Enter') this.handleCreatePoll(); }); document.getElementById('new-option-input').addEventListener('keypress', (e) => { if (e.key === 'Enter') this.handleAddOptionFromModal(); }); // Close modal on background click document.getElementById('add-option-modal').addEventListener('click', (e) => { if (e.target.id === 'add-option-modal') { this.hideAddOptionModal(); } }); } handleJoinRoom() { const roomIdInput = document.getElementById('room-id'); const peerId = roomIdInput.value.trim(); this.showLoading(true); if (peerId) { // Connect to existing peer (host) this.peerManager.joinRoom(peerId) .then(() => { this.showNotification('Connected to host successfully!', 'success'); this.showPollCreation(); }) .catch(error => { this.showNotification('Failed to connect: ' + error.message, 'error'); console.error('Connect error:', error); }) .finally(() => { this.showLoading(false); }); } else { // Act as host - just show poll creation this.peerManager.createRoom(); this.showNotification('You are the host. Share your Peer ID with others to connect.', 'success'); this.showPollCreation(); this.showLoading(false); } } async copyPeerId() { const peerId = this.peerManager.getPeerId(); if (peerId) { try { await navigator.clipboard.writeText(peerId); this.showNotification('Peer ID copied to clipboard!', 'success'); } catch (error) { // Fallback for older browsers const textArea = document.createElement('textarea'); textArea.value = peerId; document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); this.showNotification('Peer ID copied to clipboard!', 'success'); } } } handleCreatePoll() { const questionInput = document.getElementById('poll-question'); const optionInputs = document.querySelectorAll('.option-text'); const options = []; console.log('Question input:', questionInput); console.log('Found option inputs:', optionInputs.length); // Check if question input exists if (!questionInput) { console.error('Question input not found!'); this.showNotification('Error: Question input not found', 'error'); return; } const question = questionInput.value ? questionInput.value.trim() : ''; console.log('Question:', question); optionInputs.forEach((input, index) => { console.log(`Input ${index}:`, input, 'value:', input?.value); if (input && typeof input.value !== 'undefined') { const text = input.value.trim(); if (text) { options.push(text); } } else { console.warn(`Input ${index} is invalid or has no value property`); } }); console.log('Final options:', options); if (!question) { this.showNotification('Please enter a poll question', 'error'); return; } if (options.length < 2) { this.showNotification('Please enter at least 2 options', 'error'); return; } try { this.pollManager.createPoll(question, options); this.showNotification('Poll created successfully!', 'success'); } catch (error) { console.error('Create poll error:', error); this.showNotification('Failed to create poll: ' + error.message, 'error'); } } showAddOptionModal() { const modal = document.getElementById('add-option-modal'); const input = document.getElementById('new-option-input'); modal.classList.remove('hidden'); input.value = ''; input.focus(); } hideAddOptionModal() { const modal = document.getElementById('add-option-modal'); const input = document.getElementById('new-option-input'); modal.classList.add('hidden'); input.value = ''; } handleAddOptionFromModal() { const input = document.getElementById('new-option-input'); const optionText = input.value.trim(); if (!optionText) { this.showNotification('Please enter an option text', 'error'); return; } try { this.pollManager.addOption(optionText); this.hideAddOptionModal(); this.showNotification('Option added successfully!', 'success'); } catch (error) { this.showNotification('Failed to add option: ' + error.message, 'error'); } } handleAddPollOption() { this.showAddOptionModal(); } handleResetPoll() { if (confirm('Are you sure you want to reset all votes?')) { try { this.pollManager.resetPoll(); this.showNotification('Poll reset successfully!', 'success'); } catch (error) { this.showNotification('Failed to reset poll: ' + error.message, 'error'); } } } handleNewPoll() { this.pollManager.createNewPoll(); this.showPollCreation(); this.clearPollForm(); } addOptionInput() { const container = document.getElementById('options-container'); const optionCount = container.children.length; const optionDiv = document.createElement('div'); optionDiv.className = 'option-input'; optionDiv.innerHTML = ` `; container.appendChild(optionDiv); this.updateOptionRemoveButtons(); // Add event listener to new input const newInput = optionDiv.querySelector('.option-text'); newInput.addEventListener('keypress', (e) => { if (e.key === 'Enter') this.handleCreatePoll(); }); // Add event listener to remove button const removeBtn = optionDiv.querySelector('.remove-option-btn'); removeBtn.addEventListener('click', () => { optionDiv.remove(); this.updateOptionRemoveButtons(); this.updateOptionPlaceholders(); }); // Focus on new input newInput.focus(); } updateOptionRemoveButtons() { const optionInputs = document.querySelectorAll('.option-input'); const removeButtons = document.querySelectorAll('.remove-option-btn'); removeButtons.forEach((btn, index) => { if (optionInputs.length <= 2) { btn.classList.add('hidden'); } else { btn.classList.remove('hidden'); } }); } updateOptionPlaceholders() { const optionInputs = document.querySelectorAll('.option-text'); optionInputs.forEach((input, index) => { input.placeholder = `Option ${index + 1}`; }); } clearPollForm() { document.getElementById('poll-question').value = ''; const container = document.getElementById('options-container'); container.innerHTML = `
`; this.updateOptionRemoveButtons(); } showPollCreation() { document.getElementById('connection-section').classList.add('hidden'); document.getElementById('poll-creation').classList.remove('hidden'); document.getElementById('active-poll').classList.add('hidden'); } showActivePoll() { document.getElementById('connection-section').classList.add('hidden'); document.getElementById('poll-creation').classList.add('hidden'); document.getElementById('active-poll').classList.remove('hidden'); } updatePeerId(peerId) { const element = document.getElementById('peer-id'); if (element) { element.textContent = peerId || 'Loading...'; } } renderPoll(poll) { if (!poll) return; this.showActivePoll(); // Update poll question document.getElementById('poll-question-display').textContent = poll.question; // Render options const optionsContainer = document.getElementById('poll-options'); optionsContainer.innerHTML = ''; const totalVotes = poll.options.reduce((sum, opt) => sum + opt.votes, 0); const myVotedOption = this.pollManager.getMyVotedOption(); poll.options.forEach(option => { const optionDiv = document.createElement('div'); optionDiv.className = 'poll-option'; const hasVoted = this.pollManager.hasVoted(option.id); const myVotedOption = this.pollManager.getMyVotedOption(); console.log(`Option ${option.id}: hasVoted=${hasVoted}, myVotedOption=${myVotedOption}`); if (hasVoted) { optionDiv.classList.add('voted'); } else if (myVotedOption) { // User has voted but not for this option - this is a change vote option optionDiv.classList.add('change-vote'); } const percentage = totalVotes > 0 ? (option.votes / totalVotes * 100).toFixed(1) : 0; optionDiv.innerHTML = `
${option.text} ${option.votes} votes
`; optionDiv.addEventListener('click', () => { const myVotedOption = this.pollManager.getMyVotedOption(); if (this.pollManager.hasVoted(option.id)) { // Clicking your current vote - unvote if (confirm('Remove your vote?')) { const success = this.pollManager.unvote(); if (success) { this.showNotification('Vote removed!', 'success'); } } } else { // Either first vote or changing vote const success = this.pollManager.vote(option.id); if (success) { if (myVotedOption) { this.showNotification('Vote changed successfully!', 'success'); } else { this.showNotification('Vote recorded!', 'success'); } } } }); optionsContainer.appendChild(optionDiv); }); } showNotification(message, type = 'info') { const notification = document.getElementById('notification'); notification.textContent = message; notification.className = `notification ${type}`; notification.classList.remove('hidden'); setTimeout(() => { notification.classList.add('hidden'); }, 3000); } showLoading(show) { const overlay = document.getElementById('loading-overlay'); if (show) { overlay.classList.remove('hidden'); } else { overlay.classList.add('hidden'); } } updatePeersList() { // Use the peer manager's updatePeersList method this.peerManager.updatePeersList(); } updatePollsList(polls) { const pollsList = document.getElementById('polls-list'); if (!pollsList) return; if (polls.length === 0) { pollsList.innerHTML = '

No polls created yet

'; return; } pollsList.innerHTML = ''; polls.forEach(poll => { const pollDiv = document.createElement('div'); pollDiv.className = 'poll-item'; if (this.pollManager.getCurrentPoll() && this.pollManager.getCurrentPoll().id === poll.id) { pollDiv.classList.add('active'); } const totalVotes = poll.options.reduce((sum, opt) => sum + opt.votes, 0); const createdDate = new Date(poll.createdAt).toLocaleString(); pollDiv.innerHTML = `
${poll.question}
${totalVotes} votes • ${createdDate}
`; pollDiv.addEventListener('click', () => { this.pollManager.selectPoll(poll.id); }); pollsList.appendChild(pollDiv); }); } }