Adjusted financial simulation for taxes.

This commit is contained in:
Josh 2025-04-18 12:22:00 +00:00
parent e3d804e01a
commit 126a17543c
3 changed files with 307 additions and 12 deletions

View File

@ -0,0 +1,244 @@
// src/components/ScenarioEditModal.js
import React, { useState, useEffect } from 'react';
import authFetch from '../utils/authFetch';
const ScenarioEditModal = ({
show,
onClose,
financialProfile,
setFinancialProfile,
collegeProfile,
setCollegeProfile,
apiURL,
authFetch,
}) => {
const [formData, setFormData] = useState({});
// Populate local formData whenever show=true
useEffect(() => {
if (!show) return;
setFormData({
// From financialProfile:
currentSalary: financialProfile?.current_salary ?? 0,
monthlyExpenses: financialProfile?.monthly_expenses ?? 0,
monthlyDebtPayments: financialProfile?.monthly_debt_payments ?? 0,
retirementSavings: financialProfile?.retirement_savings ?? 0,
emergencySavings: financialProfile?.emergency_fund ?? 0,
monthlyRetirementContribution: financialProfile?.retirement_contribution ?? 0,
monthlyEmergencyContribution: financialProfile?.emergency_contribution ?? 0,
surplusEmergencyAllocation: financialProfile?.extra_cash_emergency_pct ?? 50,
surplusRetirementAllocation: financialProfile?.extra_cash_retirement_pct ?? 50,
// From collegeProfile:
studentLoanAmount: collegeProfile?.existing_college_debt ?? 0,
interestRate: collegeProfile?.interest_rate ?? 5,
loanTerm: collegeProfile?.loan_term ?? 10,
loanDeferralUntilGraduation: !!collegeProfile?.loan_deferral_until_graduation,
academicCalendar: collegeProfile?.academic_calendar ?? 'monthly',
annualFinancialAid: collegeProfile?.annual_financial_aid ?? 0,
calculatedTuition: collegeProfile?.tuition ?? 0,
extraPayment: collegeProfile?.extra_payment ?? 0,
partTimeIncome: 0, // or fetch from DB if you store it
gradDate: collegeProfile?.expected_graduation ?? '',
programType: collegeProfile?.program_type ?? '',
creditHoursPerYear: collegeProfile?.credit_hours_per_year ?? 0,
hoursCompleted: collegeProfile?.hours_completed ?? 0,
programLength: collegeProfile?.program_length ?? 0,
inCollege:
collegeProfile?.college_enrollment_status === 'currently_enrolled' ||
collegeProfile?.college_enrollment_status === 'prospective_student',
expectedSalary: collegeProfile?.expected_salary ?? financialProfile?.current_salary ?? 0,
});
}, [show, financialProfile, collegeProfile]);
// Handle form changes in local state
const handleChange = (e) => {
const { name, type, value, checked } = e.target;
setFormData((prev) => ({
...prev,
[name]:
type === 'checkbox'
? checked
: type === 'number'
? parseFloat(value) || 0
: value
}));
};
// SAVE: Update DB and local states, then close
const handleSave = async () => {
try {
// 1) Update the backend (financialProfile + collegeProfile):
// (Adjust endpoints/methods as needed in your codebase)
await authFetch(`${apiURL}/premium/financial-profile`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
current_salary: formData.currentSalary,
monthly_expenses: formData.monthlyExpenses,
monthly_debt_payments: formData.monthlyDebtPayments,
retirement_savings: formData.retirementSavings,
emergency_fund: formData.emergencySavings,
retirement_contribution: formData.monthlyRetirementContribution,
emergency_contribution: formData.monthlyEmergencyContribution,
extra_cash_emergency_pct: formData.surplusEmergencyAllocation,
extra_cash_retirement_pct: formData.surplusRetirementAllocation
})
});
await authFetch(`${apiURL}/premium/college-profile`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
existing_college_debt: formData.studentLoanAmount,
interest_rate: formData.interestRate,
loan_term: formData.loanTerm,
loan_deferral_until_graduation: formData.loanDeferralUntilGraduation,
academic_calendar: formData.academicCalendar,
annual_financial_aid: formData.annualFinancialAid,
tuition: formData.calculatedTuition,
extra_payment: formData.extraPayment,
expected_graduation: formData.gradDate,
program_type: formData.programType,
credit_hours_per_year: formData.creditHoursPerYear,
hours_completed: formData.hoursCompleted,
program_length: formData.programLength,
college_enrollment_status: formData.inCollege
? 'currently_enrolled'
: 'not_enrolled',
expected_salary: formData.expectedSalary
})
});
// 2) Update local React state so your useEffect triggers re-simulation
setFinancialProfile((prev) => ({
...prev,
current_salary: formData.currentSalary,
monthly_expenses: formData.monthlyExpenses,
monthly_debt_payments: formData.monthlyDebtPayments,
retirement_savings: formData.retirementSavings,
emergency_fund: formData.emergencySavings,
retirement_contribution: formData.monthlyRetirementContribution,
emergency_contribution: formData.monthlyEmergencyContribution,
extra_cash_emergency_pct: formData.surplusEmergencyAllocation,
extra_cash_retirement_pct: formData.surplusRetirementAllocation
}));
setCollegeProfile((prev) => ({
...prev,
existing_college_debt: formData.studentLoanAmount,
interest_rate: formData.interestRate,
loan_term: formData.loanTerm,
loan_deferral_until_graduation: formData.loanDeferralUntilGraduation,
academic_calendar: formData.academicCalendar,
annual_financial_aid: formData.annualFinancialAid,
tuition: formData.calculatedTuition,
extra_payment: formData.extraPayment,
expected_graduation: formData.gradDate,
program_type: formData.programType,
credit_hours_per_year: formData.creditHoursPerYear,
hours_completed: formData.hoursCompleted,
program_length: formData.programLength,
college_enrollment_status: formData.inCollege
? 'currently_enrolled'
: 'not_enrolled',
expected_salary: formData.expectedSalary
}));
// 3) Close the modal
onClose();
} catch (err) {
console.error('Error saving scenario changes:', err);
// Optionally show a toast or error UI
}
};
// If show=false, don't render anything
if (!show) return null;
return (
<div className="modal-backdrop">
<div className="modal-container">
<h2 className="text-xl font-bold mb-4">Edit Scenario Inputs</h2>
{/* EXAMPLE FIELDS: Add all the fields you actually want visible */}
<div className="mb-3">
<label className="block font-semibold">Current Salary</label>
<input
type="number"
name="currentSalary"
value={formData.currentSalary}
onChange={handleChange}
className="border px-2 py-1 w-full"
/>
</div>
<div className="mb-3">
<label className="block font-semibold">Monthly Expenses</label>
<input
type="number"
name="monthlyExpenses"
value={formData.monthlyExpenses}
onChange={handleChange}
className="border px-2 py-1 w-full"
/>
</div>
<div className="mb-3">
<label className="block font-semibold">Tuition</label>
<input
type="number"
name="calculatedTuition"
value={formData.calculatedTuition}
onChange={handleChange}
className="border px-2 py-1 w-full"
/>
</div>
<div className="mb-3">
<label className="block font-semibold">Annual Financial Aid</label>
<input
type="number"
name="annualFinancialAid"
value={formData.annualFinancialAid}
onChange={handleChange}
className="border px-2 py-1 w-full"
/>
</div>
{/* Example checkbox for loan deferral */}
<div className="mb-3 flex items-center">
<input
type="checkbox"
name="loanDeferralUntilGraduation"
checked={formData.loanDeferralUntilGraduation}
onChange={handleChange}
className="mr-2"
/>
<label>Defer loan payments until graduation</label>
</div>
{/* Add all other fields you want to expose... */}
{/* Modal Buttons */}
<div className="flex justify-end mt-6">
<button
onClick={onClose}
className="px-4 py-2 mr-2 border rounded"
>
Cancel
</button>
<button
onClick={handleSave}
className="bg-blue-600 text-white px-4 py-2 rounded"
>
Save
</button>
</div>
</div>
</div>
);
};
export default ScenarioEditModal;

View File

@ -4,6 +4,64 @@ import moment from 'moment';
* Single-filer federal tax calculation (2023). * Single-filer federal tax calculation (2023).
* Includes standard deduction ($13,850). * Includes standard deduction ($13,850).
*/ */
const APPROX_STATE_TAX_RATES = {
AL: 0.05,
AK: 0.00,
AZ: 0.025,
AR: 0.05,
CA: 0.07,
CO: 0.045,
CT: 0.055,
DE: 0.05,
FL: 0.00,
GA: 0.05,
HI: 0.06,
ID: 0.058,
IL: 0.05,
IN: 0.035,
IA: 0.05,
KS: 0.05,
KY: 0.05,
LA: 0.04,
ME: 0.055,
MD: 0.05,
MA: 0.05,
MI: 0.0425,
MN: 0.06,
MS: 0.04,
MO: 0.05,
MT: 0.05,
NE: 0.05,
NV: 0.00,
NH: 0.00, // ignoring interest/dividend nuance
NJ: 0.057,
NM: 0.045,
NY: 0.06,
NC: 0.0475,
ND: 0.02,
OH: 0.04,
OK: 0.045,
OR: 0.07,
PA: 0.03,
RI: 0.045,
SC: 0.04,
SD: 0.00,
TN: 0.00,
TX: 0.00,
UT: 0.045,
VT: 0.055,
VA: 0.05,
WA: 0.00,
WV: 0.05,
WI: 0.05,
WY: 0.00,
DC: 0.05
};
/**
* 2) Single-filer federal tax calculation (2023).
* Includes standard deduction ($13,850).
*/
function calculateAnnualFederalTaxSingle(annualIncome) { function calculateAnnualFederalTaxSingle(annualIncome) {
const STANDARD_DEDUCTION_SINGLE = 13850; const STANDARD_DEDUCTION_SINGLE = 13850;
const taxableIncome = Math.max(0, annualIncome - STANDARD_DEDUCTION_SINGLE); const taxableIncome = Math.max(0, annualIncome - STANDARD_DEDUCTION_SINGLE);
@ -35,20 +93,13 @@ function calculateAnnualFederalTaxSingle(annualIncome) {
} }
/** /**
* Example state tax calculation. * 3) Example approximate state tax calculation.
* Currently a simple flat rate based on `stateCode` from a small dictionary. * Retrieves a single "effective" tax rate from the dictionary
* You can replace with bracket-based logic if desired. * and returns a simple multiplication of annualIncome * rate.
*/ */
function calculateAnnualStateTax(annualIncome, stateCode) { function calculateAnnualStateTax(annualIncome, stateCode) {
// Example dictionary of flat rates (not real data!) // Default to 5% if not found in dictionary
const stateTaxInfo = { const rate = APPROX_STATE_TAX_RATES[stateCode] ?? 0.05;
CA: 0.08, // 8%
NY: 0.06, // 6%
TX: 0.00,
FL: 0.00,
GA: 0.05
};
const rate = stateTaxInfo[stateCode] ?? 0.05; // default 5% if not found
return annualIncome * rate; return annualIncome * rate;
} }

Binary file not shown.