Budget Planning Tool

Budget Planning Tool

Monthly Budget Planning Tool

Budget Summary

Total Income

$0.00

Total Expenses

$0.00

Net Savings

$0.00

Expense Breakdown by Category

All Expenses

Item Category Amount

Income Sources

Expense Items

Expense Breakdown by Category

All Expenses

Item Category Amount
`; // Call the dashboard renderer on the clone bpt_renderDashboard(bpt_pdfRenderClone, true); } /** * Generates and downloads a PDF of the dashboard */ async function bpt_downloadPDF() { if (typeof jspdf === 'undefined' || typeof html2canvas === 'undefined') { console.error("BPT Tool Error: jsPDF or html2canvas library not loaded."); alert("Error: PDF libraries failed to load. Please check console."); return; } // 1. Create and render the high-res clone bpt_renderPdfClone(); const { jsPDF } = window.jspdf; try { // 2. Render canvas from the clone const canvas = await html2canvas(bpt_pdfRenderClone, { scale: 2, // High resolution useCORS: true, }); const imgData = canvas.toDataURL('image/png'); const imgWidth = canvas.width; const imgHeight = canvas.height; // Use 'pt' for units. A4 is 595.28 x 841.89 const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); // Scale image to fit pdf width const ratio = imgHeight / imgWidth; const scaledImgHeight = (pdfWidth / imgWidth) * imgHeight; let heightLeft = scaledImgHeight; let position = 0; // y-position of the image on the page const margin = 40; // 40pt margin const contentWidth = pdfWidth - (margin * 2); const contentHeight = (contentWidth * imgHeight) / imgWidth; // 3. Add the first page pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); // 4. Add subsequent pages if needed while (heightLeft > 0) { position -= (pdfHeight - margin * 2); pdf.addPage(); pdf.addImage(imgData, 'PNG', margin, position + margin, contentWidth, contentHeight); heightLeft -= (pdfHeight - margin * 2); } pdf.save('Budget_Report.pdf'); } catch (error) { console.error("BPT Tool Error: PDF generation failed.", error); alert("An error occurred while generating the PDF. Please try again."); } } // --- EVENT LISTENERS --- // Tab link clicks bpt_tabLinks.forEach((link, index) => { link.addEventListener('click', () => bpt_switchTab(index)); }); // Next/Prev button clicks if (bpt_prevButton) { bpt_prevButton.addEventListener('click', () => { if (bpt_currentTab > 0) bpt_switchTab(bpt_currentTab - 1); }); } if (bpt_nextButton) { bpt_nextButton.addEventListener('click', () => { if (bpt_currentTab < bpt_tabLinks.length - 1) bpt_switchTab(bpt_currentTab + 1); }); } // PDF download if (bpt_downloadPdfButton) { bpt_downloadPdfButton.addEventListener('click', bpt_downloadPDF); } // --- Config Tab "Add" Buttons --- if (bpt_addIncomeButton) { bpt_addIncomeButton.addEventListener('click', () => { const newItem = { id: bpt_incomeIdCounter++, source: '', amount: 0 }; bpt_data.income.push(newItem); bpt_incomeContainer.appendChild(bpt_createIncomeInput(newItem)); }); } if (bpt_addExpenseButton) { bpt_addExpenseButton.addEventListener('click', () => { const newItem = { id: bpt_expenseIdCounter++, item: '', category: 'Other', amount: 0 }; bpt_data.expenses.push(newItem); bpt_expensesContainer.appendChild(bpt_createExpenseInput(newItem)); }); } // --- Config Tab "Remove" Buttons & Input Changes (Event Delegation) --- if (bpt_configTab) { // Handle remove clicks bpt_configTab.addEventListener('click', (e) => { const removeButton = e.target.closest('.bpt-remove-item'); if (!removeButton) return; const entryDiv = removeButton.closest('[data-id]'); const id = parseInt(entryDiv.getAttribute('data-id'), 10); if (entryDiv.querySelector('.bpt-input-income-source')) { bpt_data.income = bpt_data.income.filter(item => item.id !== id); } else if (entryDiv.querySelector('.bpt-input-expense-item')) { bpt_data.expenses = bpt_data.expenses.filter(item => item.id !== id); } entryDiv.remove(); // Live update dashboard if active if (bpt_currentTab === 0) { bpt_renderDashboard(); } }); // Handle input changes bpt_configTab.addEventListener('change', () => { bpt_updateDataFromConfig(); if (bpt_currentTab === 0) { bpt_renderDashboard(); } }); } // --- INITIALIZATION --- bpt_initSampleData(); bpt_renderConfig(); bpt_renderDashboard(); // Set initial tab state bpt_tabPanes.forEach((pane, index) => { pane.classList.toggle('hidden', index !== 0); pane.classList.toggle('bpt-active', index === 0); }); });