diff --git a/.env b/.env
index 2d66382..ac15385 100644
--- a/.env
+++ b/.env
@@ -2,7 +2,7 @@ CORS_ALLOWED_ORIGINS=https://dev1.aptivaai.com,http://34.16.120.118:3000,http://
SERVER1_PORT=5000
SERVER2_PORT=5001
SERVER3_PORT=5002
-IMG_TAG=4cfdf84-202508101351
+IMG_TAG=b0cbb65-202508101532
ENV_NAME=dev
PROJECT=aptivaai-dev
\ No newline at end of file
diff --git a/src/components/CareerExplorer.js b/src/components/CareerExplorer.js
index e88f2fe..9bdf272 100644
--- a/src/components/CareerExplorer.js
+++ b/src/components/CareerExplorer.js
@@ -384,11 +384,11 @@ const handleCareerClick = useCallback(
const s = salaryRes.data;
const salaryData = s && Object.keys(s).length
? [
- { percentile: '10th Percentile', regionalSalary: +s.regional?.regional_PCT10 || 0, nationalSalary: +s.national?.national_PCT10 || 0 },
- { percentile: '25th Percentile', regionalSalary: +s.regional?.regional_PCT25 || 0, nationalSalary: +s.national?.national_PCT25 || 0 },
+ { percentile: '10th Percentile', regionalSalary: +s.regional?.regional_PCT10 || 0, nationalSalary: +s.national?.national_PCT10 || 0 },
+ { percentile: '25th Percentile', regionalSalary: +s.regional?.regional_PCT25 || 0, nationalSalary: +s.national?.national_PCT25 || 0 },
{ percentile: 'Median', regionalSalary: +s.regional?.regional_MEDIAN || 0, nationalSalary: +s.national?.national_MEDIAN || 0 },
- { percentile: '75th Percentile', regionalSalary: +s.regional?.regional_PCT75 || 0, nationalSalary: +s.national?.national_PCT75 || 0 },
- { percentile: '90th Percentile', regionalSalary: +s.regional?.regional_PCT90 || 0, nationalSalary: +s.national?.national_PCT90 || 0 },
+ { percentile: '75th Percentile', regionalSalary: +s.regional?.regional_PCT75 || 0, nationalSalary: +s.national?.national_PCT75 || 0 },
+ { percentile: '90th Percentile', regionalSalary: +s.regional?.regional_PCT90 || 0, nationalSalary: +s.national?.national_PCT90 || 0 },
]
: [];
@@ -618,7 +618,6 @@ useEffect(() => {
:
3;
-
const defaultMeaningValue = 3;
// 4) open the InterestMeaningModal instead of using prompt()
@@ -684,44 +683,72 @@ useEffect(() => {
});
};
+ const stripSoc = (s = '') => s.split('.')[0];
// ------------------------------------------------------
// "Select for Education" => navigate with CIP codes
// ------------------------------------------------------
// CareerExplorer.js
-const handleSelectForEducation = (career) => {
+// CareerExplorer.js
+const handleSelectForEducation = async (career) => {
if (!career) return;
- // ─── 1. Ask first ─────────────────────────────────────────────
const ok = window.confirm(
`Are you sure you want to move on to Educational Programs for “${career.title}”?`
);
if (!ok) return;
- // ─── 2. Make sure we have a full SOC code ─────────────────────
const fullSoc = career.soc_code || career.code || '';
- if (!fullSoc) {
+ const baseSoc = stripSoc(fullSoc);
+ if (!baseSoc) {
alert('Sorry – this career is missing a valid SOC code.');
return;
}
- // ─── 3. Find & clean CIP codes (may be empty) ─────────────────
- const match = masterCareerRatings.find(r => r.soc_code === fullSoc);
- const rawCips = match?.cip_codes ?? []; // original array
- const cleanedCips = cleanCipCodes(rawCips); // “0402”, “1409”, …
+ // 1) try local JSON by base SOC (tolerates .00 vs none)
+ const match = masterCareerRatings.find(r => stripSoc(r.soc_code) === baseSoc);
+ let rawCips = Array.isArray(match?.cip_codes) ? match.cip_codes : [];
+ let cleanedCips = cleanCipCodes(rawCips);
- // ─── 4. Persist ONE tidy object for later pages ───────────────
+ // 2) fallback: ask server2 to map SOC→CIP if local didn’t have any
+ if (!cleanedCips.length) {
+ try {
+ const candidates = [
+ fullSoc, // as-is
+ baseSoc, // stripped
+ fullSoc.includes('.') ? null : `${fullSoc}.00` // add .00 if missing
+ ].filter(Boolean);
+
+ let fromApi = null;
+ for (const soc of candidates) {
+ const res = await fetch(`/api/cip/${soc}`);
+ if (res.ok) {
+ const { cipCode } = await res.json();
+ if (cipCode) { fromApi = cipCode; break; }
+ }
+ }
+
+ if (fromApi) {
+ rawCips = [fromApi];
+ cleanedCips = cleanCipCodes(rawCips);
+ }
+ } catch {
+ // best-effort fallback; continue
+ }
+ }
+
+ // Persist for the next page (keep raw list if we have it)
const careerForStorage = {
...career,
soc_code : fullSoc,
- cip_code : rawCips // keep the raw list; page cleans them again if needed
+ cip_code : rawCips
};
localStorage.setItem('selectedCareer', JSON.stringify(careerForStorage));
- // ─── 5. Off we go ─────────────────────────────────────────────
+ // Navigate with the robust base SOC + cleaned CIP prefixes
navigate('/educational-programs', {
state: {
- socCode : fullSoc,
- cipCodes : cleanedCips, // can be [], page handles it
+ socCode : baseSoc,
+ cipCodes : cleanedCips, // can be [] if absolutely nothing found
careerTitle : career.title,
userZip : userZipcode,
userState : userState
@@ -729,7 +756,6 @@ const handleSelectForEducation = (career) => {
});
};
-
// ------------------------------------------------------
// Filter logic for jobZone, Fit
// ------------------------------------------------------
diff --git a/src/components/CareerRoadmap.js b/src/components/CareerRoadmap.js
index fcd496f..49ba3a2 100644
--- a/src/components/CareerRoadmap.js
+++ b/src/components/CareerRoadmap.js
@@ -29,6 +29,7 @@ import parseFloatOrZero from '../utils/ParseFloatorZero.js';
import { getFullStateName } from '../utils/stateUtils.js';
import CareerCoach from "./CareerCoach.js";
import ChatCtx from '../contexts/ChatCtx.js';
+import FinancialDisclaimer from './FinancialDisclaimer.js';
import { Button } from './ui/button.js';
import { Pencil } from 'lucide-react';
@@ -78,6 +79,7 @@ async function createCareerProfileFromSearch(selCareer) {
throw new Error('createCareerProfileFromSearch: selCareer.title is required');
}
+
/* -----------------------------------------------------------
* 1) Do we already have that title?
* --------------------------------------------------------- */
@@ -1497,7 +1499,8 @@ const handleMilestonesCreated = useCallback(
Loan Paid Off: diff --git a/src/components/FinancialDisclaimer.js b/src/components/FinancialDisclaimer.js new file mode 100644 index 0000000..e454b98 --- /dev/null +++ b/src/components/FinancialDisclaimer.js @@ -0,0 +1,29 @@ +export default function FinancialDisclaimer() { + return ( +
+ Important: These projections are educational estimates and not financial, tax, + legal, or investment advice. Federal tax is approximated using the single‑filer standard deduction + ($13,850) and 2023 federal brackets; state tax is a flat percentage by + state from an internal table. Estimates exclude Social Security/Medicare (FICA), + local taxes, itemized deductions, credits, AMT, capital‑gains rules, and self‑employment taxes. Actual outcomes + vary. +
+ +