Retirement Age
${projectionData.inputs.retirementAge}
`;
};
const downloadPDF = () => {
if (!projectionData) {
alert('Please run a calculation first on the "Projections Dashboard" tab.');
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' });
const theme = document.querySelector('input[name="theme"]:checked').value;
const page = { width: doc.internal.pageSize.getWidth(), height: doc.internal.pageSize.getHeight() };
const margin = 50;
let y;
const colors = theme === 'wealth'
? { bg: '#065f46', text: '#FFFFFF', primary: '#1f2937', secondary: '#4b5563', accent: '#10b981' }
: { bg: '#1e40af', text: '#FFFFFF', primary: '#212529', secondary: '#495057', accent: '#3b82f6' };
// --- Header ---
doc.setFillColor(colors.bg);
doc.rect(0, 0, page.width, 90, 'F');
doc.setFont('helvetica', 'bold');
doc.setFontSize(22);
doc.setTextColor(colors.text);
doc.text('Retirement Investment Plan', margin, 55);
doc.setFontSize(10);
doc.text(`Generated on: ${new Date().toLocaleDateString('en-US')}`, margin, 75);
y = 130;
// --- Summary Section ---
doc.setFont('helvetica', 'bold');
doc.setFontSize(14);
doc.setTextColor(colors.primary);
doc.text('Retirement Outlook', margin, y);
y += 20;
doc.autoTable({
startY: y,
theme: 'grid',
headStyles: { fillColor: colors.accent },
body: [
['Projected Nest Egg', formatter.format(projectionData.finalBalance)],
['Estimated Monthly Income (4% Rule)', formatter.format(projectionData.monthlyRetirementIncome)],
['Total Contributions', formatter.format(projectionData.totalContributions + projectionData.inputs.currentSavings)],
['Total Investment Growth', formatter.format(projectionData.totalGrowth)],
]
});
y = doc.autoTable.previous.finalY + 30;
// --- Input Assumptions ---
doc.setFont('helvetica', 'bold');
doc.setFontSize(14);
doc.setTextColor(colors.primary);
doc.text('Planning Assumptions', margin, y);
y += 20;
const { inputs, strategy } = projectionData;
doc.autoTable({
startY: y,
theme: 'striped',
headStyles: { fillColor: colors.accent },
head: [['Parameter', 'Value']],
body: [
['Current Age', inputs.currentAge],
['Retirement Age', inputs.retirementAge],
['Current Savings', formatter.format(inputs.currentSavings)],
['Initial Monthly Contribution', formatter.format(inputs.monthlyContribution)],
['Annual Contribution Increase', `${(inputs.salaryIncrease * 100).toFixed(1)}%`],
['Investment Strategy', `${strategy.name} (${strategy.return}% est. return)`],
]
});
y = doc.autoTable.previous.finalY + 30;
// --- Chart ---
if (y > page.height - 250) {
doc.addPage(); y = margin;
}
const chartImage = projectionChart.toBase64Image();
doc.addImage(chartImage, 'PNG', margin, y, page.width - margin*2, (page.width - margin*2) / 2);
doc.save(`retirement-plan.pdf`);
};
// --- Event Listeners ---
tabs.forEach((tab, index) => tab.addEventListener('click', () => showTab(index)));
prevBtn.addEventListener('click', () => navigateTab(-1));
nextBtn.addEventListener('click', () => navigateTab(1));
riskSlider.addEventListener('input', updateStrategyUI);
calculateBtn.addEventListener('click', calculateProjections);
downloadPdfBtn.addEventListener('click', downloadPDF);
// --- Initialization ---
showTab(0);
updateStrategyUI();
});