Added data flow fixes for Confirm Career Selection button and rendering logic fix
This commit is contained in:
parent
b3ff06c0fc
commit
dd1d6bec88
@ -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 */}
|
||||||
@ -118,9 +125,36 @@ const CareerSearch = ({ onSelectCareer, initialCareer }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 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>
|
||||||
|
)}
|
||||||
|
{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>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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,22 +45,27 @@ 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();
|
||||||
@ -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 {
|
||||||
@ -558,18 +559,20 @@ const MilestoneTracker = ({ selectedCareer: initialCareer, careerClusters }) =>
|
|||||||
<div className="career-search-container minimized">
|
<div className="career-search-container minimized">
|
||||||
<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">
|
||||||
|
BIN
user_profile.db
BIN
user_profile.db
Binary file not shown.
Loading…
Reference in New Issue
Block a user