diff --git a/.build.hash b/.build.hash index 1ea272f..60740fe 100644 --- a/.build.hash +++ b/.build.hash @@ -1 +1 @@ -77b19da169acfc9f13cfa14f2fb425fea6c03ef4-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b +e520c3d4f21d892f230efe5f06e338b842191dd6-372bcf506971f56c4911b429b9f5de5bc37ed008-e9eccd451b778829eb2f2c9752c670b707e1268b diff --git a/docker-compose.yml b/docker-compose.yml index 1df5a45..1c9f3db 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -182,6 +182,7 @@ services: networks: [default, aptiva-shared] environment: GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY} + ENV_NAME: ${ENV_NAME} ports: ["80:80", "443:443"] volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro diff --git a/src/App.js b/src/App.js index c41bdb1..5fd1678 100644 --- a/src/App.js +++ b/src/App.js @@ -442,6 +442,12 @@ const cancelLogout = () => { > Educational Programs + + Education Repayment Calculator + @@ -689,6 +695,7 @@ const cancelLogout = () => { Preparing β€” Overview Educational Programs + Education Repayment Calculator )} diff --git a/src/components/EnhancingLanding.js b/src/components/EnhancingLanding.js index 6f618a5..1fd8ff4 100644 --- a/src/components/EnhancingLanding.js +++ b/src/components/EnhancingLanding.js @@ -1,64 +1,60 @@ import React from "react"; import { useNavigate } from "react-router-dom"; import { Button } from "./ui/button.js"; -import EconomicProjections from "./EconomicProjections.js"; - -/* simple pill-style label */ -const Chip = ({ label }) => ( - - {label} - βœ“ in Career Coach - -); export default function EnhancingLanding({ userProfile }) { const navigate = useNavigate(); - const socCode = userProfile?.socCode; - const stateName = userProfile?.state; return ( -
-
+
+
+ {/* Title + intro (centered, blue headline) */} +

+ Enhancing Your Career +

+

+ Build momentum in your current role and prepare for your next step. + Use Career Coach for guided milestones, and fine-tune your materials + with the Resume Optimizer. +

- {/* πŸ“Œ Current status */} -
-

- πŸ“Œ Your Current Status & Next Steps -

-

- Evaluate where you are in your career and discover upcoming milestones with our AI recommendations. -

- - - -
- -
-
- - {/* πŸš€ How do I get there */} -
-

πŸš€ How Do I Get There?

- -
- - - - + {/* Feature tiles (inside the main card) */} +
+ {/* Career Coach */} +
+

Career Coach

+

+ Guided milestones for networking, interview prep, and job search. +

+
+ +
-

- All of these tools live inside the Career Coach. Open it any time using the button above. -

-
+ {/* Resume Optimizer (separate tool) */} +
+

Resume Optimizer

+

+ Improve wording, keywords, and formatting to match target roles. +

+
+ +
+
+
+ + {/* Divider + lower subsection to mirror the secondary blocks on other landings */} +
+ +

Your Current Status & Next Steps

+

+ Evaluate where you are in your career and discover upcoming milestones + with our AI recommendations. +

diff --git a/src/components/LoanRepaymentDrawer.js b/src/components/LoanRepaymentDrawer.js index 517f11b..fac9054 100644 --- a/src/components/LoanRepaymentDrawer.js +++ b/src/components/LoanRepaymentDrawer.js @@ -6,6 +6,8 @@ import { Button } from './ui/button.js'; import { getNearbySchools } from '../utils/getNearbySchools.js'; import UpsellSummary from './UpsellSummary.js'; import { useNavigate } from 'react-router-dom'; +import api from '../auth/apiClient.js'; + /* ───────────────────────── CONSTANTS ───────────────────────── */ const DEGREE_OPTS = [ @@ -32,9 +34,21 @@ export default function LoanRepaymentDrawer({ }) { /* Hooks must always run – return null later if !open */ /* ── Remote data for auto-suggest ─ */ - const [cipData, setCipData] = useState([]); const [schoolSearch, setSchoolSearch] = useState(''); - const [icData, setIcData] = useState([]); + const [selectedSchool, setSelectedSchool] = useState({ name: '', unitId: null }); + const [schoolSug, setSchoolSug] = useState([]); // [{name, unitId}] + const [schoolSugOpen, setSchoolSugOpen] = useState(false); + const [schoolHi, setSchoolHi] = useState(-1); + + // Program auto-suggest (depends on selectedSchool) + const [programSearch, setProgramSearch] = useState(''); + const [selectedProgram, setSelectedProgram] = useState(''); // exact string + const [programSug, setProgramSug] = useState([]); // [{program}] + const [programSugOpen, setProgramSugOpen] = useState(false); + const [programHi, setProgramHi] = useState(-1); + + // Degree types (filtered by school + program) + const [degreeTypes, setDegreeTypes] = useState([]); // ['Bachelor's Degree', ...] /* ── Simple form fields ─ */ const [degree, setDegree] = useState(''); @@ -62,106 +76,114 @@ const getAnnualTuition = (schoolsArr, typed, isGrad, resid) => pickField(schoolsArr?.[0] ?? {}, isGrad, resid) || (typed ? Number(typed) : 0); +// Degree menu: prefer backend-provided types (if any), else fall back +const degreeMenu = degreeTypes.length ? degreeTypes : DEGREE_OPTS; -/* ── memo’ed degree list for current school ── */ -const schoolDegrees = useMemo(() => { - if (!schoolSearch.trim()) return []; - const list = cipData - .filter(r => r.INSTNM.toLowerCase() === schoolSearch.toLowerCase()) - .map(r => r.CREDDESC); - return [...new Set(list)]; -}, [schoolSearch, cipData]); - -const degreeMenu = schoolDegrees.length ? schoolDegrees : DEGREE_OPTS; const isGrad = /(Master|Doctoral|First Professional|Graduate|Certificate)/i.test(degree); const annualTuition= getAnnualTuition(schools, tuition, isGrad, tuitionType); const showUpsell = user && !user.is_premium && !user.is_pro_premium; -useEffect(() => { - if (!open) return; - if (schools.length) return; - if (!cipCodes.length) return; - + useEffect(() => { + if (!open) return; + if (schools.length) return; + if (!cipCodes.length) return; (async () => { try { const seed = await getNearbySchools(cipCodes, userZip, userState); if (seed.length) setSchools(seed); - } catch (e) { - console.warn('auto-seed schools failed:', e); - } + } catch (e) { console.warn('auto-seed schools failed:', e); } })(); }, [open, schools.length, cipCodes.join('-'), userZip, userState, setSchools]); - /* ════════════════════════════════════════════════════ - FETCH CIP DATA (only once the drawer is ever opened) - ════════════════════════════════════════════════════ */ - useEffect(() => { - if (!open || cipData.length) return; - fetch('/cip_institution_mapping_new.json') - .then(r => r.text()) - .then(text => - text - .split('\n') - .map(l => { try { return JSON.parse(l); } catch { return null; } }) - .filter(Boolean) - ) - .then(arr => setCipData(arr)) - .catch(e => console.error('CIP fetch error', e)); - }, [open, cipData.length]); + /* ───────── SCHOOL SUGGEST (server) ───────── */ - /* ════════════════════════════════════════════════════ - SCHOOL AUTOCOMPLETE LIST (memoised) - ════════════════════════════════════════════════════ */ - const suggestions = useMemo(() => { - if (!schoolSearch.trim()) return []; - const low = schoolSearch.toLowerCase(); - const set = new Set( - cipData - .filter(r => r.INSTNM.toLowerCase().includes(low)) - .map(r => r.INSTNM) - ); - return [...set].slice(0, 10); - }, [schoolSearch, cipData]); - - useEffect(() => { - if (!open || icData.length) return; - fetch('/ic2023_ay.csv') - .then(r => r.text()) - .then(text => { - const [header, ...rows] = text.split('\n').map(l => l.split(',')); - return rows.map(row => - Object.fromEntries(row.map((v, i) => [header[i], v])) - ); - }) - .then(setIcData) - .catch(e => console.error('iPEDS load fail', e)); -}, [open, icData.length]); - -/* ───────── auto-tuition when schoolSearch settles ───────── */ useEffect(() => { - if (!schoolSearch.trim() || !icData.length) return; - const rec = cipData.find(r => r.INSTNM.toLowerCase() === schoolSearch.toLowerCase()); - if (!rec) return; - const match = icData.find(r => r.UNITID === rec.UNITID); - if (!match) return; - - const calc = () => { - const grad = /(Master|Doctoral|First Professional|Graduate|Certificate)/i.test(degree); - if (!grad) { - return tuitionType === 'inState' - ? parseFloat(match.TUITION1 || match.TUITION2 || '') - : parseFloat(match.TUITION3 || ''); + if (!open) return; + const q = schoolSearch.trim(); + if (q.length < 2) { setSchoolSug([]); return; } + let cancelled = false; + (async () => { + try { + const { data } = await api.get('/api/schools/suggest', { + params: { query: q, limit: 10 }, + withCredentials: true, + }); + if (!cancelled) setSchoolSug(Array.isArray(data) ? data : []); + } catch (e) { + if (!cancelled) setSchoolSug([]); } - return tuitionType === 'inState' - ? parseFloat(match.TUITION5 || match.TUITION6 || '') - : parseFloat(match.TUITION7 || ''); - }; + })(); + return () => { cancelled = true; }; +}, [open, schoolSearch]); - const est = calc(); - if (est && !tuitionManual) setTuition(String(est)); -}, [schoolSearch, tuitionType, degree, cipData, icData, tuitionManual]); + +/* ───────── PROGRAM SUGGEST (server; depends on school) ───────── */ +useEffect(() => { + if (!open) return; + if (!selectedSchool?.name) { setProgramSug([]); return; } + const q = programSearch.trim(); + if (q.length < 2) { setProgramSug([]); return; } + let cancelled = false; + (async () => { + try { + const { data } = await api.get('/api/programs/suggest', { + params: { school: selectedSchool.name, query: q, limit: 10 }, + withCredentials: true, + }); + if (!cancelled) setProgramSug(Array.isArray(data) ? data : []); + } catch (e) { + if (!cancelled) setProgramSug([]); + } + })(); + return () => { cancelled = true; }; +}, [open, selectedSchool?.name, programSearch]); +/* ───────── DEGREE TYPES (server; depends on school+program) ───────── */ +useEffect(() => { + if (!open) return; + if (!selectedSchool?.name || !selectedProgram) { setDegreeTypes([]); return; } + let cancelled = false; + (async () => { + try { + const { data } = await api.get('/api/programs/types', { + params: { school: selectedSchool.name, program: selectedProgram }, + withCredentials: true, + }); + const types = Array.isArray(data?.types) ? data.types : []; + if (!cancelled) setDegreeTypes(types); + } catch (e) { + if (!cancelled) setDegreeTypes([]); + } + })(); + return () => { cancelled = true; }; +}, [open, selectedSchool?.name, selectedProgram]); + + + /* ───────── TUITION ESTIMATE (server) ───────── */ +useEffect(() => { + if (!open) return; + if (!selectedSchool?.unitId) return; + if (!degree) return; + if (tuitionManual) return; // user overrode + (async () => { + try { + const { data } = await api.get('/api/tuition/estimate', { + params: { + unitId : String(selectedSchool.unitId), + programType: degree, + inState : tuitionType === 'inState' ? 1 : 0, + inDistrict: 0, + creditHoursPerYear: 0, // use school's full-time figure (server picks full when 0) + }, + withCredentials: true, + }); + if (data?.estimate) setTuition(String(data.estimate)); + } catch (e) { + // keep existing value; user can enter manually + } + })(); +},[open, selectedSchool?.unitId, degree, tuitionType, tuitionManual]); /* ════════════════════════════════════════════════════ ESC --> close convenience @@ -200,7 +222,7 @@ const handleContinue = () => { } const stub = { - name : schoolSearch || 'Unknown School', + name : (selectedSchool?.name || schoolSearch || 'Unknown School'), degreeType : degree || 'Unspecified', programLength : 4, tuition : parseFloat(tuition), @@ -247,23 +269,89 @@ const handleContinue = () => { className="space-y-4" onSubmit={e => { e.preventDefault(); handleContinue(); }} > - {/* School name (optional) */} -
+ {/* School name (server suggest) */} +
setSchoolSearch(e.target.value)} - list="school-suggestions" + onChange={e => { + setSchoolSearch(e.target.value); + setSelectedSchool({ name:'', unitId:null }); + setSchoolSugOpen(true); setSchoolHi(-1); + // Clear program/degree when school changes + setProgramSearch(''); setSelectedProgram(''); setDegree(''); setDegreeTypes([]); + }} + onFocus={() => setSchoolSugOpen(true)} + onBlur={() => setTimeout(() => setSchoolSugOpen(false), 120)} placeholder="Start typing…" className="mt-1 w-full rounded border px-3 py-2 text-sm" - onBlur={e => setSchoolSearch(e.target.value.trim())} + onKeyDown={e => { + if (!schoolSugOpen || schoolSug.length === 0) return; + if (e.key === 'ArrowDown') { e.preventDefault(); setSchoolHi(h => Math.min(h + 1, schoolSug.length - 1)); } + else if (e.key === 'ArrowUp') { e.preventDefault(); setSchoolHi(h => Math.max(h - 1, 0)); } + else if (e.key === 'Enter' && schoolHi >= 0) { + e.preventDefault(); + const opt = schoolSug[schoolHi]; setSchoolSearch(opt.name); setSelectedSchool(opt); setSchoolSugOpen(false); + } + }} /> - - {suggestions.map((s, i) => ( - + {schoolSugOpen && schoolSug.length > 0 && ( +
+ {schoolSug.map((s, i) => ( + + ))} +
+ )} +
+ + {/* Program (server suggest, requires selected school) */} +
+ + { setProgramSearch(e.target.value); setSelectedProgram(''); setProgramSugOpen(true); setProgramHi(-1); }} + onFocus={() => setProgramSugOpen(true)} + onBlur={() => setTimeout(() => setProgramSugOpen(false), 120)} + placeholder={selectedSchool?.name ? 'Start typing…' : 'Pick a school first'} + disabled={!selectedSchool?.name} + className="mt-1 w-full rounded border px-3 py-2 text-sm disabled:bg-gray-100" + onKeyDown={e => { + if (!programSugOpen || programSug.length === 0) return; + if (e.key === 'ArrowDown') { e.preventDefault(); setProgramHi(h => Math.min(h + 1, programSug.length - 1)); } + else if (e.key === 'ArrowUp') { e.preventDefault(); setProgramHi(h => Math.max(h - 1, 0)); } + else if (e.key === 'Enter' && programHi >= 0) { + e.preventDefault(); + const opt = programSug[programHi]; setProgramSearch(opt.program); setSelectedProgram(opt.program); setProgramSugOpen(false); + } + }} + /> + {programSugOpen && programSug.length > 0 && ( +
+ {programSug.map((s, i) => ( + + ))} +
+ )}
{/* Residency */} @@ -286,6 +374,7 @@ const handleContinue = () => { value={degree} onChange={e => setDegree(e.target.value)} className="mt-1 w-full rounded border px-3 py-2 text-sm" + disabled={degreeTypes.length === 0 && !selectedProgram} > {degreeMenu.map((d, i) => ( diff --git a/src/components/PlanningLanding.js b/src/components/PlanningLanding.js index 57bbdfa..f98f368 100644 --- a/src/components/PlanningLanding.js +++ b/src/components/PlanningLanding.js @@ -1,3 +1,4 @@ +// src/components/PlanningLanding.jsx import React from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from './ui/button.js'; @@ -6,46 +7,52 @@ function PlanningLanding() { const navigate = useNavigate(); return ( -
-
-

- Planning Your Career -

-

- Discover career options that match your interests, skills, and potential. - AptivaAI helps you find your ideal career path, provides insights into educational requirements, - expected salaries, job market trends, and more. -

+
+
+ {/* Header */} +
+

+ Planning Your Career +

+

+ Discover career options that match your interests, skills, and + potential. AptivaAI helps you explore ideal paths, understand + educational requirements, compare salaries, and analyze job market + trendsβ€”all in one place. +

+
-
- -
- -

- Identify your interests and discover careers aligned with your strengths. + {/* Options grid */} +

+ {/* Interest Inventory */} +
+

Interest Inventory

+

+ Identify your interests and discover careers aligned with your + strengths.

+
-
- -

- Research detailed career profiles, job descriptions, salaries, and employment outlooks. + {/* Career Explorer */} +

+

Career Explorer

+

+ Research career profiles, job descriptions, salaries, and + employment outlooks.

-
- -
- -

- Find the right educational programs, degrees, and certifications needed to pursue your chosen career. -

-
diff --git a/src/components/PreparingLanding.js b/src/components/PreparingLanding.js index 4415f06..f2ebbba 100644 --- a/src/components/PreparingLanding.js +++ b/src/components/PreparingLanding.js @@ -1,27 +1,26 @@ -// src/components/PreparingLanding.js +// src/components/PreparingLanding.js import React, { useState, useCallback, useEffect, useContext } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, useLocation } from 'react-router-dom'; import { Button } from './ui/button.js'; import LoanRepaymentDrawer from './LoanRepaymentDrawer.js'; import { ProfileCtx } from '../App.js'; function PreparingLanding() { const navigate = useNavigate(); - + const location = useLocation(); const { user } = useContext(ProfileCtx); /* ─── Drawer visibility ─────────────────────────────── */ const [showLoan, setShowLoan] = useState(false); /* ─── Stub-school state lives here; Drawer mutates it ─ */ - const [schools, setSchools] = useState([]); // [] β†’ quick-fill form - const [cipCodes] = useState([]); // you may hold these at page level - const [userZip] = useState(''); + const [schools, setSchools] = useState([]); // [] β†’ quick-fill form + const [cipCodes] = useState([]); // you may hold these at page level + const [userZip] = useState(''); const [loanResults, setLoanResults] = useState([]); - /* Esc -to-close convenience */ - const escHandler = useCallback(e => { + const escHandler = useCallback((e) => { if (e.key === 'Escape') setShowLoan(false); }, []); useEffect(() => { @@ -29,58 +28,83 @@ function PreparingLanding() { return () => window.removeEventListener('keydown', escHandler); }, [showLoan, escHandler]); + /* ─── Auto-open drawer when routed from nav ───────── */ + useEffect(() => { + // support either query ?loan=1 or navigation state { openLoan: true } + try { + const qs = new URLSearchParams(location.search); + const viaQuery = qs.get('loan') === '1'; + const viaState = location.state && location.state.openLoan === true; + if ((viaQuery || viaState) && !showLoan) { + setShowLoan(true); + } + } catch {} + }, [location.search, location.state, showLoan]); + return ( -
-
+
+
{/* ───────────────── TITLE / INTRO ───────────────── */} -

- Preparing for Your (Next) Career -

-

- Build the right skills and plan your education so you can confidently - enterβ€”or transition intoβ€”your new career. -

+
+

+ Preparing for Your (Next) Career +

+

+ Build the right skills and plan your education so you can confidently + enterβ€”or transition intoβ€”your new career. +

+
{/* ──────────────── 1) PATH CHOICE ──────────────── */}

Which Path Fits You?

- We can help you identify whether a  - skills-based program (certifications, bootcamps) or a  - formal education route (two- or four-year college) - is the best fit. Whichever path you choose, AptivaAI will help you map next stepsβ€”from applying to graduating. - + We can help you identify whether a skills-based program (certifications, bootcamps) or a{' '} + formal education route (two- or four-year college) is the best fit. Whichever path you choose, + AptivaAI will help you map next stepsβ€”from applying to graduating.

-
- - +
+ {/* Education path card */} +
+

Plan My Education Path

+

+ Compare degrees, certificates, and training paths for your target role. +

+ +
+ + {/* Loan/Cost card */} +
+

Cost of Education & Loan Repayment

+

+ Estimate total costs and monthly payments with realistic assumptions. +

+ +
- {/* ──────────────── 2) LOAN BLURB ──────────────── */} -
-

Financing Your Future

-

- Already have an idea of where you want to enroll? Compare costs, - estimate student-loan repayments, and map out work-study or part-time - opportunities. Our integrated LoanRepayment tool shows - realistic monthly payments so you can make confident choices. -

-
- - {/* ──────────────── 3) INTEREST INVENTORY ──────────────── */} + {/* ──────────────── 2) STILL EXPLORING ──────────────── */}

Still Exploring?

- Want to revisit career possibilities? Retake our Interest Inventory to - see other matching paths. + Want to revisit career possibilities? Retake our Interest Inventory to see other matching paths.

-
@@ -90,7 +114,11 @@ function PreparingLanding() { {showLoan && ( setShowLoan(false)} + onClose={() => { + setShowLoan(false); + // clear nav flag so it doesn’t auto-reopen + navigate({ pathname: location.pathname }, { replace: true, state: {} }); + }} schools={schools} setSchools={setSchools} results={loanResults} diff --git a/src/components/RetirementLanding.js b/src/components/RetirementLanding.js index d554ef8..2b227a6 100644 --- a/src/components/RetirementLanding.js +++ b/src/components/RetirementLanding.js @@ -1,25 +1,39 @@ -import React from 'react'; -import { useNavigate } from 'react-router-dom'; -import { Button } from './ui/button.js'; +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { Button } from "./ui/button.js"; -function RetirementLanding() { +export default function RetirementLanding() { const navigate = useNavigate(); return ( -
-
-

+
+
+ {/* Title + intro (centered, blue headline) */} +

Retirement Planning

-

- Plan strategically and financially for retirement. AptivaAI provides you with clear financial projections, milestone tracking, and scenario analysis for a secure future. +

+ Plan strategically and financially for retirement. Model scenarios, + understand trade-offs, and track the milestones that keep you on course.

-
- + + {/* Feature tile(s) inside main card */} +
+ {/* Retirement Planner */} +
+

Retirement Planner

+

+ Compare scenarios, project savings and income, and get AI guidance to + fine-tune your plan. +

+
+ +
+
); } - -export default RetirementLanding; diff --git a/src/components/SignIn.js b/src/components/SignIn.js index 0047b0a..f4f5f48 100644 --- a/src/components/SignIn.js +++ b/src/components/SignIn.js @@ -84,14 +84,17 @@ function SignIn({ setIsAuthenticated, setUser }) { }; return ( -
+
{showSessionExpiredMsg && (
Your session has expired. Please sign in again.
)} -
-

Sign In

+
+ {/* Wordmark (text-only) */} +
AptivaAI
+

Sign In

+

Career guidance powered by data β€” enhanced by AI

{error && (

@@ -99,24 +102,24 @@ function SignIn({ setIsAuthenticated, setUser }) {

)} -
+ @@ -125,7 +128,7 @@ function SignIn({ setIsAuthenticated, setUser }) {

Don’t have an account?{' '} - + Sign Up

@@ -133,7 +136,7 @@ function SignIn({ setIsAuthenticated, setUser }) {
Forgot your password? diff --git a/src/components/SignInLanding.js b/src/components/SignInLanding.js index 468ca1d..ecd9d75 100644 --- a/src/components/SignInLanding.js +++ b/src/components/SignInLanding.js @@ -1,44 +1,89 @@ -// SignInLanding.jsx +// src/components/SignInLanding.jsx import React from 'react'; import { Link } from 'react-router-dom'; function SignInLanding({ user }) { return ( -
-

- Welcome to AptivaAI {user?.firstname}! -

-

- At AptivaAI, we aim to arm you with as much information as possible to make informed career decisions. Today’s workplace is changing faster than ever, driven largely by AIβ€”but our goal is to use that same technology to empower job seekers, not replace them. +

+ {/* Soft brand header band */} +
+
+ AptivaAI +
+

+ Welcome{user?.firstname ? `, ${user.firstname}` : ''}! +

+

+ Career guidance powered by data β€” enhanced by AI +

+
-We blend data-backed insights with human-centered design, enhanced -not driven by- AI. Giving you practical recommendations and real-world context so you stay in the driver’s seat of your career. Whether you’re planning your first step, advancing your current role, or ready to pivot entirely, our platform keeps you in controlβ€”helping you adapt, grow, and thrive on your own terms. + {/* Intro copy */} +

+ At AptivaAI, we aim to arm you with as much information as possible to + make informed career decisions. Today’s workplace is changing faster + than ever, driven largely by AIβ€”but our goal is to use that same + technology to empower job seekers, not replace them. +
+
+ We blend data-backed insights with human-centered design, enhancedβ€”not + driven byβ€”AI. Giving you practical recommendations and real-world + context so you stay in the driver’s seat of your career. Whether you’re + planning your first step, advancing your current role, or ready to pivot + entirely, our platform keeps you in controlβ€”helping you adapt, grow, and + thrive on your own terms.

-
    -
  • Planning: Just starting out? Looking for a different career that is a better fit? Explore options and figure out what careers match your interests and skills.
  • -
  • Preparing: Know what you want but just not how to get there? Gain education, skills, or certifications required to start or transition.
  • -
  • Enhancing: You've got some experience in your field but want to know how to get to the next level? Advance, seek promotions, or shift roles for an established professional.
  • -
  • Retirement: On your happy path and want to make sure you're financially ready when the time comes? Prepare financially and strategically for retirement.
  • -
-

- Where would you like to go next? -

- {/* Mobile: stacked full-width; Desktop: original inline buttons with spacing */} -
- - Go to Exploring +

Where would you like to go next?

+ + {/* Four clickable tiles */} +
+ +
Planning
+

+ Just starting out or exploring a better fit? See careers that match + your interests and skills. +

- - Go to Preparing + + +
Preparing
+

+ Know your target role but not the path? Find education, skills, or + certifications to start or transition. +

- - Go to Enhancing + + +
Enhancing
+

+ Already in-field? Chart your next stepβ€”promotions, role shifts, and + growth moves. +

- - Go to Retirement + + +
Retirement
+

+ On your happy path? Make sure the finances line up when the time + comes. +

+ ); }