milestone tracker UI improvements - untested due to navigation issues

This commit is contained in:
Josh 2025-05-01 16:01:56 +00:00
parent e1f1782b01
commit 9404135915

View File

@ -1,5 +1,4 @@
// src/components/MilestoneTracker.js // src/components/MilestoneTracker.js
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -22,8 +21,8 @@ import CareerSearch from './CareerSearch.js';
import MilestoneTimeline from './MilestoneTimeline.js'; import MilestoneTimeline from './MilestoneTimeline.js';
import AISuggestedMilestones from './AISuggestedMilestones.js'; import AISuggestedMilestones from './AISuggestedMilestones.js';
import ScenarioEditModal from './ScenarioEditModal.js'; import ScenarioEditModal from './ScenarioEditModal.js';
import './MilestoneTracker.css'; import './MilestoneTracker.css'; // keeps your local styles
import './MilestoneTimeline.css'; import './MilestoneTimeline.css'; // keeps your local styles
import { simulateFinancialProjection } from '../utils/FinancialProjectionService.js'; import { simulateFinancialProjection } from '../utils/FinancialProjectionService.js';
ChartJS.register( ChartJS.register(
@ -53,7 +52,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
// Real user snapshot // Real user snapshot
const [financialProfile, setFinancialProfile] = useState(null); const [financialProfile, setFinancialProfile] = useState(null);
// Scenario row (with planned_* overrides) from GET /api/premium/career-profile/:careerPathId // Scenario row (with planned_* overrides)
const [scenarioRow, setScenarioRow] = useState(null); const [scenarioRow, setScenarioRow] = useState(null);
// scenario's collegeProfile row // scenario's collegeProfile row
@ -151,8 +150,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
}, [careerPathId, apiURL]); }, [careerPathId, apiURL]);
// -------------------------------------------------- // --------------------------------------------------
// 3) Once we have (financialProfile, scenarioRow, collegeProfile), // 3) Once we have (financialProfile, scenarioRow, collegeProfile), run initial simulation
// run initial simulation with the scenario's milestones + impacts
// -------------------------------------------------- // --------------------------------------------------
useEffect(() => { useEffect(() => {
if (!financialProfile || !scenarioRow || !collegeProfile) return; if (!financialProfile || !scenarioRow || !collegeProfile) return;
@ -168,7 +166,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
const milestonesData = await milRes.json(); const milestonesData = await milRes.json();
const allMilestones = milestonesData.milestones || []; const allMilestones = milestonesData.milestones || [];
// 2) fetch impacts for each // 2) fetch impacts for each milestone
const impactPromises = allMilestones.map(m => const impactPromises = allMilestones.map(m =>
authFetch(`${apiURL}/premium/milestone-impacts?milestone_id=${m.id}`) authFetch(`${apiURL}/premium/milestone-impacts?milestone_id=${m.id}`)
.then(r => r.ok ? r.json() : null) .then(r => r.ok ? r.json() : null)
@ -185,7 +183,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
})); }));
const allImpacts = milestonesWithImpacts.flatMap(m => m.impacts); const allImpacts = milestonesWithImpacts.flatMap(m => m.impacts);
// 3) Build the merged profile w/ scenario overrides // 3) Build the merged profile
const mergedProfile = buildMergedProfile( const mergedProfile = buildMergedProfile(
financialProfile, financialProfile,
scenarioRow, scenarioRow,
@ -377,7 +375,8 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
); );
return ( return (
<div className="milestone-tracker"> <div className="milestone-tracker max-w-screen-lg mx-auto px-4 py-6 space-y-6">
{/* Career Select */}
<CareerSelectDropdown <CareerSelectDropdown
existingCareerPaths={existingCareerPaths} existingCareerPaths={existingCareerPaths}
selectedCareer={selectedCareer} selectedCareer={selectedCareer}
@ -389,6 +388,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
authFetch={authFetch} authFetch={authFetch}
/> />
{/* Milestone Timeline */}
<MilestoneTimeline <MilestoneTimeline
careerPathId={careerPathId} careerPathId={careerPathId}
authFetch={authFetch} authFetch={authFetch}
@ -397,6 +397,7 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
onMilestoneUpdated={reSimulate} onMilestoneUpdated={reSimulate}
/> />
{/* AI-Suggested Milestones */}
<AISuggestedMilestones <AISuggestedMilestones
career={selectedCareer?.career_name} career={selectedCareer?.career_name}
careerPathId={careerPathId} careerPathId={careerPathId}
@ -405,9 +406,10 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
projectionData={projectionData} projectionData={projectionData}
/> />
{/* Chart Section */}
{projectionData.length > 0 && ( {projectionData.length > 0 && (
<div className="bg-white p-4 mt-6 rounded shadow"> <div className="bg-white p-4 rounded shadow space-y-4">
<h3 className="text-lg font-semibold mb-2">Financial Projection</h3> <h3 className="text-lg font-semibold">Financial Projection</h3>
<Line <Line
data={{ data={{
labels: projectionData.map((p) => p.month), labels: projectionData.map((p) => p.month),
@ -485,22 +487,26 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
</div> </div>
)} )}
<div className="mt-4"> {/* Simulation Length Input */}
<label>Simulation Length (years): </label> <div className="space-x-2">
<label className="font-medium">Simulation Length (years):</label>
<input <input
type="text" type="text"
value={simulationYearsInput} value={simulationYearsInput}
onChange={handleSimulationYearsChange} onChange={handleSimulationYearsChange}
onBlur={handleSimulationYearsBlur} onBlur={handleSimulationYearsBlur}
className="border rounded p-1 w-16"
/> />
</div> </div>
{/* Career Search */}
<CareerSearch <CareerSearch
onCareerSelected={(careerObj) => { onCareerSelected={(careerObj) => {
setPendingCareerForModal(careerObj.title); setPendingCareerForModal(careerObj.title);
}} }}
/> />
{/* Modal */}
<ScenarioEditModal <ScenarioEditModal
show={showEditModal} show={showEditModal}
onClose={() => setShowEditModal(false)} onClose={() => setShowEditModal(false)}
@ -512,15 +518,15 @@ const MilestoneTracker = ({ selectedCareer: initialCareer }) => {
authFetch={authFetch} authFetch={authFetch}
/> />
{pendingCareerForModal && ( {/* Confirm new career scenario */}
{pendingCareerForModal && (
<button <button
onClick={() => { onClick={() => {
// Example: Actually adopt this career as a new scenario or update the DB // Example action
console.log('User confirmed new career path:', pendingCareerForModal); console.log('User confirmed new career path:', pendingCareerForModal);
// Perhaps you open another modal or POST to your API
// Then reset pendingCareerForModal:
setPendingCareerForModal(null); setPendingCareerForModal(null);
}} }}
className="bg-blue-500 hover:bg-blue-600 text-white font-semibold px-4 py-2 rounded"
> >
Confirm Career Change to {pendingCareerForModal} Confirm Career Change to {pendingCareerForModal}
</button> </button>