diff --git a/src/components/MilestoneTracker.js b/src/components/MilestoneTracker.js index 6121bd3..dd61855 100644 --- a/src/components/MilestoneTracker.js +++ b/src/components/MilestoneTracker.js @@ -268,6 +268,11 @@ export default function MilestoneTracker({ selectedCareer: initialCareer }) { const location = useLocation(); const apiURL = process.env.REACT_APP_API_URL; + const [interestStrategy, setInterestStrategy] = useState('NONE'); // 'NONE' | 'FLAT' | 'MONTE_CARLO' + const [flatAnnualRate, setFlatAnnualRate] = useState(0.06); // 6% default + const [randomRangeMin, setRandomRangeMin] = useState(-0.03); // -3% monthly + const [randomRangeMax, setRandomRangeMax] = useState(0.08); // 8% monthly + // Basic states const [userProfile, setUserProfile] = useState(null); const [financialProfile, setFinancialProfile] = useState(null); @@ -276,9 +281,6 @@ export default function MilestoneTracker({ selectedCareer: initialCareer }) { const [selectedCareer, setSelectedCareer] = useState(initialCareer || null); const [careerProfileId, setCareerProfileId] = useState(null); const [scenarioRow, setScenarioRow] = useState(null); - const [aiRisk, setAiRisk] = useState(null); - const [aiRiskLoading, setAiRiskLoading] = useState(false); - const [aiRiskError, setAiRiskError] = useState(null); const [collegeProfile, setCollegeProfile] = useState(null); const [strippedSocCode, setStrippedSocCode] = useState(null); @@ -458,81 +460,6 @@ export default function MilestoneTracker({ selectedCareer: initialCareer }) { setStrippedSocCode(stripSocCode(found.soc_code)); }, [scenarioRow, masterCareerRatings]); - useEffect(() => { - // If we have no SOC code or scenarioRow is missing, reset - if (!strippedSocCode || !scenarioRow?.career_name) { - setAiRisk(null); - return; - } - - async function fetchAiRisk() { - setAiRiskLoading(true); - setAiRiskError(null); - - try { - // 1) Attempt local DB first - const localRes = await fetch(`${apiURL}/ai-risk/${strippedSocCode}`); - if (localRes.ok) { - const localData = await localRes.json(); - setAiRisk(localData); - } else if (localRes.status === 404) { - // 2) If not found => call GPT route - // We'll pass minimal data if we don't have job description or tasks - const chatPayload = { - socCode: strippedSocCode, - careerName: scenarioRow.career_name, - jobDescription: '', // or optionally fetch from O*NET / tasks - tasks: [] - }; - - // POST to your server3 public route - const gptRes = await fetch(`${apiURL}/public/ai-risk-analysis`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(chatPayload), - }); - if (!gptRes.ok) { - throw new Error('GPT call failed'); - } - const gptData = await gptRes.json(); - - // 3) Store in server2 so we skip GPT next time - await fetch(`${apiURL}/ai-risk`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - socCode: strippedSocCode, - careerName: gptData.careerName, - jobDescription: gptData.jobDescription, - tasks: gptData.tasks, - riskLevel: gptData.riskLevel, - reasoning: gptData.reasoning, - }) - }); - - // 4) Set it in state - setAiRisk({ - socCode: strippedSocCode, - careerName: scenarioRow.career_name, - riskLevel: gptData.riskLevel, - reasoning: gptData.reasoning - }); - } else { - // Some other error code - throw new Error(`AI Risk fetch error: ${localRes.status}`); - } - } catch (err) { - console.error('Error fetching AI risk =>', err); - setAiRiskError('Failed to load AI risk data.'); - setAiRisk(null); - } finally { - setAiRiskLoading(false); - } - } - - fetchAiRisk(); -}, [strippedSocCode, scenarioRow?.career_name, apiURL]); - // 6) Salary useEffect(() => { if (!strippedSocCode) { @@ -717,7 +644,13 @@ export default function MilestoneTracker({ selectedCareer: initialCareer }) { startDate: new Date().toISOString(), simulationYears, - milestoneImpacts: allImpacts + milestoneImpacts: allImpacts, + + interestStrategy, + flatAnnualRate, + monthlyReturnSamples: [], // or keep an array if you have historical data + randomRangeMin, + randomRangeMax }; const { projectionData: pData, loanPaidOffMonth } = @@ -739,7 +672,7 @@ export default function MilestoneTracker({ selectedCareer: initialCareer }) { useEffect(() => { if (!financialProfile || !scenarioRow || !collegeProfile) return; buildProjection(); - }, [financialProfile, scenarioRow, collegeProfile, careerProfileId, apiURL, simulationYears]); + }, [financialProfile, scenarioRow, collegeProfile, careerProfileId, apiURL, simulationYears, interestStrategy, flatAnnualRate, randomRangeMin, randomRangeMax]); // Build chart datasets / annotations const milestoneAnnotationLines = {}; @@ -965,34 +898,18 @@ if (aiLoading || clickCount >= DAILY_CLICK_LIMIT) {
+ Current Career:{' '} + {scenarioRow?.career_name || '(Select a career)'} +
+ {yearsInCareer && (- Current Career:{' '} - {scenarioRow?.career_name || '(Select a career)'} + Time in this career: {yearsInCareer}{' '} + {yearsInCareer === '<1' ? 'year' : 'years'}
- {yearsInCareer && ( -- Time in this career: {yearsInCareer}{' '} - {yearsInCareer === '<1' ? 'year' : 'years'} -
- )} - -Loading AI risk...
- ) : aiRiskError ? ( -{aiRiskError}
- ) : aiRisk ? ( -No AI risk data available
- )} -