import { ClipLoader } from 'react-spinners';
import LoanRepayment from './LoanRepayment.js';
import SchoolFilters from './SchoolFilters';
import './PopoutPanel.css';
import { useState, useEffect } from 'react';
function PopoutPanel({
isVisible,
data = {},
userState = 'N/A', // Passed explicitly from Dashboard
loading = false,
error = null,
closePanel,
updateChatbotContext,
}) {
const [isCalculated, setIsCalculated] = useState(false);
const [results, setResults] = useState([]); // Store loan repayment calculation results
const [loadingCalculation, setLoadingCalculation] = useState(false);
const [persistedROI, setPersistedROI] = useState({});
const [programLengths, setProgramLengths] = useState([]);
const [sortBy, setSortBy] = useState('tuition'); // Default sorting
const [maxTuition, setMaxTuition] = useState(50000); // Set default max tuition value
const [maxDistance, setMaxDistance] = useState(200); // Set default max distance value
const {
jobDescription = null,
tasks = null,
title = 'Career Details',
economicProjections = {},
salaryData = [],
schools = [],
} = data || {};
useEffect(() => {
setResults([]);
setIsCalculated(false);
}, [sortBy, maxTuition, maxDistance]); // Ensure no other dependencies!
useEffect(() => {
setProgramLengths(schools.map(school => getProgramLength(school['CREDDESC'])));
}, [schools]);
useEffect(() => {
console.log("📩 Updating Chatbot Context from PopoutPanel:", data);
if (data && Object.keys(data).length > 0) {
updateChatbotContext({
careerDetails: data,
schools,
salaryData,
economicProjections,
results,
persistedROI, // ✅ Make sure ROI is included!
});
} else {
console.log("⚠️ No valid PopoutPanel data to update chatbot context.");
}
}, [data, schools, salaryData, economicProjections, results, persistedROI, updateChatbotContext]);
if (!isVisible) return null;
if (loading || loadingCalculation) {
return (
Loading Career Details...
);
}
// Get program length for calculating tuition
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
};
function handleClosePanel() {
setResults([]); // Clear only LoanRepayment results
setIsCalculated(false); // Reset calculation state
closePanel(); // Maintain existing close behavior
}
/** 🔹 Apply Sorting & Filtering Directly at Render Time **/
const filteredAndSortedSchools = [...schools]
.filter(school => {
const inStateCost = parseFloat(school['In_state cost']);
const distance = parseFloat(school['distance'].replace(' mi', ''));
return (
inStateCost <= maxTuition &&
distance <= maxDistance
);
})
.sort((a, b) => {
if (sortBy === 'tuition') return a['In_state cost'] - b['In_state cost'];
if (sortBy === 'distance') return a['distance'] - b['distance'];
return 0;
});
return (
{/* Header with Close & Plan My Path Buttons */}
{title}
{/* Job Description and Tasks */}
Job Description
{jobDescription || 'No description available'}
Expected Tasks
{tasks && tasks.length > 0 ? (
{tasks.map((task, index) => (
- {task}
))}
) : (
No tasks available for this career path.
)}
{/* Economic Projections */}
Economic Projections for {userState}
{economicProjections && typeof economicProjections === 'object' ? (
- 2022 Employment: {economicProjections['2022 Employment'] || 'N/A'}
- 2032 Employment: {economicProjections['2032 Employment'] || 'N/A'}
- Total Change: {economicProjections['Total Change'] || 'N/A'}
) : (
No economic projections available for this career path.
)}
{/* Salary Data Points */}
Salary Data
{salaryData.length > 0 ? (
Percentile |
Regional Salary |
US Salary |
{salaryData.map((point, index) => (
{point.percentile} |
{point.regionalSalary > 0 ? `$${parseInt(point.regionalSalary, 10).toLocaleString()}` : 'N/A'} |
{point.nationalSalary > 0 ? `$${parseInt(point.nationalSalary, 10).toLocaleString()}` : 'N/A'} |
))}
) : (
Salary data is not available.
)}
{/* Schools Offering Programs Section */}
Schools Offering Programs
{/* Header and Filters - Not part of grid */}
{filteredAndSortedSchools.length > 0 ? (
filteredAndSortedSchools.map((school, index) => (
{school['INSTNM']}
Degree Type: {school['CREDDESC'] || 'Degree type not available for this program'}
In-State Tuition: ${school['In_state cost'] || 'Tuition not available for this school'}
Out-of-State Tuition: ${school['Out_state cost'] || 'Tuition not available for this school'}
Distance: {school['distance'] || 'Distance to school not available'}
))
) : (
No schools of higher education are available in your state for this career path.
)}
{/* Loan Repayment Analysis */}
Loan Repayment Analysis
({
schoolName: school['INSTNM'],
inState: parseFloat(school['In_state cost']) || 0,
outOfState: parseFloat(school['Out_state cost']) || 0,
inStateGraduate: parseFloat(school['In State Graduate']) || parseFloat(school['In_state cost']) || 0,
outStateGraduate: parseFloat(school['Out State Graduate']) || parseFloat(school['Out_state cost']) || 0,
degreeType: school['CREDDESC'],
programLength: programLengths[index],
}))}
salaryData={salaryData}
setResults={setResults}
setLoading={setLoadingCalculation}
setPersistedROI={setPersistedROI} // ✅ Store ROI after calculation
/>
{/* Results Display */}
{results.length > 0 && (
Comparisons by School over the life of the loan
{results.map((result, index) => (
{result.schoolName} - {result.degreeType || 'Degree type not available'}
Total Tuition: ${result.totalTuition}
Monthly Payment: ${result.monthlyPayment}
Total Monthly Payment (with extra): ${result.totalMonthlyPayment}
Total Loan Cost: ${result.totalLoanCost}
Net Gain: ${result.netGain}
Monthly Salary (Gross): ${result.monthlySalary}
))}
)}
);
}
export default PopoutPanel;