138 lines
4.9 KiB
JavaScript
138 lines
4.9 KiB
JavaScript
import moment from 'moment';
|
|
|
|
// Function to simulate monthly financial projection
|
|
// src/utils/FinancialProjectionService.js
|
|
|
|
export function simulateFinancialProjection(userProfile) {
|
|
const {
|
|
currentSalary,
|
|
monthlyExpenses,
|
|
monthlyDebtPayments,
|
|
studentLoanAmount,
|
|
interestRate, // ✅ Corrected
|
|
loanTerm, // ✅ Corrected
|
|
extraPayment,
|
|
expectedSalary,
|
|
emergencySavings,
|
|
retirementSavings,
|
|
monthlyRetirementContribution,
|
|
monthlyEmergencyContribution,
|
|
gradDate,
|
|
fullTimeCollegeStudent: inCollege,
|
|
partTimeIncome,
|
|
startDate,
|
|
programType,
|
|
isFullyOnline,
|
|
creditHoursPerYear,
|
|
calculatedTuition,
|
|
hoursCompleted,
|
|
loanDeferralUntilGraduation,
|
|
programLength
|
|
} = userProfile;
|
|
|
|
const monthlyLoanPayment = calculateLoanPayment(studentLoanAmount, interestRate, loanTerm);
|
|
|
|
let totalEmergencySavings = emergencySavings;
|
|
let totalRetirementSavings = retirementSavings;
|
|
let loanBalance = studentLoanAmount;
|
|
let projectionData = [];
|
|
|
|
const graduationDate = gradDate ? new Date(gradDate) : null;
|
|
let milestoneIndex = 0;
|
|
let loanPaidOffMonth = null;
|
|
|
|
// Dynamic credit hours based on the program type
|
|
let requiredCreditHours;
|
|
switch (programType) {
|
|
case "Associate Degree":
|
|
requiredCreditHours = 60;
|
|
break;
|
|
case "Bachelor's Degree":
|
|
requiredCreditHours = 120;
|
|
break;
|
|
case "Master's Degree":
|
|
requiredCreditHours = 30;
|
|
break;
|
|
case "Doctoral Degree":
|
|
requiredCreditHours = 60;
|
|
break;
|
|
default:
|
|
requiredCreditHours = 120;
|
|
}
|
|
|
|
const remainingCreditHours = requiredCreditHours - hoursCompleted;
|
|
const programDuration = Math.ceil(remainingCreditHours / creditHoursPerYear);
|
|
const tuitionCost = calculatedTuition;
|
|
const totalTuitionCost = tuitionCost * programDuration;
|
|
|
|
const date = new Date(startDate);
|
|
for (let month = 0; month < 240; month++) {
|
|
date.setMonth(date.getMonth() + 1);
|
|
|
|
if (loanBalance <= 0 && !loanPaidOffMonth) {
|
|
loanPaidOffMonth = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
|
|
}
|
|
|
|
let tuitionCostThisMonth = 0;
|
|
if (inCollege && !loanDeferralUntilGraduation) {
|
|
tuitionCostThisMonth = totalTuitionCost / programDuration / 12;
|
|
}
|
|
|
|
let thisMonthLoanPayment = 0;
|
|
|
|
if (loanDeferralUntilGraduation && graduationDate && date < graduationDate) {
|
|
const interestForMonth = loanBalance * (interestRate / 100 / 12); // ✅ Corrected here
|
|
loanBalance += interestForMonth;
|
|
} else if (loanBalance > 0) {
|
|
const interestForMonth = loanBalance * (interestRate / 100 / 12); // ✅ Corrected here
|
|
const principalForMonth = Math.min(loanBalance, monthlyLoanPayment + extraPayment - interestForMonth);
|
|
loanBalance -= principalForMonth;
|
|
loanBalance = Math.max(loanBalance, 0);
|
|
thisMonthLoanPayment = monthlyLoanPayment + extraPayment;
|
|
}
|
|
|
|
const salaryNow = graduationDate && date >= graduationDate ? expectedSalary : currentSalary;
|
|
|
|
const totalMonthlyExpenses = monthlyExpenses
|
|
+ tuitionCostThisMonth
|
|
+ monthlyDebtPayments
|
|
+ thisMonthLoanPayment;
|
|
|
|
const monthlyIncome = salaryNow / 12;
|
|
|
|
let extraCash = monthlyIncome - totalMonthlyExpenses - monthlyRetirementContribution - monthlyEmergencyContribution;
|
|
extraCash = Math.max(extraCash, 0);
|
|
|
|
// update savings explicitly with contributions first
|
|
totalEmergencySavings += monthlyEmergencyContribution + (extraCash * 0.3);
|
|
totalRetirementSavings += monthlyRetirementContribution + (extraCash * 0.7);
|
|
totalRetirementSavings *= (1 + 0.07 / 12);
|
|
|
|
// netSavings calculation fixed
|
|
projectionData.push({
|
|
month: `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`,
|
|
salary: salaryNow,
|
|
monthlyIncome: monthlyIncome,
|
|
expenses: totalMonthlyExpenses,
|
|
loanPayment: thisMonthLoanPayment,
|
|
retirementContribution: monthlyRetirementContribution,
|
|
emergencyContribution: monthlyEmergencyContribution,
|
|
netSavings: monthlyIncome - totalMonthlyExpenses, // Exclude contributions here explicitly!
|
|
totalEmergencySavings,
|
|
totalRetirementSavings,
|
|
loanBalance
|
|
});
|
|
|
|
}
|
|
|
|
|
|
return { projectionData, loanPaidOffMonth, emergencySavings };
|
|
}
|
|
|
|
function calculateLoanPayment(principal, annualRate, years) {
|
|
const monthlyRate = annualRate / 100 / 12;
|
|
const numPayments = years * 12;
|
|
return (principal * monthlyRate) / (1 - Math.pow(1 + monthlyRate, -numPayments));
|
|
}
|
|
|