`;
sliie_inputData.projectionTableData = []; // For PDF
const displayYears = [1];
if (projectionYears > 1) {
if (projectionYears > 2) { // Add mid-point if more than 2 years
let midYear = Math.ceil(projectionYears / 2);
if (midYear === 1) midYear = 2; // ensure mid isn't same as start if projectionYears = 2 or 3
if (midYear < projectionYears) displayYears.push(midYear);
}
displayYears.push(projectionYears); // Add end year
}
// Ensure unique, sorted years
const uniqueDisplayYears = [...new Set(displayYears)].sort((a,b) => a-b);
for (const year of uniqueDisplayYears) {
const nominalAnnualSalaryYearY = startingAnnualSalary * Math.pow(1 + avgSalaryGrowthRate, year -1); // Salary at start of year 'y'
const nominalMonthlySalaryYearY = nominalAnnualSalaryYearY / 12;
const realAnnualSalaryYearY = nominalAnnualSalaryYearY / Math.pow(1 + avgInflationRate, year -1); // Real value at start of year 'y'
const realMonthlySalaryYearY = realAnnualSalaryYearY / 12;
const realLoanPaymentValueYearY = monthlyLoanPayment / Math.pow(1 + avgInflationRate, year -1); // Real value of payment made during year 'y'
const paymentAsPercentOfNominal = nominalMonthlySalaryYearY > 0 ? (monthlyLoanPayment / nominalMonthlySalaryYearY) * 100 : Infinity;
const rowData = {
year: year,
nominalMonthlySalary: nominalMonthlySalaryYearY,
realMonthlySalary: realMonthlySalaryYearY,
nominalLoanPayment: monthlyLoanPayment,
realLoanPaymentValue: realLoanPaymentValueYearY,
paymentAsPercentOfNominal: paymentAsPercentOfNominal
};
sliie_inputData.projectionTableData.push(rowData);
tableHTML += `
Over time, the real value of your fixed ${sliie_formatCurrency(monthlyLoanPayment)} loan payment decreases due to inflation. For example, in Year ${projectionYears}, it's projected to be worth ${sliie_formatCurrency(sliie_inputData.projectionTableData[sliie_inputData.projectionTableData.length-1].realLoanPaymentValue)} in today's dollars.
If your salary grows over time (as projected at ${sliie_formatPercent(avgSalaryGrowthRate*100)} annually), your fixed loan payment should consume a smaller percentage of your nominal income.
The "Payment as % of Nominal Salary" shows how the burden of your fixed payment might change relative to your growing paycheck.
This is an estimation. Actual inflation and salary growth can vary significantly from these assumptions.
`;
sliie_domElements.resultsContainer.innerHTML = tableHTML + insightsHTML;
if (sliie_domElements.pdfDownloadBtn) {
sliie_domElements.pdfDownloadBtn.classList.remove('sliie-hidden');
}
}
function sliie_hexToRgb(hex) {
if (!hex || typeof hex !== 'string') return null;
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; });
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null;
}
function sliie_generatePdf() {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined' || typeof window.jspdf.jsPDF.API === 'undefined' || typeof window.jspdf.jsPDF.API.autoTable === 'undefined') {
alert("PDF generation library is not loaded. Please try again later."); return;
}
if (!sliie_validateTab1() || !sliie_validateTab2()) {
alert("Please ensure all inputs are correctly filled before generating PDF.");
if (!sliie_validateTab1()) sliie_navigateToTab('sliie-tab1');
else if (!sliie_validateTab2()) sliie_navigateToTab('sliie-tab2');
return;
}
sliie_calculateAndDisplayImpact();
if (sliie_domElements.resultsContainer && sliie_domElements.resultsContainer.innerHTML.includes("sliie-error-message")) {
alert("Cannot generate PDF due to errors in input or calculation. Please correct them."); return;
}
const ActualJsPDF = window.jspdf.jsPDF;
const doc = new ActualJsPDF();
const { monthlyLoanPayment, startingAnnualSalary, projectionYears, avgInflationRate, avgSalaryGrowthRate, projectionTableData } = sliie_inputData;
doc.setFontSize(18);
const primaryColorRGB = sliie_hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--sliie-primary-color').trim()) || {r:103,g:58,b:183};
const secondaryColorRGB = sliie_hexToRgb(getComputedStyle(document.documentElement).getPropertyValue('--sliie-secondary-color').trim()) || {r:81,g:45,b:168};
doc.setTextColor(primaryColorRGB.r, primaryColorRGB.g, primaryColorRGB.b);
doc.text("Student Loan Inflation Impact Estimate", 105, 20, null, null, "center");
doc.setFontSize(11);
doc.setTextColor(33,33,33);
let startY = 30;
doc.text(`Initial Monthly Loan Payment: ${sliie_formatCurrency(monthlyLoanPayment)}`, 14, startY); startY += 6;
doc.text(`Starting Annual Salary: ${sliie_formatCurrency(startingAnnualSalary)}`, 14, startY); startY += 6;
doc.text(`Projection Period: ${projectionYears} years`, 14, startY); startY += 6;
doc.text(`Assumed Avg. Annual Inflation: ${sliie_formatPercent(avgInflationRate*100)}`, 14, startY); startY += 6;
doc.text(`Assumed Avg. Annual Salary Growth: ${sliie_formatPercent(avgSalaryGrowthRate*100)}`, 14, startY);
startY += 10;
const tableHeadFillColor = [secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b];
const tableHeaders = [["Year", "Nominal Monthly Salary", "Real Monthly Salary (Today's $)", "Nominal Loan Payment", "Real Value of Payment (Today's $)", "Payment as % of Nominal Salary"]];
const tableBody = projectionTableData.map(row => [
`Year ${row.year}`,
sliie_formatCurrency(row.nominalMonthlySalary),
sliie_formatCurrency(row.realMonthlySalary),
sliie_formatCurrency(row.nominalLoanPayment),
sliie_formatCurrency(row.realLoanPaymentValue),
isFinite(row.paymentAsPercentOfNominal) ? sliie_formatPercent(row.paymentAsPercentOfNominal) : 'N/A'
]);
doc.autoTable({
startY: startY,
head: tableHeaders,
body: tableBody,
theme: 'grid',
headStyles: { fillColor: tableHeadFillColor, textColor: 255, fontSize:9, fontStyle:'bold' },
styles: { fontSize: 8.5, cellPadding: 2 },
margin: { left: 14, right: 14 },
columnStyles: { 0: {cellWidth: 15}, 5: {fontStyle:'bold'}}
});
startY = doc.autoTable.previous.finalY + 12;
doc.setFontSize(11);
doc.setTextColor(secondaryColorRGB.r, secondaryColorRGB.g, secondaryColorRGB.b);
doc.text("Key Insights:", 14, startY); startY += 7;
doc.setFontSize(9);
doc.setTextColor(33,33,33);
const insightsPDF = [
`- Over time, the real value of your fixed ${sliie_formatCurrency(monthlyLoanPayment)} loan payment decreases due to inflation. For example, in Year ${projectionYears}, it's projected to be worth ${sliie_formatCurrency(projectionTableData[projectionTableData.length-1].realLoanPaymentValue)} in today's dollars.`,
`- If your salary keeps pace with or outpaces inflation (as projected at ${sliie_formatPercent(avgSalaryGrowthRate*100)} annually), your fixed loan payment should consume a smaller percentage of your nominal income.`,
`- The \"Payment as % of Nominal Salary\" shows how the burden of your fixed payment might change relative to your growing paycheck.`,
`- This is an estimation. Actual inflation and salary growth can vary significantly from these assumptions.`
];
insightsPDF.forEach(insight => {
const splitInsight = doc.splitTextToSize(insight, doc.internal.pageSize.width - 28);
doc.text(splitInsight, 14, startY);
startY += (splitInsight.length * (doc.getLineHeight() / doc.internal.scaleFactor * 0.8)) + 1.5;
});
doc.setFontSize(9);
doc.setTextColor(120);
doc.text(`Report generated on: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}`, 14, doc.internal.pageSize.height - 10);
doc.save("Student_Loan_Inflation_Impact.pdf");
}
window.sliie_switchTab = sliie_switchTab;
window.sliie_navigateToTab = sliie_navigateToTab;
window.sliie_generatePdf = sliie_generatePdf;