dev1/src/components/CareerModal.js
Josh 5838f782e7
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
removed files from tracking, dependencies, fixed encryption
2025-08-19 12:24:54 +00:00

292 lines
11 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.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { AlertTriangle } from 'lucide-react';
import isAllOther from '../utils/isAllOther.js';
function CareerModal({ career, careerDetails, closeModal, addCareerToList }) {
const [error, setError] = useState(null);
const [loadingRisk, setLoadingRisk] = useState(false);
const aiRisk = careerDetails?.aiRisk || null;
const fmt = (v) =>
typeof v === 'number'
? v.toLocaleString()
: (v ?? '—');
// Handle your normal careerDetails loading logic
if (careerDetails?.error) {
return (
<div className="fixed inset-0 bg-gray-900 bg-opacity-70 flex justify-center items-center z-50">
<div className="bg-white rounded-lg shadow-lg p-6 max-w-xl">
<p className="text-lg text-gray-700 mb-4">
{careerDetails.error}
</p>
<button
onClick={closeModal}
className="bg-red-500 text-white p-2 rounded"
>
Close
</button>
</div>
</div>
);
}
if (!careerDetails || careerDetails.salaryData === undefined) {
return (
<div className="fixed inset-0 bg-gray-900 bg-opacity-70 flex justify-center items-center overflow-auto z-50" role="dialog" aria-modal="true">
<div className="bg-white rounded-lg shadow-lg p-6">
<p className="text-lg text-gray-700">Loading career details...</p>
</div>
</div>
);
}
if (error) return <div>{error}</div>;
// Helper for "stability" rating
const calculateStabilityRating = (salaryData) => {
const medianSalaryObj = salaryData.find((s) => s.percentile === 'Median');
const medianSalary =
medianSalaryObj?.regionalSalary || medianSalaryObj?.nationalSalary || 0;
if (medianSalary >= 90000) return 5;
if (medianSalary >= 70000) return 4;
if (medianSalary >= 50000) return 3;
if (medianSalary >= 30000) return 2;
return 1;
};
return (
<div className="fixed inset-0 bg-gray-900 bg-opacity-70 flex justify-center items-center overflow-auto z-50" role="dialog" aria-modal="true">
<div className="bg-white rounded-lg shadow-lg w-full max-w-5xl p-6 m-4 max-h-[90vh] overflow-y-auto">
{isAllOther(career) && (
<div className="mb-4 flex items-start rounded-md border-l-4 border-yellow-500 bg-yellow-50 p-3">
<AlertTriangle className="mt-[2px] mr-2 h-5 w-5 text-yellow-600" />
<p className="text-sm text-yellow-800">
You've selected an "umbrella" field that covers a wide range of careers—many
people begin a career journey with a broad interest area and we don't want to discourage
anyone from taking this approach. It's just difficult to display detailed career data
and daytoday tasks for this “allother” occupation. Use it as a starting point,
keep exploring specializations, and we can show you richer insights as soon as you are able
to narrow it down to a more specific role. If you know this is the field for you, go ahead to
add it to your comparison list or move straight into Preparing & Upskilling for Your Career!
</p>
</div>
)}
{/* Title row */}
<div className="flex justify-between items-center mb-4 pb-2 border-b">
<div>
<h2 className="text-2xl font-bold text-blue-600">
{careerDetails.title}
</h2>
{/* AI RISK SECTION */}
{aiRisk && aiRisk.riskLevel && aiRisk.reasoning && (
<div className="text-sm text-gray-500 mt-1">
<strong>AI Risk Level:</strong> {aiRisk.riskLevel}
<br />
<span>{aiRisk.reasoning}</span>
</div>
)}
{!aiRisk && (
<p className="text-sm text-gray-500 mt-1">No AI risk data available</p>
)}
</div>
{/* Buttons */}
<div className="flex gap-2">
<button
onClick={() => {
const stabilityRating = calculateStabilityRating(
careerDetails.salaryData
);
addCareerToList({
...careerDetails,
ratings: {
stability: stabilityRating,
},
});
closeModal();
}}
className="text-white bg-green-500 hover:bg-green-600 rounded px-3 py-1"
>
Add to Comparison
</button>
<button
onClick={closeModal}
className="text-white bg-red-500 hover:bg-red-600 rounded px-3 py-1"
>
Close
</button>
</div>
</div>
{/* Job Description */}
{careerDetails.jobDescription && (
<div className="mb-4">
<h3 className="text-lg font-semibold mb-1">Job Description:</h3>
<p className="text-gray-700">{careerDetails.jobDescription}</p>
</div>
)}
{/* Tasks */}
{careerDetails.tasks?.length > 0 && (
<div className="mb-4 border-t pt-3">
<h3 className="text-lg font-semibold mb-2">Tasks:</h3>
<ul className="list-disc pl-5 space-y-1">
{careerDetails.tasks.map((task, i) => (
<li key={i}>{task}</li>
))}
</ul>
</div>
)}
{(careerDetails.salaryData?.length > 0 ||
(careerDetails.economicProjections &&
(careerDetails.economicProjections.state ||
careerDetails.economicProjections.national))) && (
<div className="flex flex-col md:flex-row gap-4 border-t pt-3">
{/* ── Salary table ───────────────────────── */}
{careerDetails.salaryData?.length > 0 && (
<div className="md:w-1/2 overflow-x-auto">
<h3 className="text-lg font-semibold mb-2">Salary Data</h3>
<table className="w-full text-left border border-gray-300 rounded">
<thead className="bg-gray-100">
<tr>
<th className="px-3 py-2 border-b">Percentile</th>
<th className="px-3 py-2 border-b">Regional Salary</th>
<th className="px-3 py-2 border-b">National Salary</th>
</tr>
</thead>
<tbody>
{careerDetails.salaryData.map((row, i) => (
<tr key={i}>
<td className="px-3 py-2 border-b">{row.percentile}</td>
<td className="px-3 py-2 border-b">
{Number.isFinite(row.regionalSalary) ? `$${fmt(row.regionalSalary)}` : ''}
</td>
<td className="px-3 py-2 border-b">
{Number.isFinite(row.nationalSalary) ? `$${fmt(row.nationalSalary)}` : ''}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
{/* ── Economic projections ───────────────── */}
{(careerDetails.economicProjections?.state ||
careerDetails.economicProjections?.national) && (
<div className="md:w-1/2 overflow-x-auto">
<h3 className="text-lg font-semibold mb-2">Economic Projections</h3>
<table className="w-full text-left border border-gray-300 rounded">
<thead className="bg-gray-100">
<tr>
<th className="px-3 py-2 border-b"></th>
{careerDetails.economicProjections.state && (
<th className="px-3 py-2 border-b">
{careerDetails.economicProjections.state.area}
</th>
)}
{careerDetails.economicProjections.national && (
<th className="px-3 py-2 border-b">National</th>
)}
</tr>
</thead>
<tbody>
<tr>
<td className="px-3 py-2 border-b font-semibold">
Current Jobs
</td>
{careerDetails.economicProjections.state && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.state.base)}
</td>
)}
{careerDetails.economicProjections.national && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.national.base)}
</td>
)}
</tr>
<tr>
<td className="px-3 py-2 border-b font-semibold">
Jobs in&nbsp;10&nbsp;yrs
</td>
{careerDetails.economicProjections.state && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.state.projection)}
</td>
)}
{careerDetails.economicProjections.national && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.national.projection)}
</td>
)}
</tr>
<tr>
<td className="px-3 py-2 border-b font-semibold">Growth%</td>
{careerDetails.economicProjections.state && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.state.percentChange)}%
</td>
)}
{careerDetails.economicProjections.national && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.national.percentChange)}%
</td>
)}
</tr>
<tr>
<td className="px-3 py-2 border-b font-semibold">
Annual Openings
</td>
{careerDetails.economicProjections.state && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.state.annualOpenings)}
</td>
)}
{careerDetails.economicProjections.national && (
<td className="px-3 py-2 border-b">
{fmt(careerDetails.economicProjections.national.annualOpenings)}
</td>
)}
</tr>
</tbody>
</table>
{/* Conditional disclaimer when AI risk is Moderate or High */}
{(aiRisk?.riskLevel === 'Moderate' || aiRisk?.riskLevel === 'High') && (
<p className="text-sm text-red-600 mt-2">
Note: These 10year projections may change if AIdriven tools
significantly affect {careerDetails.title} tasks. With a&nbsp;
<strong>{aiRisk?.riskLevel?.toLowerCase()}</strong> AI risk, its possible
some responsibilities could be automated over time.
</p>
)}
</div>
)}
</div>
)}
</div>
</div>
);
}
export default CareerModal;