`;
reportHTML += `
Minimalist Budget Targets (Monthly)
`;
const budgetTableData = [];
predefinedEssentials.forEach(cat => {
if(cat.targetAmount > 0) budgetTableData.push([cat.name, formatCurrency(cat.targetAmount)]);
});
customEssentials.filter(c => c.name.trim() !== '' && c.targetAmount > 0).forEach(cat => {
budgetTableData.push([cat.name, formatCurrency(cat.targetAmount)]);
});
if (targetDiscretionary > 0) {
budgetTableData.push(["Intentional Discretionary Fund", formatCurrency(targetDiscretionary)]);
}
if(budgetTableData.length > 0){
reportHTML += `
| Category | Target Amount |
`;
budgetTableData.forEach(row => reportHTML += `| ${row[0]} | ${row[1]} |
`);
reportHTML += `
`;
} else {
reportHTML += `
No specific targets set for essential categories or discretionary fund.
`;
}
reportHTML += `
Total Target Minimalist Monthly Expenses: ${formatCurrency(totalMinimalistExpenses)}
`;
reportHTML += `
Potential Monthly Savings
(Income - Target Minimalist Expenses):
${formatCurrency(potentialSavings)}
`;
// Comparison part - if data exists from Tab 2
let totalCurrentEssentialSpendingReport = 0;
predefinedEssentials.forEach(cat => totalCurrentEssentialSpendingReport += cat.currentAmount || 0);
customEssentials.forEach(cat => totalCurrentEssentialSpendingReport += cat.currentAmount || 0);
const currentOtherDiscSpendReport = parseFloat(document.getElementById('mb_currentOtherDiscretionarySpending')?.value || 0) || 0; // Check if element exists
const totalCurrentSpendingReport = totalCurrentEssentialSpendingReport + currentOtherDiscSpendReport;
if (totalCurrentSpendingReport > 0 || currentOtherDiscSpendReport > 0) { // Indicates Tab 2 might have been used
const totalPotentialSwitchSavingsReport = totalCurrentSpendingReport - totalMinimalistExpenses;
reportHTML += `
Current Spending vs. Target Comparison
Total Current Monthly Spending: ${formatCurrency(totalCurrentSpendingReport)}
Total Minimalist Budget Target: ${formatCurrency(totalMinimalistExpenses)}
Total Potential Savings by Switching:
${formatCurrency(totalPotentialSwitchSavingsReport)}
`;
}
summaryReportContentEl.innerHTML = reportHTML;
}
// --- PDF Download ---
if (downloadPdfBtn) {
downloadPdfBtn.addEventListener('click', () => {
if (typeof jsPDF === 'undefined') { alert('PDF library (jsPDF) is not loaded.'); return; }
const doc = new jsPDF('p', 'pt', 'letter');
if (typeof doc.autoTable !== 'function') { alert('PDF table library (jspdf-autotable) is not loaded correctly.'); return; }
const currentCurrency = currencySymbolInput.value || '$';
const pageWidth = doc.internal.pageSize.getWidth();
const margin = 40;
let yPos = margin;
const todayFormatted = new Date(2025, 4, 15).toLocaleDateString(); // Using fixed date for consistency
doc.setFontSize(18);
doc.setTextColor(document.documentElement.style.getPropertyValue('--primary-color') || '#007bff');
doc.text("My Minimalist Budget Plan", pageWidth / 2, yPos, { align: 'center' });
yPos += 15;
doc.setFontSize(9); doc.setTextColor(100);
doc.text(`Date Created: ${todayFormatted} | Currency: ${currentCurrency}`, pageWidth / 2, yPos, { align: 'center' });
yPos += 25;
function addPdfSectionTitle(title) { /* ... */
if (yPos > doc.internal.pageSize.getHeight() - 60) { doc.addPage(); yPos = margin; }
doc.setFontSize(14);
doc.setTextColor(document.documentElement.style.getPropertyValue('--primary-darker-color') || '#0056b3');
doc.text(title, margin, yPos);
yPos += 15;
doc.setFontSize(10); doc.setTextColor(40);
}
const income = parseFloat(netMonthlyIncomeInput.value) || 0;
let targetEssentials = predefinedEssentials.reduce((sum, cat) => sum + (cat.targetAmount || 0), 0);
let customEssentialSpending = customEssentials.reduce((sum, cat) => sum + (cat.targetAmount || 0), 0);
targetEssentials += customEssentialSpending;
const targetDiscretionary = parseFloat(discretionaryFundInput.value) || 0;
const totalMinimalistExpenses = targetEssentials + targetDiscretionary;
const potentialSavings = income - totalMinimalistExpenses;
// Section 1: Income
addPdfSectionTitle("1. Income");
doc.autoTable({ startY: yPos, theme: 'plain', body: [["Net Monthly Income:", formatCurrency(income, currentCurrency)]], columnStyles: {0: {fontStyle: 'bold'}}});
yPos = doc.lastAutoTable.finalY + 15;
// Section 2: Minimalist Budget Allocation
addPdfSectionTitle("2. Minimalist Budget Allocation (Monthly)");
const budgetTableHead = [['Category', 'Target Spending']];
const budgetTableBody = [];
predefinedEssentials.forEach(cat => {
if (cat.targetAmount > 0) budgetTableBody.push([cat.name, formatCurrency(cat.targetAmount, currentCurrency)]);
});
customEssentials.filter(c => c.name.trim() !== '' && c.targetAmount > 0).forEach(cat => {
budgetTableBody.push([cat.name, formatCurrency(cat.targetAmount, currentCurrency)]);
});
if (targetDiscretionary > 0) {
budgetTableBody.push(["Intentional Discretionary Fund", formatCurrency(targetDiscretionary, currentCurrency)]);
}
if(budgetTableBody.length === 0) budgetTableBody.push(["No specific targets set.", "-"]);
doc.autoTable({
head: budgetTableHead, body: budgetTableBody, startY: yPos, theme: 'grid',
headStyles: { fillColor: [0, 123, 255], fontSize: 10 }, bodyStyles: { fontSize: 9 }
});
yPos = doc.lastAutoTable.finalY + 5;
doc.setFont(undefined, 'bold');
doc.text(`Total Target Minimalist Monthly Expenses: ${formatCurrency(totalMinimalistExpenses, currentCurrency)}`, margin, yPos);
yPos += 15;
doc.setFont(undefined, 'normal');
// Section 3: Potential Monthly Savings
addPdfSectionTitle("3. Potential Monthly Savings (with Minimalist Budget)");
doc.autoTable({ startY: yPos, theme: 'plain', body: [
[{content: "(Income - Target Minimalist Expenses):", styles:{fontStyle:'bold'}},
{content: formatCurrency(potentialSavings, currentCurrency), styles:{fontStyle:'bold', textColor: potentialSavings >=0 ? [34,139,34] : [220,53,69] }}]
]});
yPos = doc.lastAutoTable.finalY + 15;
// Section 4: Current Spending vs. Target Comparison (Optional)
let totalCurrentEssentialSpendingPdf = 0;
predefinedEssentials.forEach(cat => totalCurrentEssentialSpendingPdf += cat.currentAmount || 0);
customEssentials.forEach(cat => totalCurrentEssentialSpendingPdf += cat.currentAmount || 0);
const currentOtherDiscSpendPdf = parseFloat(document.getElementById('mb_currentOtherDiscretionarySpending')?.value || 0) || 0;
const totalCurrentSpendingPdf = totalCurrentEssentialSpendingPdf + currentOtherDiscSpendPdf;
if (totalCurrentSpendingPdf > 0 || currentOtherDiscSpendPdf > 0) { // If any current spending was entered
addPdfSectionTitle("4. Current Spending vs. Target Comparison");
const totalPotentialSwitchSavingsPdf = totalCurrentSpendingPdf - totalMinimalistExpenses;
doc.autoTable({ startY: yPos, theme: 'striped', body: [
["Total Current Monthly Spending:", formatCurrency(totalCurrentSpendingPdf, currentCurrency)],
["Total Minimalist Budget Target:", formatCurrency(totalMinimalistExpenses, currentCurrency)],
[{content: "Total Potential Additional Savings by Switching:", styles:{fontStyle:'bold'}},
{content: formatCurrency(totalPotentialSwitchSavingsPdf, currentCurrency), styles:{fontStyle:'bold', textColor: totalPotentialSwitchSavingsPdf >=0 ? [34,139,34] : [220,53,69] }}]
], columnStyles: {0: {fontStyle:'bold'}}});
yPos = doc.lastAutoTable.finalY + 5;
}
doc.save('Minimalist_Budget_Plan.pdf');
});
}
// --- Initial Load & Setup ---
renderEssentialCategoryInputs();
renderCustomEssentialFields(); // Initial render for custom (will be empty)
updatePlanTabSummary();
populateCurrentSpendingInputs(); // So Tab 2 is ready if navigated to
renderSummaryReportTab(); // Initial render for summary tab
showTab(0);
});