Post Performance Analysis Dashboard

Post Performance Analysis

Analyze engagement, reach, and clicks for your online content.

Overall Performance

Engagement Over Time

Engagement by Post Type

Performance Log

Date Post Title Type Reach Engagement Eng. Rate

Enter Post Data

${avgEngRate.toFixed(2)}%

Top Post Type

${topPostType}

`; }; const renderDataTable = () => { dataTableBody.innerHTML = ''; const sortedPosts = [...state.posts].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedPosts.forEach(p => { const engagement = calculateEngagement(p); const engRate = calculateEngRate(p); const row = ` ${p.date} ${p.title} ${p.type} ${formatNumber(p.reach)} ${formatNumber(engagement)} ${engRate.toFixed(2)}% `; dataTableBody.innerHTML += row; }); }; const renderCharts = () => { // Engagement Trend Chart const engagementByDate = state.posts.reduce((acc, p) => { acc[p.date] = (acc[p.date] || 0) + calculateEngagement(p); return acc; }, {}); const sortedDates = Object.keys(engagementByDate).sort((a, b) => new Date(a) - new Date(b)); if (engagementChart) engagementChart.destroy(); engagementChart = new Chart(engagementCanvas.getContext('2d'), { type: 'line', data: { labels: sortedDates, datasets: [{ label: 'Total Engagement', data: sortedDates.map(date => engagementByDate[date]), borderColor: '#4f46e5', tension: 0.1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { x: { type: 'time', time: { unit: 'day' } }, y: { beginAtZero: true } } } }); // Engagement by Type const engagementByType = state.posts.reduce((acc, p) => { acc[p.type] = (acc[p.type] || 0) + calculateEngagement(p); return acc; }, {}); const typeLabels = Object.keys(engagementByType); const typeData = typeLabels.map(label => engagementByType[label]); if (typeChart) typeChart.destroy(); typeChart = new Chart(typeCanvas.getContext('2d'), { type: 'doughnut', data: { labels: typeLabels, datasets: [{ data: typeData, backgroundColor: ['#3b82f6', '#ef4444', '#10b981'] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } } }); }; const renderConfigRows = () => { configRowsContainer.innerHTML = ''; const sortedPosts = [...state.posts].sort((a,b) => b.id - a.id); sortedPosts.forEach(p => { 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') ? parseInt(e.target.value, 10) || 0 : e.target.value; const post = state.posts.find(p => p.id === id); if (post) post[field] = value; renderAll(); }; const handleAddPost = () => { const newId = state.posts.length > 0 ? Math.max(...state.posts.map(p => p.id)) + 1 : 1; const today = new Date().toISOString().split('T')[0]; state.posts.push({ id: newId, date: today, title: "New Post", type: "Image", reach: 0, likes: 0, comments: 0, shares: 0 }); renderAll(); }; const handleRemovePost = (e) => { const id = parseInt(e.target.dataset.id); state.posts = state.posts.filter(p => p.id !== id); renderAll(); }; const addConfigEventListeners = () => { document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange)); document.querySelectorAll('.remove-btn').forEach(button => button.addEventListener('click', handleRemovePost)); }; const handleDownloadPdf = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden'); Chart.defaults.animation = false; html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible'); Chart.defaults.animation = true; 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('Post-Performance-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(); }; 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 && addPostBtn && downloadPdfBtn) { addPostBtn.addEventListener('click', handleAddPost); downloadPdfBtn.addEventListener('click', handleDownloadPdf); renderAll(); updateTabButtons(); } else { console.error("Essential dashboard elements could not be found."); } });
Scroll to Top