From 733dba46a87fbbb7f838efa2d8b31a200dd66463 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 24 Apr 2025 11:53:31 +0000 Subject: [PATCH] Milestone hard refresh added. --- src/components/MilestoneTimeline.js | 232 +++++++++--------------- src/components/MultiScenarioView.js | 48 ++--- src/components/ScenarioContainer.js | 123 ++++--------- src/utils/FinancialProjectionService.js | 3 - user_profile.db | Bin 106496 -> 106496 bytes 5 files changed, 134 insertions(+), 272 deletions(-) diff --git a/src/components/MilestoneTimeline.js b/src/components/MilestoneTimeline.js index 996c37b..60e2ade 100644 --- a/src/components/MilestoneTimeline.js +++ b/src/components/MilestoneTimeline.js @@ -3,13 +3,13 @@ import React, { useEffect, useState, useCallback } from 'react'; const today = new Date(); -const MilestoneTimeline = ({ +export default function MilestoneTimeline({ careerPathId, authFetch, activeView, setActiveView, - onMilestoneUpdated // optional callback if you want the parent to be notified of changes -}) => { + onMilestoneUpdated +}) { const [milestones, setMilestones] = useState({ Career: [], Financial: [] }); // "new or edit" milestone form data @@ -22,8 +22,6 @@ const MilestoneTimeline = ({ impacts: [], isUniversal: 0 }); - - // We'll track which existing impacts are removed so we can do a DELETE if needed const [impactsToDelete, setImpactsToDelete] = useState([]); const [showForm, setShowForm] = useState(false); @@ -33,17 +31,17 @@ const MilestoneTimeline = ({ const [showTaskForm, setShowTaskForm] = useState(null); const [newTask, setNewTask] = useState({ title: '', description: '', due_date: '' }); - // For the Copy wizard + // The copy wizard const [scenarios, setScenarios] = useState([]); const [copyWizardMilestone, setCopyWizardMilestone] = useState(null); // ------------------------------------------------------------------ - // 1) Impact Helper Functions (define them first to avoid scoping errors) + // 1) HELPER FUNCTIONS (defined above usage) // ------------------------------------------------------------------ - // Insert a new blank impact into newMilestone.impacts - const addNewImpact = () => { - setNewMilestone(prev => ({ + // Insert a new blank impact + function addNewImpact() { + setNewMilestone((prev) => ({ ...prev, impacts: [ ...prev.impacts, @@ -56,53 +54,33 @@ const MilestoneTimeline = ({ } ] })); - }; + } // Remove an impact from newMilestone.impacts - const removeImpact = (idx) => { - setNewMilestone(prev => { + function removeImpact(idx) { + setNewMilestone((prev) => { const newImpacts = [...prev.impacts]; const removed = newImpacts[idx]; - if (removed.id) { - // queue up for DB DELETE - setImpactsToDelete(old => [...old, removed.id]); + if (removed && removed.id) { + // queue for DB DELETE + setImpactsToDelete((old) => [...old, removed.id]); } newImpacts.splice(idx, 1); return { ...prev, impacts: newImpacts }; }); - }; + } // Update a specific impact property - const updateImpact = (idx, field, value) => { - setNewMilestone(prev => { + function updateImpact(idx, field, value) { + setNewMilestone((prev) => { const newImpacts = [...prev.impacts]; newImpacts[idx] = { ...newImpacts[idx], [field]: value }; return { ...prev, impacts: newImpacts }; }); - }; + } // ------------------------------------------------------------------ - // 2) Load scenarios (for copy wizard) - // ------------------------------------------------------------------ - useEffect(() => { - async function loadScenarios() { - try { - const res = await authFetch('/api/premium/career-profile/all'); - if (res.ok) { - const data = await res.json(); - setScenarios(data.careerPaths || []); - } else { - console.error('Failed to load scenarios. Status:', res.status); - } - } catch (err) { - console.error('Error loading scenarios for copy wizard:', err); - } - } - loadScenarios(); - }, [authFetch]); - - // ------------------------------------------------------------------ - // 3) Fetch milestones for the current scenario + // 2) fetchMilestones => local state // ------------------------------------------------------------------ const fetchMilestones = useCallback(async () => { if (!careerPathId) return; @@ -114,12 +92,12 @@ const MilestoneTimeline = ({ } const data = await res.json(); if (!data.milestones) { - console.warn('No milestones returned:', data); + console.warn('No milestones field in response:', data); return; } const categorized = { Career: [], Financial: [] }; - data.milestones.forEach(m => { + data.milestones.forEach((m) => { if (categorized[m.milestone_type]) { categorized[m.milestone_type].push(m); } else { @@ -138,9 +116,27 @@ const MilestoneTimeline = ({ }, [fetchMilestones]); // ------------------------------------------------------------------ - // 4) "Edit" an existing milestone => load impacts + // 3) Load scenarios for copy wizard // ------------------------------------------------------------------ - const handleEditMilestone = async (m) => { + useEffect(() => { + async function loadScenarios() { + try { + const res = await authFetch('/api/premium/career-profile/all'); + if (res.ok) { + const data = await res.json(); + setScenarios(data.careerPaths || []); + } + } catch (err) { + console.error('Error loading scenarios for copy wizard:', err); + } + } + loadScenarios(); + }, [authFetch]); + + // ------------------------------------------------------------------ + // 4) Edit Milestone => fetch impacts + // ------------------------------------------------------------------ + async function handleEditMilestone(m) { try { setImpactsToDelete([]); @@ -158,7 +154,7 @@ const MilestoneTimeline = ({ date: m.date || '', progress: m.progress || 0, newSalary: m.new_salary || '', - impacts: fetchedImpacts.map(imp => ({ + impacts: fetchedImpacts.map((imp) => ({ id: imp.id, impact_type: imp.impact_type || 'ONE_TIME', direction: imp.direction || 'subtract', @@ -171,16 +167,15 @@ const MilestoneTimeline = ({ setEditingMilestone(m); setShowForm(true); - } catch (err) { - console.error('Error editing milestone:', err); + console.error('Error in handleEditMilestone:', err); } - }; + } // ------------------------------------------------------------------ - // 5) Save (create or update) a milestone => handle impacts if needed + // 5) Save (create/update) => handle impacts // ------------------------------------------------------------------ - const saveMilestone = async () => { + async function saveMilestone() { if (!activeView) return; const url = editingMilestone @@ -219,7 +214,6 @@ const MilestoneTimeline = ({ const savedMilestone = await res.json(); console.log('Milestone saved/updated:', savedMilestone); - // If financial => handle impacts if (activeView === 'Financial') { // 1) Delete old impacts for (const impactId of impactsToDelete) { @@ -232,7 +226,6 @@ const MilestoneTimeline = ({ } } } - // 2) Insert/Update new impacts for (let i = 0; i < newMilestone.impacts.length; i++) { const imp = newMilestone.impacts[i]; @@ -253,7 +246,7 @@ const MilestoneTimeline = ({ }); if (!impRes.ok) { const errImp = await impRes.json(); - console.error('Failed updating existing impact:', errImp); + console.error('Failed updating impact:', errImp); } } else { // new => POST @@ -277,20 +270,10 @@ const MilestoneTimeline = ({ } } - // optional local state update to avoid re-fetch - setMilestones((prev) => { - const newState = { ...prev }; - if (editingMilestone) { - newState[activeView] = newState[activeView].map(m => - m.id === editingMilestone.id ? savedMilestone : m - ); - } else { - newState[activeView].push(savedMilestone); - } - return newState; - }); + // Optionally re-fetch or update local + await fetchMilestones(); - // reset the form + // reset form setShowForm(false); setEditingMilestone(null); setNewMilestone({ @@ -304,22 +287,18 @@ const MilestoneTimeline = ({ }); setImpactsToDelete([]); - // optionally re-fetch from DB - // await fetchMilestones(); - if (onMilestoneUpdated) { onMilestoneUpdated(); } - } catch (err) { console.error('Error saving milestone:', err); } - }; + } // ------------------------------------------------------------------ - // 6) addTask => attach a new task to an existing milestone + // 6) Add Task // ------------------------------------------------------------------ - const addTask = async (milestoneId) => { + async function addTask(milestoneId) { try { const taskPayload = { milestone_id: milestoneId, @@ -343,32 +322,18 @@ const MilestoneTimeline = ({ const createdTask = await res.json(); console.log('Task created:', createdTask); - // update local state - setMilestones((prev) => { - const newState = { ...prev }; - ['Career', 'Financial'].forEach((cat) => { - newState[cat] = newState[cat].map((m) => { - if (m.id === milestoneId) { - return { - ...m, - tasks: [...(m.tasks || []), createdTask] - }; - } - return m; - }); - }); - return newState; - }); + // Re-fetch so the timeline shows the new task + await fetchMilestones(); setNewTask({ title: '', description: '', due_date: '' }); setShowTaskForm(null); } catch (err) { console.error('Error adding task:', err); } - }; + } // ------------------------------------------------------------------ - // 7) "Copy" wizard -> after copying => re-fetch or local update + // 7) Copy Wizard => now with brute force refresh // ------------------------------------------------------------------ function CopyMilestoneWizard({ milestone, scenarios, onClose, authFetch }) { const [selectedScenarios, setSelectedScenarios] = useState([]); @@ -376,13 +341,9 @@ const MilestoneTimeline = ({ if (!milestone) return null; function toggleScenario(scenarioId) { - setSelectedScenarios(prev => { - if (prev.includes(scenarioId)) { - return prev.filter(id => id !== scenarioId); - } else { - return [...prev, scenarioId]; - } - }); + setSelectedScenarios((prev) => + prev.includes(scenarioId) ? prev.filter((id) => id !== scenarioId) : [...prev, scenarioId] + ); } async function handleCopy() { @@ -397,16 +358,10 @@ const MilestoneTimeline = ({ }); if (!res.ok) throw new Error('Failed to copy milestone'); - const data = await res.json(); - console.log('Copied milestone to new scenarios:', data); + // Brute force page refresh + window.location.reload(); - onClose(); // close wizard - - // re-fetch or update local - await fetchMilestones(); - if (onMilestoneUpdated) { - onMilestoneUpdated(); - } + onClose(); } catch (err) { console.error('Error copying milestone:', err); } @@ -418,7 +373,7 @@ const MilestoneTimeline = ({

Copy Milestone to Other Scenarios

Milestone: {milestone.title}

- {scenarios.map(s => ( + {scenarios.map((s) => (