Adjusted financial simulation for taxes.
This commit is contained in:
parent
d6eaa22d87
commit
f0de365358
244
src/components/ScenarioEditModal.js
Normal file
244
src/components/ScenarioEditModal.js
Normal 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;
|
@ -4,6 +4,64 @@ import moment from 'moment';
|
||||
* Single-filer federal tax calculation (2023).
|
||||
* 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) {
|
||||
const STANDARD_DEDUCTION_SINGLE = 13850;
|
||||
const taxableIncome = Math.max(0, annualIncome - STANDARD_DEDUCTION_SINGLE);
|
||||
@ -35,20 +93,13 @@ function calculateAnnualFederalTaxSingle(annualIncome) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Example state tax calculation.
|
||||
* Currently a simple flat rate based on `stateCode` from a small dictionary.
|
||||
* You can replace with bracket-based logic if desired.
|
||||
* 3) Example approximate state tax calculation.
|
||||
* Retrieves a single "effective" tax rate from the dictionary
|
||||
* and returns a simple multiplication of annualIncome * rate.
|
||||
*/
|
||||
function calculateAnnualStateTax(annualIncome, stateCode) {
|
||||
// Example dictionary of flat rates (not real data!)
|
||||
const stateTaxInfo = {
|
||||
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
|
||||
// Default to 5% if not found in dictionary
|
||||
const rate = APPROX_STATE_TAX_RATES[stateCode] ?? 0.05;
|
||||
return annualIncome * rate;
|
||||
}
|
||||
|
||||
|
BIN
user_profile.db
BIN
user_profile.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user