Social Media Marketing Budget Estimator

Campaign Setup

Platform & Activity Costing

Select Social Media Platforms for Advertising

General Social Media Marketing Costs

Enter estimated costs for broader activities. Specify frequency if not a one-time cost for the entire campaign.

Total Estimated Campaign Cost: $0.00

Budget Summary & Report

Campaign Name:

Campaign Duration:

Total Estimated SMM Budget: $0.00

Estimated Cost Breakdown

Cost ComponentEstimated Cost ($)% of Total
GRAND TOTAL: $0.00 100%

Budget Allocation by Activity Type

Ad Spend Allocation by Platform

Select platforms above to enter ad spend.

'; } } function smmbRenderGeneralCostsInputs() { const container = document.getElementById('smmbGeneralCostsContainer'); container.innerHTML = ''; smmbGeneralCostCategories.forEach(cat => { if (!smmbPlannedCosts.general[cat.id]) { // Initialize if not present smmbPlannedCosts.general[cat.id] = { cost: 0, frequency: cat.defaultFreq }; } const currentData = smmbPlannedCosts.general[cat.id]; const sectionDiv = document.createElement('div'); sectionDiv.className = 'smmb-form-grid'; // Use grid for layout within each general cost // Cost Input let formGroup = document.createElement('div'); formGroup.className = 'smmb-form-group'; let label = document.createElement('label'); label.htmlFor = `generalcost_${cat.id}`; label.textContent = `${cat.name} ($):`; formGroup.appendChild(label); let input = document.createElement('input'); input.type = 'number'; input.id = `generalcost_${cat.id}`; input.value = currentData.cost || 0; input.min = 0; input.placeholder = `Estimated Cost`; input.oninput = () => { smmbPlannedCosts.general[cat.id].cost = parseFloat(input.value) || 0; }; formGroup.appendChild(input); let small = document.createElement('small'); small.textContent = cat.costHint; formGroup.appendChild(small); sectionDiv.appendChild(formGroup); // Frequency Select formGroup = document.createElement('div'); formGroup.className = 'smmb-form-group'; label = document.createElement('label'); label.htmlFor = `genfreq_${cat.id}`; label.textContent = `Frequency:`; formGroup.appendChild(label); let select = document.createElement('select'); select.id = `genfreq_${cat.id}`; select.innerHTML = ` `; select.onchange = () => { smmbPlannedCosts.general[cat.id].frequency = select.value; }; formGroup.appendChild(select); sectionDiv.appendChild(formGroup); container.appendChild(sectionDiv); if (cat.id !== smmbGeneralCostCategories[smmbGeneralCostCategories.length -1].id) { container.appendChild(document.createElement('hr')); } }); } function smmbGetCampaignDurationMonths() { smmbSaveCampaignSettings(); // ensure settings are current const type = smmbCampaignSettings.budgetPeriodType; if (type === "Monthly") return 1; if (type === "Quarterly") return 3; if (type === "CustomWeeks") return (smmbCampaignSettings.customDurationWeeks / 4.33); // Avg weeks in month return 0; // Should not happen } window.smmbUpdateAndDisplayEstimates = function() { smmbSaveCampaignSettings(); // Ensure latest settings from Tab 1 are used let totalCampaignCost = 0; // Ad Spend for (const platformId in smmbPlannedCosts.adSpend) { const platformData = smmbPlannedCosts.adSpend[platformId]; if (platformData.selected) { totalCampaignCost += platformData.amountForCampaign || 0; } } // General Costs (normalized to campaign duration) const campaignDurationMonths = smmbGetCampaignDurationMonths(); for (const catId in smmbPlannedCosts.general) { const item = smmbPlannedCosts.general[catId]; let costForPeriod = item.cost || 0; if (item.frequency === "Monthly") { costForPeriod *= campaignDurationMonths; } else if (item.frequency === "Quarterly") { costForPeriod *= (campaignDurationMonths / 3); } else if (item.frequency === "Annually") { costForPeriod *= (campaignDurationMonths / 12); } // "OneTimeForCampaign" is already for the period item.calculatedCostForCampaign = costForPeriod; // Store normalized cost totalCampaignCost += costForPeriod; } document.getElementById('smmbTotalCampaignEstimate').textContent = `$${totalCampaignCost.toFixed(2)}`; } // --- Summary Report (Tab 3) --- function smmbUpdateFullSummaryReport() { smmbUpdateAndDisplayEstimates(); // Calculate all costs first document.getElementById('smmbReportCampaignName').textContent = smmbCampaignSettings.campaignName; let durationText = ""; if (smmbCampaignSettings.budgetPeriodType === 'CustomWeeks') { durationText = `${smmbCampaignSettings.customDurationWeeks} Weeks`; } else { durationText = smmbCampaignSettings.budgetPeriodType; } document.getElementById('smmbReportCampaignDuration').textContent = durationText; const targetBudget = smmbCampaignSettings.overallTargetBudget; const targetBudgetP = document.getElementById('smmbReportTargetBudgetP'); const targetBudgetSpan = document.getElementById('smmbReportTargetBudget'); const statusP = document.getElementById('smmbReportBudgetStatusP'); const statusSpan = document.getElementById('smmbReportBudgetStatus'); let totalEstimatedCost = 0; const costsByActivity = {}; // For chart and table breakdown // Ad spend breakdown costsByActivity['Ad Spend'] = 0; const adSpendPlatformLabels = []; const adSpendPlatformData = []; for (const platformId in smmbPlannedCosts.adSpend) { const platformData = smmbPlannedCosts.adSpend[platformId]; if (platformData.selected && platformData.amountForCampaign > 0) { const platformDef = smmbAvailablePlatforms.find(p => p.id === platformId); costsByActivity['Ad Spend'] += platformData.amountForCampaign; adSpendPlatformLabels.push(platformDef.name); adSpendPlatformData.push(platformData.amountForCampaign); } } totalEstimatedCost += costsByActivity['Ad Spend']; // General costs breakdown for (const catId in smmbPlannedCosts.general) { const itemData = smmbPlannedCosts.general[catId]; const categoryDef = smmbGeneralCostCategories.find(c => c.id === catId); if (itemData.calculatedCostForCampaign > 0) { costsByActivity[categoryDef.name] = itemData.calculatedCostForCampaign; totalEstimatedCost += itemData.calculatedCostForCampaign; } } document.getElementById('smmbReportTotalEstimatedBudget').textContent = `$${totalEstimatedCost.toFixed(2)}`; document.getElementById('smmbSummaryGrandTotal').textContent = `$${totalEstimatedCost.toFixed(2)}`; if (targetBudget > 0) { targetBudgetSpan.textContent = `$${targetBudget.toFixed(2)}`; targetBudgetP.style.display = 'block'; statusP.style.display = 'block'; if (totalEstimatedCost > targetBudget) { statusSpan.textContent = `Over Target by $${(totalEstimatedCost - targetBudget).toFixed(2)}`; statusSpan.style.color = varGet('--smmb-danger-color'); } else if (totalEstimatedCost < targetBudget) { statusSpan.textContent = `Under Target by $${(targetBudget - totalEstimatedCost).toFixed(2)}`; statusSpan.style.color = varGet('--smmb-success-color'); } else { statusSpan.textContent = "On Target"; statusSpan.style.color = varGet('--smmb-success-color'); } } else { targetBudgetP.style.display = 'none'; statusP.style.display = 'none'; } const summaryTableBody = document.getElementById('smmbSummaryBreakdownTable').querySelector('tbody'); summaryTableBody.innerHTML = ''; const activityChartLabels = []; const activityChartData = []; for (const activityName in costsByActivity) { if (costsByActivity[activityName] > 0) { const row = summaryTableBody.insertRow(); row.insertCell().textContent = activityName; let cell = row.insertCell(); cell.textContent = costsByActivity[activityName].toFixed(2); cell.className = 'smmb-amount-cell'; cell = row.insertCell(); cell.textContent = totalEstimatedCost > 0 ? ((costsByActivity[activityName] / totalEstimatedCost) * 100).toFixed(1) + '%' : '0.0%'; cell.className = 'smmb-amount-cell'; activityChartLabels.push(activityName); activityChartData.push(costsByActivity[activityName]); } } smmbRenderPieChart('smmbActivityTypeChart', activityChartLabels, activityChartData, 'smmbActivityTypeChartInstance', 'Spend by Activity'); const adSpendChartContainer = document.getElementById('smmbAdSpendChartContainer'); if(adSpendPlatformLabels.length > 0 && adSpendPlatformData.some(d => d > 0)) { adSpendChartContainer.style.display = 'block'; smmbRenderBarChart('smmbAdSpendPlatformChart', adSpendPlatformLabels, adSpendPlatformData, 'smmbAdSpendPlatformChartInstance', 'Ad Spend by Platform'); } else { adSpendChartContainer.style.display = 'none'; if(window.smmbAdSpendPlatformChartInstance) window.smmbAdSpendPlatformChartInstance.destroy(); window.smmbAdSpendPlatformChartInstance = null; } } function smmbRenderPieChart(canvasId, labels, data, chartInstanceVarName, chartLabel) { const chartCanvas = document.getElementById(canvasId); if (!chartCanvas || typeof Chart === 'undefined') { if(chartCanvas) chartCanvas.parentElement.innerHTML = "

Chart library not loaded.

"; return; } const ctx = chartCanvas.getContext('2d'); const chartColors = ['#1DA1F2', '#E1306C', '#FFC107', '#28A745', '#6F42C1', '#FD7E14', '#6C757D']; if (window[chartInstanceVarName]) window[chartInstanceVarName].destroy(); if (labels.length > 0 && data.some(d => d > 0)) { window[chartInstanceVarName] = new Chart(ctx, { type: 'pie', data: { labels: labels, datasets: [{ label: chartLabel, data: data, backgroundColor: labels.map((_,i)=>chartColors[i % chartColors.length]), borderColor: varGet('--smmb-light-text'), borderWidth:1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' }, tooltip: {callbacks: {label: c=>`${c.label}: $${c.parsed.toFixed(2)}`}} } } }); } else { ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.textAlign='center'; ctx.fillStyle = varGet('--smmb-secondary-color'); ctx.font = "16px Arial"; ctx.fillText(`No data for "${chartLabel}" chart.`, ctx.canvas.width/2, ctx.canvas.height/2); window[chartInstanceVarName] = null; } } function smmbRenderBarChart(canvasId, labels, data, chartInstanceVarName, chartLabel) { const chartCanvas = document.getElementById(canvasId); if (!chartCanvas || typeof Chart === 'undefined') { if(chartCanvas) chartCanvas.parentElement.innerHTML = "

Chart library not loaded.

"; return; } const ctx = chartCanvas.getContext('2d'); const chartColors = ['#1DA1F2', '#E1306C', '#FFC107', '#28A745', '#6F42C1', '#FD7E14', '#6C757D']; if (window[chartInstanceVarName]) window[chartInstanceVarName].destroy(); if (labels.length > 0 && data.some(d => d > 0)) { window[chartInstanceVarName] = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: chartLabel, data: data, backgroundColor: labels.map((_,i)=>chartColors[i % chartColors.length]) }] }, options: { responsive: true, maintainAspectRatio: false, scales: {y:{beginAtZero:true, ticks:{callback:v=>`$${v}`}}}, plugins: { legend: { display:false }, tooltip: {callbacks: {label: c=>`${c.label}: $${c.parsed.y.toFixed(2)}`}} } } }); } else { ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.textAlign='center'; ctx.fillStyle = varGet('--smmb-secondary-color'); ctx.font = "16px Arial"; ctx.fillText(`No data for "${chartLabel}" chart.`, ctx.canvas.width/2, ctx.canvas.height/2); window[chartInstanceVarName] = null; } } function varGet(varName) { return getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); } // --- PDF Download --- window.smmbDownloadPDF = function() { if (typeof jsPDF === 'undefined' || typeof autoTable === 'undefined') { alert("PDF libraries not loaded."); return; } const { jsPDF: JSPDF } = window.jspdf; const localAutoTable = window.jspdf.autoTable; const doc = new JSPDF(); smmbUpdateFullSummaryReport(); // Ensure data is current const campaignName = smmbCampaignSettings.campaignName; let durationText = smmbCampaignSettings.budgetPeriodType === 'CustomWeeks' ? `${smmbCampaignSettings.customDurationWeeks} Weeks` : smmbCampaignSettings.budgetPeriodType; const generationDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) + " (Reference Time: Friday, May 16, 2025)"; doc.setFontSize(18); doc.setTextColor(varGet('--smmb-primary-color')); doc.text(campaignName, doc.internal.pageSize.getWidth() / 2, 15, { align: 'center' }); doc.setFontSize(11); doc.setTextColor(varGet('--smmb-dark-text')); doc.text(`Campaign Duration: ${durationText}`, 14, 25); doc.text(`Report Generated: ${generationDate}`, doc.internal.pageSize.getWidth() - 14, 25, { align: 'right' }); let yPos = 35; const totalEstimatedCost = parseFloat(document.getElementById('smmbReportTotalEstimatedBudget').textContent.replace('$', '')); doc.setFontSize(12); doc.setTextColor(varGet('--smmb-primary-color')); doc.text("Overall Budget Summary", 14, yPos); yPos += 7; doc.setFontSize(10); doc.setTextColor(varGet('--smmb-dark-text')); doc.text(`Total Estimated SMM Budget: $${totalEstimatedCost.toFixed(2)}`, 14, yPos); yPos += 5; if (smmbCampaignSettings.overallTargetBudget > 0) { doc.text(`Target Budget: $${smmbCampaignSettings.overallTargetBudget.toFixed(2)}`, 14, yPos); yPos += 5; doc.text(`Status vs Target: ${document.getElementById('smmbReportBudgetStatus').textContent}`, 14, yPos); yPos+=5; } yPos += 5; doc.setFontSize(12); doc.setTextColor(varGet('--smmb-primary-color')); doc.text("Estimated Cost Breakdown", 14, yPos); yPos += 7; const tableBody = []; // Ad spend let totalAdSpend = 0; for (const platformId in smmbPlannedCosts.adSpend) { const platformData = smmbPlannedCosts.adSpend[platformId]; if (platformData.selected && platformData.amountForCampaign > 0) { const platformDef = smmbAvailablePlatforms.find(p => p.id === platformId); tableBody.push([`${platformDef.name} Ad Spend`, platformData.amountForCampaign.toFixed(2), totalEstimatedCost > 0 ? ((platformData.amountForCampaign / totalEstimatedCost) * 100).toFixed(1) + '%' : '0.0%']); totalAdSpend += platformData.amountForCampaign; } } // General costs for (const catId in smmbPlannedCosts.general) { const itemData = smmbPlannedCosts.general[catId]; const categoryDef = smmbGeneralCostCategories.find(c => c.id === catId); if (itemData.calculatedCostForCampaign > 0) { tableBody.push([categoryDef.name, itemData.calculatedCostForCampaign.toFixed(2), totalEstimatedCost > 0 ? ((itemData.calculatedCostForCampaign / totalEstimatedCost) * 100).toFixed(1) + '%' : '0.0%']); } } localAutoTable(doc, { head: [['Cost Component', 'Estimated Cost ($)', '% of Total']], body: tableBody, startY: yPos, theme: 'grid', headStyles: { fillColor: varGet('--smmb-primary-color'), textColor: varGet('--smmb-light-text')}, footStyles: { fillColor: [220,220,220], textColor: varGet('--smmb-dark-text'), fontStyle: 'bold'}, styles: { fontSize: 9, cellPadding: 2 }, columnStyles: { 1: {halign: 'right'}, 2: {halign: 'right'} }, foot: [[ {content: 'GRAND TOTAL ESTIMATED BUDGET:', styles: {halign: 'right'}}, {content: `$${totalEstimatedCost.toFixed(2)}`, styles: {halign: 'right'}}, {content: `100.0%`, styles: {halign: 'right'}} ]], didDrawPage: data => yPos = data.cursor.y }); yPos = doc.lastAutoTable.finalY + 10; // Charts const chartsToPrint = [ {canvasId: 'smmbActivityTypeChart', title: 'Budget Allocation by Activity Type', instance: window.smmbActivityTypeChartInstance}, ]; if (totalAdSpend > 0 && window.smmbAdSpendPlatformChartInstance) { // Only add ad spend chart if there is ad spend chartsToPrint.push({canvasId: 'smmbAdSpendPlatformChart', title: 'Ad Spend Allocation by Platform', instance: window.smmbAdSpendPlatformChartInstance}); } chartsToPrint.forEach(chartInfo => { const chartCanvas = document.getElementById(chartInfo.canvasId); if (chartCanvas && chartInfo.instance && chartInfo.instance.data.datasets[0].data.length > 0 && chartInfo.instance.data.datasets[0].data.some(d => d > 0)) { if (yPos > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); yPos = 20;} doc.setFontSize(12); doc.setTextColor(varGet('--smmb-primary-color')); doc.text(chartInfo.title, doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 7; try { const chartImage = chartCanvas.toDataURL('image/png', 1.0); const imgProps = doc.getImageProperties(chartImage); const pdfChartWidth = doc.internal.pageSize.getWidth() * 0.7; const chartHeight = (imgProps.height * pdfChartWidth) / imgProps.width; const xOffset = (doc.internal.pageSize.getWidth() - pdfChartWidth) / 2; if (yPos + chartHeight > doc.internal.pageSize.getHeight() -10 ) { doc.addPage(); yPos = 20; doc.text(chartInfo.title + " (cont.)", doc.internal.pageSize.getWidth() / 2, yPos, {align: 'center'}); yPos += 7; } doc.addImage(chartImage, 'PNG', xOffset, yPos, pdfChartWidth, chartHeight); yPos += chartHeight + 5; } catch(e) { console.error(`Error adding chart ${chartInfo.canvasId} to PDF:`, e); } } }); doc.save(`${campaignName.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_smm_budget.pdf`); } // --- Initialization --- smmbRenderPlatformSelection(); smmbRenderPlatformAdSpendInputs(); // Initial call to set up this section smmbRenderGeneralCostsInputs(); smmbUpdateAndDisplayEstimates(); smmbShowTab(0); });
Scroll to Top