Business Performance Dashboard

MRR (Current)

$0

Operating Margin

0%

LTV : CAC Ratio

0:1

Revenue / Employee

$0

Monthly Recurring Revenue (MRR) Growth

OpEx Breakdown (YTD)

LTV vs. CAC

Manage Monthly Data

Monthly Data Records

MonthRevenueProfitCACAction

Error: A required library is missing.

'; return; } // --- DATA MANAGEMENT --- let monthlyData = JSON.parse(localStorage.getItem('bpd_monthlyData')) || []; const getSampleData = () => { const data = []; const year = new Date('2025-07-08').getFullYear(); for (let i = 0; i < 6; i++) { // First 6 months of 2025 const month = `${year}-${String(i + 1).padStart(2, '0')}`; const revenue = 45000 + (i * 5000) + Math.random() * 5000; const newCustomers = 20 + i * 3 + Math.random() * 5; data.push({ month, revenue: revenue, cogs: revenue * 0.2, // 20% COGS marketingSpend: 6000 + i * 500, opex: 15000, newCustomers: newCustomers, employees: 10 + i }); } monthlyData = data; }; if (monthlyData.length === 0) getSampleData(); const saveState = () => localStorage.setItem('bpd_monthlyData', JSON.stringify(monthlyData)); // --- CHART INSTANCES & UTILITIES --- let mrrChart, opexChart, ltvCacChart; const tabButtons = document.querySelectorAll('.bpd-tab-button'); const tabContents = document.querySelectorAll('.bpd-tab-content'); const nextBtn = document.getElementById('bpd-next-btn'); const prevBtn = document.getElementById('bpd-prev-btn'); const formatCurrency = (val) => val.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); // --- RENDER FUNCTIONS --- const renderAll = () => { try { const processedData = processData(); renderKPIs(processedData); renderMrrChart(processedData); renderOpexChart(processedData); renderLtvCacChart(processedData); renderManageTable(); updateNavButtons(); } catch(error) { console.error("Dashboard rendering failed:", error); } }; const processData = () => { const sortedData = [...monthlyData].sort((a,b) => new Date(a.month) - new Date(b.month)); const calculatedData = sortedData.map(d => { const profit = d.revenue - d.cogs - d.opex - d.marketingSpend; const cac = d.newCustomers > 0 ? d.marketingSpend / d.newCustomers : 0; const grossMargin = 1 - (d.cogs / d.revenue); const ltv = d.revenue / d.newCustomers * grossMargin * 3; // Simplified LTV (3 year lifetime) return {...d, profit, cac, ltv }; }); return calculatedData; }; const renderKPIs = (data) => { const latestMonth = data[data.length - 1] || {}; const ytdRevenue = data.reduce((sum, d) => sum + d.revenue, 0); const ytdProfit = data.reduce((sum, d) => sum + d.profit, 0); const ytdOpMargin = ytdRevenue > 0 ? (ytdProfit / ytdRevenue) * 100 : 0; const ltvToCacRatio = latestMonth.cac > 0 ? latestMonth.ltv / latestMonth.cac : 0; document.getElementById('bpd-mrr-kpi').textContent = formatCurrency(latestMonth.revenue || 0); const opMarginEl = document.getElementById('bpd-op-margin-kpi'); opMarginEl.textContent = `${ytdOpMargin.toFixed(1)}%`; opMarginEl.className = ytdOpMargin >= 0 ? 'positive' : 'negative'; const ltvCacEl = document.getElementById('bpd-ltv-cac-kpi'); ltvCacEl.textContent = `${ltvToCacRatio.toFixed(1)} : 1`; ltvCacEl.className = ltvToCacRatio >= 3 ? 'positive' : 'negative'; document.getElementById('bpd-rev-per-emp-kpi').textContent = formatCurrency((latestMonth.revenue || 0) / (latestMonth.employees || 1)); }; const renderMrrChart = (data) => { const options = { chart: { type: 'area', height: 350, toolbar: { show: false } }, series: [{ name: 'MRR', data: data.map(d => d.revenue.toFixed(0)) }], xaxis: { categories: data.map(d => new Date(d.month + '-02').toLocaleString('default', { month: 'short', year: '2-digit' })) }, yaxis: { labels: { formatter: (val) => formatCurrency(val / 1000) + 'k' } }, stroke: { curve: 'smooth' }, colors: ['var(--bpd-secondary-color)'], dataLabels: { enabled: false } }; if(mrrChart) mrrChart.destroy(); document.querySelector("#bpd-mrr-chart").innerHTML = ''; mrrChart = new ApexCharts(document.querySelector("#bpd-mrr-chart"), options); mrrChart.render(); }; const renderOpexChart = (data) => { const ytdData = data.reduce((acc, d) => { acc.cogs += d.cogs; acc.marketingSpend += d.marketingSpend; acc.opex += d.opex; return acc; }, { cogs: 0, marketingSpend: 0, opex: 0 }); const options = { chart: { type: 'donut', height: 350 }, series: [ytdData.cogs, ytdData.marketingSpend, ytdData.opex], labels: ['COGS', 'Marketing', 'Operations'], legend: { position: 'bottom' } }; if(opexChart) opexChart.destroy(); document.querySelector("#bpd-opex-chart").innerHTML = ''; opexChart = new ApexCharts(document.querySelector("#bpd-opex-chart"), options); opexChart.render(); }; const renderLtvCacChart = (data) => { const latestMonth = data[data.length - 1] || {}; const options = { chart: { type: 'bar', height: 350, toolbar: { show: false } }, series: [{ name: 'Value', data: [latestMonth.ltv || 0, latestMonth.cac || 0] }], xaxis: { categories: ['Customer Lifetime Value (LTV)', 'Customer Acquisition Cost (CAC)'] }, plotOptions: { bar: { distributed: true } }, colors: ['var(--bpd-success-color)', 'var(--bpd-danger-color)'], legend: { show: false }, tooltip: { y: { formatter: (val) => formatCurrency(val) } } }; if(ltvCacChart) ltvCacChart.destroy(); document.querySelector("#bpd-ltv-cac-bar-chart").innerHTML = ''; ltvCacChart = new ApexCharts(document.querySelector("#bpd-ltv-cac-bar-chart"), options); ltvCacChart.render(); }; const renderManageTable = () => { const tbody = document.getElementById('bpd-data-tbody'); tbody.innerHTML = ''; const data = processData(); data.sort((a,b) => new Date(b.month) - new Date(a.month)).forEach(d => { tbody.innerHTML += ` ${d.month} ${formatCurrency(d.revenue)} ${formatCurrency(d.profit)} ${formatCurrency(d.cac)} `; }); }; // --- EVENT HANDLING --- const switchTab = (tabId) => { tabContents.forEach(c => c.style.display = 'none'); tabButtons.forEach(b => b.classList.remove('active')); const activeContent = document.getElementById(tabId); const activeButton = document.querySelector(`.bpd-tab-button[data-tab="${tabId}"]`); if (activeContent && activeButton) { activeContent.style.display = 'block'; activeButton.classList.add('active'); } updateNavButtons(); }; const updateNavButtons = () => { const i = [...tabButtons].findIndex(b => b.classList.contains('active')); prevBtn.disabled = i === 0; nextBtn.disabled = i === tabButtons.length - 1; }; tabButtons.forEach(b => b.addEventListener('click', () => switchTab(b.dataset.tab))); nextBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i < tabButtons.length - 1) switchTab(tabButtons[i+1].dataset.tab); }); prevBtn.addEventListener('click', () => { const i = [...tabButtons].findIndex(b=>b.classList.contains('active')); if (i > 0) switchTab(tabButtons[i-1].dataset.tab); }); document.getElementById('bpd-data-form').addEventListener('submit', e => { e.preventDefault(); const month = document.getElementById('bpd-data-month').value; const newData = { month: month, revenue: parseFloat(document.getElementById('bpd-data-revenue').value), cogs: parseFloat(document.getElementById('bpd-data-cogs').value), marketingSpend: parseFloat(document.getElementById('bpd-data-marketing').value), opex: parseFloat(document.getElementById('bpd-data-opex').value), newCustomers: parseInt(document.getElementById('bpd-data-new-customers').value), employees: parseInt(document.getElementById('bpd-data-employees').value) }; const existingIndex = monthlyData.findIndex(d => d.month === month); if (existingIndex > -1) monthlyData[existingIndex] = newData; else monthlyData.push(newData); saveState(); renderAll(); e.target.reset(); }); document.getElementById('bpd-data-tbody').addEventListener('click', e => { if (e.target.tagName === 'BUTTON') { const month = e.target.dataset.month; if (confirm(`Are you sure you want to delete all data for ${month}?`)) { monthlyData = monthlyData.filter(d => d.month !== month); saveState(); renderAll(); } } }); // --- PDF EXPORT --- document.getElementById('bpd-download-pdf-btn').addEventListener('click', function() { const btn = this; btn.textContent = 'Generating...'; btn.disabled = true; const content = document.getElementById('bpd-pdf-capture-area'); html2canvas(content, { scale: 2 }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgHeight = (canvas.height * pdfWidth) / canvas.width; pdf.setFontSize(18); pdf.text('Business Performance Report', pdfWidth / 2, 15, { align: 'center' }); pdf.addImage(imgData, 'PNG', 0, 25, pdfWidth, imgHeight); pdf.save('Business_Performance_Report.pdf'); }).finally(() => { btn.textContent = 'Download Report'; btn.disabled = false; }); }); // --- INITIALIZATION --- renderAll(); });
Scroll to Top