dev1/src/components/CareerSuggestions.js

128 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;