diff --git a/backend/.env b/.env similarity index 100% rename from backend/.env rename to .env diff --git a/backend/CIP_institution_mapping_fixed.json b/backend/CIP_institution_mapping_fixed.json old mode 100755 new mode 100644 diff --git a/backend/server.js b/backend/server.js index af23f7a..20a2c62 100755 --- a/backend/server.js +++ b/backend/server.js @@ -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); diff --git a/backend/server2.js b/backend/server2.js index 93f30a5..8ef7f20 100755 --- a/backend/server2.js +++ b/backend/server2.js @@ -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); }); diff --git a/package-lock.json b/package-lock.json index 15a5ed4..b22e616 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js index ae84d13..612fc39 100644 --- a/src/components/Dashboard.js +++ b/src/components/Dashboard.js @@ -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,73 +39,85 @@ 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}` }, + }); + + if (profileResponse.ok) { + const profileData = await profileResponse.json(); + console.log('Fetched User Profile:', profileData); + + 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); + } + }; - 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 - ); - - setSchools(filteredSchools); - }; + 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'); return; } - + try { 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}`); + + 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 && ( setSelectedCareer(null)} diff --git a/src/components/EconomicProjections.js b/src/components/EconomicProjections.js index b0f3135..7361a62 100644 --- a/src/components/EconomicProjections.js +++ b/src/components/EconomicProjections.js @@ -6,22 +6,30 @@ 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 } catch (err) { setError('Error fetching economic projections.'); console.error('Error fetching projections:', err); } }; + + fetchProjections(); } diff --git a/src/components/EducationalPrograms.js b/src/components/EducationalPrograms.js index e11306e..cd43b5c 100644 --- a/src/components/EducationalPrograms.js +++ b/src/components/EducationalPrograms.js @@ -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
{error}
; diff --git a/src/components/InterestInventory.js b/src/components/InterestInventory.js index 5114579..be8ba72 100644 --- a/src/components/InterestInventory.js +++ b/src/components/InterestInventory.js @@ -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', diff --git a/src/components/PopoutPanel.js b/src/components/PopoutPanel.js index ee0669e..dc95638 100644 --- a/src/components/PopoutPanel.js +++ b/src/components/PopoutPanel.js @@ -1,125 +1,26 @@ -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); - - 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 ( -
- -

No Career Selected

-
- ); - } +function PopoutPanel({ + career = {}, + schools = [], + salaryData = {}, + economicProjections = {}, + tuitionData = {}, + loading = false, + error = null, + closePanel +}) { + console.log('PopoutPanel Props:', { career, schools, salaryData, economicProjections, tuitionData, loading, error }); + // 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 ( +
+ +

No Career Selected

+
+ ); + } + + const tenthPercentileSalary = salaryData?.find( (point) => point.percentile === '10th Percentile' )?.value || 0; + return (
@@ -176,47 +88,44 @@ function PopoutPanel({ career, closePanel }) {

No economic projections available.

)} - {/* Salary Data Points */} - - -

Salary Data

- {salaryData && salaryData.length > 0 ? ( - - - - - + {/* Salary Data Points */} +

Salary Data

+ {salaryData && salaryData.length > 0 ? ( +
PercentileSalary
+ + + + + + + + {salaryData.map((point, index) => ( + + + - - - {salaryData.map((point, index) => ( - - - - - ))} - -
PercentileSalary
{point.percentile} + {point.value > 0 ? `$${parseInt(point.value, 10).toLocaleString()}` : 'N/A'} +
{point.percentile} - {point.value > 0 ? `$${parseInt(point.value, 10).toLocaleString()}` : 'N/A'} -
- ) : ( -

No salary data available.

- )} - - {/* Loan Repayment Analysis */} - {tenthPercentileSalary > 0 && ( - parseFloat(s.inStateTuition) || 0), - outOfState: schools.map((s) => parseFloat(s.outOfStateTuition) || 0), - }} - salaryData={[{ percentile: '10th Percentile', value: tenthPercentileSalary, growthRate: 0.03 }]} - earningHorizon={10} - /> - )} + ))} + + + ) : ( +

No salary data available.

+ )} + {/* Loan Repayment Analysis */} + {tenthPercentileSalary > 0 && ( + parseFloat(s.inStateTuition) || 0), + outOfState: schools.map((s) => parseFloat(s.outOfStateTuition) || 0), + }} + salaryData={[{ percentile: '10th Percentile', value: tenthPercentileSalary, growthRate: 0.03 }]} + earningHorizon={10} + /> + )}
); } -export default PopoutPanel; \ No newline at end of file +export default PopoutPanel; diff --git a/src/utils/apiUtils.js b/src/utils/apiUtils.js new file mode 100644 index 0000000..4de3798 --- /dev/null +++ b/src/utils/apiUtils.js @@ -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 []; + } +}; +