diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c519660 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,62 @@ +{ + "editor.insertSpaces": true, + // Ignores the warning when Git is missing + "git.ignoreMissingGitWarning": true, + // Disable crash reports being sent to Microsoft. + "telemetry.enableCrashReporter": false, + // Disable usage data and errors being sent to Microsoft. + "telemetry.enableTelemetry": false, + "editor.formatOnSave": true, + "cmake.configureOnOpen": false, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8", + "editor.formatOnSave": true + }, + "autopep8.args": ["--max-line-length=200"], + "editor.detectIndentation": false, + "git.confirmSync": false, + "editor.rulers": [ + { + "column": 120 + } + ], + "git.autofetch": true, + "files.autoSave": "onFocusChange", + "cSpell.language": "en-GB", + "C_Cpp.formatting": "disabled", + "cmake.showOptionsMovedNotification": false, + "diffEditor.renderSideBySide": false, + "terminal.integrated.commandsToSkipShell": ["matlab.interrupt"], + "[matlab]": { + "editor.defaultFormatter": "AffenWiesel.matlab-formatter" + }, + "workbench.editorAssociations": { + "*.pdf": "latex-workshop-pdf-hook" + }, + "notebook.output.textLineLimit": 50, + "prettier.printWidth": 130, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "prettier.useTabs": true, + "editor.tabSize": 4, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[cpp]": { + "editor.defaultFormatter": "ms-vscode.cpptools" + }, + "C_Cpp.default.cppStandard": "gnu++23", + "C_Cpp.default.cStandard": "gnu23", + "diffEditor.hideUnchangedRegions.enabled": true, + "python.createEnvironment.trigger": "off", + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "importSorter.generalConfiguration.sortOnBeforeSave": true, + "cSpell.words": [ + "vars" + ] +} + + diff --git a/eslint.config.mjs b/eslint.config.mjs index c85fb67..1ea5b2f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -6,11 +6,12 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const compat = new FlatCompat({ - baseDirectory: __dirname, + baseDirectory: __dirname, }); -const eslintConfig = [ - ...compat.extends("next/core-web-vitals", "next/typescript"), -]; - -export default eslintConfig; +export default tseslint.config([...compat.extends("next/core-web-vitals", "next/typescript")], { + rules: { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error", + }, +}); diff --git a/next.config.ts b/next.config.ts index e9ffa30..7921f35 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + /* config options here */ }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 2eba268..2baa5c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,17 @@ "dependencies": { "@prisma/client": "^6.4.1", "@types/mapbox-gl": "^3.4.1", + "axios": "^1.9.0", + "bcrypt": "^5.1.1", + "bcryptjs": "^3.0.2", "body-parser": "^2.2.0", "csv-parser": "^3.2.0", + "easy-peasy": "^6.1.0", "express": "^5.1.0", "fs": "^0.0.1-security", "jwt-decode": "^4.0.0", "leaflet": "^1.9.4", + "lodash": "^4.17.21", "mapbox-gl": "^3.10.0", "next": "15.1.7", "path": "^0.12.7", @@ -24,10 +29,12 @@ "react-dom": "^19.0.0", "react-icons": "^5.5.0", "react-leaflet": "^5.0.0", - "react-node": "^1.0.2" + "react-node": "^1.0.2", + "swr": "^2.3.3" }, "devDependencies": { "@eslint/eslintrc": "^3", + "@types/bcrypt": "^5.0.2", "@types/express": "^5.0.1", "@types/node": "^20", "@types/react": "^19", @@ -52,6 +59,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/runtime": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", @@ -1102,6 +1121,26 @@ "integrity": "sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==", "license": "BSD-3-Clause" }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, "node_modules/@mapbox/point-geometry": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", @@ -1448,6 +1487,16 @@ "tslib": "^2.8.0" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", + "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -1604,7 +1653,7 @@ "version": "19.0.10", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1614,7 +1663,7 @@ "version": "19.0.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" @@ -1888,6 +1937,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -1924,6 +1979,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2000,6 +2067,26 @@ "node": ">= 8" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -2207,6 +2294,12 @@ "node": ">= 0.4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -2233,6 +2326,17 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2258,6 +2362,20 @@ "node": "*" } }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -2504,6 +2622,15 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -2555,6 +2682,27 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -2617,6 +2765,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" + }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -2694,7 +2848,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/csv-parser": { @@ -2839,6 +2993,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2848,12 +3017,20 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -2934,6 +3111,42 @@ "dev": true, "license": "MIT" }, + "node_modules/easy-peasy": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/easy-peasy/-/easy-peasy-6.1.0.tgz", + "integrity": "sha512-zW7mUATJRohNWWSrihmeFhS85jjsIHa1ptTDn6bSXa2DXh8Zeawfpmm1LtKa+Y6jNNz5aQlMjWZ8uuuVk5bdVQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.6", + "fast-deep-equal": "^3.1.3", + "immer": "^9.0.21", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "ts-toolbelt": "^9.6.0", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.0 || ^19.0", + "@types/react-dom": "^18.0 || ^19.0", + "react": "^18.0 || ^19.0", + "react-dom": "^18.0 || ^19.0", + "react-native": ">=0.59" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3111,7 +3324,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3730,7 +3942,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -3868,6 +4079,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -3901,6 +4132,42 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3925,6 +4192,36 @@ "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==", "license": "ISC" }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3979,6 +4276,74 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/geojson-vt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", @@ -4248,7 +4613,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -4260,6 +4624,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -4288,6 +4658,19 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -4330,6 +4713,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -4593,7 +4986,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5079,6 +5471,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5106,6 +5504,30 @@ "dev": true, "license": "ISC" }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/mapbox-gl": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-3.10.0.tgz", @@ -5252,6 +5674,31 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -5404,6 +5851,47 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5414,11 +5902,23 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6041,6 +6541,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6222,6 +6728,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -6259,6 +6779,21 @@ "node": ">=0.10.0" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -6282,6 +6817,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -6364,6 +6905,43 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -6495,7 +7073,6 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6550,6 +7127,12 @@ "node": ">= 18" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -6808,6 +7391,15 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -7129,6 +7721,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.3.tgz", + "integrity": "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/tailwindcss": { "version": "3.4.17", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", @@ -7207,6 +7812,44 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "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==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -7309,6 +7952,12 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", @@ -7329,6 +7978,12 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/ts-toolbelt": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", + "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==", + "license": "Apache-2.0" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -7512,6 +8167,15 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util": { "version": "0.10.4", "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", @@ -7525,7 +8189,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/util/node_modules/inherits": { @@ -7554,6 +8217,22 @@ "pbf": "^3.2.1" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7658,6 +8337,56 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -7769,6 +8498,12 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/yaml": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", diff --git a/package.json b/package.json index d6f5621..99e4e22 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,17 @@ "dependencies": { "@prisma/client": "^6.4.1", "@types/mapbox-gl": "^3.4.1", + "axios": "^1.9.0", + "bcrypt": "^5.1.1", "bcryptjs": "^3.0.2", "body-parser": "^2.2.0", "csv-parser": "^3.2.0", + "easy-peasy": "^6.1.0", "express": "^5.1.0", "fs": "^0.0.1-security", "jwt-decode": "^4.0.0", "leaflet": "^1.9.4", + "lodash": "^4.17.21", "mapbox-gl": "^3.10.0", "next": "15.1.7", "path": "^0.12.7", @@ -28,10 +32,12 @@ "react-dom": "^19.0.0", "react-icons": "^5.5.0", "react-leaflet": "^5.0.0", - "react-node": "^1.0.2" + "react-node": "^1.0.2", + "swr": "^2.3.3" }, "devDependencies": { "@eslint/eslintrc": "^3", + "@types/bcrypt": "^5.0.2", "@types/express": "^5.0.1", "@types/node": "^20", "@types/react": "^19", diff --git a/public/destruction.jpg b/public/destruction.jpg new file mode 100644 index 0000000..be11f26 Binary files /dev/null and b/public/destruction.jpg differ diff --git a/public/education.png b/public/education.png new file mode 100644 index 0000000..b8ca0e8 Binary files /dev/null and b/public/education.png differ diff --git a/public/facebook.webp b/public/facebook.webp new file mode 100644 index 0000000..3765b0b Binary files /dev/null and b/public/facebook.webp differ diff --git a/public/insta.webp b/public/insta.webp new file mode 100644 index 0000000..804fdb9 Binary files /dev/null and b/public/insta.webp differ diff --git a/public/linkedIn.png b/public/linkedIn.png new file mode 100644 index 0000000..720154f Binary files /dev/null and b/public/linkedIn.png differ diff --git a/public/research.jpg b/public/research.jpg new file mode 100644 index 0000000..150e1b2 Binary files /dev/null and b/public/research.jpg differ diff --git a/public/road.jpg b/public/road.jpg new file mode 100644 index 0000000..a29f228 Binary files /dev/null and b/public/road.jpg differ diff --git a/public/tech.jpg b/public/tech.jpg new file mode 100644 index 0000000..35f76db Binary files /dev/null and b/public/tech.jpg differ diff --git a/public/tsunamiWaves.jpg b/public/tsunamiWaves.jpg new file mode 100644 index 0000000..4b64e8d Binary files /dev/null and b/public/tsunamiWaves.jpg differ diff --git a/public/x_logo.jpg b/public/x_logo.jpg new file mode 100644 index 0000000..2b2c789 Binary files /dev/null and b/public/x_logo.jpg differ diff --git a/src/app/api/earthquakes/route.ts b/src/app/api/earthquakes/route.ts new file mode 100644 index 0000000..114ba70 --- /dev/null +++ b/src/app/api/earthquakes/route.ts @@ -0,0 +1,65 @@ +import { NextResponse } from "next/server"; + +import { PrismaClient } from "@prisma/client"; + +const usingPrisma = false; +let prisma: PrismaClient; +if (usingPrisma) prisma = new PrismaClient(); + +export async function GET(request: Request) { + try { + const events = [ + { + id: "1234", + title: "Earthquake in Germany", + text1: "Magnitude 8.5", + text2: "30 minutes ago", + magnitude: 8.5, + longitude: 10.4515, // Near Berlin, Germany + latitude: 52.52, + }, + { + id: "2134", + title: "Earthquake in California", + text1: "Magnitude 5.3", + text2: "2 hours ago", + magnitude: 5.3, + longitude: -122.4194, // Near San Francisco, California, USA + latitude: 37.7749, + }, + { + id: "2314", + title: "Tremor in Japan", + text1: "Magnitude 4.7", + text2: "5 hours ago", + magnitude: 4.7, + longitude: 139.6917, // Near Tokyo, Japan + latitude: 35.6762, + }, + { + id: "2341", + title: "Tremor in Spain", + text1: "Magnitude 2.1", + text2: "10 hours ago", + magnitude: 2.1, + longitude: -3.7038, // Near Madrid, Spain + latitude: 40.4168, + }, + ]; + + let earthquakes; + if (usingPrisma) earthquakes = await prisma.earthquakes.findMany(); + + if (earthquakes) { + return NextResponse.json({ message: "Got earthquakes successfully", earthquakes }, { status: 200 }); + } else { + return NextResponse.json({ message: "Got earthquakes successfully", earthquakes: events }, { status: 200 }); + // return NextResponse.json({ message: "Failed to get earthquakes" }, { status: 401 }); + } + } catch (error) { + console.error("Error in earthquakes endpoint:", error); + return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); + } finally { + if (usingPrisma) await prisma.$disconnect(); + } +} diff --git a/src/app/api/functions/csvReadWrite.ts b/src/app/api/functions/csvReadWrite.ts index 6683182..250e4c9 100644 --- a/src/app/api/functions/csvReadWrite.ts +++ b/src/app/api/functions/csvReadWrite.ts @@ -1,68 +1,69 @@ -import path from "path"; -import fs from "fs"; import csv from "csv-parser"; +import fs from "fs"; +import path from "path"; export type User = { - name: string; - email: string; - password: string; + name: string; + email: string; + password: string; + accessLevel: string; }; /** * @returns {array} - Array of Objects containing user data */ export async function readUserCsv(): Promise { - return new Promise((resolve, reject) => { - // Dynamic CSV location generation - let csvPath = path.dirname(__dirname); // /login - csvPath = path.dirname(csvPath); // /api - csvPath = path.dirname(csvPath); // /app - csvPath = path.dirname(csvPath); // /src - csvPath = path.dirname(csvPath); // /[project] - csvPath = path.dirname(csvPath); // /termor-tracker - csvPath = path.join(csvPath, "src", "databases", "Users.csv"); + return new Promise((resolve, reject) => { + // Dynamic CSV location generation + let csvPath = path.dirname(__dirname); // /login + csvPath = path.dirname(csvPath); // /api + csvPath = path.dirname(csvPath); // /app + csvPath = path.dirname(csvPath); // /src + csvPath = path.dirname(csvPath); // /[project] + csvPath = path.dirname(csvPath); // /termor-tracker + csvPath = path.join(csvPath, "src", "databases", "Users.csv"); - // Forms array for user data - let results: User[] = []; - // Reads data and adds it to results - fs.createReadStream(csvPath) - .pipe(csv()) - .on("data", (data) => results.push(data)) - .on("end", () => { - resolve(results); - }) - .on("error", (error) => { - reject(error); - }); - }); + // Forms array for user data + let results: User[] = []; + // Reads data and adds it to results + fs.createReadStream(csvPath) + .pipe(csv()) + .on("data", (data) => results.push(data)) + .on("end", () => { + resolve(results); + }) + .on("error", (error) => { + reject(error); + }); + }); } export function findUserByEmail(users: User[], email: string): User | undefined { - return users.find((user) => user.email === email); + return users.find((user) => user.email === email); } export async function passwordStrengthCheck(password: string): Promise { - if (password.length < 8) { - return "short"; - } else if (password.length > 16) { - return "long"; - } - const lowercaseRegex = /[a-z]/; - const uppercaseRegex = /[A-Z]/; - const digitRegex = /\d/; - const specialCharRegex = /[!@#$%^&*]/; - if (!lowercaseRegex.test(password)) { - return "no lower"; - } else if (!uppercaseRegex.test(password)) { - return "no upper"; - } else if (!digitRegex.test(password)) { - return "no digit"; - } else if (!specialCharRegex.test(password)) { - return "no special"; - } else { - return "secure"; - } - return "end of function"; + if (password.length < 8) { + return "short"; + } else if (password.length > 16) { + return "long"; + } + const lowercaseRegex = /[a-z]/; + const uppercaseRegex = /[A-Z]/; + const digitRegex = /\d/; + const specialCharRegex = /[!@#$%^&*]/; + if (!lowercaseRegex.test(password)) { + return "no lower"; + } else if (!uppercaseRegex.test(password)) { + return "no upper"; + } else if (!digitRegex.test(password)) { + return "no digit"; + } else if (!specialCharRegex.test(password)) { + return "no special"; + } else { + return "secure"; + } + return "end of function"; } /** @@ -71,28 +72,28 @@ export async function passwordStrengthCheck(password: string): Promise { * @returns {Promise} */ export async function writeUserCsv(users: User[]): Promise { - return new Promise((resolve, reject) => { - // Dynamic CSV location generation - let csvPath = path.dirname(__dirname); // /login - csvPath = path.dirname(csvPath); // /api - csvPath = path.dirname(csvPath); // /app - csvPath = path.dirname(csvPath); // /src - csvPath = path.dirname(csvPath); // /[project] - csvPath = path.dirname(csvPath); // /termor-tracker - csvPath = path.join(csvPath, "src", "databases", "Users.csv"); + return new Promise((resolve, reject) => { + // Dynamic CSV location generation + let csvPath = path.dirname(__dirname); // /login + csvPath = path.dirname(csvPath); // /api + csvPath = path.dirname(csvPath); // /app + csvPath = path.dirname(csvPath); // /src + csvPath = path.dirname(csvPath); // /[project] + csvPath = path.dirname(csvPath); // /termor-tracker + csvPath = path.join(csvPath, "src", "databases", "Users.csv"); - // Prepare CSV data as a string - const headers = "name,email,password"; // CSV headers - const rows = users.map((user) => `${user.name},${user.email},${user.password}`); - const csvData = `${headers}\n${rows.join("\n")}`; + // Prepare CSV data as a string + const headers = "name,email,password,level"; // CSV headers + const rows = users.map((user) => `${user.name},${user.email},${user.password},${user.accessLevel}`); + const csvData = `${headers}\n${rows.join("\n")}`; - // Write data to the file - fs.writeFile(csvPath, csvData, (error) => { - if (error) { - reject(error); // Reject promise on error - } else { - resolve(); // Resolve the promise if successful - } - }); - }); -} \ No newline at end of file + // Write data to the file + fs.writeFile(csvPath, csvData, (error) => { + if (error) { + reject(error); // Reject promise on error + } else { + resolve(); // Resolve the promise if successful + } + }); + }); +} diff --git a/src/app/api/login/route.ts b/src/app/api/login/route.ts index 0bd9cb0..a5ef4f7 100644 --- a/src/app/api/login/route.ts +++ b/src/app/api/login/route.ts @@ -1,30 +1,46 @@ +import bcrypt from "bcrypt"; import { NextResponse } from "next/server"; -import {User, readUserCsv, findUserByEmail} from "../functions/csvReadWrite" + +import { PrismaClient } from "@prisma/client"; + +import { findUserByEmail, readUserCsv, User } from "../functions/csvReadWrite"; + +const usingPrisma = false; +let prisma: PrismaClient; +if (usingPrisma) prisma = new PrismaClient(); export async function POST(request: Request) { - try { - const body = await request.json(); // Parse incoming JSON data - const {email, password } = body; - console.log("Login API received data"); + try { + const body = await request.json(); // Parse incoming JSON data + const { email, password } = body; - const userData = await readUserCsv(); + const userData = await readUserCsv(); + console.log(userData); + console.log("Email:", email); // ! remove + console.log("Password:", password); // ! remove - console.log(userData) - console.log("Email:", email); // ! remove - console.log("Password:", password);// ! remove + let foundUser; - const foundUser = findUserByEmail(userData,email) - if (foundUser && foundUser.password === password) { - console.log("User Details Correct") - return NextResponse.json({ message: "Login successful!" }, { status: 200 }); - } else { - console.log("User email or password is invalid") - return NextResponse.json({ message: "Email and/or password are invalid" }, { status: 401 }); - } + if (usingPrisma) { + foundUser = await prisma.user.findUnique({ + where: { + email: email, // use the email to uniquely identify the user + }, + }); + } else { + foundUser = findUserByEmail(userData, email); + } - - } catch (error) { - console.error("Error in signup endpoint:", error); - return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); - } -} \ No newline at end of file + if (foundUser && (await bcrypt.compare(password, usingPrisma ? foundUser.hashedPassword : foundUser.password))) { + // todo remove password from returned user + return NextResponse.json({ message: "Login successful!", user: foundUser }, { status: 200 }); + } else { + return NextResponse.json({ message: "Email and/or password are invalid" }, { status: 401 }); + } + } catch (error) { + console.error("Error in signup endpoint:", error); + return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); + } finally { + if (usingPrisma) await prisma.$disconnect(); + } +} diff --git a/src/app/api/observatories/route.ts b/src/app/api/observatories/route.ts new file mode 100644 index 0000000..e4021df --- /dev/null +++ b/src/app/api/observatories/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; + +import { PrismaClient } from "@prisma/client"; + +const usingPrisma = false; +let prisma: PrismaClient; +if (usingPrisma) prisma = new PrismaClient(); + +export async function GET(request: Request) { + try { + const events = [ + { + id: "1234", + title: "Earthquake - Berlin Observatory", + text1: "Logged by ", + text2: "30 minutes ago", + longitude: 10.4515, // Near Berlin, Germany + latitude: 52.52, + }, + { + id: "2134", + title: "New Observatory - Phuket, Thailand", + text1: "Dr. Neil Armstrong", + text2: "2 weeks ago", + longitude: -122.4194, + latitude: 37.7749, + }, + { + id: "2314", + title: "Observatory Scientist Change", + text1: "Dr. Samantha Green new lead scientist", + text2: "1 month ago", + longitude: 139.6917, + latitude: 35.6762, + }, + ]; + + // todo get earthquakes associated with observatories + let observatories; + if (usingPrisma) observatories = await prisma.observatories.findMany(); + + if (observatories) { + return NextResponse.json({ message: "Got observatories successfully", observatories }, { status: 200 }); + } else { + return NextResponse.json({ message: "Got observatories successfully", observatories: events }, { status: 200 }); + // return NextResponse.json({ message: "Failed to get observatories" }, { status: 401 }); + } + } catch (error) { + console.error("Error in observatories endpoint:", error); + return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); + } finally { + if (usingPrisma) await prisma.$disconnect(); + } +} diff --git a/src/app/api/signup/route.ts b/src/app/api/signup/route.ts index 062b1b9..9360f6c 100644 --- a/src/app/api/signup/route.ts +++ b/src/app/api/signup/route.ts @@ -1,56 +1,83 @@ +import bcrypt from "bcrypt"; import { NextResponse } from "next/server"; -import {User, readUserCsv, writeUserCsv, findUserByEmail, passwordStrengthCheck} from "../functions/csvReadWrite" + +import { PrismaClient } from "@prisma/client"; + +import { findUserByEmail, passwordStrengthCheck, readUserCsv, User, writeUserCsv } from "../functions/csvReadWrite"; + +const usingPrisma = false; +let prisma: PrismaClient; +if (usingPrisma) prisma = new PrismaClient(); export async function POST(request: Request) { - try { - const body = await request.json(); // Parse incoming JSON data - const {name, email, password } = body; - console.log("Signin API received data"); + try { + const body = await request.json(); // Parse incoming JSON data + let { email, password, name } = body; + const accessLevel = "basic"; - const userData = await readUserCsv(); + const userData = await readUserCsv(); - console.log(userData) - console.log("Name:", name); // ! remove - console.log("Email:", email); // ! remove - console.log("Password:", password);// ! remove + console.log(userData); + console.log("Name:", name); // ! remove + console.log("Email:", email); // ! remove + console.log("Password:", password); // ! remove - const foundUser = findUserByEmail(userData,email) + let foundUser; - if (foundUser) { - console.log("Email already in the system") - return NextResponse.json({ message: "Sorry, this email is already in use" }, { status: 409 }); - } + if (usingPrisma) { + foundUser = await prisma.user.findUnique({ + where: { + email: email, // use the email to uniquely identify the user + }, + }); + } else { + foundUser = findUserByEmail(userData, email); + } - const passwordCheckResult = await passwordStrengthCheck(password) - - if (passwordCheckResult === "short"){ - return NextResponse.json({ message: "Your password is shorter than 8 characters" }, { status: 400 }); - } else if (passwordCheckResult === "long"){ - return NextResponse.json({ message: "Your password is longer than 16 characters" }, { status: 400 }); - } else if (passwordCheckResult === "no lower"){ - return NextResponse.json({ message: "Your password must contain a lowercase letters" }, { status: 400 }); - } else if (passwordCheckResult === "no upper"){ - return NextResponse.json({ message: "Your password must contain a uppercase letters" }, { status: 400 }); - } else if (passwordCheckResult === "no digit"){ - return NextResponse.json({ message: "Your password must contain a number" }, { status: 400 }); - } else if (passwordCheckResult === "no special"){ - return NextResponse.json({ message: "Your password must contain a special character (!@#$%^&*)" }, { status: 400 }); - } else if (passwordCheckResult === "end of function"){ - return NextResponse.json({ message: "Password check script failure" }, { status: 500 }); - } else { - try { - userData.push(body) - await writeUserCsv(userData) - return NextResponse.json({ message: "Account Created" }, { status: 201 }); - } catch(error) { - console.error("Error in writting :", error); - return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); - } - } + if (foundUser) { + return NextResponse.json({ message: "Sorry, this email is already in use" }, { status: 409 }); + } + const passwordCheckResult = await passwordStrengthCheck(password); - } catch (error) { - console.error("Error in signup endpoint:", error); - return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); - } -} \ No newline at end of file + if (passwordCheckResult === "short") { + return NextResponse.json({ message: "Your password is shorter than 8 characters" }, { status: 400 }); + } else if (passwordCheckResult === "long") { + return NextResponse.json({ message: "Your password is longer than 16 characters" }, { status: 400 }); + } else if (passwordCheckResult === "no lower") { + return NextResponse.json({ message: "Your password must contain a lowercase letters" }, { status: 400 }); + } else if (passwordCheckResult === "no upper") { + return NextResponse.json({ message: "Your password must contain a uppercase letters" }, { status: 400 }); + } else if (passwordCheckResult === "no digit") { + return NextResponse.json({ message: "Your password must contain a number" }, { status: 400 }); + } else if (passwordCheckResult === "no special") { + return NextResponse.json({ message: "Your password must contain a special character (!@#$%^&*)" }, { status: 400 }); + } else if (passwordCheckResult === "end of function") { + return NextResponse.json({ message: "Password check script failure" }, { status: 500 }); + } else { + try { + const passwordHash = await bcrypt.hash(password, 10); + if (usingPrisma) { + // todo add sending back newUser + const newUser = await prisma.user.create({ + data: { + name, + email, + passwordHash, + }, + }); + } else { + userData.push({ name, email, password: passwordHash, accessLevel }); + } + await writeUserCsv(userData); + return NextResponse.json({ message: "Account Created" }, { status: 201 }); + } catch (error) { + console.error("Error in writting :", error); + return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); + } + } + } catch (error) { + console.error("Error in signup endpoint:", error); + return NextResponse.json({ message: "Internal Server Error" }, { status: 500 }); + } +} diff --git a/src/app/contact-us/page.tsx b/src/app/contact-us/page.tsx index 42c71ef..955d99c 100644 --- a/src/app/contact-us/page.tsx +++ b/src/app/contact-us/page.tsx @@ -1,183 +1,151 @@ "use client"; +import Image from "next/image"; import React, { useState } from "react"; const ContactUs = () => { - const [formData, setFormData] = useState({ - name: "", - email: "", - message: "", - }); + const [formData, setFormData] = useState({ + name: "", + email: "", + message: "", + }); - const handleChange = (e) => { - setFormData({ ...formData, [e.target.name]: e.target.value }); - }; + const handleChange = (e: { target: { name: any; value: any } }) => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; - const handleSubmit = (e) => { - e.preventDefault(); - console.log("Form submitted with data:", formData); - // Handle form submission, like sending data to a server - alert("Thank you for reaching out! We will get back to you soon."); - setFormData({ name: "", email: "", message: "" }); // Clear form - }; + const handleSubmit = (e: { preventDefault: () => void }) => { + e.preventDefault(); + console.log("Form submitted with data:", formData); + alert("Thank you for reaching out! We will get back to you soon."); + setFormData({ name: "", email: "", message: "" }); + }; - return ( -
-
-

- Contact Us -

-

- Have questions or concerns about earthquake preparedness? Contact us - using the form below or through the provided contact details. -

- - {/* Flexbox Layout for Form and Contact Details */} -
- - {/* Contact Form */} -
-
-
- - -
+ return ( +
+ Logo -
- - -
+ {/* Overlay for readability */} +
+ {/* Container */} +
+ {/* Header */} +

Contact Us

+

+ Have questions or concerns about earthquake preparedness? Contact us using the form below or through the provided + contact details. +

-
- -