Initial commit

This commit is contained in:
Josh 2024-12-25 17:35:29 +00:00
parent 85dfd14aa8
commit e07dc32b51
11 changed files with 377 additions and 388 deletions

View File

0
backend/CIP_institution_mapping_fixed.json Executable file → Normal file
View File

View File

@ -22,7 +22,7 @@ const db = new sqlite3.Database(dbPath, (err) => {
}
});
dotenv.config({ path: path.resolve(__dirname, '../backend/.env') }); // Load environment variables
dotenv.config({ path: path.resolve('/home/jcoakley/aptiva-dev1-app/.env') }); // Adjust the path based on your folder structure
const SECRET_KEY = process.env.SECRET_KEY || 'supersecurekey'; // Use a secure key in production
console.log('ONET_USERNAME:', process.env.ONET_USERNAME);
console.log('ONET_PASSWORD:', process.env.ONET_PASSWORD);

View File

@ -9,7 +9,7 @@ import { fileURLToPath } from 'url'; // Import fileURLToPath to handle the curre
import { open } from 'sqlite'; // Use the open method directly from sqlite package
import sqlite3 from 'sqlite3';
dotenv.config({ path: '/home/jcoakley/aptiva-dev1-app/backend/.env' }); // Load environment variables
dotenv.config({ path: path.resolve('/home/jcoakley/aptiva-dev1-app/.env') }); // Adjust the path based on your folder structure
console.log('ONET_USERNAME:', process.env.ONET_USERNAME);
console.log('ONET_PASSWORD:', process.env.ONET_PASSWORD);
@ -346,7 +346,7 @@ app.get('/api/cip/:socCode', (req, res) => {
res.status(404).json({ error: 'CIP code not found for this SOC code' });
});
app.get('/CIP_institution_mapping_fixed.json', (req, res) => {
app.get('/api/CIP_institution_mapping_fixed.json', (req, res) => {
const filePath = path.join(__dirname, 'CIP_institution_mapping_fixed.json'); // Adjust the path if needed
res.sendFile(filePath);
});

333
package-lock.json generated
View File

@ -106,14 +106,6 @@
"url": "https://opencollective.com/babel"
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/eslint-parser": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz",
@ -139,14 +131,6 @@
"node": ">=10"
}
},
"node_modules/@babel/eslint-parser/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/generator": {
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz",
@ -188,14 +172,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz",
@ -216,14 +192,6 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-create-regexp-features-plugin": {
"version": "7.26.3",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz",
@ -240,14 +208,6 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/helper-define-polyfill-provider": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz",
@ -1597,14 +1557,6 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/plugin-transform-shorthand-properties": {
"version": "7.25.9",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz",
@ -1846,14 +1798,6 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@babel/preset-modules": {
"version": "0.1.6-no-external-plugins",
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
@ -2831,6 +2775,17 @@
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@ -2901,6 +2856,18 @@
"semver": "^7.3.5"
}
},
"node_modules/@npmcli/fs/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@npmcli/move-file": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
@ -2915,18 +2882,6 @@
"node": ">=10"
}
},
"node_modules/@npmcli/move-file/node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"optional": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -3674,6 +3629,17 @@
}
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/experimental-utils": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz",
@ -3798,6 +3764,17 @@
}
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
@ -3843,6 +3820,17 @@
"node": ">=4.0"
}
},
"node_modules/@typescript-eslint/utils/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
@ -4718,14 +4706,6 @@
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
"node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.10.6",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz",
@ -5134,18 +5114,6 @@
"node": ">=10"
}
},
"node_modules/cacache/node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"optional": true,
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/cacache/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@ -5877,6 +5845,17 @@
}
}
},
"node_modules/css-loader/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/css-minimizer-webpack-plugin": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz",
@ -7140,14 +7119,6 @@
"node": ">=0.10.0"
}
},
"node_modules/eslint-plugin-import/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-jest": {
"version": "25.7.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz",
@ -7200,27 +7171,27 @@
}
},
"node_modules/eslint-plugin-react": {
"version": "7.37.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz",
"integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==",
"version": "7.37.3",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.3.tgz",
"integrity": "sha512-DomWuTQPFYZwF/7c9W2fkKkStqZmBd3uugfqBYLdkZ3Hii23WzZuOLUskGxB8qkSKqftxEeGL1TB2kMhrce0jA==",
"dependencies": {
"array-includes": "^3.1.8",
"array.prototype.findlast": "^1.2.5",
"array.prototype.flatmap": "^1.3.2",
"array.prototype.flatmap": "^1.3.3",
"array.prototype.tosorted": "^1.1.4",
"doctrine": "^2.1.0",
"es-iterator-helpers": "^1.1.0",
"es-iterator-helpers": "^1.2.1",
"estraverse": "^5.3.0",
"hasown": "^2.0.2",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
"object.entries": "^1.1.8",
"object.fromentries": "^2.0.8",
"object.values": "^1.2.0",
"object.values": "^1.2.1",
"prop-types": "^15.8.1",
"resolve": "^2.0.0-next.5",
"semver": "^6.3.1",
"string.prototype.matchall": "^4.0.11",
"string.prototype.matchall": "^4.0.12",
"string.prototype.repeat": "^1.0.0"
},
"engines": {
@ -7268,14 +7239,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/eslint-plugin-react/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-testing-library": {
"version": "5.11.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz",
@ -8059,6 +8022,17 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@ -9512,14 +9486,6 @@
"node": ">=8"
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/istanbul-lib-report": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
@ -9547,6 +9513,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/istanbul-lib-report/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-lib-source-maps": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
@ -10122,6 +10099,17 @@
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/jest-snapshot/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jest-util": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
@ -10694,6 +10682,17 @@
"npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@ -10971,14 +10970,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/make-fetch-happen": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
@ -11296,14 +11287,14 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/mkdirp-classic": {
@ -11403,6 +11394,17 @@
"node": ">=10"
}
},
"node_modules/node-abi/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
@ -11509,6 +11511,18 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/node-gyp/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -12655,6 +12669,17 @@
"webpack": "^5.0.0"
}
},
"node_modules/postcss-loader/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/postcss-logical": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz",
@ -13947,6 +13972,17 @@
"node": ">=10"
}
},
"node_modules/react-scripts/node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/react-spinners": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.15.0.tgz",
@ -14558,14 +14594,11 @@
}
},
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/send": {
@ -15746,6 +15779,17 @@
"node": ">=4"
}
},
"node_modules/svgo/node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/svgo/node_modules/nth-check": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@ -15880,17 +15924,6 @@
"node": ">=8"
}
},
"node_modules/tar/node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/tar/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@ -1,3 +1,4 @@
// Dashboard.js
import axios from 'axios';
import React, { useState, useCallback, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
@ -5,6 +6,7 @@ import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, Toolti
import { CareerSuggestions } from './CareerSuggestions.js';
import PopoutPanel from './PopoutPanel.js';
import { Bar } from 'react-chartjs-2';
import { fetchSchools } from '../utils/apiUtils.js';
import './Dashboard.css';
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);
@ -17,16 +19,16 @@ function Dashboard() {
const [riaSecScores, setRiaSecScores] = useState([]);
const [selectedCareer, setSelectedCareer] = useState(null);
const [schools, setSchools] = useState([]);
const [salaryData, setSalaryData] = useState(null);
const [salaryData, setSalaryData] = useState([]);
const [economicProjections, setEconomicProjections] = useState(null);
const [tuitionData, setTuitionData] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [cipCode, setCipCode] = useState(null);
const [userState, setUserState] = useState(null);
const [areaTitle, setAreaTitle] = useState(null);
const apiUrl = process.env.REACT_APP_API_URL;
useEffect(() => {
// Redirect if no data is available
if (location.state) {
const { careerSuggestions: suggestions, riaSecScores: scores } = location.state || {};
setCareerSuggestions(suggestions || []);
@ -37,26 +39,36 @@ function Dashboard() {
}
}, [location.state, navigate]);
const fetchSchools = async (cipCode, userState) => {
const response = await axios.get(`${apiUrl}/api/CIP_institution_mapping_fixed.json`);
const schoolsData = response.data;
useEffect(() => {
const fetchUserProfile = async () => {
try {
const token = localStorage.getItem('token');
const profileResponse = await fetch(`http://localhost:5000/api/user-profile`, {
headers: { Authorization: `Bearer ${token}` },
});
const cleanedCipCode = cipCode.replace('.', '').slice(0, 4);
const filteredSchools = schoolsData.filter(
(school) =>
typeof school['CIP Code'] === 'string' &&
school['CIP Code'].replace('.', '') === cleanedCipCode &&
school['State'] === userState
);
if (profileResponse.ok) {
const profileData = await profileResponse.json();
console.log('Fetched User Profile:', profileData);
setSchools(filteredSchools);
};
const { state, area } = profileData; // Use 'area' instead of 'AREA_TITLE'
setUserState(state);
setAreaTitle(area && area.trim() ? area.trim() : ''); // Ensure 'area' is set correctly
console.log('Profile Data Set:', { state, area });
} else {
console.error('Failed to fetch user profile');
}
} catch (error) {
console.error('Error fetching user profile:', error);
}
};
fetchUserProfile();
}, []);
const handleCareerClick = useCallback(
async (career) => {
console.log('Career clicked:', career);
const socCode = career.code;
if (!socCode) {
console.error('SOC Code is missing');
setError('SOC Code is missing');
@ -67,43 +79,45 @@ function Dashboard() {
setLoading(true);
setError(null);
// Step 1: Fetch user profile to get state/area
const token = localStorage.getItem('token');
const profileResponse = await fetch(`${apiUrl}/api/user-profile`, {
headers: { Authorization: `Bearer ${token}` },
});
const { state: userState, area: userArea } = await profileResponse.json();
// Step 2: Fetch CIP Code for SOC Code
const cipResponse = await fetch(`${apiUrl}/api/cip/${socCode}`);
const { cipCode } = await cipResponse.json();
if (!cipResponse.ok) {
console.error('Failed to fetch CIP Code');
setError('Failed to fetch CIP Code');
return;
}
const { cipCode } = await cipResponse.json();
if (!cipCode) throw new Error('Failed to fetch CIP Code');
const cleanedCipCode = cipCode.replace('.', '').slice(0, 4);
// Step 3: Fetch all dependent data after fetching CIP Code
setSelectedCareer(career);
setSchools([]);
setEconomicProjections(null);
setTuitionData(null);
await fetchSchools(cleanedCipCode, userState);
const filteredSchools = await fetchSchools(cleanedCipCode, userState);
const cleanedSocCode = socCode.split('.')[0];
const economicResponse = await axios.get(`/api/projections/${cleanedSocCode}`);
setEconomicProjections(economicResponse.data);
const tuitionResponse = await axios.get(`/api/tuition/${cleanedCipCode}`, {
const economicResponse = await axios.get(`http://localhost:5001/api/projections/${cleanedSocCode}`);
const tuitionResponse = await axios.get(`http://localhost:5001/api/tuition/${cleanedCipCode}`, {
params: { state: userState },
});
setTuitionData(tuitionResponse.data);
const salaryResponse = await axios.get(`/api/salary`, {
params: { socCode: cleanedSocCode, area: userArea },
console.log('Salary Data Request Params:', { socCode: cleanedSocCode, area: areaTitle });
const salaryResponse = await axios.get(`http://localhost:5001/api/salary`, {
params: { socCode: cleanedSocCode, area: areaTitle },
});
setSalaryData(salaryResponse.data);
const salaryDataPoints = [
{ percentile: '10th Percentile', value: salaryResponse.data.A_PCT10 || 0 },
{ percentile: '25th Percentile', value: salaryResponse.data.A_PCT25 || 0 },
{ percentile: 'Median', value: salaryResponse.data.A_MEDIAN || 0 },
{ percentile: '75th Percentile', value: salaryResponse.data.A_PCT75 || 0 },
{ percentile: '90th Percentile', value: salaryResponse.data.A_PCT90 || 0 },
];
setSelectedCareer(career);
setSchools(filteredSchools);
setEconomicProjections(economicResponse.data);
setTuitionData(tuitionResponse.data);
setSalaryData(salaryDataPoints);
} catch (error) {
console.error('Error processing career click:', error.message);
setError('Failed to load data');
@ -111,7 +125,7 @@ function Dashboard() {
setLoading(false);
}
},
[]
[userState, apiUrl, areaTitle]
);
const chartData = {
@ -142,8 +156,8 @@ function Dashboard() {
{selectedCareer && (
<PopoutPanel
career={selectedCareer}
schools={schools || []} // Default empty array
salaryData={salaryData || {}} // Default null
schools={schools || []}
salaryData={salaryData || []}
economicProjections={economicProjections || {}}
tuitionData={tuitionData || {}}
closePanel={() => setSelectedCareer(null)}

View File

@ -6,14 +6,20 @@ function EconomicProjections({ socCode }) {
const [projections, setProjections] = useState(null);
const [error, setError] = useState(null);
console.log(axios.defaults.baseURL); // Check if baseURL is set
useEffect(() => {
if (socCode) {
const cleanedSocCode = socCode.split('.')[0]; // Clean the SOC code inside the component
console.log(`Fetching economic projections for cleaned SOC code: ${cleanedSocCode}`);
const fetchProjections = async () => {
const projectionsUrl = process.env.NODE_ENV === 'production'
? '/api/projections/' // In production, routed through Nginx
: 'http://localhost:5001/api/projections/'; // In development, backend is running on localhost:5001
try {
const response = await axios.get(`/api/projections/${cleanedSocCode}`);
const response = await axios.get(`http://localhost:5001/api/projections/${cleanedSocCode}`);
console.log('Projection Response:', response.data); // Log the projection response
setProjections(response.data); // Set the projections data in state
@ -23,6 +29,8 @@ function EconomicProjections({ socCode }) {
}
};
fetchProjections();
}
}, [socCode]); // This runs when the socCode prop changes

View File

@ -1,41 +1,28 @@
import React, { useState, useEffect } from 'react';
import { fetchSchools } from '../utils/apiUtils.ja';
function EducationalPrograms({ cipCode }) {
function EducationalPrograms({ cipCode, userState }) {
const [schools, setSchools] = useState([]);
const [error, setError] = useState(null);
useEffect(() => {
const fetchSchools = async () => {
if (!cipCode) {
console.error('CIP Code is missing or undefined');
setError('CIP Code is missing or undefined');
const loadSchools = async () => {
if (!cipCode || !userState) {
setError('CIP Code or user state is missing');
return;
}
try {
const response = await fetch('https://dev.aptivaai.com/api/CIP_institution_mapping_fixed.json'); // Path to the public folder
if (!response.ok) {
throw new Error(`Failed to fetch schools: ${response.status}`);
}
const schoolsData = await response.json();
console.log('Schools data fetched:', schoolsData); // Log the fetched data to verify
// Filter the schools by CIP Code and State 'Georgia'
const filteredSchools = schoolsData.filter(school =>
school['CIP Code'] === cipCode && school['State'] === 'Georgia'
);
console.log('Filtered Schools:', filteredSchools); // Log the filtered result
setSchools(filteredSchools); // Update the state with filtered schools
const filteredSchools = await fetchSchools(cipCode, userState);
setSchools(filteredSchools);
} catch (error) {
console.error('Error fetching schools:', error);
setError('Failed to load schools data');
}
};
fetchSchools();
}, [cipCode]); // Trigger fetch when CIP Code changes
loadSchools();
}, [cipCode, userState]);
if (error) {
return <div className="error">{error}</div>;

View File

@ -12,11 +12,9 @@ const InterestInventory = () => {
const [careerSuggestions, setCareerSuggestions] = useState([]);
const fetchQuestions = async () => {
const baseUrl = process.env.NODE_ENV === 'production'
? '/api/onet/questions' // Production, assuming it's routed by Nginx
: 'http://localhost:5001/api/onet/questions'; // Development, backend runs on localhost:5000
const baseUrl = process.env.REACT_APP_API_URL || 'http://localhost:5001'; // Default to localhost:5001 for development
const url = `${baseUrl}/api/onet/questions?start=1&end=60`; // Make sure the endpoint is correctly appended to the base URL
const url = `${baseUrl}?start=1&end=60`;
try {
const response = await fetch(url, {
method: 'GET',

View File

@ -1,124 +1,25 @@
import React, { useState, useEffect } from 'react';
// PopoutPanel.js
import ClipLoader from 'react-spinners/ClipLoader.js';
import LoanRepayment from './LoanRepayment.js';
import EconomicProjections from './EconomicProjections.js';
import EducationalPrograms from './EducationalPrograms.js';
import './PopoutPanel.css';
function PopoutPanel({ career, closePanel }) {
const [schools, setSchools] = useState([]);
const [salaryData, setSalaryData] = useState(null);
const [economicProjections, setEconomicProjections] = useState(null);
const [tuitionData, setTuitionData] = useState(null);
const [userState, setUserState] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
function PopoutPanel({
career = {},
schools = [],
salaryData = {},
economicProjections = {},
tuitionData = {},
loading = false,
error = null,
closePanel
}) {
console.log('PopoutPanel Props:', { career, schools, salaryData, economicProjections, tuitionData, loading, error });
useEffect(() => {
const fetchData = async () => {
setLoading(true);
setError(null);
try {
const socCode = career?.code; // Extract SOC code
if (!socCode) throw new Error('SOC code is missing in career data.');
console.log(`Fetching data for SOC Code: ${socCode}`);
// Step 1: Fetch user profile for state and area
const token = localStorage.getItem('token');
const profileResponse = await fetch('/api/user-profile', {
method: 'GET',
headers: { Authorization: `Bearer ${token}` },
});
const profileData = await profileResponse.json();
const userArea = profileData?.area || '';
const userState = profileData?.state || '';
setUserState(userState);
console.log(`User State: ${userState}, User Area: ${userArea}`);
// Step 2: Fetch SOC-to-CIP mapping
const socToCipResponse = await fetch(`/api/cip/${socCode}`);
if (!socToCipResponse.ok) throw new Error(`Failed to fetch CIP code: ${socToCipResponse.status}`);
const { cipCode } = await socToCipResponse.json();
const cleanedCipCode = cipCode?.replace('.', '').slice(0, 4) || '';
console.log('Resolved and Cleaned CIP Code:', cleanedCipCode);
// Step 3: Fetch Schools Offering Programs
const schoolsResponse = await fetch('/api/CIP_institution_mapping_fixed.json');
const schoolsData = await schoolsResponse.json();
const filteredSchools = Array.isArray(schoolsData)
? schoolsData.filter(
(school) =>
school?.['CIP Code']?.replace('.', '') === cleanedCipCode &&
school?.['State'] === userState
)
: [];
// Step 4: Fetch Tuition Data
const tuitionResponse = await fetch(`/api/tuition/${cleanedCipCode}?state=${userState}`);
const tuitionData = await tuitionResponse.json();
// Merge tuition data into the schools
const schoolsWithTuition = filteredSchools.map((school) => ({
...school,
inStateTuition: tuitionData?.inStateTuition || 'N/A',
outOfStateTuition: tuitionData?.outOfStateTuition || 'N/A',
}));
setSchools(schoolsWithTuition);
// Step 5: Fetch Economic Projections
const cleanedSocCode = socCode.replace(/\.\d+$/, ''); // Removes decimals
const projectionsResponse = await fetch(`/api/projections/${cleanedSocCode}`);
if (!projectionsResponse.ok) throw new Error(`Failed to fetch projections: ${projectionsResponse.status}`);
const projectionsData = await projectionsResponse.json();
setEconomicProjections(projectionsData || {});
// Helper function to validate salary values
const sanitizeSalaryValue = (value) => {
const numValue = parseFloat(value);
return isNaN(numValue) ? 0 : numValue; // Replace invalid data with 0
};
// Step 6: Fetch Salary Data
const salaryResponse = await fetch(`/api/salary?socCode=${cleanedSocCode}&area=${userArea}`);
if (!salaryResponse.ok) throw new Error(`Failed to fetch salary data: ${salaryResponse.status}`);
const salaryDataResponse = await salaryResponse.json();
console.log('Salary Data Response:', salaryDataResponse);
// Map the database columns into a usable format
const salaryDataPoints = [
{ percentile: '10th Percentile', value: salaryDataResponse.A_PCT10 || 0 },
{ percentile: '25th Percentile', value: salaryDataResponse.A_PCT25 || 0 },
{ percentile: 'Median', value: salaryDataResponse.A_MEDIAN || 0 },
{ percentile: '75th Percentile', value: salaryDataResponse.A_PCT75 || 0 },
{ percentile: '90th Percentile', value: salaryDataResponse.A_PCT90 || 0 },
];
setSalaryData(salaryDataPoints);
} catch (err) {
console.error('Error fetching salary data:', err.message);
setError(err.message);
} finally {
setLoading(false);
}
};
if (career) {
fetchData();
}
}, [career]);
if (!career) {
return (
<div className="popout-panel">
<button className="close-btn" onClick={closePanel}>X</button>
<h2>No Career Selected</h2>
</div>
);
}
// Validation Checks
const isValidCareer = career && career.title && career.code;
const isValidSchools = Array.isArray(schools) && schools.length > 0;
const isValidSalaryData = salaryData && Object.keys(salaryData).length > 0;
const isValidProjections = economicProjections && Object.keys(economicProjections).length > 0;
if (loading) {
return (
@ -140,9 +41,20 @@ function PopoutPanel({ career, closePanel }) {
);
}
if (!career) {
return (
<div className="popout-panel">
<button className="close-btn" onClick={closePanel}>X</button>
<h2>No Career Selected</h2>
</div>
);
}
const tenthPercentileSalary = salaryData?.find(
(point) => point.percentile === '10th Percentile'
)?.value || 0;
return (
<div className="popout-panel">
<button className="close-btn" onClick={closePanel}>X</button>
@ -176,45 +88,42 @@ function PopoutPanel({ career, closePanel }) {
<p>No economic projections available.</p>
)}
{/* Salary Data Points */}
<h3>Salary Data</h3>
{salaryData && salaryData.length > 0 ? (
<table>
<thead>
<tr>
<th>Percentile</th>
<th>Salary</th>
{/* Salary Data Points */}
<h3>Salary Data</h3>
{salaryData && salaryData.length > 0 ? (
<table>
<thead>
<tr>
<th>Percentile</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
{salaryData.map((point, index) => (
<tr key={index}>
<td>{point.percentile}</td>
<td>
{point.value > 0 ? `$${parseInt(point.value, 10).toLocaleString()}` : 'N/A'}
</td>
</tr>
</thead>
<tbody>
{salaryData.map((point, index) => (
<tr key={index}>
<td>{point.percentile}</td>
<td>
{point.value > 0 ? `$${parseInt(point.value, 10).toLocaleString()}` : 'N/A'}
</td>
</tr>
))}
</tbody>
</table>
) : (
<p>No salary data available.</p>
)}
{/* Loan Repayment Analysis */}
{tenthPercentileSalary > 0 && (
<LoanRepayment
tuitionCosts={{
inState: schools.map((s) => parseFloat(s.inStateTuition) || 0),
outOfState: schools.map((s) => parseFloat(s.outOfStateTuition) || 0),
}}
salaryData={[{ percentile: '10th Percentile', value: tenthPercentileSalary, growthRate: 0.03 }]}
earningHorizon={10}
/>
)}
))}
</tbody>
</table>
) : (
<p>No salary data available.</p>
)}
{/* Loan Repayment Analysis */}
{tenthPercentileSalary > 0 && (
<LoanRepayment
tuitionCosts={{
inState: schools.map((s) => parseFloat(s.inStateTuition) || 0),
outOfState: schools.map((s) => parseFloat(s.outOfStateTuition) || 0),
}}
salaryData={[{ percentile: '10th Percentile', value: tenthPercentileSalary, growthRate: 0.03 }]}
earningHorizon={10}
/>
)}
</div>
);
}

40
src/utils/apiUtils.js Normal file
View File

@ -0,0 +1,40 @@
import axios from 'axios';
//fetch areas by state
export const fetchAreasByState = async (state) => {
try {
const apiUrl = process.env.REACT_APP_API_URL || '';
const response = await fetch('http://127.0.0.1:5001/api/CIP_institution_mapping_fixed.json');
if (response.status === 200) {
return response.data.areas; // Assume the API returns a list of areas
} else {
console.error('Failed to fetch areas:', response.status);
return [];
}
} catch (error) {
console.error('Error fetching areas:', error.message);
return [];
}
};
//fetch schools
export const fetchSchools = async (cipCode, userState) => {
try {
const response = await axios.get('http://127.0.0.1:5001/api/CIP_institution_mapping_fixed.json');
const schoolsData = response.data;
const cleanedCipCode = cipCode.replace('.', '').slice(0, 4);
return schoolsData.filter(
(school) =>
typeof school['CIP Code'] === 'string' &&
school['CIP Code'].replace('.', '') === cleanedCipCode &&
school['State'] === userState
);
} catch (error) {
console.error('Error fetching schools:', error);
return [];
}
};