128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
||
import axios from 'axios';
|
||
import './Dashboard.css';
|
||
|
||
const apiUrl = process.env.REACT_APP_API_URL || ''; // ✅ Load API URL directly
|
||
|
||
export function CareerSuggestions({ careerSuggestions = [], userState, areaTitle, onCareerClick }) {
|
||
const [updatedCareers, setUpdatedCareers] = useState([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [progress, setProgress] = useState(0);
|
||
|
||
useEffect(() => {
|
||
if (!careerSuggestions || careerSuggestions.length === 0) {
|
||
setLoading(false);
|
||
return;
|
||
}
|
||
|
||
const token = localStorage.getItem('token'); // Get auth token
|
||
|
||
const checkCareerDataAvailability = async () => {
|
||
setLoading(true);
|
||
setProgress(0);
|
||
const totalSteps = careerSuggestions.length * 4; // Each career has 4 API checks
|
||
let completedSteps = 0;
|
||
|
||
const updateProgress = () => {
|
||
completedSteps += 1;
|
||
setProgress((completedSteps / totalSteps) * 100);
|
||
};
|
||
|
||
const careerPromises = careerSuggestions.map(async (career) => {
|
||
try {
|
||
const headers = {
|
||
Authorization: `Bearer ${token}`,
|
||
Accept: 'application/json',
|
||
};
|
||
|
||
const fetchJSON = async (url) => {
|
||
try {
|
||
const response = await axios.get(url, { headers });
|
||
updateProgress(); // ✅ Update progress on success
|
||
return response.data;
|
||
} catch (error) {
|
||
console.warn(`⚠️ Error fetching ${url}:`, error.response?.status);
|
||
updateProgress(); // ✅ Update progress even if failed
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// Fetch Data in Parallel
|
||
const [cipData, jobDetailsData, economicData, salaryResponse] = await Promise.all([
|
||
fetchJSON(`${apiUrl}/cip/${career.code}`),
|
||
fetchJSON(`${apiUrl}/onet/career-description/${career.code}`),
|
||
fetchJSON(`${apiUrl}/projections/${career.code.split('.')[0]}`),
|
||
axios.get(`${apiUrl}/salary`, {
|
||
params: { socCode: career.code.split('.')[0], area: areaTitle },
|
||
headers,
|
||
}).then((res) => {
|
||
updateProgress();
|
||
return res.data;
|
||
}).catch((error) => {
|
||
updateProgress();
|
||
if (error.response?.status === 404) {
|
||
console.warn(`⚠️ Salary data missing for ${career.title} (${career.code})`);
|
||
return null;
|
||
}
|
||
return error.response;
|
||
}),
|
||
]);
|
||
|
||
const isCipMissing = !cipData || Object.keys(cipData).length === 0;
|
||
const isJobDetailsMissing = !jobDetailsData || Object.keys(jobDetailsData).length === 0;
|
||
const isEconomicMissing = !economicData || Object.values(economicData).every(val => val === "N/A" || val === "*");
|
||
const isSalaryMissing = salaryResponse === null || salaryResponse === undefined;
|
||
|
||
const isLimitedData = isCipMissing || isJobDetailsMissing || isEconomicMissing || isSalaryMissing;
|
||
if (isLimitedData) console.log(`⚠️ Setting limitedData for ${career.title} (${career.code})`);
|
||
|
||
return { ...career, limitedData: isLimitedData };
|
||
|
||
} catch (error) {
|
||
console.error(`Error checking API response for ${career.title}:`, error);
|
||
return { ...career, limitedData: true };
|
||
}
|
||
});
|
||
|
||
try {
|
||
const updatedCareerList = await Promise.all(careerPromises);
|
||
setUpdatedCareers(updatedCareerList);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
checkCareerDataAvailability();
|
||
}, [careerSuggestions, apiUrl, userState, areaTitle]);
|
||
|
||
return (
|
||
<div>
|
||
|
||
{loading ? (
|
||
<div className="progress-container">
|
||
<div className="progress-bar" style={{
|
||
width: `${progress}%`,
|
||
maxWidth: "100%", }}>
|
||
{Math.round(progress)}%
|
||
</div>
|
||
<p>Loading Career Suggestions...</p>
|
||
</div>
|
||
) : (
|
||
<div className="career-suggestions-grid">
|
||
{updatedCareers.map((career) => (
|
||
<button
|
||
key={career.code}
|
||
className={`career-button ${career.limitedData ? 'limited-data' : ''}`}
|
||
onClick={() => onCareerClick(career)}
|
||
>
|
||
{career.title} {career.limitedData && <span className="warning-icon">⚠️</span>}
|
||
</button>
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default CareerSuggestions;
|