Error: Could not load required libraries.
';
return;
}
let mktg_channelChart;
const TABS = ['dashboardTab', 'dataInputTab'];
let mktg_currentTabIndex = 0;
const sampleData = [
{ channel: "Google Ads", spend: 12500, impressions: 850000, clicks: 42500, leads: 1200, conversions: 250, revenue: 65000 },
{ channel: "Facebook Ads", spend: 8000, impressions: 1200000, clicks: 30000, leads: 950, conversions: 150, revenue: 40000 },
{ channel: "Organic Search (SEO)", spend: 4500, impressions: 0, clicks: 18000, leads: 600, conversions: 180, revenue: 54000 },
{ channel: "Email Marketing", spend: 1500, impressions: 0, clicks: 9000, leads: 1500, conversions: 350, revenue: 70000 },
];
function mktg_initialize() {
document.getElementById('mktg-start-date').value = '2025-04-01';
document.getElementById('mktg-end-date').value = '2025-06-30';
sampleData.forEach(d => mktg_add_row(d));
mktg_updateDashboard();
mktg_updateNavButtons();
}
window.mktg_add_row = function(data = {}) {
const tableBody = document.getElementById('mktg-input-table-body');
const row = tableBody.insertRow();
row.innerHTML = `
|
|
|
|
|
|
|
|
`;
}
function mktg_collectAndProcessData() {
const rows = document.getElementById('mktg-input-table-body').rows;
return Array.from(rows).map(row => {
const getVal = (selector) => parseFloat(row.querySelector(`.${selector}`).value) || 0;
const spend = getVal('spend');
const clicks = getVal('clicks');
const leads = getVal('leads');
const conversions = getVal('conversions');
const revenue = getVal('revenue');
return {
channel: row.querySelector('.channel').value,
spend, clicks, leads, conversions, revenue,
cpc: clicks > 0 ? spend / clicks : 0,
cpl: leads > 0 ? spend / leads : 0,
roas: spend > 0 ? revenue / spend : 0,
};
});
}
window.mktg_updateDashboard = function() {
const data = mktg_collectAndProcessData();
mktg_updateKpisAndFunnel(data);
mktg_updateChannelChart(data);
mktg_renderTable(data);
mktg_changeTab('dashboardTab');
}
function mktg_updateKpisAndFunnel(data) {
const total = data.reduce((acc, item) => {
Object.keys(item).forEach(key => {
if (typeof item[key] === 'number') acc[key] = (acc[key] || 0) + item[key];
});
return acc;
}, {});
const overallROAS = total.spend > 0 ? total.revenue / total.spend : 0;
const overallCPL = total.leads > 0 ? total.spend / total.leads : 0;
document.getElementById('kpi-spend').textContent = `$${total.spend.toLocaleString()}`;
document.getElementById('kpi-revenue').textContent = `$${total.revenue.toLocaleString()}`;
document.getElementById('kpi-roas').textContent = `${overallROAS.toFixed(2)}x`;
document.getElementById('kpi-leads').textContent = total.leads.toLocaleString();
document.getElementById('kpi-cpl').textContent = `$${overallCPL.toFixed(2)}`;
// Funnel
document.getElementById('funnel-clicks').textContent = total.clicks.toLocaleString();
document.getElementById('funnel-leads').textContent = total.leads.toLocaleString();
document.getElementById('funnel-conversions').textContent = total.conversions.toLocaleString();
document.getElementById('funnel-cvr1').textContent = `${(total.clicks > 0 ? (total.leads / total.clicks) * 100 : 0).toFixed(1)}%`;
document.getElementById('funnel-cvr2').textContent = `${(total.leads > 0 ? (total.conversions / total.leads) * 100 : 0).toFixed(1)}%`;
// Date Range
const start = document.getElementById('mktg-start-date').value;
const end = document.getElementById('mktg-end-date').value;
document.getElementById('mktg-date-range-display').textContent = `Showing data for ${start} to ${end}`;
}
function mktg_updateChannelChart(data) {
const ctx = document.getElementById('mktg-channel-chart');
if (mktg_channelChart) mktg_channelChart.destroy();
const sortedByRevenue = [...data].sort((a,b) => b.revenue - a.revenue);
mktg_channelChart = new Chart(ctx, {
type: 'bar',
data: {
labels: sortedByRevenue.map(d => d.channel),
datasets: [{
label: 'Revenue ($)',
data: sortedByRevenue.map(d => d.revenue),
backgroundColor: '#4299e1',
borderColor: '#2b6cb0',
borderWidth: 1
}]
},
options: {
responsive: true, maintainAspectRatio: false, indexAxis: 'y',
scales: { x: { beginAtZero: true, ticks: { callback: v => '$' + v.toLocaleString() } } },
plugins: { legend: { display: false } }
}
});
}
function mktg_renderTable(data) {
const tableBody = document.getElementById('mktg-table-body');
tableBody.innerHTML = '';
data.forEach(d => {
tableBody.innerHTML += `
| ${d.channel} |
$${d.spend.toLocaleString()} |
${d.clicks.toLocaleString()} |
$${d.cpc.toFixed(2)} |
${d.leads.toLocaleString()} |
$${d.cpl.toFixed(2)} |
${d.conversions.toLocaleString()} |
$${d.revenue.toLocaleString()} |
${d.roas.toFixed(2)}x |
`;
});
}
window.mktg_downloadPDF = function() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const data = mktg_collectAndProcessData();
doc.setFontSize(20);
doc.text("Marketing Performance Report", 105, 20, { align: 'center' });
const start = document.getElementById('mktg-start-date').value;
const end = document.getElementById('mktg-end-date').value;
doc.setFontSize(12);
doc.text(`Period: ${start} to ${end}`, 105, 28, { align: 'center' });
const chartCanvas = document.getElementById('mktg-channel-chart').toDataURL('image/png', 1.0);
doc.addImage(chartCanvas, 'PNG', 15, 40, 180, 100);
const tableHead = [['Channel', 'Spend', 'Clicks', 'CPC', 'Leads', 'CPL', 'Conversions', 'Revenue', 'ROAS']];
const tableBody = data.map(d => [d.channel, `$${d.spend.toLocaleString()}`, d.clicks.toLocaleString(), `$${d.cpc.toFixed(2)}`, d.leads.toLocaleString(), `$${d.cpl.toFixed(2)}`, d.conversions.toLocaleString(), `$${d.revenue.toLocaleString()}`, `${d.roas.toFixed(2)}x`]);
doc.autoTable({
head: tableHead, body: tableBody,
startY: 150, theme: 'grid',
headStyles: { fillColor: '#2c5282' }
});
doc.save('Marketing_Performance_Report.pdf');
}
// --- TABBING & NAVIGATION ---
window.mktg_changeTab = function(tabId) {
document.querySelectorAll('.mktg-tab-content').forEach(c => c.classList.remove('active'));
document.querySelectorAll('.mktg-tab-button').forEach(b => b.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
const activeButton = Array.from(document.querySelectorAll('.mktg-tab-button')).find(btn => btn.getAttribute('onclick').includes(tabId));
if (activeButton) activeButton.classList.add('active');
mktg_currentTabIndex = TABS.indexOf(tabId);
mktg_updateNavButtons();
}
window.mktg_navigateTabs = function(direction) {
let newIndex = mktg_currentTabIndex;
if (direction === 'next') newIndex = Math.min(newIndex + 1, TABS.length - 1);
else if (direction === 'prev') newIndex = Math.max(newIndex - 1, 0);
mktg_changeTab(TABS[newIndex]);
}
function mktg_updateNavButtons() {
const prevBtn = document.getElementById('mktg-prev-btn');
const nextBtn = document.getElementById('mktg-next-btn');
if(prevBtn) prevBtn.disabled = mktg_currentTabIndex === 0;
if(nextBtn) nextBtn.disabled = mktg_currentTabIndex === TABS.length - 1;
}
mktg_initialize();
});