162 lines
5.0 KiB
JavaScript
162 lines
5.0 KiB
JavaScript
import { ClipLoader } from 'react-spinners';
|
|
import LoanRepayment from './LoanRepayment.js';
|
|
import './PopoutPanel.css';
|
|
|
|
function PopoutPanel({
|
|
data = {},
|
|
userState = 'N/A', // Passed explicitly from Dashboard
|
|
loading = false,
|
|
error = null,
|
|
closePanel
|
|
}) {
|
|
console.log('PopoutPanel Props:', { data, loading, error, userState });
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="popout-panel">
|
|
<button className="close-btn" onClick={closePanel}>X</button>
|
|
<h2>Loading Career Details...</h2>
|
|
<ClipLoader size={35} color="#4A90E2" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="popout-panel">
|
|
<button className="close-btn" onClick={closePanel}>X</button>
|
|
<h2>Error Loading Career Details</h2>
|
|
<p style={{ color: 'red' }}>{error}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Handle empty data gracefully
|
|
if (!data || Object.keys(data).length === 0) {
|
|
return (
|
|
<div className="popout-panel">
|
|
<button onClick={closePanel}>Close</button>
|
|
<h2>No Career Data Available</h2>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Safely access nested data with fallbacks
|
|
const {
|
|
title = 'Career Details',
|
|
economicProjections = {},
|
|
salaryData = [],
|
|
schools = [],
|
|
tuitionData = []
|
|
} = data;
|
|
|
|
const tenthPercentileSalary = salaryData?.find(
|
|
(point) => point.percentile === '10th Percentile'
|
|
)?.value || 0;
|
|
|
|
const getProgramLength = (degreeType) => {
|
|
if (degreeType?.includes("Associate")) return 2;
|
|
if (degreeType?.includes("Bachelor")) return 4;
|
|
if (degreeType?.includes("Master")) return 6;
|
|
if (degreeType?.includes("Doctoral") || degreeType?.includes("First Professional")) return 8;
|
|
if (degreeType?.includes("Certificate")) return 1;
|
|
return 4; // Default to 4 years if unspecified
|
|
};
|
|
|
|
return (
|
|
<div className="popout-panel">
|
|
<button onClick={closePanel}>Close</button>
|
|
<h2>{title}</h2>
|
|
|
|
{/* Schools Offering Programs */}
|
|
<h3>Schools Offering Programs</h3>
|
|
{Array.isArray(schools) && schools.length > 0 ? (
|
|
<ul>
|
|
{schools.map((school, index) => {
|
|
const matchingTuitionData = tuitionData.find(
|
|
(tuition) =>
|
|
tuition['school.name']?.toLowerCase().trim() ===
|
|
school['Institution Name']?.toLowerCase().trim()
|
|
);
|
|
|
|
return (
|
|
<li key={index}>
|
|
<strong>{school['Institution Name']}</strong>
|
|
<br />
|
|
Degree Type: {school['CREDDESC'] || 'N/A'}
|
|
<br />
|
|
In-State Tuition: ${matchingTuitionData?.['latest.cost.tuition.in_state'] || 'N/A'}
|
|
<br />
|
|
Out-of-State Tuition: ${matchingTuitionData?.['latest.cost.tuition.out_of_state'] || 'N/A'}
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
) : (
|
|
<p>No schools available.</p>
|
|
)}
|
|
|
|
|
|
{/* Economic Projections */}
|
|
<h3>Economic Projections for {userState}</h3>
|
|
{economicProjections && typeof economicProjections === 'object' ? (
|
|
<ul>
|
|
<li>2022 Employment: {economicProjections['2022 Employment'] || 'N/A'}</li>
|
|
<li>2032 Employment: {economicProjections['2032 Employment'] || 'N/A'}</li>
|
|
<li>Total Change: {economicProjections['Total Change'] || 'N/A'}</li>
|
|
</ul>
|
|
) : (
|
|
<p>No economic projections available.</p>
|
|
)}
|
|
|
|
{/* Salary Data Points */}
|
|
<h3>Salary Data</h3>
|
|
{salaryData && salaryData.length > 0 ? (
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Percentile</th>
|
|
<th>Salary</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{salaryData.map((point, index) => (
|
|
<tr key={index}>
|
|
<td>{point.percentile}</td>
|
|
<td>
|
|
{point.value > 0 ? `$${parseInt(point.value, 10).toLocaleString()}` : 'N/A'}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
) : (
|
|
<p>No salary data available.</p>
|
|
)}
|
|
|
|
{/* Loan Repayment Analysis */}
|
|
{tenthPercentileSalary > 0 && (
|
|
<LoanRepayment
|
|
schools={schools.map((school) => {
|
|
const matchingTuitionData = tuitionData.find(
|
|
(tuition) =>
|
|
tuition['school.name']?.toLowerCase().trim() ===
|
|
school['Institution Name']?.toLowerCase().trim()
|
|
);
|
|
const years = getProgramLength(school['CREDDESC']);
|
|
return {
|
|
schoolName: school['Institution Name'],
|
|
inState: parseFloat(matchingTuitionData?.['latest.cost.tuition_in_state'] * years) || 0,
|
|
outOfState: parseFloat(matchingTuitionData?.['latest.cost.tuition_out_of_state'] * years) || 0,
|
|
};
|
|
})}
|
|
salaryData={[{ percentile: '10th Percentile', value: tenthPercentileSalary, growthRate: 0.03 }]}
|
|
earningHorizon={10}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default PopoutPanel;
|