Fixed MilestoneTracker.js to be the Where Am I now section.
This commit is contained in:
parent
98661b1c5a
commit
0ea62392dd
@ -71,14 +71,17 @@ const authenticatePremiumUser = (req, res, next) => {
|
||||
// GET the latest selected career profile
|
||||
app.get('/api/premium/career-profile/latest', authenticatePremiumUser, async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT *
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date,
|
||||
DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date
|
||||
FROM career_profiles
|
||||
WHERE user_id = ?
|
||||
ORDER BY start_date DESC
|
||||
LIMIT 1
|
||||
`, [req.id]);
|
||||
|
||||
`;
|
||||
const [rows] = await pool.query(sql, [req.id]);
|
||||
res.json(rows[0] || {});
|
||||
} catch (error) {
|
||||
console.error('Error fetching latest career profile:', error);
|
||||
@ -89,13 +92,16 @@ app.get('/api/premium/career-profile/latest', authenticatePremiumUser, async (re
|
||||
// GET all career profiles for the user
|
||||
app.get('/api/premium/career-profile/all', authenticatePremiumUser, async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT *
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date,
|
||||
DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date
|
||||
FROM career_profiles
|
||||
WHERE user_id = ?
|
||||
ORDER BY start_date ASC
|
||||
`, [req.id]);
|
||||
|
||||
`;
|
||||
const [rows] = await pool.query(sql, [req.id]);
|
||||
res.json({ careerProfiles: rows });
|
||||
} catch (error) {
|
||||
console.error('Error fetching career profiles:', error);
|
||||
@ -107,12 +113,17 @@ app.get('/api/premium/career-profile/all', authenticatePremiumUser, async (req,
|
||||
app.get('/api/premium/career-profile/:careerProfileId', authenticatePremiumUser, async (req, res) => {
|
||||
const { careerProfileId } = req.params;
|
||||
try {
|
||||
const [rows] = await pool.query(`
|
||||
SELECT *
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date,
|
||||
DATE_FORMAT(projected_end_date, '%Y-%m-%d') AS projected_end_date
|
||||
FROM career_profiles
|
||||
WHERE id = ?
|
||||
AND user_id = ?
|
||||
`, [careerProfileId, req.id]);
|
||||
LIMIT 1
|
||||
`;
|
||||
const [rows] = await pool.query(sql, [careerProfileId, req.id]);
|
||||
|
||||
if (!rows[0]) {
|
||||
return res.status(404).json({ error: 'Career profile not found or not yours.' });
|
||||
@ -124,6 +135,7 @@ app.get('/api/premium/career-profile/:careerProfileId', authenticatePremiumUser,
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// POST a new career profile (upsert)
|
||||
app.post('/api/premium/career-profile', authenticatePremiumUser, async (req, res) => {
|
||||
const {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,16 @@ const OnboardingContainer = () => {
|
||||
const nextStep = () => setStep(step + 1);
|
||||
const prevStep = () => setStep(step - 1);
|
||||
|
||||
function parseFloatOrNull(value) {
|
||||
// If user left it blank ("" or undefined), treat it as NULL.
|
||||
if (value == null || value === '') {
|
||||
return null;
|
||||
}
|
||||
const parsed = parseFloat(value);
|
||||
// If parseFloat can't parse, also return null
|
||||
return isNaN(parsed) ? null : parsed;
|
||||
}
|
||||
|
||||
console.log('Final collegeData in OnboardingContainer:', collegeData);
|
||||
|
||||
// Final “all done” submission when user finishes the last step
|
||||
@ -29,16 +39,13 @@ const OnboardingContainer = () => {
|
||||
// Build a scenarioPayload that includes optional planned_* fields:
|
||||
const scenarioPayload = {
|
||||
...careerData,
|
||||
planned_monthly_expenses: parseFloat(careerData.planned_monthly_expenses) || 0,
|
||||
planned_monthly_debt_payments: parseFloat(careerData.planned_monthly_debt_payments) || 0,
|
||||
planned_monthly_retirement_contribution:
|
||||
parseFloat(careerData.planned_monthly_retirement_contribution) || 0,
|
||||
planned_monthly_emergency_contribution:
|
||||
parseFloat(careerData.planned_monthly_emergency_contribution) || 0,
|
||||
planned_surplus_emergency_pct: parseFloat(careerData.planned_surplus_emergency_pct) || 0,
|
||||
planned_surplus_retirement_pct:
|
||||
parseFloat(careerData.planned_surplus_retirement_pct) || 0,
|
||||
planned_additional_income: parseFloat(careerData.planned_additional_income) || 0,
|
||||
planned_monthly_expenses: parseFloatOrNull(careerData.planned_monthly_expenses),
|
||||
planned_monthly_debt_payments: parseFloatOrNull(careerData.planned_monthly_debt_payments),
|
||||
planned_monthly_retirement_contribution: parseFloatOrNull(careerData.planned_monthly_retirement_contribution),
|
||||
planned_monthly_emergency_contribution: parseFloatOrNull(careerData.planned_monthly_emergency_contribution),
|
||||
planned_surplus_emergency_pct: parseFloatOrNull(careerData.planned_surplus_emergency_pct),
|
||||
planned_surplus_retirement_pct: parseFloatOrNull(careerData.planned_surplus_retirement_pct),
|
||||
planned_additional_income: parseFloatOrNull(careerData.planned_additional_income),
|
||||
};
|
||||
|
||||
// 1) POST career-profile (scenario)
|
||||
@ -62,7 +69,11 @@ const OnboardingContainer = () => {
|
||||
});
|
||||
if (!financialRes.ok) throw new Error('Failed to save financial profile');
|
||||
|
||||
// 3) POST college-profile (now uses career_profile_id)
|
||||
// 3) Only do college-profile if user is "currently_enrolled" or "prospective_student"
|
||||
if (
|
||||
careerData.college_enrollment_status === 'currently_enrolled' ||
|
||||
careerData.college_enrollment_status === 'prospective_student'
|
||||
) {
|
||||
const mergedCollege = {
|
||||
...collegeData,
|
||||
career_profile_id,
|
||||
@ -74,8 +85,11 @@ const OnboardingContainer = () => {
|
||||
body: JSON.stringify(mergedCollege),
|
||||
});
|
||||
if (!collegeRes.ok) throw new Error('Failed to save college profile');
|
||||
} else {
|
||||
console.log('Skipping college-profile upsert because user is not enrolled/planning.');
|
||||
}
|
||||
|
||||
// All done → navigate away
|
||||
// Done => navigate
|
||||
navigate('/milestone-tracker');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
@ -606,16 +606,24 @@ export default function ScenarioEditModal({
|
||||
collegePayload.loan_deferral_until_graduation = 1;
|
||||
}
|
||||
|
||||
// 3) Upsert college
|
||||
// 3) Upsert or skip
|
||||
if (finalCollegeStatus === 'currently_enrolled' ||
|
||||
finalCollegeStatus === 'prospective_student')
|
||||
{
|
||||
const colRes = await authFetch('/api/premium/college-profile', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(collegePayload)
|
||||
body: JSON.stringify(collegePayload),
|
||||
});
|
||||
if (!colRes.ok) {
|
||||
const msg2 = await colRes.text();
|
||||
throw new Error(`College upsert failed: ${msg2}`);
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping college-profile upsert in EditScenarioModal because user not enrolled');
|
||||
// Optionally: if you want to delete an existing college profile:
|
||||
// await authFetch(`/api/premium/college-profile/delete/${updatedScenarioId}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
// 4) Re-fetch scenario, college, financial => aggregator => simulate
|
||||
const [scenResp2, colResp2, finResp] = await Promise.all([
|
||||
|
@ -433,6 +433,7 @@ export function simulateFinancialProjection(userProfile) {
|
||||
loanBalance: +loanBalance.toFixed(2),
|
||||
|
||||
loanPaymentThisMonth: +(monthlyLoanPayment + extraPayment).toFixed(2),
|
||||
totalSavings: (currentEmergencySavings + currentRetirementSavings).toFixed(2),
|
||||
|
||||
fedYTDgross: +fedYTDgross.toFixed(2),
|
||||
fedYTDtax: +fedYTDtax.toFixed(2),
|
||||
|
22
src/utils/fetchCareerEnrichment.js
Normal file
22
src/utils/fetchCareerEnrichment.js
Normal file
@ -0,0 +1,22 @@
|
||||
// utils/fetchCareerEnrichment.js
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
export async function fetchCareerEnrichment(apiUrl, socCode, area) {
|
||||
// strippedSoc = remove decimals from e.g. "15-1132.00" => "15-1132"
|
||||
const strippedSoc = socCode.includes('.') ? socCode.split('.')[0] : socCode;
|
||||
|
||||
const [cipData, jobDetailsData, economicData, salaryData] = await Promise.all([
|
||||
axios.get(`${apiUrl}/cip/${socCode}`).catch(() => null),
|
||||
axios.get(`${apiUrl}/onet/career-description/${socCode}`).catch(() => null),
|
||||
axios.get(`${apiUrl}/projections/${strippedSoc}`, { params: { area } }).catch(() => null),
|
||||
axios.get(`${apiUrl}/salary`, { params: { socCode: strippedSoc, area } }).catch(() => null),
|
||||
]);
|
||||
|
||||
return {
|
||||
cip: cipData?.data || null,
|
||||
jobDetails: jobDetailsData?.data || null,
|
||||
economic: economicData?.data || null,
|
||||
salary: salaryData?.data || null,
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user