// Main application entry point class P2PPollApp { constructor() { this.peerManager = null; this.pollManager = null; this.uiController = null; this.isInitialized = false; } async initialize() { try { // Initialize peer manager this.peerManager = new PeerManager(); this.pollManager = new PollManager(this.peerManager); this.uiController = new UIController(this.peerManager, this.pollManager); // Set up event handlers this.setupEventHandlers(); // Initialize peer connection await this.peerManager.initialize(); // Load saved data this.pollManager.loadFromLocalStorage(); // If there are saved polls, update the sidebar const savedPolls = this.pollManager.getAvailablePolls(); if (savedPolls.length > 0) { this.uiController.updatePollsList(savedPolls); } this.isInitialized = true; console.log('P2P Poll App initialized successfully'); } catch (error) { console.error('Failed to initialize app:', error); this.uiController?.showNotification('Failed to initialize app: ' + error.message, 'error'); } } setupEventHandlers() { // Peer manager events this.peerManager.onConnectionStatusChange = (status, peerId) => { this.uiController.updatePeerId(peerId); if (status === 'connected') { this.uiController.showNotification('Connected to P2P network', 'success'); } else if (status === 'disconnected') { this.uiController.showNotification('Disconnected from P2P network', 'error'); } }; this.peerManager.onPeerConnected = (peerId) => { this.uiController.showNotification(`Peer ${peerId} connected`, 'success'); // If we're the host and have polls, send them to the new peer if (this.peerManager.isHost) { const availablePolls = this.pollManager.getAvailablePolls(); if (availablePolls.length > 0) { availablePolls.forEach(poll => { this.peerManager.sendMessage(peerId, { type: 'poll_update', poll: poll, senderId: this.peerManager.getPeerId() }); }); // Also send current poll if there is one const currentPoll = this.pollManager.getCurrentPoll(); if (currentPoll) { this.peerManager.sendMessage(peerId, { type: 'current_poll', poll: currentPoll, senderId: this.peerManager.getPeerId() }); } } } else { this.peerManager.sendMessage(peerId, { type: 'sync_request', senderId: this.peerManager.getPeerId() }); } }; this.peerManager.onPeerDisconnected = (peerId) => { this.uiController.showNotification(`Peer ${peerId} disconnected`, 'info'); }; this.peerManager.onMessageReceived = (message, senderId) => { this.handleMessage(message, senderId); }; // Poll manager events this.pollManager.onPollCreated = (poll) => { this.uiController.renderPoll(poll); }; this.pollManager.onPollUpdated = (poll) => { this.uiController.renderPoll(poll); }; this.pollManager.onPollSelected = (poll) => { if (poll) { this.uiController.renderPoll(poll); this.uiController.showActivePoll(); } else { this.uiController.showPollCreation(); } }; this.pollManager.onPollsListUpdated = (polls) => { this.uiController.updatePollsList(polls); }; } handleMessage(message, senderId) { console.log('Processing message:', message, 'from:', senderId); switch (message.type) { case 'poll_update': this.pollManager.syncPoll(message.poll); break; case 'current_poll': this.pollManager.syncPoll(message.poll); if (this.pollManager.getCurrentPoll() && this.pollManager.getCurrentPoll().id === message.poll.id) { this.uiController.renderPoll(message.poll); this.uiController.showActivePoll(); } break; case 'vote': this.pollManager.handleVoteMessage(message.optionId, message.voterId); break; case 'unvote': this.pollManager.handleUnvoteMessage(message.voterId); break; case 'poll_reset': this.pollManager.handlePollReset(); break; case 'sync_request': const currentPoll = this.pollManager.getCurrentPoll(); if (currentPoll) { this.peerManager.sendMessage(senderId, { type: 'current_poll', poll: currentPoll, senderId: this.peerManager.getPeerId() }); } const availablePolls = this.pollManager.getAvailablePolls(); availablePolls.forEach(poll => { this.peerManager.sendMessage(senderId, { type: 'poll_update', poll: poll, senderId: this.peerManager.getPeerId() }); }); break; default: console.warn('Unknown message type:', message.type); } } destroy() { if (this.peerManager) { this.peerManager.destroy(); } } } document.addEventListener('DOMContentLoaded', async () => { const app = new P2PPollApp(); try { await app.initialize(); } catch (error) { console.error('App initialization failed:', error); // Show error message to user const errorDiv = document.createElement('div'); errorDiv.className = 'notification error'; errorDiv.textContent = 'Failed to initialize app. Please refresh the page.'; errorDiv.style.position = 'fixed'; errorDiv.style.top = '20px'; errorDiv.style.right = '20px'; errorDiv.style.zIndex = '1001'; document.body.appendChild(errorDiv); } // Cleanup on page unload window.addEventListener('beforeunload', () => { app.destroy(); }); }); // Handle page visibility changes document.addEventListener('visibilitychange', () => { if (document.hidden) { console.log('Page hidden - connection may become unstable'); } else { console.log('Page visible - checking connection status'); } });