New Refinanced Loan
New Monthly Payment: ${slrc_formatCurrency(newMonthlyPayment)}
New Loan Term: ${newTermYears * 12} months (${newTermYears} years)
Total Interest Paid: ${slrc_formatCurrency(totalInterestNew)}
Upfront Refinancing Fees: ${slrc_formatCurrency(refiFees)}
Total Cost (Interest + Fees): ${slrc_formatCurrency(totalCostNewLoan)}
Refinancing Impact
Change in Monthly Payment:
${monthlyPaymentDifference > 0 ? `Save ${slrc_formatCurrency(monthlyPaymentDifference)}` : (monthlyPaymentDifference < 0 ? `Increase by ${slrc_formatCurrency(Math.abs(monthlyPaymentDifference))}` : 'No Change')} / month
Potential Lifetime Savings:
${lifetimeSavings > 0 ? `Save ${slrc_formatCurrency(lifetimeSavings)}` : (lifetimeSavings < 0 ? `Cost ${slrc_formatCurrency(Math.abs(lifetimeSavings))} more` : 'No Overall Savings')}
Breakeven Point for Fees: ${typeof breakevenMonths === 'number' ? `${breakevenMonths} months` : breakevenMonths}
`;
// Populate New Loan Amortization Table
const amortTableBody = document.querySelector('#slrc-new-loan-amortization-table tbody');
amortTableBody.innerHTML = '';
slrc_comparisonDataForPdf.newLoanAmortization.forEach(row => {
const tr = amortTableBody.insertRow();
tr.insertCell().textContent = row.month;
tr.insertCell().textContent = slrc_formatCurrency(row.payment);
tr.insertCell().textContent = slrc_formatCurrency(row.principal);
tr.insertCell().textContent = slrc_formatCurrency(row.interest);
tr.insertCell().textContent = slrc_formatCurrency(row.balance);
});
slrc_navigateToTab(2); // Go to results tab
}
function slrc_generatePDF() {
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') {
alert('PDF generation library (jsPDF) is not loaded.'); return;
}
const JSPDF_CONSTRUCTOR = window.jspdf.jsPDF;
const tempDoc = new JSPDF_CONSTRUCTOR();
if (typeof tempDoc.autoTable !== 'function') {
alert('jsPDF AutoTable plugin is not loaded.'); return;
}
if (Object.keys(slrc_comparisonDataForPdf).length === 0) {
alert('Please compare loans first to generate a PDF.'); return;
}
const doc = new JSPDF_CONSTRUCTOR({ orientation: 'p' });
const data = slrc_comparisonDataForPdf;
let yPos = 15;
const pageMargin = 15;
const pageWidth = doc.internal.pageSize.getWidth();
const usableWidth = pageWidth - (2 * pageMargin);
const primaryColor = [74, 144, 226]; // #4a90e2
const headingColor = [59, 124, 184]; // #3b7cb8
const textColor = [44, 62, 80]; // #2c3e50
const savingsGreen = [92, 184, 92]; // #5cb85c
const costRed = [217, 83, 79]; // #d9534f
function addMainHeader(text) {
doc.setFontSize(16);
doc.setTextColor(headingColor[0], headingColor[1], headingColor[2]);
doc.text(text, pageWidth / 2, yPos, { align: 'center' });
yPos += 12;
}
function addSectionHeader(text) {
if (yPos > doc.internal.pageSize.getHeight() - 30) { doc.addPage(); yPos = pageMargin; }
doc.setFontSize(12);
doc.setFont(undefined, 'bold');
doc.setTextColor(primaryColor[0], primaryColor[1], primaryColor[2]);
doc.text(text, pageMargin, yPos);
yPos += 8;
doc.setFont(undefined, 'normal');
}
function addWarning(textLines) {
if (yPos > doc.internal.pageSize.getHeight() - (textLines.length * 5) - 15) { doc.addPage(); yPos = pageMargin; }
doc.setFontSize(9);
doc.setTextColor(costRed[0], costRed[1], costRed[2]); // Red for warning
doc.setFillColor(252,248,227); // Light yellow background #fcf8e3
const textHeight = (textLines.length * 4) + (textLines.length > 1 ? (textLines.length-1)*1.5 : 0) + 8; // Approximate height
doc.rect(pageMargin - 2, yPos - 3, usableWidth + 4, textHeight, 'F');
doc.text("Important: Refinancing Federal Loans", pageMargin, yPos);
yPos +=5;
textLines.forEach(line => {
doc.text("• " + line, pageMargin + 3, yPos);
yPos += 4.5;
});
yPos += 5; // Spacing after warning
doc.setTextColor(textColor[0], textColor[1], textColor[2]); // Reset color
}
addMainHeader("Student Loan Refinancing Comparison");
// Federal Loan Warning if applicable
if (data.currentLoanType === 'federal' || data.currentLoanType === 'mix') {
const warningLines = [
"Refinancing federal loans into a private loan means permanent loss of federal benefits:",
" - Income-Driven Repayment (IDR) plans (SAVE, PAYE, etc.)",
" - Public Service Loan Forgiveness (PSLF) & other federal forgiveness.",
" - Federal deferment and forbearance options.",
" - Potential future federal relief measures." ,
"Carefully consider if savings outweigh losing these protections."
];
addWarning(warningLines);
}
// Inputs Summary
addSectionHeader("Your Inputs:");
const inputsForPdf = [
["Total Current Loan Balance:", slrc_formatCurrency(data.currentBalance)],
["Current Avg. Interest Rate:", `${data.currentAnnualRate.toFixed(2)}%`],
["Current Total Monthly Payment:", slrc_formatCurrency(data.currentMonthlyPayment)],
["Type of Current Loans:", data.currentLoanType.charAt(0).toUpperCase() + data.currentLoanType.slice(1)],
["New Refinanced Interest Rate:", `${data.newAnnualRate.toFixed(2)}%`],
["New Refinanced Loan Term:", `${data.newTermYears} years`],
["Upfront Refinancing Fees:", slrc_formatCurrency(data.refiFees)],
];
doc.autoTable({
startY: yPos, body: inputsForPdf, theme: 'grid',
styles: { fontSize: 9, cellPadding: 2 },
headStyles: {fillColor: primaryColor}, // Not using head explicitly here
columnStyles: { 0: { fontStyle: 'bold' } },
didDrawPage: function (hookData){ yPos = hookData.cursor.y ? hookData.cursor.y +10 : pageMargin; }
});
yPos = doc.lastAutoTable.finalY ? doc.lastAutoTable.finalY + 10 : yPos;
// Comparison Summary
if (yPos > doc.internal.pageSize.getHeight() - 80) { doc.addPage(); yPos = pageMargin; }
addSectionHeader("Refinancing Comparison Summary:");
const comparisonForPdf = [
["Metric", "Current Loan (Estimate)", "New Refinanced Loan"],
["Monthly Payment", slrc_formatCurrency(data.currentMonthlyPayment), slrc_formatCurrency(data.newMonthlyPayment)],
["Remaining Term", `${data.remainingPaymentsCurrent} months (~${data.remainingTermYearsCurrent.toFixed(1)} yrs)`, `${data.newTermYears * 12} months (${data.newTermYears} yrs)`],
["Total Future Interest Paid", slrc_formatCurrency(data.totalFutureInterestCurrent), slrc_formatCurrency(data.totalInterestNew)],
["Total Future Payments", slrc_formatCurrency(data.currentMonthlyPayment * data.remainingPaymentsCurrent), slrc_formatCurrency(data.newMonthlyPayment * data.newTermYears * 12)],
["Upfront Fees", "N/A", slrc_formatCurrency(data.refiFees)],
["Total Cost (Future Interest + Fees)", slrc_formatCurrency(data.totalFutureInterestCurrent), slrc_formatCurrency(data.totalCostNewLoan)],
];
doc.autoTable({
startY: yPos,
head: [comparisonForPdf[0]], // Use first row as head
body: comparisonForPdf.slice(1),
theme: 'striped',
headStyles: { fillColor: primaryColor, textColor: [255,255,255], fontStyle: 'bold' },
styles: { fontSize: 8, cellPadding: 2 },
didDrawPage: function (hookData){ yPos = hookData.cursor.y ? hookData.cursor.y +10 : pageMargin; }
});
yPos = doc.lastAutoTable.finalY ? doc.lastAutoTable.finalY + 10 : yPos;
// Savings Details
if (yPos > doc.internal.pageSize.getHeight() - 40) { doc.addPage(); yPos = pageMargin; }
addSectionHeader("Overall Impact:");
let mpdText = data.monthlyPaymentDifference > 0 ? `Save ${slrc_formatCurrency(data.monthlyPaymentDifference)} / month` :
data.monthlyPaymentDifference < 0 ? `Increase by ${slrc_formatCurrency(Math.abs(data.monthlyPaymentDifference))} / month` :
'No Change / month';
let lsText = data.lifetimeSavings > 0 ? `Save ${slrc_formatCurrency(data.lifetimeSavings)}` :
data.lifetimeSavings < 0 ? `Cost ${slrc_formatCurrency(Math.abs(data.lifetimeSavings))} more` :
'No Overall Savings/Cost Change';
const impactData = [
["Change in Monthly Payment:", mpdText],
["Potential Lifetime Savings:", lsText],
["Breakeven Point for Fees:", typeof data.breakevenMonths === 'number' ? `${data.breakevenMonths} months` : data.breakevenMonths]
];
doc.autoTable({
startY: yPos, body: impactData, theme: 'plain',
styles: { fontSize: 9, cellPadding: 2 },
columnStyles: { 0: { fontStyle: 'bold'} },
didParseCell: function(hookData){
if(hookData.row.index === 0) hookData.cell.styles.textColor = data.monthlyPaymentDifference > 0 ? savingsGreen : (data.monthlyPaymentDifference < 0 ? costRed : textColor);
if(hookData.row.index === 1) hookData.cell.styles.textColor = data.lifetimeSavings > 0 ? savingsGreen : (data.lifetimeSavings < 0 ? costRed : textColor);
},
didDrawPage: function (hookData){ yPos = hookData.cursor.y ? hookData.cursor.y +10 : pageMargin; }
});
yPos = doc.lastAutoTable.finalY ? doc.lastAutoTable.finalY + 10 : yPos;
// New Loan Amortization Schedule (if space allows or new page)
if (data.newLoanAmortization && data.newLoanAmortization.length > 0) {
if (yPos > doc.internal.pageSize.getHeight() - 50) { doc.addPage(); yPos = pageMargin; } // Check space
addSectionHeader("New Refinanced Loan Amortization Schedule:");
const amortBody = data.newLoanAmortization.map(row => [
row.month, slrc_formatCurrency(row.payment), slrc_formatCurrency(row.principal),
slrc_formatCurrency(row.interest), slrc_formatCurrency(row.balance)
]);
doc.autoTable({
startY: yPos,
head: [['Month', 'Payment', 'Principal', 'Interest', 'Balance']],
body: amortBody, theme: 'striped',
headStyles: { fillColor: primaryColor, textColor: [255,255,255] },
styles: { fontSize: 7, cellPadding: 1.5, halign: 'right' },
columnStyles: { 0: { halign: 'center' } },
didDrawPage: function (hookData){ yPos = hookData.cursor.y ? hookData.cursor.y +10 : pageMargin; }
});
}
doc.save("Student_Loan_Refinancing_Comparison.pdf");
}