249 lines
8.4 KiB
JavaScript
249 lines
8.4 KiB
JavaScript
// src/components/MultiScenarioView.js
|
||
import React, { useEffect, useState } from 'react';
|
||
import authFetch from '../utils/authFetch.js';
|
||
import ScenarioContainer from './ScenarioContainer.js';
|
||
import { Button } from './ui/button.js';
|
||
|
||
export default function MultiScenarioView() {
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState(null);
|
||
|
||
// The user’s single overall financial profile
|
||
const [financialProfile, setFinancialProfile] = useState(null);
|
||
|
||
// The list of scenario "headers" (rows from career_profiles)
|
||
const [scenarios, setScenarios] = useState([]);
|
||
|
||
useEffect(() => {
|
||
loadScenariosAndFinancial();
|
||
}, []);
|
||
|
||
/**
|
||
* Fetch user’s financial profile + scenario list
|
||
*/
|
||
async function loadScenariosAndFinancial() {
|
||
setLoading(true);
|
||
setError(null);
|
||
|
||
try {
|
||
// 1) fetch user’s global financialProfile
|
||
const finRes = await authFetch('/api/premium/financial-profile');
|
||
if (!finRes.ok) throw new Error(`FinancialProfile error: ${finRes.status}`);
|
||
const finData = await finRes.json();
|
||
|
||
// 2) fetch scenario list
|
||
const scenRes = await authFetch('/api/premium/career-profile/all');
|
||
if (!scenRes.ok) throw new Error(`Scenarios error: ${scenRes.status}`);
|
||
const scenData = await scenRes.json();
|
||
|
||
setFinancialProfile(finData);
|
||
setScenarios(scenData.careerProfiles || []);
|
||
} catch (err) {
|
||
console.error('MultiScenarioView load error:', err);
|
||
setError(err.message || 'Failed to load multi-scenarios');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create a brand-new scenario with minimal defaults
|
||
*/
|
||
async function handleAddScenario() {
|
||
try {
|
||
const body = {
|
||
career_name: 'New Scenario ' + new Date().toLocaleDateString(),
|
||
status: 'planned',
|
||
start_date: new Date().toISOString(),
|
||
college_enrollment_status: 'not_enrolled',
|
||
currently_working: 'no'
|
||
};
|
||
|
||
const res = await authFetch('/api/premium/career-profile', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(body)
|
||
});
|
||
if (!res.ok) throw new Error(`Add scenario error: ${res.status}`);
|
||
|
||
// reload
|
||
await loadScenariosAndFinancial();
|
||
} catch (err) {
|
||
alert(err.message);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Clone a scenario:
|
||
* (A) create new scenario row from old scenario fields
|
||
* (B) also clone old scenario’s college_profile
|
||
*/
|
||
async function handleCloneScenario(oldScenario) {
|
||
try {
|
||
// 1) create the new scenario row
|
||
const scenarioPayload = {
|
||
scenario_title: oldScenario.scenario_title
|
||
? oldScenario.scenario_title + ' (Copy)'
|
||
: null,
|
||
career_name: oldScenario.career_name
|
||
? oldScenario.career_name + ' (Copy)'
|
||
: 'Untitled (Copy)',
|
||
status: oldScenario.status,
|
||
start_date: oldScenario.start_date,
|
||
projected_end_date: oldScenario.projected_end_date,
|
||
college_enrollment_status: oldScenario.college_enrollment_status,
|
||
currently_working: oldScenario.currently_working || 'no',
|
||
|
||
planned_monthly_expenses: oldScenario.planned_monthly_expenses,
|
||
planned_monthly_debt_payments: oldScenario.planned_monthly_debt_payments,
|
||
planned_monthly_retirement_contribution:
|
||
oldScenario.planned_monthly_retirement_contribution,
|
||
planned_monthly_emergency_contribution:
|
||
oldScenario.planned_monthly_emergency_contribution,
|
||
planned_surplus_emergency_pct: oldScenario.planned_surplus_emergency_pct,
|
||
planned_surplus_retirement_pct:
|
||
oldScenario.planned_surplus_retirement_pct,
|
||
planned_additional_income: oldScenario.planned_additional_income
|
||
};
|
||
|
||
const res = await authFetch('/api/premium/career-profile', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(scenarioPayload)
|
||
});
|
||
if (!res.ok) throw new Error(`Clone scenario error: ${res.status}`);
|
||
|
||
// parse the newly created scenario_id
|
||
const newScenarioData = await res.json();
|
||
const newScenarioId = newScenarioData.career_profile_id;
|
||
|
||
// 2) Clone the old scenario’s college_profile => new scenario
|
||
await cloneCollegeProfile(oldScenario.id, newScenarioId);
|
||
|
||
// 3) reload
|
||
await loadScenariosAndFinancial();
|
||
} catch (err) {
|
||
alert(`Clone scenario failed: ${err.message}`);
|
||
}
|
||
}
|
||
|
||
async function cloneCollegeProfile(oldScenarioId, newScenarioId) {
|
||
try {
|
||
// fetch old scenario’s college_profile
|
||
const getRes = await authFetch(
|
||
`/api/premium/college-profile?careerProfileId=${oldScenarioId}`
|
||
);
|
||
if (!getRes.ok) {
|
||
console.warn(
|
||
'Could not fetch old college profile for scenarioId=' + oldScenarioId
|
||
);
|
||
return;
|
||
}
|
||
|
||
let oldCollegeData = await getRes.json();
|
||
if (Array.isArray(oldCollegeData)) {
|
||
oldCollegeData = oldCollegeData[0] || null;
|
||
}
|
||
|
||
if (!oldCollegeData || !oldCollegeData.id) {
|
||
// no old college profile => nothing to clone
|
||
return;
|
||
}
|
||
|
||
// build new payload
|
||
const clonePayload = {
|
||
career_profile_id: newScenarioId,
|
||
|
||
selected_school: oldCollegeData.selected_school,
|
||
selected_program: oldCollegeData.selected_program,
|
||
program_type: oldCollegeData.program_type,
|
||
academic_calendar: oldCollegeData.academic_calendar,
|
||
|
||
is_in_state: oldCollegeData.is_in_state,
|
||
is_in_district: oldCollegeData.is_in_district,
|
||
is_online: oldCollegeData.is_online,
|
||
college_enrollment_status: oldCollegeData.college_enrollment_status,
|
||
|
||
annual_financial_aid: oldCollegeData.annual_financial_aid,
|
||
existing_college_debt: oldCollegeData.existing_college_debt,
|
||
tuition_paid: oldCollegeData.tuition_paid,
|
||
tuition: oldCollegeData.tuition,
|
||
loan_deferral_until_graduation: oldCollegeData.loan_deferral_until_graduation,
|
||
loan_term: oldCollegeData.loan_term,
|
||
interest_rate: oldCollegeData.interest_rate,
|
||
extra_payment: oldCollegeData.extra_payment,
|
||
|
||
credit_hours_per_year: oldCollegeData.credit_hours_per_year,
|
||
hours_completed: oldCollegeData.hours_completed,
|
||
program_length: oldCollegeData.program_length,
|
||
credit_hours_required: oldCollegeData.credit_hours_required,
|
||
expected_graduation: oldCollegeData.expected_graduation,
|
||
expected_salary: oldCollegeData.expected_salary
|
||
};
|
||
|
||
// insert new row in college_profiles
|
||
const postRes = await authFetch('/api/premium/college-profile', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(clonePayload)
|
||
});
|
||
if (!postRes.ok) {
|
||
console.warn(
|
||
'Could not clone old collegeProfile => new scenario',
|
||
postRes.status
|
||
);
|
||
}
|
||
} catch (err) {
|
||
console.error('Error cloning college profile:', err);
|
||
}
|
||
}
|
||
|
||
async function handleRemoveScenario(id) {
|
||
const confirmDel = window.confirm('Delete this scenario?');
|
||
if (!confirmDel) return;
|
||
|
||
try {
|
||
const res = await authFetch(`/api/premium/career-profile/${id}`, {
|
||
method: 'DELETE'
|
||
});
|
||
if (!res.ok) throw new Error(`Delete scenario error: ${res.status}`);
|
||
await loadScenariosAndFinancial();
|
||
} catch (err) {
|
||
alert(err.message);
|
||
}
|
||
}
|
||
|
||
if (loading) return <p>Loading scenarios...</p>;
|
||
if (error) return <p style={{ color: 'red' }}>{error}</p>;
|
||
|
||
// show only first 2 scenarios
|
||
const visibleScenarios = scenarios.slice(0, 2);
|
||
|
||
return (
|
||
<div style={{ margin: '1rem' }}>
|
||
{/* Add Scenario button */}
|
||
<div style={{ marginBottom: '1rem' }}>
|
||
<Button onClick={handleAddScenario}>+ Add Scenario</Button>
|
||
</div>
|
||
|
||
{/* Display 1 or 2 scenarios side by side */}
|
||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '1rem' }}>
|
||
{visibleScenarios.map((sc) => (
|
||
<ScenarioContainer
|
||
key={sc.id}
|
||
scenario={sc}
|
||
financialProfile={financialProfile}
|
||
onClone={handleCloneScenario} // <--- pass down
|
||
onRemove={handleRemoveScenario} // <--- pass down
|
||
onEdit={(sc) => {
|
||
console.log('Edit scenario clicked:', sc);
|
||
// or open a modal if you prefer
|
||
}}
|
||
hideMilestones // if you want to hide milestone details
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|