Added data flow fixes for Confirm Career Selection button and rendering logic fix

This commit is contained in:
Josh 2025-03-25 15:55:30 +00:00
parent b3ff06c0fc
commit dd1d6bec88
4 changed files with 78 additions and 41 deletions

View File

@ -1,13 +1,14 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Input } from "./ui/input.js"; // Assuming Input is a basic text input component import { Input } from "./ui/input.js"; // Assuming Input is a basic text input component
const CareerSearch = ({ onSelectCareer, initialCareer }) => { const CareerSearch = ({ onSelectCareer, existingCareerPaths }) => {
const [careerClusters, setCareerClusters] = useState({}); const [careerClusters, setCareerClusters] = useState({});
const [selectedCluster, setSelectedCluster] = useState(""); const [selectedCluster, setSelectedCluster] = useState("");
const [selectedSubdivision, setSelectedSubdivision] = useState(""); const [selectedSubdivision, setSelectedSubdivision] = useState("");
const [selectedCareer, setSelectedCareer] = useState(""); const [selectedCareer, setSelectedCareer] = useState("");
const [careerSearch, setCareerSearch] = useState(""); const [careerSearch, setCareerSearch] = useState("");
useEffect(() => { useEffect(() => {
const fetchCareerClusters = async () => { const fetchCareerClusters = async () => {
try { try {
@ -62,6 +63,12 @@ const CareerSearch = ({ onSelectCareer, initialCareer }) => {
// Get careers based on selected subdivision // Get careers based on selected subdivision
const careers = selectedSubdivision ? careerClusters[selectedCluster]?.[selectedSubdivision] || [] : []; const careers = selectedSubdivision ? careerClusters[selectedCluster]?.[selectedSubdivision] || [] : [];
// Check if the selected career already has an existing career path
const hasCareerPath = existingCareerPaths.some(career => career.title === selectedCareer);
// Check if the selected career is the current one
const isCurrentCareer = selectedCareer === selectedCareer?.career_name;
return ( return (
<div> <div>
{/* Career Cluster Selection */} {/* Career Cluster Selection */}
@ -119,8 +126,35 @@ const CareerSearch = ({ onSelectCareer, initialCareer }) => {
)} )}
{/* Display selected career */} {/* Display selected career */}
{selectedCareer && <div>Selected Career: {selectedCareer}</div>} {selectedCareer && (
<div style={{ marginTop: '10px' }}>
<div>Selected Career: {selectedCareer}</div>
{!hasCareerPath && (
<button
onClick={() => {
const matchedCareer = careers.find(
(c) => c.title.toLowerCase() === selectedCareer.toLowerCase()
);
if (matchedCareer) {
onSelectCareer(matchedCareer.title, matchedCareer.soc); // 🔥 this triggers the update upstream
} else {
alert("Please select a valid career from the list.");
}
}}
>
Confirm Career Selection
</button>
)}
</div> </div>
)}
{hasCareerPath && (
<p>This career already has a career path. Do you want to reload it or create a new one?</p>
)}
{isCurrentCareer && (
<p>You are already on this career path.</p>
)}
</div>
); );
}; };

View File

@ -38,7 +38,7 @@ function GettingStarted() {
<div className="premium-access"> <div className="premium-access">
<h3>Already know your path?</h3> <h3>Already know your path?</h3>
<p>You can skip ahead and begin planning your milestones now.</p> <p>You can skip ahead and begin planning your milestones now.</p>
<button className="premium-button" onClick={() => navigate('/milestone-tracker')}> <button className="premium-button" onClick={() => navigate('/milestone-tracker', { state: { fromGettingStarted: true } })}>
Access Milestone Tracker <span className="premium-label">(Premium)</span> Access Milestone Tracker <span className="premium-label">(Premium)</span>
</button> </button>
</div> </div>

View File

@ -31,6 +31,9 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
const [careerSubdivision, setCareerSubdivision] = useState(''); const [careerSubdivision, setCareerSubdivision] = useState('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [sessionHandled, setSessionHandled] = useState(false); const [sessionHandled, setSessionHandled] = useState(false);
const [hasHandledCareerPath, setHasHandledCareerPath] = useState(false);
const [existingCareerPaths, setExistingCareerPaths] = useState([]); // To store existing career paths
const handleUnauthorized = () => { const handleUnauthorized = () => {
@ -42,23 +45,28 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
const apiURL = process.env.REACT_APP_API_URL; const apiURL = process.env.REACT_APP_API_URL;
useEffect(() => { useEffect(() => {
if (selectedCareer) { const fetchExistingPaths = async () => {
// First check when user navigates to this page const response = await fetch('/api/career-paths'); // Replace with the actual API endpoint
handleCareerPathDecision(selectedCareer); const data = await response.json();
} setExistingCareerPaths(data);
}, [selectedCareer]); };
fetchExistingPaths();
}, []);
useEffect(() => { useEffect(() => {
if (location.state?.selectedCareer) { const fromState = location.state?.selectedCareer;
setSelectedCareer(location.state.selectedCareer);
setCareerPathId(location.state.selectedCareer.career_path_id); if (fromState && !hasHandledCareerPath) {
loadMilestonesFromServer(location.state.selectedCareer.career_path_id); setSelectedCareer(fromState);
} else { setCareerPathId(fromState.career_path_id);
console.warn('No career selected; prompting user to select one.'); loadMilestonesFromServer(fromState.career_path_id);
setCareerPathId(null); handleCareerPathDecision(fromState.career_name);
setHasHandledCareerPath(true);
} }
}, [location.state]); }, [location.state]);
useEffect(() => { useEffect(() => {
loadMilestonesFromServer(); loadMilestonesFromServer();
}, [selectedCareer]); }, [selectedCareer]);
@ -85,17 +93,19 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
}) })
.then(data => { .then(data => {
if (data && data.id) { if (!location.state?.selectedCareer && data && data.id) {
setCareerPathId(data.id); setCareerPathId(data.id);
} else { setSelectedCareer({
setCareerPathId(null); // No existing career path for new user career_name: data.career_name,
career_path_id: data.id,
});
} }
}) })
.catch((error) => { .catch((error) => {
console.error("Could not fetch latest career path:", error); console.error("Could not fetch latest career path:", error);
setCareerPathId(null); setCareerPathId(null);
}); });
}, []); }, []);
const authFetch = async (url, options = {}) => { const authFetch = async (url, options = {}) => {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
@ -129,8 +139,11 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
}; };
const handleCareerPathDecision = async (careerName) => { const handleCareerPathDecision = async (careerName) => {
if (hasHandledCareerPath || !careerName || careerName === 'Not Selected') return; // ✅ already processed, do nothing
setHasHandledCareerPath(true); // ✅ prevent duplicate handling
setLoading(true); setLoading(true);
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
const response = await authFetch('/api/premium/planned-path', { const response = await authFetch('/api/premium/planned-path', {
method: 'POST', method: 'POST',
body: JSON.stringify({ career_name: careerName }), body: JSON.stringify({ career_name: careerName }),
@ -142,6 +155,8 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
const data = await response.json(); const data = await response.json();
setLoading(false); setLoading(false);
const fromGettingStarted = location?.state?.fromGettingStarted;
if (data.action_required === 'reload_or_create') { if (data.action_required === 'reload_or_create') {
const decision = window.confirm( `A career path for "${data.title}" already exists.\n\nClick OK to RELOAD the existing path.\nClick Cancel to CREATE a new one.`); const decision = window.confirm( `A career path for "${data.title}" already exists.\n\nClick OK to RELOAD the existing path.\nClick Cancel to CREATE a new one.`);
@ -153,8 +168,12 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
} else if (data.action_required === 'new_created') { } else if (data.action_required === 'new_created') {
setCareerPathId(data.career_path_id); setCareerPathId(data.career_path_id);
} }
if (fromGettingStarted) {
navigate(location.pathname, { replace: true, state: {} }); // clear state
}
}; };
const reloadExistingCareerPath = (careerPathId) => { const reloadExistingCareerPath = (careerPathId) => {
console.log('Reloading career path with ID:', careerPathId); console.log('Reloading career path with ID:', careerPathId);
setCareerPathId(careerPathId); setCareerPathId(careerPathId);
@ -217,26 +236,9 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
useEffect(() => { useEffect(() => {
if (selectedCareer) { if (selectedCareer) {
fetchAISuggestedMilestones(selectedCareer?.career_name); fetchAISuggestedMilestones(selectedCareer?.career_name);
prepopulateCareerFields(selectedCareer?.career_name);
} }
}, [selectedCareer]); }, [selectedCareer]);
const prepopulateCareerFields = (career) => {
if (!careerClusters) return;
for (const cluster in careerClusters) {
for (const subdivision in careerClusters[cluster]) {
if (careerClusters[cluster][subdivision].some(job => job.title === career)) {
setCareerCluster(cluster);
setCareerSubdivision(subdivision);
return;
}
}
}
setCareerCluster('');
setCareerSubdivision('');
};
const handleAddMilestone = async () => { const handleAddMilestone = async () => {
if (!careerPathId) { if (!careerPathId) {
console.error('No career_path_id available for milestone.'); console.error('No career_path_id available for milestone.');
@ -328,7 +330,6 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
const handleCareerSelection = async (career, socCode) => { const handleCareerSelection = async (career, socCode) => {
setSelectedCareer(career); setSelectedCareer(career);
setSelectedSocCode(socCode); setSelectedSocCode(socCode);
prepopulateCareerFields(career);
const token = localStorage.getItem('token'); const token = localStorage.getItem('token');
try { try {
@ -559,17 +560,19 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
<p>Not sure about this career path? Choose a different one here.</p> <p>Not sure about this career path? Choose a different one here.</p>
<CareerSearch <CareerSearch
onSelectCareer={handleCareerSelection} onSelectCareer={handleCareerSelection}
existingCareerPaths={existingCareerPaths}
initialCareer={selectedCareer} initialCareer={selectedCareer}
cluster={careerCluster} cluster={careerCluster}
subdivision={careerSubdivision} subdivision={careerSubdivision}
/> />
{selectedCareer && !careerPathId && ( {selectedCareer && (
<> <>
{selectedCareer !== selectedCareer?.career_name && (
<button onClick={() => setShowModal(true)} style={{ marginTop: '10px' }}> <button onClick={() => setShowModal(true)} style={{ marginTop: '10px' }}>
Confirm Career Selection Confirm Career Selection
</button> </button>
)}
{showModal && ( {showModal && (
<div className="modal-overlay"> <div className="modal-overlay">
<div className="modal"> <div className="modal">

Binary file not shown.