Fixed staging handlecareerclick. .pems are in this one
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Josh 2025-08-05 15:34:20 +00:00
parent d5d3c6d63b
commit 1e039bf454
4 changed files with 61 additions and 52 deletions

0
ca.pem Normal file
View File

0
client-cert.pem Normal file
View File

0
client-key.pem Normal file
View File

View File

@ -339,59 +339,69 @@ function CareerExplorer() {
} }
}, [location.state, userProfile, fetchSuggestions, navigate]); }, [location.state, userProfile, fetchSuggestions, navigate]);
/* ------------------------------------------------------ // ------------------------------------------------------
handleCareerClick  fetches all details for one career // handleCareerClick  fetch & build data for one career
---------------------------------------------------- */ // ------------------------------------------------------
const handleCareerClick = useCallback( const handleCareerClick = useCallback(
async (career) => { async (career) => {
const socCode = career.code; const socCode = career.code;
if (!socCode) return; if (!socCode) return;
/* Reset modal state & show spinner */
setSelectedCareer(career); setSelectedCareer(career);
setCareerDetails(null); // reset any previous modal setCareerDetails(null);
setLoading(true); setLoading(true);
try { try {
/* ---------- 1. CIP lookup ---------- */ /* ---------- 1. CIP lookup ---------- */
let cipCode = null; let cipCode = null;
const cipRes = await fetch(`/api/cip/${socCode}`); try {
if (cipRes.ok) { const cipRes = await fetch(`/api/cip/${socCode}`);
cipCode = (await cipRes.json()).cipCode ?? null; if (cipRes.ok) {
} cipCode = (await cipRes.json()).cipCode ?? null;
}
} catch { /* swallow */ }
/* ---------- 2. Job description & tasks ---------- */ /* ---------- 2. Job description & tasks ---------- */
let description = ''; let description = '';
let tasks = []; let tasks = [];
const jobRes = await fetch(`/api/onet/career-description/${socCode}`); try {
if (jobRes.ok) { const jobRes = await fetch(`/api/onet/career-description/${socCode}`);
const jd = await jobRes.json(); if (jobRes.ok) {
description = jd.description ?? ''; const jd = await jobRes.json();
tasks = jd.tasks ?? []; description = jd.description ?? '';
} tasks = jd.tasks ?? [];
}
} catch { /* swallow */ }
/* ---------- 3. Salary data ---------- */ /* ---------- 3. Salary data ---------- */
const salaryRes = await axios.get('/api/salary', { const salaryRes = await axios
params: { socCode: socCode.split('.')[0], area: areaTitle }, .get('/api/salary', {
}).catch(() => ({ data: {} })); params: { socCode: socCode.split('.')[0], area: areaTitle },
})
.catch(() => ({ data: {} }));
const s = salaryRes.data; const s = salaryRes.data;
const salaryDataPoints = s && Object.keys(s).length > 0 ? [ const salaryData = s && Object.keys(s).length
{ percentile: '10th Percentile', regionalSalary: +s.regional?.regional_PCT10 || 0, nationalSalary: +s.national?.national_PCT10 || 0 }, ? [
{ percentile: '25th Percentile', regionalSalary: +s.regional?.regional_PCT25 || 0, nationalSalary: +s.national?.national_PCT25 || 0 }, { percentile: '10th Percentile', regionalSalary: +s.regional?.regional_PCT10 || 0, nationalSalary: +s.national?.national_PCT10 || 0 },
{ percentile: 'Median', regionalSalary: +s.regional?.regional_MEDIAN || 0, nationalSalary: +s.national?.national_MEDIAN || 0 }, { percentile: '25th Percentile', regionalSalary: +s.regional?.regional_PCT25 || 0, nationalSalary: +s.national?.national_PCT25 || 0 },
{ percentile: '75th Percentile', regionalSalary: +s.regional?.regional_PCT75 || 0, nationalSalary: +s.national?.national_PCT75 || 0 }, { percentile: 'Median', regionalSalary: +s.regional?.regional_MEDIAN || 0, nationalSalary: +s.national?.national_MEDIAN || 0 },
{ percentile: '90th Percentile', regionalSalary: +s.regional?.regional_PCT90 || 0, nationalSalary: +s.national?.national_PCT90 || 0 }, { percentile: '75th Percentile', regionalSalary: +s.regional?.regional_PCT75 || 0, nationalSalary: +s.national?.national_PCT75 || 0 },
] : []; { percentile: '90th Percentile', regionalSalary: +s.regional?.regional_PCT90 || 0, nationalSalary: +s.national?.national_PCT90 || 0 },
]
: [];
/* ---------- 4. Economic projections ---------- */ /* ---------- 4. Economic projections ---------- */
const fullStateName = getFullStateName(userState); const fullStateName = getFullStateName(userState);
const projRes = await axios.get( const projRes = await axios
`/api/projections/${socCode.split('.')[0]}`, .get(`/api/projections/${socCode.split('.')[0]}`, {
{ params: { state: fullStateName } } params: { state: fullStateName },
).catch(() => ({ data: {} })); })
.catch(() => ({ data: {} }));
/* ---------- 5. Decide if we actually have data ---------- */ /* ---------- 5. Do we have *anything* useful? ---------- */
const haveSalary = salaryDataPoints.length > 0; const haveSalary = salaryData.length > 0;
const haveProj = !!(projRes.data.state || projRes.data.national); const haveProj = !!(projRes.data.state || projRes.data.national);
const haveJobInfo = description || tasks.length > 0; const haveJobInfo = description || tasks.length > 0;
@ -399,43 +409,43 @@ const handleCareerClick = useCallback(
setCareerDetails({ setCareerDetails({
error: `We're sorry, but detailed info for "${career.title}" isn't available right now.`, error: `We're sorry, but detailed info for "${career.title}" isn't available right now.`,
}); });
return; // stops here nothing useful to show return;
} }
/* ---------- 6. AIrisk (only if job details exist) ---------- */ /* ---------- 6. AIrisk (only if jobinfo exists) ---------- */
let aiRisk = null; let aiRisk = null;
if (haveJobInfo) { if (haveJobInfo) {
try { try {
aiRisk = (await axios.get(`/api/ai-risk/${socCode}`)).data; aiRisk = (await axios.get(`/api/ai-risk/${socCode}`)).data;
} catch (err) { } catch (err) {
if (err.response?.status === 404) { if (err.response?.status === 404) {
const aiRes = await axios.post('/api/public/ai-risk-analysis', { try {
socCode, const aiRes = await axios.post('/api/public/ai-risk-analysis', {
careerName : career.title, socCode,
jobDescription : description, careerName: career.title,
tasks, jobDescription: description,
}); tasks,
aiRisk = aiRes.data; });
// store for next time (besteffort) aiRisk = aiRes.data;
axios.post('/api/ai-risk', aiRisk).catch(() => {}); // cache for next time (besteffort)
axios.post('/api/ai-risk', aiRisk).catch(() => {});
} catch { /* GPT fallback failed ignore */ }
} }
} }
} }
/* ---------- 7. Build the final object & show modal ---------- */ /* ---------- 7. Build & show modal ---------- */
const updatedCareerDetails = { setCareerDetails({
...career, ...career,
cipCode, // may be null  EducationalPrograms handles it cipCode, // may be null downstream handles it
jobDescription: description, jobDescription: description,
tasks, tasks,
salaryData: salaryDataPoints, salaryData,
economicProjections: projRes.data ?? {}, economicProjections: projRes.data ?? {},
aiRisk, aiRisk, // can be null
}; });
} catch (fatal) {
setCareerDetails(updatedCareerDetails); console.error('[handleCareerClick] fatal:', fatal);
} catch (e) {
console.error('[handleCareerClick] fatal:', e);
setCareerDetails({ setCareerDetails({
error: `We're sorry, but detailed info for "${career.title}" isn't available right now.`, error: `We're sorry, but detailed info for "${career.title}" isn't available right now.`,
}); });
@ -446,7 +456,6 @@ const handleCareerClick = useCallback(
[areaTitle, userState] [areaTitle, userState]
); );
// ------------------------------------------------------ // ------------------------------------------------------
// handleCareerFromSearch // handleCareerFromSearch
// ------------------------------------------------------ // ------------------------------------------------------