diff --git a/src/components/EducationalProgramsPage.js b/src/components/EducationalProgramsPage.js index 5ebb0c0..d9d08d0 100644 --- a/src/components/EducationalProgramsPage.js +++ b/src/components/EducationalProgramsPage.js @@ -1,5 +1,5 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import CareerSearch from './CareerSearch.js'; import { ONET_DEFINITIONS } from './definitions.js'; import { fetchSchools, clientGeocodeZip, haversineDistance } from '../utils/apiUtils.js'; @@ -31,28 +31,36 @@ function combineIMandLV(rows) { return Array.from(map.values()); } +function ensureHttp(urlString) { + if (!urlString) return ''; + // If it already starts with 'http://' or 'https://', just return as-is. + if (/^https?:\/\//i.test(urlString)) { + return urlString; + } + // Otherwise prepend 'https://' (or 'http://'). + return `https://${urlString}`; +} + // Convert numeric importance (1β5) to star or emoji compact representation function renderImportance(val) { - // Example: star approach (rounded) - // or you can do emojis like "π΄π’π‘" etc. const max = 5; const rounded = Math.round(val); const stars = 'β '.repeat(rounded) + 'β'.repeat(max - rounded); - return `${stars}`; // e.g. β β β β β + return `${stars}`; } // Convert numeric level (0β7) to bar or block representation function renderLevel(val) { - // 7 is max, weβll do a small row of squares const max = 7; const rounded = Math.round(val); - const filled = 'β '.repeat(rounded); // 'β ' is a filled block + const filled = 'β '.repeat(rounded); const empty = 'β‘'.repeat(max - rounded); - return `${filled}${empty}`; // e.g. β β β β β β‘β‘ + return `${filled}${empty}`; } function EducationalProgramsPage() { const location = useLocation(); + const navigate = useNavigate(); const [socCode, setsocCode] = useState(location.state?.socCode || ''); const [cipCodes, setCipCodes] = useState(location.state?.cipCodes || []); @@ -87,24 +95,28 @@ function EducationalProgramsPage() { setCipCodes(cleanedCips); }; + // Fixed handleSelectSchool (removed extra brace) + const handleSelectSchool = (school) => { + const proceed = window.confirm( + 'Youβre about to move to the financial planning portion of the app, which is reserved for premium subscribers. Do you want to continue?' + ); + if (proceed) { + navigate('/financial-planner', { state: { selectedSchool: school } }); + }; + }; + function getSearchLinks(ksaName, careerTitle) { - const combinedQuery = `${careerTitle} ${ksaName}`.trim(); - const encoded = encodeURIComponent(combinedQuery); - - const courseraUrl = `https://www.coursera.org/search?query=${encoded}`; + const combinedQuery = `${careerTitle} ${ksaName}`.trim(); + const encoded = encodeURIComponent(combinedQuery); + const courseraUrl = `https://www.coursera.org/search?query=${encoded}`; + const edxUrl = `https://www.edx.org/search?q=${encoded}`; - const edxUrl = `https://www.edx.org/search?q=${encoded}`; - - - const classCentralUrl = `https://www.classcentral.com/search?q=${encoded}`; - - return [ - { title: 'Coursera', url: courseraUrl }, - { title: 'edX', url: edxUrl }, - - ]; -} + return [ + { title: 'Coursera', url: courseraUrl }, + { title: 'edX', url: edxUrl }, + ]; + } // Load KSA data once useEffect(() => { @@ -138,22 +150,14 @@ function EducationalProgramsPage() { setKsaForCareer([]); return; } - // 1) filter by socCode let filtered = allKsaData.filter((r) => r.onetSocCode === socCode); - // 2) skip suppress=Y filtered = filtered.filter((r) => r.recommendSuppress !== 'Y'); - // 3) keep scaleIDs in [IM,LV] filtered = filtered.filter((r) => ['IM', 'LV'].includes(r.scaleID)); - // combine IM + LV let combined = combineIMandLV(filtered); - - // only keep items with importanceValue >=3 combined = combined.filter((item) => { return item.importanceValue !== null && item.importanceValue >= 3; }); - - // sort by importanceValue desc combined.sort((a, b) => (b.importanceValue || 0) - (a.importanceValue || 0)); setKsaForCareer(combined); @@ -195,7 +199,8 @@ function EducationalProgramsPage() { try { const fetchedSchools = await fetchSchools(cipCodes); - let userLat = null, userLng = null; + let userLat = null; + let userLng = null; if (userZip) { try { const geoResult = await clientGeocodeZip(userZip); @@ -230,6 +235,7 @@ function EducationalProgramsPage() { // Sort schools in useMemo const filteredAndSortedSchools = useMemo(() => { + if (!schools) return []; let result = [...schools]; @@ -266,12 +272,8 @@ function EducationalProgramsPage() { } else { // Sort by in-state tuition result.sort((a, b) => { - const tA = a['In_state cost'] - ? parseFloat(a['In_state cost']) - : Infinity; - const tB = b['In_state cost'] - ? parseFloat(b['In_state cost']) - : Infinity; + const tA = a['In_state cost'] ? parseFloat(a['In_state cost']) : Infinity; + const tB = b['In_state cost'] ? parseFloat(b['In_state cost']) : Infinity; return tA - tB; }); } @@ -279,54 +281,59 @@ function EducationalProgramsPage() { return result; }, [schools, inStateOnly, userState, maxTuition, maxDistance, sortBy]); - // Render the KSA as a table row with emoji + // Render a single KSA row function renderKsaRow(k, idx, careerTitle) { - // k is the object => { elementName, importanceValue, levelValue, ksa_type } - const elementName = k.elementName; - const impStars = renderImportance(k.importanceValue); - const lvlBars = k.levelValue !== null ? renderLevel(k.levelValue) : 'n/a'; - const links = getSearchLinks(elementName, careerTitle); - const definition = ONET_DEFINITIONS[elementName] || "No definition available"; - return ( -
Loading KSA data...
; if (ksaError) return{ksaError}
; if (!socCode) returnPlease select a career to see KSA data.
; if (!ksaForCareer.length) { - returnNo Knowledge, Skills, and Abilites data found for {careerTitle}
; + returnNo Knowledge, Skills, and Abilities data found for {careerTitle}
; } - // Separate them const knowledge = ksaForCareer.filter((k) => k.ksa_type === 'Knowledge'); const skillRows = ksaForCareer.filter((k) => k.ksa_type === 'Skill'); const abilities = ksaForCareer.filter((k) => k.ksa_type === 'Ability'); @@ -334,10 +341,10 @@ function EducationalProgramsPage() { return (Degree Type: {school['CREDDESC'] || 'N/A'}
-In-State Tuition: ${school['In_state cost'] || 'N/A'}
-Out-of-State Tuition: ${school['Out_state cost'] || 'N/A'}
-- Distance:{' '} - {school.distance !== null ? `${school.distance} mi` : 'N/A'} -
-- Website:{' '} + {school['Website'] ? ( - {school['Website']} + {school['INSTNM'] || 'Unnamed School'} ) : ( - 'N/A' + school['INSTNM'] || 'Unnamed School' )} -
+ +Degree Type: {school['CREDDESC'] || 'N/A'}
+In-State Tuition: ${school['In_state cost'] || 'N/A'}
+Out-of-State Tuition: ${school['Out_state cost'] || 'N/A'}
+Distance: {school.distance !== null ? `${school.distance} mi` : 'N/A'}
+ +No schools matching your filters.
- )} + ); + })}