Platform Analytics Dashboard

Platform Analytics Dashboard

Track followers, views, and revenue across Twitch, YouTube, etc.

Overall Performance

Follower Growth Over Time

Views by Platform

Recent Performance Log

Date Platform Views New Followers Revenue

Enter Daily Platform Data

${formatNumber(totalViews)}

Total Revenue

${formatCurrency(totalRevenue)}

Avg. Revenue/View

$${avgRevenuePerView.toFixed(4)}

`; }; const renderDataTable = () => { dataTableBody.innerHTML = ''; const sortedLogs = [...state.logs].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedLogs.forEach(log => { const row = ` ${log.date} ${log.platform} ${formatNumber(log.views)} ${formatNumber(log.followers)} ${formatCurrency(log.revenue)} `; dataTableBody.innerHTML += row; }); }; const renderCharts = () => { // Follower Growth Chart with Plotly const followersByDate = state.logs.reduce((acc, log) => { acc[log.date] = (acc[log.date] || 0) + log.followers; return acc; }, {}); const sortedDates = Object.keys(followersByDate).sort((a, b) => new Date(a) - new Date(b)); const followerTrace = { x: sortedDates, y: sortedDates.map(date => followersByDate[date]), type: 'scatter', mode: 'lines+markers', line: { color: '#8b5cf6' } }; const followerLayout = { margin: { l: 50, r: 20, b: 40, t: 20 }, xaxis: { title: 'Date' }, yaxis: { title: 'New Followers' } }; Plotly.newPlot('followerTrendChart', [followerTrace], followerLayout, {responsive: true}); // Views by Platform with Plotly const viewsByPlatform = state.logs.reduce((acc, log) => { acc[log.platform] = (acc[log.platform] || 0) + log.views; return acc; }, {}); const platformLabels = Object.keys(viewsByPlatform); const platformData = platformLabels.map(label => viewsByPlatform[label]); const platformTrace = { labels: platformLabels, values: platformData, type: 'pie', hole: 0.4, marker: { colors: ['#FF0000', '#9146FF', '#000000'] // YouTube, Twitch, TikTok } }; const platformLayout = { margin: { l: 20, r: 20, b: 20, t: 40 }, showlegend: true }; Plotly.newPlot('platformChart', [platformTrace], platformLayout, {responsive: true}); }; const renderConfigRows = () => { configRowsContainer.innerHTML = ''; const sortedLogs = [...state.logs].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedLogs.forEach(log => { configRowsContainer.innerHTML += `
`.replaceAll('class="config-input"', 'class="config-input w-full border-gray-300 rounded-md shadow-sm"'); }); addConfigEventListeners(); }; // --- EVENT HANDLERS --- const handleConfigChange = (e) => { const id = parseInt(e.target.dataset.id); const field = e.target.dataset.field; const value = (e.target.type === 'number') ? parseFloat(e.target.value) || 0 : e.target.value; const log = state.logs.find(l => l.id === id); if (log) log[field] = value; renderAll(); }; const handleAddLog = () => { const newId = state.logs.length > 0 ? Math.max(...state.logs.map(l => l.id)) + 1 : 1; const today = new Date().toISOString().split('T')[0]; state.logs.push({ id: newId, date: today, platform: "YouTube", views: 0, followers: 0, revenue: 0 }); renderAll(); }; const handleRemoveLog = (e) => { const id = parseInt(e.target.dataset.id); state.logs = state.logs.filter(l => l.id !== id); renderAll(); }; const addConfigEventListeners = () => { document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange)); document.querySelectorAll('.remove-btn').forEach(button => button.addEventListener('click', handleRemoveLog)); }; const handleDownloadPdf = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden'); html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible'); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgWidth = pdfWidth - 20; const imgHeight = canvas.height * imgWidth / canvas.width; pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight); pdf.save('Platform-Analytics-Dashboard.pdf'); }); }; // --- TABBING LOGIC --- let currentTabIndex = 0; const updateTabButtons = () => { prevTabBtn.disabled = currentTabIndex === 0; nextTabBtn.disabled = currentTabIndex === tabContents.length - 1; }; const switchTab = (index) => { tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); tabButtons[index].classList.add('active'); tabContents[index].classList.add('active'); currentTabIndex = index; updateTabButtons(); if (index === 0) { // Redraw plotly charts on tab switch to ensure correct sizing setTimeout(renderCharts, 10); } }; tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index))); prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); }); // --- INITIALIZATION --- if (kpiContainer && addLogBtn && downloadPdfBtn) { addLogBtn.addEventListener('click', handleAddLog); downloadPdfBtn.addEventListener('click', handleDownloadPdf); renderAll(); updateTabButtons(); } else { console.error("Essential dashboard elements could not be found."); } });
Scroll to Top