// What's That!? - Popup Script class PopupController { constructor() { this.currentTab = 'relationships'; this.stats = null; this.availableChats = []; this.selectedChat = null; this.init(); } init() { this.setupEventListeners(); this.loadAvailableChats(); this.loadStats(); this.checkWhatsAppStatus(); } setupEventListeners() { // Tab switching document.querySelectorAll('.tab-button').forEach(button => { button.addEventListener('click', (e) => { this.switchTab(e.target.dataset.tab); }); }); // Action buttons document.getElementById('refreshBtn').addEventListener('click', () => { this.loadStats(); }); document.getElementById('clearBtn').addEventListener('click', () => { this.clearData(); }); // Chat selector document.getElementById('chatSelect').addEventListener('change', (e) => { this.selectChat(e.target.value); }); document.getElementById('refreshChatsBtn').addEventListener('click', () => { this.loadAvailableChats(); }); } switchTab(tabName) { // Update tab buttons document.querySelectorAll('.tab-button').forEach(btn => { btn.classList.remove('active'); }); document.querySelector(`[data-tab="${tabName}"]`).classList.add('active'); // Update tab panels document.querySelectorAll('.tab-panel').forEach(panel => { panel.classList.remove('active'); }); document.getElementById(tabName).classList.add('active'); this.currentTab = tabName; this.renderCurrentTab(); } async loadStats() { try { this.showLoading(); // Request stats from background script const response = await chrome.runtime.sendMessage({ type: 'GET_STATS' }); if (response && response.stats) { this.stats = response.stats; this.updateOverview(); this.renderCurrentTab(); this.updateStatus('Data loaded successfully', 'success'); } else { this.updateStatus('No data available', 'warning'); this.showNoData(); } } catch (error) { console.error('Error loading stats:', error); this.updateStatus('Error loading data', 'error'); this.showError(); } } updateOverview() { if (!this.stats) return; document.getElementById('totalMessages').textContent = this.stats.totalMessages || 0; document.getElementById('totalReactions').textContent = this.stats.totalReactions || 0; } renderCurrentTab() { if (!this.stats) return; switch (this.currentTab) { case 'relationships': this.renderRelationships(); break; case 'by-sender': this.renderBySender(); break; case 'by-reactor': this.renderByReactor(); break; case 'top-reactions': this.renderTopReactions(); break; } } renderRelationships() { const container = document.querySelector('.relationships-content'); if (!this.stats.relationships || this.stats.relationships.length === 0) { container.innerHTML = '
No relationship data available
'; return; } let html = ''; // Show top 20 relationships this.stats.relationships.slice(0, 20).forEach((rel, index) => { const strengthPercent = (rel.strength * 100).toFixed(1); const likelihoodPercent = (rel.likelihood * 100).toFixed(1); const focusPercent = (rel.focus * 100).toFixed(1); html += `
${this.escapeHtml(rel.from)} ${this.escapeHtml(rel.to)}
${strengthPercent}% strength
Reactions
${rel.reactions}
total
Likelihood
${likelihoodPercent}%
${rel.reactions}/${rel.totalMessagesBy} msgs
Focus
${focusPercent}%
of their reactions
`; }); container.innerHTML = html; } renderBySender() { const container = document.getElementById('bySenderResults'); if (!this.stats.bySender || Object.keys(this.stats.bySender).length === 0) { container.innerHTML = '
No sender data available
'; return; } const html = Object.entries(this.stats.bySender) .sort((a, b) => { const aTotal = Object.values(a[1]).reduce((sum, count) => sum + count, 0); const bTotal = Object.values(b[1]).reduce((sum, count) => sum + count, 0); return bTotal - aTotal; }) .map(([sender, reactors]) => { const totalReactions = Object.values(reactors).reduce((sum, count) => sum + count, 0); const topReactor = Object.entries(reactors) .sort((a, b) => b[1] - a[1])[0]; return `
${this.escapeHtml(sender)} ${totalReactions} reactions
${Object.entries(reactors) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([reactor, count]) => `
${this.escapeHtml(reactor)} ${count}
`).join('')}
${topReactor ? `
Most reactions from: ${this.escapeHtml(topReactor[0])} (${topReactor[1]})
` : ''}
`; }).join(''); container.innerHTML = html; } renderByReactor() { const container = document.getElementById('byReactorResults'); if (!this.stats.byReactor || Object.keys(this.stats.byReactor).length === 0) { container.innerHTML = '
No reactor data available
'; return; } const html = Object.entries(this.stats.byReactor) .sort((a, b) => { const aTotal = Object.values(a[1]).reduce((sum, count) => sum + count, 0); const bTotal = Object.values(b[1]).reduce((sum, count) => sum + count, 0); return bTotal - aTotal; }) .map(([reactor, senders]) => { const totalReactions = Object.values(senders).reduce((sum, count) => sum + count, 0); const topSender = Object.entries(senders) .sort((a, b) => b[1] - a[1])[0]; return `
${this.escapeHtml(reactor)} ${totalReactions} reactions given
${Object.entries(senders) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([sender, count]) => `
${this.escapeHtml(sender)} ${count}
`).join('')}
${topSender ? `
Reacts most to: ${this.escapeHtml(topSender[0])} (${topSender[1]})
` : ''}
`; }).join(''); container.innerHTML = html; } renderTopReactions() { const container = document.getElementById('topReactionsResults'); if (!this.stats.topReactions || Object.keys(this.stats.topReactions).length === 0) { container.innerHTML = '
No top reactions data available
'; return; } const html = Object.entries(this.stats.topReactions) .map(([sender, reactors]) => `
${this.escapeHtml(sender)}
${Object.entries(reactors) .map(([reactor, count]) => `
${this.escapeHtml(reactor)} ${count}
`).join('')}
`).join(''); container.innerHTML = html; } async clearData() { if (confirm('Are you sure you want to clear all reaction data?')) { try { await chrome.runtime.sendMessage({ type: 'CLEAR_DATA' }); this.stats = null; this.updateOverview(); this.showNoData(); this.updateStatus('Data cleared', 'success'); } catch (error) { console.error('Error clearing data:', error); this.updateStatus('Error clearing data', 'error'); } } } checkWhatsAppStatus() { chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { const currentTab = tabs[0]; if (currentTab && currentTab.url.includes('web.whatsapp.com')) { this.updateStatus('WhatsApp Web detected', 'success'); } else { this.updateStatus('Open WhatsApp Web to start tracking', 'warning'); } }); } updateStatus(message, type) { const statusText = document.querySelector('.status-text'); const statusDot = document.querySelector('.status-dot'); statusText.textContent = message; statusDot.className = `status-dot ${type}`; } showLoading() { document.querySelectorAll('.results-container').forEach(container => { container.innerHTML = '
Loading data...
'; }); } showNoData() { document.querySelectorAll('.results-container').forEach(container => { container.innerHTML = '
No reaction data available yet. Start chatting on WhatsApp Web!
'; }); } showError() { document.querySelectorAll('.results-container').forEach(container => { container.innerHTML = '
Error loading data. Please try refreshing.
'; }); } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } async loadAvailableChats() { try { // Request available chats from content script const response = await chrome.runtime.sendMessage({ type: 'GET_AVAILABLE_CHATS' }); if (response && response.chats) { this.availableChats = response.chats; this.populateChatSelector(); } else { this.showChatSelectorError('No chats found'); } } catch (error) { console.error('Error loading chats:', error); this.showChatSelectorError('Error loading chats'); } } populateChatSelector() { const chatSelect = document.getElementById('chatSelect'); chatSelect.innerHTML = ''; if (this.availableChats.length === 0) { chatSelect.innerHTML = ''; return; } // Add default option const defaultOption = document.createElement('option'); defaultOption.value = ''; defaultOption.textContent = 'Select a chat/group...'; chatSelect.appendChild(defaultOption); // Add chat options this.availableChats.forEach(chat => { const option = document.createElement('option'); option.value = chat.id; option.textContent = chat.name; chatSelect.appendChild(option); }); } showChatSelectorError(message) { const chatSelect = document.getElementById('chatSelect'); chatSelect.innerHTML = ``; } async selectChat(chatId) { if (!chatId) { this.selectedChat = null; this.stats = null; this.updateOverview(); this.showNoData(); return; } this.selectedChat = chatId; try { // Request stats for the selected chat const response = await chrome.runtime.sendMessage({ type: 'GET_STATS_FOR_CHAT', chatId: chatId }); if (response && response.stats) { this.stats = response.stats; this.updateOverview(); this.renderCurrentTab(); this.updateStatus(`Data loaded for ${this.getChatName(chatId)}`, 'success'); } else { this.updateStatus('No data available for this chat', 'warning'); this.showNoData(); } } catch (error) { console.error('Error loading chat stats:', error); this.updateStatus('Error loading chat data', 'error'); this.showError(); } } getChatName(chatId) { const chat = this.availableChats.find(c => c.id === chatId); return chat ? chat.name : 'Unknown Chat'; } } // Initialize popup when DOM is loaded document.addEventListener('DOMContentLoaded', () => { new PopupController(); });