diff --git a/src/components/LoanRepayment.js b/src/components/LoanRepayment.js index 575f875..e6482aa 100644 --- a/src/components/LoanRepayment.js +++ b/src/components/LoanRepayment.js @@ -7,7 +7,7 @@ function LoanRepayment({ setResults, setLoading, }) { - const [expectedSalary, setExpectedSalary] = useState(''); + const [expectedSalary, setExpectedSalary] = useState(0); const [tuitionType, setTuitionType] = useState('inState'); // Tuition type: inState or outOfState const [interestRate, setInterestRate] = useState(5.5); // Interest rate const [loanTerm, setLoanTerm] = useState(10); // Loan term in years @@ -86,8 +86,8 @@ function LoanRepayment({ const totalLoanCost = extraMonthlyPayment * monthsWithExtra; let salary = Number(expectedSalary) || 0; - let netGain = 'N/A'; - let monthlySalary = 'N/A'; + let netGain = 0; + let monthlySalary = 0; if (salary > 0) { const totalSalary = salary * loanTerm; @@ -150,7 +150,8 @@ function LoanRepayment({ setCurrentSalary(e.target.value)} - placeholder="Enter your current salary" /> + placeholder="Enter your current salary" + />
diff --git a/src/components/PopoutPanel.css b/src/components/PopoutPanel.css index 637c98e..b6f1899 100644 --- a/src/components/PopoutPanel.css +++ b/src/components/PopoutPanel.css @@ -100,40 +100,10 @@ color: #666; } -/* 🔹 Filter Section Styling */ -.filter-section { - background: #f8f8f8; - padding: 10px; - border-radius: 5px; - margin-bottom: 15px; -} - -.filter-section h3 { - margin-bottom: 10px; - font-size: 16px; -} - -.filter-section label { - display: block; - font-size: 14px; - margin-bottom: 5px; - font-weight: bold; -} - -.filter-section input { - width: 100%; - padding: 5px; - margin-bottom: 10px; - border: 1px solid #ccc; - border-radius: 4px; -} - -.filter-section select { - width: 100%; - padding: 5px; - margin-bottom: 10px; - border: 1px solid #ccc; - border-radius: 4px; +.filter-controls { + display: flex; + align-items: center; + gap: 20px; } /* Schools section: Grid layout with clear separation */ diff --git a/src/components/PopoutPanel.js b/src/components/PopoutPanel.js index 726af67..fe12602 100644 --- a/src/components/PopoutPanel.js +++ b/src/components/PopoutPanel.js @@ -1,5 +1,6 @@ import { ClipLoader } from 'react-spinners'; import LoanRepayment from './LoanRepayment.js'; +import SchoolFilters from './SchoolFilters'; import './PopoutPanel.css'; import { useState, useEffect } from 'react'; @@ -15,21 +16,23 @@ function PopoutPanel({ const [results, setResults] = useState([]); // Store loan repayment calculation results const [loadingCalculation, setLoadingCalculation] = useState(false); const [persistedROI, setPersistedROI] = useState({}); + const [sortBy, setSortBy] = useState('tuition'); // Default sorting + const [tuitionRange, setTuitionRange] = useState([0, 50000]); + const [distanceRange, setDistanceRange] = useState([0, 200]); const { jobDescription = null, tasks = null, title = 'Career Details', - economicProjections = {}, + economicProjections = {}, salaryData = [], - schools = [], + schools = [], } = data || {}; useEffect(() => { - setResults([]); setIsCalculated(false); - }, [schools]); + }, [sortBy, tuitionRange, distanceRange]); if (!isVisible) return null; @@ -59,6 +62,31 @@ function PopoutPanel({ closePanel(); // Maintain existing close behavior } + + /** 🔹 Apply Sorting & Filtering Directly at Render Time **/ + const filteredAndSortedSchools = [...schools] + .filter(school => { + // Convert tuition to a number + const inStateCost = parseFloat(school['In_state cost']); + + // Remove " mi" from distance and convert it to a number + const distance = parseFloat(school['distance'].replace(' mi', '')); + + console.log(`Filtering School: ${school['INSTNM']} | Tuition: ${inStateCost} | Distance: ${distance}`); + + return ( + inStateCost >= tuitionRange[0] && + inStateCost <= tuitionRange[1] && + distance >= distanceRange[0] && + distance <= distanceRange[1] + ); + }) + .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 (
@@ -124,16 +152,74 @@ function PopoutPanel({ )}
+ {/* Sorting & Filtering UI */} +
+
+ + setSortBy('tuition')} + /> Tuition + setSortBy('distance')} + /> Distance +
+ + + setTuitionRange([Number(e.target.value), tuitionRange[1]])} + /> + setTuitionRange([tuitionRange[0], Number(e.target.value)])} + /> + + + setDistanceRange([Number(e.target.value), distanceRange[1]])} + /> + setDistanceRange([distanceRange[0], Number(e.target.value)])} + /> +
+ + {/* Schools Offering Programs Section */}

Schools Offering Programs

- {schools.length > 0 ? ( - schools.map((school, index) => ( + {filteredAndSortedSchools.length > 0 ? ( + filteredAndSortedSchools.map((school, index) => (
{school['INSTNM']}
-
Degree Type: {school['CREDDESC'] || 'Degree type information is not available for this program'}
-
In-State Tuition: ${school['In_state cost'] || 'Tuition information is not available for this school'}
-
Out-of-State Tuition: ${school['Out_state cost'] || 'Tuition information is not available for this school'}
+
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'}
Website: {school['Website']} @@ -148,7 +234,7 @@ function PopoutPanel({ {/* Loan Repayment Analysis */}

Loan Repayment Analysis

({ + schools={filteredAndSortedSchools.map(school => ({ schoolName: school['INSTNM'], inState: parseFloat(school['In_state cost']) || 0, outOfState: parseFloat(school['Out_state cost']) || 0, diff --git a/src/components/SchoolFilters b/src/components/SchoolFilters new file mode 100644 index 0000000..e409bb4 --- /dev/null +++ b/src/components/SchoolFilters @@ -0,0 +1,115 @@ +import React, { useState } from 'react'; +import './SchoolFilters.css'; + +function SchoolFilters({ schools, setFilteredSchools }) { + const [sortBy, setSortBy] = useState('tuition'); // Default: Sort by Tuition + const [tuitionRange, setTuitionRange] = useState([0, 50000]); // Example range + const [distanceRange, setDistanceRange] = useState([0, 200]); // Example range + + // Sorting function + const sortSchools = (schools) => { + return [...schools].sort((a, b) => { + if (sortBy === 'tuition') return a.inState - b.inState; + if (sortBy === 'distance') return a.distance - b.distance; + return 0; + }); + }; + + // Filtering function + const filterSchools = (schools) => { + return schools.filter((school) => + school.inState >= tuitionRange[0] && + school.inState <= tuitionRange[1] && + school.distance >= distanceRange[0] && + school.distance <= distanceRange[1] + ); + }; + + // Apply sorting & filtering when values change + const updateFilteredSchools = () => { + let updatedSchools = sortSchools(schools); + updatedSchools = filterSchools(updatedSchools); + setFilteredSchools(updatedSchools); + }; + + // Effect to update results on change + React.useEffect(() => { + updateFilteredSchools(); + }, [sortBy, tuitionRange, distanceRange, schools]); + + return ( +
+

Sort & Filter Schools

+ + {/* Sorting Options */} +
+ +
+ setSortBy('tuition')} + /> + +
+
+ setSortBy('distance')} + /> + +
+
+ + {/* Filtering Options */} +
+ + setTuitionRange([Number(e.target.value), tuitionRange[1]])} + /> + setTuitionRange([tuitionRange[0], Number(e.target.value)])} + /> +
+ +
+ + setDistanceRange([Number(e.target.value), distanceRange[1]])} + /> + setDistanceRange([distanceRange[0], Number(e.target.value)])} + /> +
+
+ ); +} + +export default SchoolFilters;