Sustainable Budgeting for Eco-Friendly Living

Sustainable Budgeting for Eco-Friendly Living

Current Monthly Spending Habits

Enter your estimated current monthly spending for each category. This will form your baseline.

Total Current Monthly Spending: $0.00

Explore Eco-Friendly Alternatives

For each area, input your current typical monthly spend for that specific habit and then estimate the cost of a more sustainable alternative. Note down the eco-benefits you perceive and decide if you want to consider this change.

Sustainable Budget Summary & Action Plan

Please input your current spending (Tab 1) and explore alternatives (Tab 2), then click the button above.

${savingText}

`; container.appendChild(itemDiv); }); } catch(e) { console.error("Error in sbel_renderEcoAlternatives:", e.stack); } } function sbel_updateEcoChoice(itemId, field, value) { try { if (!sbel_ecoChoices[itemId]) { sbel_ecoChoices[itemId] = { currentSpend: 0, alternativeSpend: 0, ecoBenefitNotes: '', considerChange: false }; } if (field === 'currentSpend' || field === 'alternativeSpend') { sbel_ecoChoices[itemId][field] = parseFloat(value) || 0; } else if (field === 'considerChange'){ sbel_ecoChoices[itemId][field] = value; // boolean } else { sbel_ecoChoices[itemId][field] = value; // notes (string) } const itemData = sbel_ecoChoices[itemId]; const monthlySaving = itemData.currentSpend - itemData.alternativeSpend; const annualSaving = monthlySaving * 12; let savingText = "No change in cost."; let savingClass = ""; if (monthlySaving > 0) { savingText = `Monthly Saving: ${sbel_formatCurrency(monthlySaving)} | Annual Saving: ${sbel_formatCurrency(annualSaving)}`; savingClass = "sbel-saving"; } else if (monthlySaving < 0) { savingText = `Monthly Extra Cost: ${sbel_formatCurrency(Math.abs(monthlySaving))} | Annual Extra Cost: ${sbel_formatCurrency(Math.abs(annualSaving))}`; savingClass = "sbel-extra-cost"; } const savingTextEl = document.getElementById(`eco-${itemId}-savingText`); if(savingTextEl){ savingTextEl.innerHTML = savingText; savingTextEl.className = `sbel-cost-comparison ${savingClass}`; } } catch(e) { console.error("Error in sbel_updateEcoChoice:", e.stack); } } function sbel_calculateSummary() { try { let baselineTotal = 0; for (const catId in sbel_currentSpendings) { baselineTotal += sbel_currentSpendings[catId]; } const baselineTotalEl = document.getElementById('sbel-summaryBaselineTotal'); if(baselineTotalEl) baselineTotalEl.textContent = sbel_formatCurrency(baselineTotal); let totalMonthlySavingsFromChanges = 0; const actionPlanList = document.getElementById('sbel-actionPlanList'); if(actionPlanList) actionPlanList.innerHTML = ''; let actionItemsExist = false; sbel_eco_alternatives_config.forEach(ecoConfig => { const choice = sbel_ecoChoices[ecoConfig.id]; if (choice && choice.considerChange) { actionItemsExist = true; const diff = choice.currentSpend - choice.alternativeSpend; totalMonthlySavingsFromChanges += diff; if (actionPlanList) { const listItem = document.createElement('div'); listItem.className = 'sbel-action-plan-item'; let savingText = ""; if (diff > 0) savingText = `(Saves ${sbel_formatCurrency(diff)}/month)`; else if (diff < 0) savingText = `(Costs ${sbel_formatCurrency(Math.abs(diff))}/month extra)`; listItem.innerHTML = ` ${ecoConfig.areaName} ${savingText} Benefit: ${choice.ecoBenefitNotes || "N/A"} `; actionPlanList.appendChild(listItem); } } }); const projectedEcoTotal = baselineTotal - totalMonthlySavingsFromChanges; const summaryEcoTotalEl = document.getElementById('sbel-summaryEcoTotal'); if(summaryEcoTotalEl) summaryEcoTotalEl.textContent = sbel_formatCurrency(projectedEcoTotal); const savingElement = document.getElementById('sbel-totalPotentialSavingMonthly'); const annualSavingElement = document.getElementById('sbel-annualPotentialSaving'); if (savingElement) savingElement.innerHTML = `Total Potential Monthly Savings: ${sbel_formatCurrency(totalMonthlySavingsFromChanges)}`; if (annualSavingElement) annualSavingElement.innerHTML = `Total Potential Annual Savings: ${sbel_formatCurrency(totalMonthlySavingsFromChanges * 12)}`; const noActionEl = document.getElementById('sbel-noActionItems'); if(noActionEl) noActionEl.style.display = actionItemsExist ? 'none' : 'block'; const summaryContainerEl = document.getElementById('sbel-summaryOutputContainer'); if(summaryContainerEl) summaryContainerEl.style.display = 'block'; const noSummaryMsgEl = document.getElementById('sbel-noSummaryMessage'); if(noSummaryMsgEl) noSummaryMsgEl.style.display = 'none'; sbel_pdfDataStore = { baselineTotal, projectedEcoTotal, totalMonthlySavingsFromChanges, ecoChoices: JSON.parse(JSON.stringify(sbel_ecoChoices)), ecoAlternativesConfig: sbel_eco_alternatives_config, currentSpendingsRaw: JSON.parse(JSON.stringify(sbel_currentSpendings)) }; } catch(error) { console.error("Error calculating summary:", error.stack); alert("Error calculating summary. Check console for details."); sbel_pdfDataStore = null; } } function sbel_downloadPDF() { try { if (!sbel_pdfDataStore) { sbel_calculateSummary(); // Ensure data is calculated before PDF generation if (!sbel_pdfDataStore) { // Check again after calculation alert("Please input data and calculate the summary first (Tab 3 -> View/Refresh Summary)."); return; } } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF library (jsPDF) not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt'); if (typeof doc.autoTable !== 'function') { alert('PDF Table plugin (jsPDF-AutoTable) not loaded.'); return; } const data = sbel_pdfDataStore; const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--sbel-primary-color').trim(); const textColor = getComputedStyle(document.documentElement).getPropertyValue('--sbel-text-color').trim(); let yPos = 40; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Sustainable Budget & Eco-Living Plan", doc.internal.pageSize.getWidth() / 2, yPos, { align: 'center' }); yPos += 25; doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Budget Overview (Monthly)", 14, yPos); yPos += 15; const summaryData = [ ["Baseline Monthly Spending:", sbel_formatCurrency(data.baselineTotal)], ["Projected Monthly Spending with Eco-Changes:", sbel_formatCurrency(data.projectedEcoTotal)], [{content: "Total Potential Monthly Savings:", styles:{fontStyle:'bold'}}, {content: sbel_formatCurrency(data.totalMonthlySavingsFromChanges), styles:{fontStyle:'bold', textColor: data.totalMonthlySavingsFromChanges >= 0 ? primaryColor : getComputedStyle(document.documentElement).getPropertyValue('--sbel-accent-color').trim()}}], ["Total Potential Annual Savings:", sbel_formatCurrency(data.totalMonthlySavingsFromChanges * 12)] ]; doc.autoTable({ startY: yPos, body: summaryData, theme: 'plain', styles: { fontSize: 9, cellPadding:3 }, columnStyles: {0:{fontStyle:'bold', cellWidth:250}}}); yPos = doc.lastAutoTable.finalY + 20; doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Eco-Action Plan (Changes Considered)", 14, yPos); yPos += 15; const actionPlanHeaders = [["Area of Change", "Current Spend ($/mo)", "Alternative Spend ($/mo)", "Monthly Saving ($)", "Eco-Benefit Notes"]]; const actionPlanBody = []; data.ecoAlternativesConfig.forEach(config => { const choice = data.ecoChoices[config.id]; if (choice && choice.considerChange) { const saving = choice.currentSpend - choice.alternativeSpend; actionPlanBody.push([ config.areaName, choice.currentSpend.toFixed(2), choice.alternativeSpend.toFixed(2), saving.toFixed(2), choice.ecoBenefitNotes || "N/A" ]); } }); if (actionPlanBody.length > 0) { doc.autoTable({ startY: yPos, head: actionPlanHeaders, body: actionPlanBody, theme: 'grid', headStyles: { fillColor: primaryColor, textColor: [255,255,255], fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 2, overflow: 'linebreak' }, columnStyles: { 1:{halign:'right'}, 2:{halign:'right'}, 3:{halign:'right'}, 4:{cellWidth:150} } }); yPos = doc.lastAutoTable.finalY + 15; } else { doc.setFontSize(9); doc.setTextColor(textColor); doc.text("No specific eco-actions were selected for the plan.", 14, yPos); yPos+=10; } if (yPos > doc.internal.pageSize.getHeight() - 80 && Object.keys(data.currentSpendingsRaw).length > 0) { doc.addPage(); yPos = 40; } doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Baseline Monthly Spending Details (Summary)", 14, yPos); yPos += 15; const baselineHeaders = [["Category", "Current Monthly Spend ($)"]]; const baselineBody = []; sbel_budget_categories.forEach(catConfig => { const spend = data.currentSpendingsRaw[catConfig.id] || 0; if(spend > 0) { baselineBody.push([catConfig.name, spend.toFixed(2)]); } }); if(baselineBody.length > 0) { doc.autoTable({ startY: yPos, head: baselineHeaders, body: baselineBody, theme: 'striped', headStyles: { fillColor: primaryColor, textColor: [255,255,255], fontStyle: 'bold' }, styles: { fontSize: 9, cellPadding: 2 }, columnStyles: { 1:{halign:'right'} } }); } else { doc.setFontSize(9); doc.setTextColor(textColor); doc.text("No baseline spending details were entered.", 14, yPos); } const pageCount = doc.internal.getNumberOfPages(); for (let i = 1; i <= pageCount; i++) { doc.setPage(i); doc.setFontSize(8); doc.setTextColor(150); doc.text(`Page ${i} of ${pageCount}`, doc.internal.pageSize.getWidth() / 2, doc.internal.pageSize.getHeight() - 10, { align: 'center' }); doc.text(`Generated on: ${new Date().toLocaleDateString('en-US', {year:'numeric', month:'short', day:'numeric'})}`, 14, doc.internal.pageSize.getHeight() - 10); doc.text(`Sustainable Budget Plan`, doc.internal.pageSize.getWidth() - 14, doc.internal.pageSize.getHeight() - 10, { align: 'right' }); } doc.save("Sustainable_Budget_Plan.pdf"); } catch(e) { console.error("Error in sbel_downloadPDF:", e.stack); alert("Error generating PDF.");} } document.addEventListener('DOMContentLoaded', () => { try { if (sbel_tabs.length > 0 && sbel_tabs[0]) sbel_openTab(null, sbel_tabs[0].id); sbel_updateNavButtons(); sbel_renderCurrentSpendingInputs(); sbel_renderEcoAlternatives(); sbel_calculateSummary(); const primaryColorVal = getComputedStyle(document.documentElement).getPropertyValue('--sbel-primary-color').trim(); if (primaryColorVal.startsWith('#')) { const r = parseInt(primaryColorVal.slice(1, 3), 16); const g = parseInt(primaryColorVal.slice(3, 5), 16); const b = parseInt(primaryColorVal.slice(5, 7), 16); if (!isNaN(r) && !isNaN(g) && !isNaN(b)) { document.documentElement.style.setProperty('--sbel-primary-color-rgb', `${r},${g},${b}`); } else { // Fallback if parsing fails document.documentElement.style.setProperty('--sbel-primary-color-rgb', `76,175,80`); } } else { // Fallback if not hex (e.g. named color, or rgb string) document.documentElement.style.setProperty('--sbel-primary-color-rgb', `76,175,80`); } } catch (e) { console.error("Error during DOMContentLoaded setup:", e.stack); alert("An error occurred initializing the tool. Please check the console (Right-click -> Inspect -> Console)."); } });
Scroll to Top