diff --git a/backend/.gitignore b/backend/.gitignore
new file mode 100644
index 0000000..7af7f04
--- /dev/null
+++ b/backend/.gitignore
@@ -0,0 +1,2 @@
+/node_modules
+.env
\ No newline at end of file
diff --git a/backend/package-lock.json b/backend/package-lock.json
new file mode 100644
index 0000000..5eed52f
--- /dev/null
+++ b/backend/package-lock.json
@@ -0,0 +1,1518 @@
+{
+ "name": "backend",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "backend",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@prisma/client": "^5.20.0",
+ "bcryptjs": "^2.4.3",
+ "cookie-parser": "^1.4.6",
+ "cors": "^2.8.5",
+ "dotenv": "^16.4.5",
+ "express": "^4.19.2",
+ "jsonwebtoken": "^9.0.2",
+ "multer": "^1.4.5-lts.1",
+ "nodemailer": "^6.9.16",
+ "prisma": "^5.20.0"
+ },
+ "devDependencies": {
+ "nodemon": "^3.1.4"
+ }
+ },
+ "node_modules/@prisma/client": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.20.0.tgz",
+ "integrity": "sha512-CLv55ZuMuUawMsxoqxGtLT3bEZoa2W8L3Qnp6rDIFWy+ZBrUcOFKdoeGPSnbBqxc3SkdxJrF+D1veN/WNynZYA==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=16.13"
+ },
+ "peerDependencies": {
+ "prisma": "*"
+ },
+ "peerDependenciesMeta": {
+ "prisma": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@prisma/debug": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.20.0.tgz",
+ "integrity": "sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/engines": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.20.0.tgz",
+ "integrity": "sha512-DtqkP+hcZvPEbj8t8dK5df2b7d3B8GNauKqaddRRqQBBlgkbdhJkxhoJTrOowlS3vaRt2iMCkU0+CSNn0KhqAQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "5.20.0",
+ "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284",
+ "@prisma/fetch-engine": "5.20.0",
+ "@prisma/get-platform": "5.20.0"
+ }
+ },
+ "node_modules/@prisma/engines-version": {
+ "version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284.tgz",
+ "integrity": "sha512-Lg8AS5lpi0auZe2Mn4gjuCg081UZf88k3cn0RCwHgR+6cyHHpttPZBElJTHf83ZGsRNAmVCZCfUGA57WB4u4JA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/fetch-engine": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.20.0.tgz",
+ "integrity": "sha512-JVcaPXC940wOGpCOwuqQRTz6I9SaBK0c1BAyC1pcz9xBi+dzFgUu3G/p9GV1FhFs9OKpfSpIhQfUJE9y00zhqw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "5.20.0",
+ "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284",
+ "@prisma/get-platform": "5.20.0"
+ }
+ },
+ "node_modules/@prisma/get-platform": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.20.0.tgz",
+ "integrity": "sha512-8/+CehTZZNzJlvuryRgc77hZCWrUDYd/PmlZ7p2yNXtmf2Una4BWnTbak3us6WVdqoz5wmptk6IhsXdG2v5fmA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "5.20.0"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/append-field": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
+ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
+ "license": "MIT"
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/bcryptjs": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+ "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
+ "license": "MIT"
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.13.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "engines": [
+ "node >= 0.8"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-parser": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
+ "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "0.7.2",
+ "cookie-signature": "1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.3",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.7.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.3.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.13.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express/node_modules/cookie": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "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==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/multer": {
+ "version": "1.4.5-lts.1",
+ "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
+ "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
+ "license": "MIT",
+ "dependencies": {
+ "append-field": "^1.0.0",
+ "busboy": "^1.0.0",
+ "concat-stream": "^1.5.2",
+ "mkdirp": "^0.5.4",
+ "object-assign": "^4.1.1",
+ "type-is": "^1.6.4",
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nodemailer": {
+ "version": "6.9.16",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
+ "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz",
+ "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nodemon/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.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==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
+ "license": "MIT"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prisma": {
+ "version": "5.20.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.20.0.tgz",
+ "integrity": "sha512-6obb3ucKgAnsGS9x9gLOe8qa51XxvJ3vLQtmyf52CTey1Qcez3A6W6ROH5HIz5Q5bW+0VpmZb8WBohieMFGpig==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/engines": "5.20.0"
+ },
+ "bin": {
+ "prisma": "build/index.js"
+ },
+ "engines": {
+ "node": ">=16.13"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.3"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true
+ },
+ "node_modules/qs": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "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/send": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.19.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "license": "MIT"
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
+ }
+ }
+}
diff --git a/backend/package.json b/backend/package.json
new file mode 100644
index 0000000..1dc90a8
--- /dev/null
+++ b/backend/package.json
@@ -0,0 +1,31 @@
+{
+ "dependencies": {
+ "@prisma/client": "^5.20.0",
+ "bcryptjs": "^2.4.3",
+ "cookie-parser": "^1.4.6",
+ "cors": "^2.8.5",
+ "dotenv": "^16.4.5",
+ "express": "^4.19.2",
+ "jsonwebtoken": "^9.0.2",
+ "multer": "^1.4.5-lts.1",
+ "nodemailer": "^6.9.16",
+ "prisma": "^5.20.0"
+ },
+ "name": "backend",
+ "version": "1.0.0",
+ "main": "src/server.js",
+ "devDependencies": {
+ "nodemon": "^3.1.4"
+ },
+ "scripts": {
+ "test2": "nodemon --inspect src/server.js",
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "dev": "nodemon src/server.js",
+ "start": "node src/server.js"
+ },
+ "type": "module",
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "description": ""
+}
diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma
new file mode 100644
index 0000000..30a90a6
--- /dev/null
+++ b/backend/prisma/schema.prisma
@@ -0,0 +1,101 @@
+// Generator to create Prisma Client
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = ["native", "darwin-arm64", "linux-musl-arm64-openssl-3.0.x"]
+}
+
+datasource db {
+ provider = "postgresql"
+ url = env("DATABASE_URL")
+ relationMode = "prisma"
+}
+
+enum Institute {
+ KJSIDS
+ SKSC
+ KJSCE
+ SIRC
+ KJSIM
+ SSA
+ KJSCEd
+ DLIS
+ MSSMPA
+}
+
+enum ApplicationStatus {
+ REJECTED
+ ACCEPTED
+ PENDING
+}
+
+enum Designation {
+ HOD
+ HOI
+ VC
+ ACCOUNTS
+ FACULTY
+ STUDENT
+}
+
+model User {
+ profileId String @id @default(uuid())
+ userName String
+ email String @unique @db.Text
+ password String
+
+ institute Institute?
+ department String?
+ designation Designation
+
+ appliedApplications Application[] @relation("AppliedApplications")
+ toValidateApplications Application[] @relation("ToValidateApplications")
+
+ @@index([email])
+}
+
+model Application {
+ applicationId String @id @default(uuid())
+ applicantId String
+ applicant User @relation("AppliedApplications", fields: [applicantId], references: [profileId])
+ institute Institute
+ department String
+
+ applicantName String
+ applicationType String
+ formData Json
+
+ formName String
+ resubmission Boolean @default(false)
+
+ facultyValidation ApplicationStatus?
+ hodValidation ApplicationStatus?
+ hoiValidation ApplicationStatus?
+ vcValidation ApplicationStatus?
+ accountsValidation ApplicationStatus?
+
+ rejectionFeedback String?
+
+ totalExpense Float @default(0)
+
+ proofOfTravel Bytes?
+ proofOfAccommodation Bytes?
+ proofOfAttendance Bytes?
+ expenseProof0 Bytes?
+ expenseProof1 Bytes?
+ expenseProof2 Bytes?
+ expenseProof3 Bytes?
+ expenseProof4 Bytes?
+ expenseProof5 Bytes?
+ expenseProof6 Bytes?
+ expenseProof7 Bytes?
+ expenseProof8 Bytes?
+ expenseProof9 Bytes?
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ validators User[] @relation("ToValidateApplications")
+
+ @@index([applicantId])
+ @@index([createdAt])
+}
diff --git a/backend/prisma/seed.js b/backend/prisma/seed.js
new file mode 100644
index 0000000..1dfc3fc
--- /dev/null
+++ b/backend/prisma/seed.js
@@ -0,0 +1,123 @@
+import prisma from "../src/config/prismaConfig.js";
+
+async function main() {
+ // Common password for all users
+ const commonPassword = "securePassword123";
+
+ // Applicant and Validator data
+ const institutes = [
+ "KJSIDS",
+ "SKSC",
+ "KJSCE",
+ "SIRC",
+ "KJSIM",
+ "SSA",
+ "KJSCEd",
+ "DLIS",
+ "MSSMPA",
+ ];
+ const departments = [
+ "Mechanical",
+ "Electronics",
+ "CBE",
+ "Electronics & Telecommunication",
+ "Computer",
+ "Information Technology",
+ "Science & Humanities",
+ "Admin",
+ "Library",
+ ];
+
+ // Create VC (single, no department or institute)
+ console.log("Seeding VC...");
+ await prisma.user.create({
+ data: {
+ userName: "Validator_VC",
+ email: "vc@example.com",
+ password: commonPassword,
+ designation: "VC",
+ },
+ });
+
+ for (const institute of institutes) {
+ // Create HOI for each institute
+ console.log(`Seeding HOI for ${institute}...`);
+ const hoiEmail = `hoi.${institute.toLowerCase()}@example.com`;
+
+ await prisma.user.create({
+ data: {
+ userName: `HOI_${institute}`,
+ email: hoiEmail,
+ password: commonPassword,
+ institute,
+ designation: "HOI",
+ },
+ });
+
+ // Create Accounts for each institute
+ console.log(`Seeding Accounts for ${institute}...`);
+ await prisma.user.create({
+ data: {
+ userName: `Validator_Accounts_${institute}`,
+ email: `accounts.${institute.toLowerCase()}@example.com`,
+ password: commonPassword,
+ institute,
+ designation: "ACCOUNTS",
+ },
+ });
+
+ for (const department of departments) {
+ // Create HOD for each department of each institute
+ console.log(`Seeding HOD for ${department} in ${institute}...`);
+ const hodEmail = `hod.${department.toLowerCase()}.${institute.toLowerCase()}@example.com`;
+
+ await prisma.user.create({
+ data: {
+ userName: `HOD_${department}_${institute}`,
+ email: hodEmail,
+ password: commonPassword,
+ institute,
+ department,
+ designation: "HOD",
+ },
+ });
+
+ // Create Faculty for each department of each institute
+ console.log(`Seeding Faculty for ${department} in ${institute}...`);
+ const facultyEmail = `faculty.${department.toLowerCase()}.${institute.toLowerCase()}@example.com`;
+
+ await prisma.user.create({
+ data: {
+ userName: `Faculty_${department}_${institute}`,
+ email: facultyEmail,
+ password: commonPassword,
+ institute,
+ department,
+ designation: "FACULTY",
+ },
+ });
+ // Create Student for each department of each institute
+ console.log(`Seeding Student for ${department} in ${institute}...`);
+ const studentEmail = `student.${department.toLowerCase()}.${institute.toLowerCase()}@example.com`;
+
+ await prisma.user.create({
+ data: {
+ userName: `Student_${department}_${institute}`,
+ email: studentEmail,
+ password: commonPassword,
+ institute,
+ department,
+ designation: "STUDENT",
+ },
+ });
+ }
+ console.log("Seeding completed!");
+ }
+}
+
+main().catch((e) => {
+ console.error(e);
+ process.exit(1);
+}).finally(async () => {
+ await prisma.$disconnect();
+});
\ No newline at end of file
diff --git a/backend/src/app.js b/backend/src/app.js
new file mode 100644
index 0000000..f2766ed
--- /dev/null
+++ b/backend/src/app.js
@@ -0,0 +1,29 @@
+import express from 'express';
+import cors from 'cors';
+import cookieParser from 'cookie-parser';
+import router from './routes/auth.js';
+import applicantRoute from './routes/applicant.js';
+import validatorRoute from './routes/validator.js';
+import generalRoute from './routes/general.js';
+import { verifyApplicantToken, verifyToken, verifyValidatorToken } from './middleware/verifyJwt.js';
+
+const app = express();
+
+// Middleware setup
+app.use(cookieParser());
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
+app.use(cors({
+ origin: true,
+ credentials: true
+}));
+
+// Route-specific middleware and routes
+app.use('/applicant', verifyApplicantToken, applicantRoute);
+app.use('/validator', verifyValidatorToken, validatorRoute);
+app.use('/general', verifyToken, generalRoute);
+
+// Authentication routes
+app.use(router);
+
+export default app;
\ No newline at end of file
diff --git a/backend/src/config/designations.js b/backend/src/config/designations.js
new file mode 100644
index 0000000..2be50b0
--- /dev/null
+++ b/backend/src/config/designations.js
@@ -0,0 +1,16 @@
+const applicantDesignations = [
+ 'STUDENT',
+ 'FACULTY',
+ 'HOD',
+ 'HOI',
+];
+
+const validatorDesignations = [
+ 'FACULTY',
+ 'HOD',
+ 'HOI',
+ 'VC',
+ 'ACCOUNTS',
+];
+
+export {applicantDesignations, validatorDesignations}
\ No newline at end of file
diff --git a/backend/src/config/prismaConfig.js b/backend/src/config/prismaConfig.js
new file mode 100644
index 0000000..191e9f0
--- /dev/null
+++ b/backend/src/config/prismaConfig.js
@@ -0,0 +1,5 @@
+import { PrismaClient } from '@prisma/client'
+
+const prisma = new PrismaClient()
+
+export default prisma;
\ No newline at end of file
diff --git a/backend/src/controllers/applicantControllers.js b/backend/src/controllers/applicantControllers.js
new file mode 100644
index 0000000..253964e
--- /dev/null
+++ b/backend/src/controllers/applicantControllers.js
@@ -0,0 +1,434 @@
+import { application } from "express";
+import prisma from "../config/prismaConfig.js";
+import sendMail from "../services/sendMail.js";
+
+const createApplication = async (req, res) => {
+ const {
+ id: applicantId,
+ email,
+ designation: applicantDesignation,
+ department,
+ institute,
+ role,
+ } = req.user;
+
+ const formData = req.body;
+
+ try {
+ if (role !== "applicant") {
+ return res
+ .status(403)
+ .send({ message: "Forbidden, Sign In as Applicant" });
+ }
+
+ const applicant = await prisma.user.findUnique({
+ where: { profileId: applicantId },
+ });
+
+ if (!applicant) {
+ return res.status(404).send({ message: "User not Found" });
+ }
+
+ // check for the formName
+ // if form name is "Travel Intimation Form", then do nothing
+ // if form name is "Post Travel Form" then get the "intimationApplicationID" from the form and check if an application with that id exists if not then return an error
+ // then check if that form dosent have any validation pending or rejected
+ // if it has then return an error
+ // if not then create the application
+
+ const formName = formData.formName;
+ if (!formName){
+ return res.status(400).send({ message: "Form Name is required" });
+ }
+
+ if (formName === "Post Travel Form") {
+ const intimationApplicationID = formData.intimationApplicationID;
+ if (intimationApplicationID === null) {
+ return res.status(400).send({ message: "Intimation Application ID is required" });
+ }
+
+ const intimationApplication = await prisma.application.findUnique({
+ where: {
+ applicationId: intimationApplicationID,
+ applicantId: applicantId,
+ },
+ });
+
+ if (!intimationApplication) {
+ return res.status(404).send({ message: "Intimation Application not found" });
+ }
+
+ if ( intimationApplication["formName"] !== "Travel Intimation Form") {
+ return res.status(400).send({ message: "Intimation Application ID is not of a Travel Intimation Form" });
+ }
+
+ const validationFields = [
+ "facultyValidation",
+ "hodValidation",
+ "hoiValidation",
+ "vcValidation",
+ "accountsValidation",
+ ];
+
+ const hasRejectedValidations = validationFields.some(
+ (field) => intimationApplication[field] === "REJECTED"
+ );
+
+ if (hasRejectedValidations) {
+ return res
+ .status(400)
+ .send({ message: "Intimation Application has rejected validations" });
+ }
+
+ const hasPendingValidations = validationFields.some(
+ (field) => intimationApplication[field] === "PENDING"
+ );
+
+ if (hasPendingValidations) {
+ return res
+ .status(400)
+ .send({ message: "Intimation Application has pending validations" });
+ }
+
+ }
+
+ const applicantName = applicant.userName;
+
+ let primarySupervisor,
+ anotherSupervisor,
+ hod,
+ hoi,
+ vc = null;
+
+ switch (applicant.designation) {
+ case "STUDENT":
+ primarySupervisor = await prisma.user.findUnique({
+ where: {
+ email: formData.primarySupervisorEmail,
+ department,
+ designation: "FACULTY",
+ institute,
+ },
+ });
+ if (!primarySupervisor) {
+ return res.status(404).send({ message: "Faculty not found (Incorrect Primary Supervisor Email)" });
+ }
+ anotherSupervisor = await prisma.user.findUnique({
+ where: {
+ email: formData.anotherSupervisorEmail,
+ department: formData.anotherSupervisorDepartment,
+ designation: "FACULTY",
+ institute,
+ },
+ });
+ if (!anotherSupervisor && formData.anotherSupervisorEmail) {
+ return res.status(404).send({ message: "Another Supervisor not found" });
+ }
+ break;
+
+ case "FACULTY":
+ hod = await prisma.user.findFirst({
+ where: { department, designation: "HOD", institute },
+ });
+ if (!hod) {
+ return res.status(404).send({ message: "HOD not found" });
+ }
+ break;
+
+ case "HOD":
+ hoi = await prisma.user.findFirst({
+ where: { designation: "HOI", institute },
+ });
+ if (!hoi) {
+ return res.status(404).send({ message: "HOI not found" });
+ }
+ break;
+
+ case "HOI":
+ vc = await prisma.user.findFirst({
+ where: { designation: "VC" },
+ });
+ if (!vc) {
+ return res.status(404).send({ message: "VC not found" });
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Security check: Make sure the proper relationships exist between the applicant and application data
+ if (applicant.designation === "STUDENT") {
+ // Validate that primary supervisor email is provided for student applications
+ if (!formData.primarySupervisorEmail) {
+ return res.status(400).send({ message: "Primary supervisor email is required for student applications" });
+ }
+ }
+
+ // Compile the validators list with available supervisors, FDC coordinator, HOD, and HOI
+ const validators = [
+ primarySupervisor && { profileId: primarySupervisor?.profileId },
+ anotherSupervisor && { profileId: anotherSupervisor?.profileId },
+ hod && { profileId: hod?.profileId },
+ hoi && { profileId: hoi?.profileId },
+ vc && { profileId: vc?.profileId },
+ ].filter(Boolean);
+
+ const {
+ proofOfTravel,
+ proofOfAccommodation,
+ proofOfAttendance,
+ ...otherFiles
+ } = req.files;
+
+ // Prepare file buffers for fixed fields
+ const proofOfTravelBuffer = proofOfTravel?.[0]?.buffer || null;
+ const proofOfAccommodationBuffer =
+ proofOfAccommodation?.[0]?.buffer || null;
+ const proofOfAttendanceBuffer = proofOfAttendance?.[0]?.buffer || null;
+
+ // Prepare an object to hold the expense proof buffers dynamically
+ const expenseProofs = {};
+
+ for (let i = 0; i < 10; i++) {
+ const expenseProofField = `expenses[${i}].expenseProof`;
+ if (otherFiles[expenseProofField]) {
+ expenseProofs[`expenseProof${i}`] =
+ otherFiles[expenseProofField][0].buffer;
+ }
+ }
+
+ const expenses = JSON.parse(formData.expenses);
+
+ const totalExpense = parseFloat(
+ expenses.reduce(
+ (total, { expenseAmount }) => total + +expenseAmount,
+ 0
+ ).toFixed(2)
+ );
+
+ formData["totalExpense"] = totalExpense;
+
+ // Construct the application data object
+ const applicationData = {
+ applicantName,
+ department,
+ institute,
+ totalExpense,
+ formData,
+ proofOfTravel: proofOfTravelBuffer,
+ proofOfAccommodation: proofOfAccommodationBuffer,
+ proofOfAttendance: proofOfAttendanceBuffer,
+ ...expenseProofs, // Add dynamically generated expense proof fields
+ facultyValidation: ["STUDENT"].includes(applicant.designation)
+ ? "PENDING"
+ : undefined,
+ hodValidation: ["FACULTY"].includes(applicant.designation)
+ ? "PENDING"
+ : undefined,
+ hoiValidation: ["HOD"].includes(applicant.designation)
+ ? "PENDING"
+ : undefined,
+ vcValidation: ["HOI"].includes(applicant.designation)
+ ? "PENDING"
+ : undefined,
+ };
+
+ // Create new application entry with linked applicant and validators
+ const newApplication = await prisma.application.create({
+ data: {
+ ...applicationData,
+ applicationType: applicant.designation === "STUDENT" ? "STUDENT" : "FACULTY",
+ applicant: {
+ connect: { profileId: applicantId },
+ },
+ validators: {
+ connect: validators,
+ },
+ formName: formData.formName,
+ },
+ });
+
+ // Store this original state to compare on future modifications
+ // We don't need to actually create a new record, the application itself
+ // will serve this purpose
+
+ // sendMail({
+ // emailId: hod.email,
+ // link: `http://localhost:5173/validator/dashboard/pending/${newApplication.applicationId}`,
+ // type: "validator",
+ // status: null,
+ // designation: null,
+ // });
+
+ res.status(201).send({
+ message: "Application created successfully",
+ data: newApplication.applicantName,
+ });
+ } catch (error) {
+ console.error("Error creating application:", error);
+ res.status(500).send({
+ message: "Error creating application",
+ error: error.message,
+ });
+ }
+};
+
+const updateApplication = async (req, res) => {
+ const {
+ id: applicantId,
+ email,
+ designation: applicantDesignation,
+ department,
+ institute,
+ role,
+ } = req.user;
+
+ const formData = req.body;
+ const applicationId = formData.applicationId;
+ delete formData.applicationId;
+
+ try {
+ if (role !== "applicant") {
+ return res
+ .status(403)
+ .send({ message: "Forbidden, Sign In as Applicant" });
+ }
+
+ const applicant = await prisma.user.findUnique({
+ where: { profileId: applicantId },
+ });
+
+ if (!applicant) {
+ return res.status(404).send({ message: "User not Found" });
+ }
+
+ // Fetch the original application to compare fields
+ const originalApplication = await prisma.application.findUnique({
+ where: { applicationId },
+ });
+
+ if (!originalApplication) {
+ return res.status(404).send({ message: "Application not found" });
+ }
+
+ const originalFormData = originalApplication.formData;
+
+ // Verify that disabled fields haven't been changed
+ // Only expenses can be edited, everything else should remain the same regardless of resubmission status
+
+ // Create a clone of the original form data for comparison
+ const safeOriginalData = JSON.parse(JSON.stringify(originalFormData));
+
+ // Create a safe copy of submitted form data for validation
+ const safeSubmittedData = { ...formData };
+
+ // Exclude expenses-related fields from comparison as they're allowed to change
+ delete safeOriginalData.expenses;
+ delete safeSubmittedData.expenses;
+ delete safeSubmittedData.resubmission;
+ delete safeOriginalData.totalExpense;
+ delete safeSubmittedData.totalExpense;
+
+ delete safeOriginalData?.proofOfTravel;
+ delete safeOriginalData?.proofOfAccommodation;
+ delete safeSubmittedData?.proofOfAttendance;
+
+ // We need to check if any non-expenses fields have been modified
+ for (const key in safeSubmittedData) {
+ // Don't check expense fields pattern (expenses[0].expenseProof, etc.)
+ if (key.startsWith('expenses[') || key === 'proofOfTravel' || key === 'proofOfAccommodation' || key === 'proofOfAttendance') {
+ continue;
+ }
+
+ // Check if the field has been modified
+ if (safeSubmittedData[key] !== safeOriginalData[key]) {
+ console.log(`Tampering detected: Field '${key}' was modified`);
+ console.log(`Original: ${safeOriginalData[key]}`);
+ console.log(`Submitted: ${safeSubmittedData[key]}`);
+
+ return res.status(403).send({
+ message: `Forbidden: Field '${key}' cannot be modified. Only expense information can be changed. Tampering detected.`,
+ });
+ }
+ }
+
+ const {
+ proofOfTravel,
+ proofOfAccommodation,
+ proofOfAttendance,
+ ...otherFiles
+ } = req.files;
+
+ // Prepare file buffers for fixed fields
+ const proofOfTravelBuffer = proofOfTravel?.[0]?.buffer || null;
+ const proofOfAccommodationBuffer =
+ proofOfAccommodation?.[0]?.buffer || null;
+ const proofOfAttendanceBuffer = proofOfAttendance?.[0]?.buffer || null;
+
+ // Prepare an object to hold the expense proof buffers dynamically
+ const expenseProofs = {};
+
+ for (let i = 0; i < 10; i++) {
+ const expenseProofField = `expenses[${i}].expenseProof`;
+ if (otherFiles[expenseProofField]) {
+ expenseProofs[`expenseProof${i}`] =
+ otherFiles[expenseProofField][0].buffer;
+ }
+ }
+
+ const expenses = JSON.parse(formData.expenses);
+
+ const totalExpense = parseFloat(
+ expenses.reduce(
+ (total, { expenseAmount }) => total + +expenseAmount,
+ 0
+ ).toFixed(2)
+ );
+
+ formData["totalExpense"] = totalExpense;
+
+ const validationFields = [
+ "facultyValidation",
+ "hodValidation",
+ "hoiValidation",
+ "vcValidation",
+ "accountsValidation",
+ ];
+
+ console.log(expenseProofs)
+
+ const updatedData = {
+ totalExpense,
+ formData,
+ proofOfTravel: proofOfTravelBuffer,
+ proofOfAccommodation: proofOfAccommodationBuffer,
+ proofOfAttendance: proofOfAttendanceBuffer,
+ resubmission: false,
+ ...expenseProofs,
+ };
+
+ for (const field of validationFields) {
+ if (originalApplication[field] === "REJECTED") {
+ updatedData[field] = "PENDING";
+ }
+ }
+
+ const updatedApplication = await prisma.application.update({
+ where: { applicationId },
+ data: updatedData,
+ });
+
+ res.status(200).send({
+ message: "Application updated successfully",
+ data: updatedApplication.applicantName,
+ });
+ } catch (error) {
+ res.status(500).send({
+ message: "Error updating application",
+ error: error.message,
+ });
+ }
+}
+
+export { createApplication, updateApplication };
diff --git a/backend/src/controllers/authControllers.js b/backend/src/controllers/authControllers.js
new file mode 100644
index 0000000..d0e3e58
--- /dev/null
+++ b/backend/src/controllers/authControllers.js
@@ -0,0 +1,130 @@
+import prisma from "../config/prismaConfig.js";
+import generateToken from "../services/generateToken.js";
+
+const applicantLogin = async (req, res) => {
+ try {
+ const { email, password } = req.body;
+
+ // Check if the applicant profile exists
+ const validProfile = await prisma.user.findUnique({
+ where: {
+ email
+ },
+ });
+
+ if (!validProfile) {
+ return res.status(404).json({
+ message: "Applicant User Doesn't exist",
+ data: null,
+ });
+ }
+
+ // Check if the password is correct
+ if (validProfile.password !== password) {
+ return res.status(404).json({
+ message: "Wrong Password",
+ data: null,
+ });
+ }
+
+ // Create token object
+ const tokenObject = {
+ id: validProfile.profileId,
+ designation: validProfile.designation,
+ department: validProfile.department,
+ institute: validProfile.institute,
+ role: "applicant",
+ };
+
+ // Generate the token
+ const token = generateToken(tokenObject);
+
+ // Set the token as a cookie
+ return res
+ .cookie("access_token", token, { sameSite: 'None', secure: true, httpOnly: true })
+ .status(200)
+ .json({
+ message: "Login Successful",
+ data: { username: validProfile.userName, token },
+ });
+ } catch (error) {
+ return res.status(500).json({
+ message: "Internal Server Error",
+ data: error.message,
+ });
+ }
+};
+
+const validatorLogin = async (req, res) => {
+ try {
+ const { email, password } = req.body;
+
+ // Check if the validator profile exists
+ let validProfile = await prisma.user.findUnique({
+ where: {
+ email
+ },
+ });
+
+ if (!validProfile) {
+ return res.status(404).json({
+ message: "Validator User Doesn't exist",
+ data: null,
+ });
+ }
+
+ // Check if the password is correct
+ if (validProfile.password !== password) {
+ return res.status(404).json({
+ message: "Wrong Password",
+ data: null,
+ });
+ }
+
+ // Create token object
+ const tokenObject = {
+ id: validProfile.profileId,
+ designation: validProfile.designation,
+ department: validProfile.department,
+ institute: validProfile.institute,
+ role: "validator",
+ };
+
+ // Generate the token
+ const token = generateToken(tokenObject);
+
+ // Set the token as a cookie
+ return res
+ .cookie("access_token", token, { sameSite: 'None', secure: true, httpOnly: true })
+ .status(200)
+ .json({
+ message: "Login Successful",
+ data: { username: validProfile.userName, token },
+ });
+ } catch (error) {
+ return res.status(500).json({
+ message: "Internal Server Error",
+ data: error.message,
+ });
+ }
+};
+
+const logout = async (req, res) => {
+ try {
+ // Clear the access token cookie
+ res.clearCookie("access_token", { httpOnly: true });
+
+ // Respond with success message
+ return res.status(200).json({
+ message: "Logout Successful",
+ data: null,
+ });
+ } catch (error) {
+ return res.status(500).json({
+ message: "Internal Server Error",
+ data: error.message,
+ });
+ }
+};
+
+export { applicantLogin, validatorLogin, logout };
diff --git a/backend/src/controllers/formatter.js b/backend/src/controllers/formatter.js
new file mode 100644
index 0000000..29446b9
--- /dev/null
+++ b/backend/src/controllers/formatter.js
@@ -0,0 +1,115 @@
+const u = {
+ expenses:
+ '[{"expenseCategory":"TRAVEL","expenseName":"Rustic Granite Ball","expenseAmount":3696,"expenseProof":{}}]',
+ cadreSize: "",
+ eventName: "Rustic Metal Chair",
+ eventVenue: "",
+ applicantAge: "",
+ eventEndDate: "",
+ eventWebsite: "",
+ modeOfTravel: "",
+ totalExpense: 3696,
+ typeOfTravel: "",
+ applicantIDNo: "",
+ proofOfTravel: "",
+ travelEndDate: "",
+ applicantEmail: "",
+ durationOfStay: "",
+ eventStartDate: "",
+ applicationType: "Individual",
+ cadreMember1Age: "",
+ cadreMember2Age: "",
+ cadreMember3Age: "",
+ cadreMember4Age: "",
+ cadreMember5Age: "",
+ cadreMember6Age: "",
+ cadreMember7Age: "",
+ cadreMember8Age: "",
+ cadreMember9Age: "",
+ purposeOfTravel: "",
+ travelStartDate: "",
+ applicantAddress: "3491 Margarette Plains",
+ applicantContact: "249-639-5239",
+ cadreMember10Age: "",
+ cadreMember1IDNo: "",
+ cadreMember2IDNo: "",
+ cadreMember3IDNo: "",
+ cadreMember4IDNo: "",
+ cadreMember5IDNo: "",
+ cadreMember6IDNo: "",
+ cadreMember7IDNo: "",
+ cadreMember8IDNo: "",
+ cadreMember9IDNo: "",
+ applicantFullName: "Rick Bahringer",
+ cadreMember10IDNo: "",
+ cadreMember1Email: "",
+ cadreMember2Email: "",
+ cadreMember3Email: "",
+ cadreMember4Email: "",
+ cadreMember5Email: "",
+ cadreMember6Email: "",
+ cadreMember7Email: "",
+ cadreMember8Email: "",
+ cadreMember9Email: "",
+ modeOfTravelOther: "",
+ proofOfAttendance: "",
+ accommodationOpted: "false",
+ applicantInstitute: "KJSCE",
+ cadreMember10Email: "",
+ applicantDepartment: "Computer",
+ cadreMember1Address: "",
+ cadreMember1Contact: "",
+ cadreMember2Address: "",
+ cadreMember2Contact: "",
+ cadreMember3Address: "",
+ cadreMember3Contact: "",
+ cadreMember4Address: "",
+ cadreMember4Contact: "",
+ cadreMember5Address: "",
+ cadreMember5Contact: "",
+ cadreMember6Address: "",
+ cadreMember6Contact: "",
+ cadreMember7Address: "",
+ cadreMember7Contact: "",
+ cadreMember8Address: "",
+ cadreMember8Contact: "",
+ cadreMember9Address: "",
+ cadreMember9Contact: "",
+ typeOfAccommodation: "",
+ accommodationAddress: "",
+ anyOtherRequirements: "",
+ cadreMember10Address: "",
+ cadreMember10Contact: "",
+ cadreMember1FullName: "",
+ cadreMember2FullName: "",
+ cadreMember3FullName: "",
+ cadreMember4FullName: "",
+ cadreMember5FullName: "",
+ cadreMember6FullName: "",
+ cadreMember7FullName: "",
+ cadreMember8FullName: "",
+ cadreMember9FullName: "",
+ proofOfAccommodation: "",
+ purposeOfTravelOther: "",
+ cadreMember10FullName: "",
+ cadreMember1Institute: "",
+ cadreMember2Institute: "",
+ cadreMember3Institute: "",
+ cadreMember4Institute: "",
+ cadreMember5Institute: "",
+ cadreMember6Institute: "",
+ cadreMember7Institute: "",
+ cadreMember8Institute: "",
+ cadreMember9Institute: "",
+ cadreMember10Institute: "",
+ cadreMember1Department: "",
+ cadreMember2Department: "",
+ cadreMember3Department: "",
+ cadreMember4Department: "",
+ cadreMember5Department: "",
+ cadreMember6Department: "",
+ cadreMember7Department: "",
+ cadreMember8Department: "",
+ cadreMember9Department: "",
+ cadreMember10Department: "",
+};
diff --git a/backend/src/controllers/generalControllers.js b/backend/src/controllers/generalControllers.js
new file mode 100644
index 0000000..64b7a84
--- /dev/null
+++ b/backend/src/controllers/generalControllers.js
@@ -0,0 +1,439 @@
+import { application } from "express";
+import prisma from "../config/prismaConfig.js";
+import {
+ applicantDesignations,
+ validatorDesignations,
+} from "../config/designations.js";
+
+const dataRoot = async (req, res) => {
+ try {
+ const user = req.user; // Contains all user info (id, designation, department, etc.)
+ const { id: profileId, email, designation, department, role } = user;
+
+ if (applicantDesignations.includes(designation) && role === "applicant") {
+ const applicant = await prisma.user.findUnique({
+ where: { profileId },
+ });
+
+ if (!applicant) {
+ return res
+ .status(404)
+ .json({ message: "Applicant not found", data: null });
+ }
+
+ delete applicant.password;
+
+ return res.status(200).json({
+ message: "Applicant Authorized",
+ user: applicant,
+ role: "Applicant",
+ });
+ } else if (
+ validatorDesignations.includes(designation) &&
+ role === "validator"
+ ) {
+ const validator = await prisma.user.findUnique({
+ where: { profileId },
+ });
+
+ if (!validator) {
+ return res
+ .status(404)
+ .json({ message: "Validator not found", data: null });
+ }
+
+ delete validator.password;
+
+ return res.status(200).json({
+ message: "Validator Authorized",
+ user: validator,
+ role: "Validator",
+ });
+ } else {
+ return res
+ .status(403)
+ .json({ message: "Unauthorized access", data: null });
+ }
+ } catch (error) {
+ // Handle any errors that occur during the process
+ console.error(error);
+ return res
+ .status(500)
+ .json({ message: "Internal Server Error", data: null });
+ }
+};
+
+const getApplicationsByStatus = async (req, res) => {
+ try {
+ const user = req.user;
+ const userId = user.id;
+ const take = parseInt(req.query.take) || 5;
+ const skip = parseInt(req.query.skip) || 0;
+ const status = req.params.status.toUpperCase(); // Expected: "PENDING", "ACCEPTED", or "REJECTED"
+ const sortBy = req.query?.sortBy;
+ const sortValue = req.query?.sortValue;
+
+ const validStatuses = ["PENDING", "ACCEPTED", "REJECTED"];
+ if (!validStatuses.includes(status)) {
+ return res.status(400).send("Invalid status");
+ }
+
+ let applications, totalApplications;
+
+ // Filter conditions for Student and Faculty
+ if (
+ applicantDesignations.includes(user.designation) &&
+ user.role === "applicant"
+ ) {
+ const baseWhere = {
+ applicantId: userId,
+ ...(status === "PENDING" && {
+ OR: [
+ { facultyValidation: "PENDING" },
+ { hodValidation: "PENDING" },
+ { hoiValidation: "PENDING" },
+ { vcValidation: "PENDING" },
+ { accountsValidation: "PENDING" },
+ ],
+ }),
+ ...(status === "ACCEPTED" && {
+ AND: [
+ { OR: [{ facultyValidation: "ACCEPTED" }, { facultyValidation: null }] },
+ { OR: [{ hodValidation: "ACCEPTED" }, { hodValidation: null }] },
+ { OR: [{ hoiValidation: "ACCEPTED" }, { hoiValidation: null }] },
+ { OR: [{ vcValidation: "ACCEPTED" }, { vcValidation: null }] },
+ {
+ OR: [
+ { accountsValidation: "ACCEPTED" },
+ { accountsValidation: null },
+ ],
+ },
+ ],
+ }),
+ ...(status === "REJECTED" && {
+ OR: [
+ { facultyValidation: "REJECTED" },
+ { hodValidation: "REJECTED" },
+ { hoiValidation: "REJECTED" },
+ { vcValidation: "REJECTED" },
+ { accountsValidation: "REJECTED" },
+ ],
+ }),
+ };
+
+ // Apply case-insensitive filter for search functionality
+ if (sortBy && sortValue) {
+ baseWhere[sortBy] = {
+ contains: sortValue,
+ mode: "insensitive",
+ };
+ }
+
+ // Count and fetch applications
+ totalApplications = await prisma.application.count({ where: baseWhere });
+ applications = await prisma.application.findMany({
+ where: baseWhere,
+ select: {
+ applicationId: true,
+ applicantName: true,
+ formData: true,
+ createdAt: true,
+ },
+ take,
+ skip,
+ orderBy: { createdAt: "desc" },
+ });
+
+ // Filter conditions for Validators (Supervisor, HOD, HOI, FDCcoordinator)
+ } else if (
+ validatorDesignations.includes(user.designation) &&
+ user.role === "validator"
+ ) {
+ const validationField = `${user.designation.toLowerCase()}Validation`;
+
+ const baseWhere = {
+ validators: { some: { profileId: userId } },
+ [validationField]: status,
+ };
+
+ if (sortBy && sortValue) {
+ baseWhere[sortBy] = {
+ contains: sortValue,
+ mode: "insensitive",
+ };
+ }
+
+ totalApplications = await prisma.application.count({
+ where: baseWhere,
+ });
+
+ applications = await prisma.application.findMany({
+ where: baseWhere,
+ select: {
+ applicationId: true,
+ applicantName: true,
+ formData: true,
+ createdAt: true,
+ },
+ take,
+ skip,
+ orderBy: { createdAt: "desc" },
+ });
+ } else {
+ // Unauthorized access for other user roles
+ return res.status(403).send("Unauthorized");
+ }
+
+ // Format response with selected fields
+ const responseApplications = applications.map((application) => ({
+ applicationId: application.applicationId,
+ applicantName: application.applicantName,
+ formData: {
+ eventName: application.formData.eventName,
+ applicantDepartment: application.formData.applicantDepartment,
+ },
+ createdAt: application.createdAt,
+ }));
+
+ return res.status(200).json({
+ message: `${status} Applications Fetched Successfully`,
+ totalApplications,
+ applications: responseApplications,
+ });
+ } catch (error) {
+ console.error(error);
+ res.status(500).send(error.message);
+ }
+};
+
+const getApplicationData = async (req, res) => {
+ try {
+ const applicationId = req.params.applicationId;
+ const user = req.user;
+
+ // Fetch application data excluding proof fields
+ const applicationFull = await prisma.application.findUnique({
+ where: {
+ applicationId: applicationId,
+ },
+ select: {
+ applicationId: true,
+ applicantId: true,
+ applicantName: true,
+ resubmission: true,
+ formData: true,
+ facultyValidation: true,
+ hodValidation: true,
+ hoiValidation: true,
+ vcValidation: true,
+ accountsValidation: true,
+ rejectionFeedback: true,
+ createdAt: true,
+ applicant: {
+ select: {
+ designation: true,
+ },
+ },
+ validators: {
+ select: {
+ profileId: true,
+ },
+ },
+ },
+ });
+
+ if (
+ applicationFull?.applicantId !== user.id &&
+ !applicationFull.validators.some(
+ (validator) => validator.profileId === user.id
+ )
+ ) {
+ return res.status(403).json({
+ message: "Unauthorized",
+ data: null,
+ });
+ }
+
+ if (!applicationFull) {
+ return res.status(404).json({
+ message: "Application not found",
+ data: null,
+ });
+ }
+
+ let currentStatus;
+
+ // Check if the user is an applicant or a validator
+ if (
+ applicantDesignations.includes(user.designation) &&
+ user.role === "applicant"
+ ) {
+ if (
+ applicationFull.facultyValidation === "PENDING" ||
+ applicationFull.hodValidation === "PENDING" ||
+ applicationFull.hoiValidation === "PENDING" ||
+ applicationFull.vcValidation === "PENDING" ||
+ applicationFull.accountsValidation === "PENDING"
+ ) {
+ currentStatus = "PENDING";
+ } else if (
+ applicationFull.facultyValidation === "REJECTED" ||
+ applicationFull.supervisorValidation === "REJECTED" ||
+ applicationFull.hodValidation === "REJECTED" ||
+ applicationFull.hoiValidation === "REJECTED" ||
+ applicationFull.fdccoordinatorValidation === "REJECTED"
+ ) {
+ currentStatus = "REJECTED";
+ } else {
+ currentStatus = "ACCEPTED";
+ }
+ } else if (
+ validatorDesignations.includes(user.designation) &&
+ user.role === "validator"
+ ) {
+ const validationField = `${user.designation.toLowerCase()}Validation`;
+
+ if (applicationFull[validationField] === "ACCEPTED") {
+ currentStatus = "ACCEPTED";
+ } else if (applicationFull[validationField] === "REJECTED") {
+ currentStatus = "REJECTED";
+ } else {
+ currentStatus = "PENDING";
+ }
+ } else {
+ return res.status(403).json({
+ message: "Unauthorized",
+ data: null,
+ });
+ }
+
+ // Respond with the full application data and current status
+ return res.status(200).json({
+ message: "Application data retrieved successfully",
+ data: { ...applicationFull, currentStatus },
+ });
+ } catch (error) {
+ console.error("Error retrieving application data:", error);
+ return res.status(500).json({
+ message: "An error occurred while retrieving the application data",
+ data: null,
+ });
+ }
+};
+
+const getFile = async (req, res) => {
+ try {
+ const { applicationId, fileName } = req.params;
+ const user = req.user;
+ const userId = user.id;
+
+ const validFileNames = [
+ "proofOfTravel",
+ "proofOfAccommodation",
+ "proofOfAttendance",
+ "expenseProof0",
+ "expenseProof1",
+ "expenseProof2",
+ "expenseProof3",
+ "expenseProof4",
+ "expenseProof5",
+ "expenseProof6",
+ "expenseProof7",
+ "expenseProof8",
+ "expenseProof9",
+ ];
+
+ if (!validFileNames.includes(fileName)) {
+ return res.status(400).json({ error: "Invalid File request" });
+ }
+
+ const fileSelection = {
+ proofOfTravel: false,
+ proofOfAccommodation: false,
+ proofOfAttendance: false,
+ expenseProof0: false,
+ expenseProof1: false,
+ expenseProof2: false,
+ expenseProof3: false,
+ expenseProof4: false,
+ expenseProof5: false,
+ expenseProof6: false,
+ expenseProof7: false,
+ expenseProof8: false,
+ expenseProof9: false,
+ };
+
+ if (validFileNames.includes(fileName)) {
+ fileSelection[fileName] = true;
+ }
+
+ let myApplication, myFile;
+
+ if (
+ applicantDesignations.includes(user.designation) &&
+ user.role === "applicant"
+ ) {
+ myApplication = await prisma.user.findUnique({
+ where: {
+ profileId: userId,
+ },
+ select: {
+ appliedApplications: {
+ where: {
+ applicationId,
+ },
+ select: fileSelection,
+ },
+ },
+ });
+ myFile = myApplication?.appliedApplications[0];
+ } else if (
+ validatorDesignations.includes(user.designation) &&
+ user.role === "validator"
+ ) {
+ myApplication = await prisma.user.findUnique({
+ where: {
+ profileId: userId,
+ },
+ select: {
+ toValidateApplications: {
+ where: {
+ applicationId,
+ },
+ select: fileSelection,
+ },
+ },
+ });
+ myFile = myApplication?.toValidateApplications[0];
+ }
+
+ if (!myFile) {
+ return res.status(404).json({ error: "File not found" });
+ }
+
+ // Retrieve the file buffer dynamically based on the fileName
+ const fileBuffer = myFile[fileName];
+
+ // If file buffer doesn't exist
+ if (!fileBuffer) {
+ return res.status(404).json({ error: "File content not found" });
+ }
+
+ // Set response headers for PDF file download
+ res.setHeader("Content-Type", "application/pdf");
+ res.setHeader(
+ "Content-Disposition",
+ `attachment; filename="${fileName}.pdf"`
+ );
+
+ // Send the file buffer as a response
+ return res.send(fileBuffer);
+ } catch (error) {
+ console.error("Error retrieving application data:", error);
+ return res.status(500).json({
+ error: "An error occurred while retrieving the application data",
+ });
+ }
+};
+
+export { getApplicationData, getFile, dataRoot, getApplicationsByStatus };
diff --git a/backend/src/controllers/validatorController.js b/backend/src/controllers/validatorController.js
new file mode 100644
index 0000000..f564c46
--- /dev/null
+++ b/backend/src/controllers/validatorController.js
@@ -0,0 +1,437 @@
+import { validatorDesignations } from "../config/designations.js";
+import prisma from "../config/prismaConfig.js";
+import sendMail from "../services/sendMail.js";
+
+const applicationAction = async (req, res) => {
+ const { id: profileId, designation, department, institute, role } = req.user;
+
+ try {
+ const {
+ applicationId,
+ action,
+ rejectionFeedback,
+ toVC,
+ resubmission,
+ expenses,
+ } = req.body; // actions = 'accepted' or 'rejected'
+
+ if (role !== "validator") {
+ return res.status(403).send("Forbidden, Sign in as a validator");
+ }
+
+ const validator = await prisma.user.findFirst({
+ where: { profileId },
+ include: {
+ toValidateApplications: {
+ where: { applicationId },
+ include: {
+ validators: {
+ select: { profileId: true, designation: true },
+ },
+ },
+ },
+ },
+ });
+
+ if (!validator) {
+ return res.status(404).send("Validator doesn't exist");
+ }
+
+ const application = validator.toValidateApplications[0];
+
+ if (!application) {
+ return res.status(404).send("Application not available");
+ }
+
+ const applicant = await prisma.user.findFirst({
+ where: { profileId: application.applicantId },
+ });
+
+ const applicantDesignation = applicant.designation;
+ const applicantDepartment = applicant.department;
+ const applicantInstitute = applicant.institute;
+ const applicantEmail = applicant.email;
+
+ const validationStatus = action.toUpperCase();
+ let resubmissionStatus = JSON.parse(resubmission) || false;
+
+ if (validationStatus !== "ACCEPTED" && validationStatus !== "REJECTED") {
+ return res.status(400).send("Invalid status");
+ }
+
+ const validationData = {};
+ let hod,
+ hoi,
+ vc,
+ accounts = null;
+
+ switch (validator.designation) {
+ case "FACULTY":
+ if (application.facultyValidation != "PENDING") {
+ return res
+ .status(400)
+ .send("Already performed an action, can't change status again");
+ }
+ validationData.facultyValidation = validationStatus;
+ if (validationStatus === "ACCEPTED") {
+ validationData.hodValidation = "PENDING";
+ hod = await prisma.user.findFirst({
+ where: {
+ designation: "HOD",
+ department: applicantDepartment,
+ institute: applicantInstitute,
+ },
+ });
+ sendMail({
+ emailId: hod.email,
+ link: `http://localhost:5173/validator/dashboard/pending/${applicationId}`,
+ type: "validator",
+ status: null,
+ designation: null,
+ });
+ }
+ sendMail({
+ emailId: applicantEmail,
+ link: `http://localhost:5173/applicant/dashboard/${validationStatus}/${applicationId}`,
+ type: "applicant",
+ status: validationStatus,
+ designation: "FACULTY",
+ });
+ break;
+ case "HOD":
+ if (application.hodValidation != "PENDING") {
+ return res
+ .status(400)
+ .send("Already performed an action, can't change status again");
+ }
+ validationData.hodValidation = validationStatus;
+ if (validationStatus === "ACCEPTED") {
+ validationData.hoiValidation = "PENDING";
+ hoi = await prisma.user.findFirst({
+ where: { designation: "HOI", institute: applicantInstitute },
+ });
+
+ sendMail({
+ emailId: hoi.email,
+ link: `http://localhost:5173/validator/dashboard/pending/${applicationId}`,
+ type: "validator",
+ status: null,
+ designation: null,
+ });
+ }
+ sendMail({
+ emailId: applicantEmail,
+ link: `http://localhost:5173/applicant/dashboard/${validationStatus}/${applicationId}`,
+ type: "applicant",
+ status: validationStatus,
+ designation: "HOD",
+ });
+ break;
+ case "HOI":
+ if (application.hoiValidation != "PENDING") {
+ return res
+ .status(400)
+ .send("Already performed an action, can't change status again");
+ }
+ validationData.hoiValidation = validationStatus;
+
+ if (validationStatus === "ACCEPTED") {
+ if (JSON.parse(toVC)) {
+ if (applicantDesignation === "STUDENT") {
+ return {
+ status: 400,
+ message:
+ "Students Applications cannot be forwared for VC validation",
+ };
+ }
+ validationData.vcValidation = "PENDING";
+ vc = await prisma.user.findFirst({
+ where: {
+ designation: "VC",
+ },
+ });
+ sendMail({
+ emailId: vc.email,
+ link: `http://localhost:5173/validator/dashboard/pending/${applicationId}`,
+ type: "validator",
+ status: null,
+ designation: null,
+ });
+ } else {
+ validationData.accountsValidation = "PENDING";
+ accounts = await prisma.user.findFirst({
+ where: { designation: "ACCOUNTS", institute: applicantInstitute },
+ });
+ sendMail({
+ emailId: accounts.email,
+ link: `http://localhost:5173/validator/dashboard/pending/${applicationId}`,
+ type: "accounts",
+ status: null,
+ designation: null,
+ });
+ }
+ }
+ sendMail({
+ emailId: applicantEmail,
+ link: `http://localhost:5173/applicant/dashboard/${validationStatus}/${applicationId}`,
+ type: "applicant",
+ status: validationStatus,
+ designation: "HOI",
+ });
+ break;
+ case "VC":
+ if (application.vcValidation != "PENDING") {
+ return res
+ .status(400)
+ .send("Already performed an action, can't change status again");
+ }
+ validationData.vcValidation = validationStatus;
+ if (validationStatus === "ACCEPTED") {
+ validationData.accountsValidation = "PENDING";
+ accounts = await prisma.user.findFirst({
+ where: { designation: "ACCOUNTS", institute: applicantInstitute },
+ });
+ sendMail({
+ emailId: accounts.email,
+ link: `http://localhost:5173/validator/dashboard/pending/${applicationId}`,
+ type: "accounts",
+ status: null,
+ designation: null,
+ });
+ }
+ sendMail({
+ emailId: applicantEmail,
+ link: `http://localhost:5173/applicant/dashboard/${validationStatus}/${applicationId}`,
+ type: "applicant",
+ status: validationStatus,
+ designation: "VC",
+ });
+ break;
+ case "ACCOUNTS":
+ if (application.accountsValidation != "PENDING") {
+ return res
+ .status(400)
+ .send("Already performed an action, can't change status again");
+ }
+ validationData.accountsValidation = validationStatus;
+ sendMail({
+ emailId: applicantEmail,
+ link: `http://localhost:5173/applicant/dashboard/${validationStatus}/${applicationId}`,
+ type: "applicant",
+ status: validationStatus,
+ designation: "ACCOUNTS",
+ });
+ break;
+ default:
+ return res.status(400).send("Invalid validator designation");
+ }
+
+ const validators = [
+ hod && { profileId: hod?.profileId },
+ hoi && { profileId: hoi?.profileId },
+ vc && { profileId: vc?.profileId },
+ accounts && { profileId: accounts?.profileId },
+ ].filter(Boolean);
+
+ if (rejectionFeedback) {
+ validationData.rejectionFeedback = rejectionFeedback;
+ }
+
+ if (validationStatus === "ACCEPTED") {
+ validationData.rejectionFeedback = null;
+ }
+
+ const newFormData = application.formData;
+
+ if (expenses) {
+ newFormData.expenses = expenses;
+ }
+
+ const response = await prisma.application.update({
+ where: {
+ applicationId: applicationId,
+ },
+ data: {
+ ...validationData,
+ resubmission: resubmissionStatus,
+ validators: {
+ connect: validators,
+ },
+ formData: newFormData,
+ },
+ select: { applicationId: true },
+ });
+
+ res.status(200).send(response);
+ } catch (error) {
+ res.status(500).send(error.message);
+ }
+};
+
+const expenseAction = async (req, res) => {
+ const { id: profileId, designation, department, institute, role } = req.user;
+
+ try {
+ const { applicationId, expense, action } = req.body;
+
+ if (role !== "validator") {
+ return res.status(403).send("Forbidden, Sign in as a validator");
+ }
+
+ const validator = await prisma.user.findFirst({
+ where: { profileId },
+ include: {
+ toValidateApplications: {
+ where: { applicationId },
+ include: {
+ validators: {
+ select: { profileId: true, designation: true },
+ },
+ },
+ },
+ },
+ });
+
+ if (!validator) {
+ return res.status(404).send("Validator doesn't exist");
+ }
+
+ const application = validator.toValidateApplications[0];
+
+ if (!application) {
+ return res.status(404).send("Application not available");
+ }
+
+ const updatedFormData = {
+ ...application.formData,
+ expenses: JSON.stringify(
+ JSON.parse(application.formData.expenses).map((singleExpense) =>
+ singleExpense.expenseId === expense.expenseId
+ ? { ...singleExpense, proofStatus: action }
+ : singleExpense
+ )
+ ),
+ };
+
+ const updatedApplication = await prisma.application.update({
+ where: {
+ applicationId,
+ },
+ data: {
+ formData: updatedFormData,
+ },
+ });
+
+ res.status(200).send(updatedApplication);
+ } catch (error) {
+ res.status(500).send(error.message);
+ }
+};
+
+const getApplicantNames = async (req, res) => {
+ const { id: profileId, designation, department, institute, role } = req.user;
+
+ try {
+ if (role !== "validator") {
+ return res.status(403).send("Forbidden");
+ }
+
+ const applicants = await prisma.application.findMany({
+ where: { validators: { some: { profileId } } },
+ select: {
+ applicantName: true,
+ },
+ distinct: ["applicantName"],
+ });
+
+ const ApplicantNames = applicants.map((application) => ({
+ key: application.applicantName.toLowerCase(),
+ value: application.applicantName,
+ }));
+
+ res.status(200).send(ApplicantNames);
+ } catch (error) {
+ console.error(error);
+ res.status(500).send(error.message);
+ }
+};
+
+const getReportData = async (req, res) => {
+ const { institute, department, year, applicationType } = req.query;
+ const {
+ id: profileId,
+ designation,
+ department: ogDepartment,
+ institute: ogInstitute,
+ role,
+ } = req.user;
+
+ try {
+ if (
+ (ogDepartment && department !== ogDepartment) ||
+ (ogInstitute && institute !== ogInstitute)
+ ) {
+ return res.status(403).send("Forbidden");
+ }
+
+ const whereClause = {
+ institute,
+ department,
+ };
+
+ if (year) {
+ whereClause.createdAt = {
+ gte: new Date(`${year}-01-01`),
+ lt: new Date(`${year}-12-31`),
+ };
+ }
+
+ if (applicationType) {
+ whereClause.applicationType = applicationType;
+ }
+
+ const applications = await prisma.application.findMany({
+ where: whereClause,
+ });
+
+ const reportData = {
+ totalApplications: applications.length,
+ acceptedApplications: applications.filter(
+ (application) =>
+ (application.facultyValidation === "ACCEPTED" ||
+ application.facultyValidation === null) &&
+ (application.hodValidation === "ACCEPTED" ||
+ application.hodValidation === null) &&
+ (application.hoiValidation === "ACCEPTED" ||
+ application.hoiValidation === null) &&
+ (application.vcValidation === "ACCEPTED" ||
+ application.vcValidation === null) &&
+ (application.accountsValidation === "ACCEPTED" ||
+ application.accountsValidation === null)
+ ),
+ rejectedApplications: applications.filter(
+ (application) =>
+ application.facultyValidation === "REJECTED" ||
+ application.hodValidation === "REJECTED" ||
+ application.hoiValidation === "REJECTED" ||
+ application.vcValidation === "REJECTED" ||
+ application.accountsValidation === "REJECTED"
+ ),
+ pendingApplications: applications.filter(
+ (application) =>
+ application.facultyValidation === "PENDING" ||
+ application.hodValidation === "PENDING" ||
+ application.hoiValidation === "PENDING" ||
+ application.vcValidation === "PENDING" ||
+ application.accountsValidation === "PENDING"
+ ),
+ };
+
+ res.status(200).send(reportData);
+ } catch (error) {
+ console.error(error);
+ res.status(500).send(error.message);
+ }
+};
+
+export { applicationAction, expenseAction, getApplicantNames, getReportData };
diff --git a/backend/src/middleware/upload.js b/backend/src/middleware/upload.js
new file mode 100644
index 0000000..fd8de51
--- /dev/null
+++ b/backend/src/middleware/upload.js
@@ -0,0 +1,24 @@
+import multer from 'multer';
+
+const storage = multer.memoryStorage();
+const upload = multer({ storage });
+
+const uploadExpenses = (req, res, next) => {
+
+ const expenseProofFields = Array.from({ length: 10 }, (_, index) => ({
+ name: `expenses[${index}].expenseProof`,
+ maxCount: 1,
+ }));
+
+ const fields = [
+ { name: 'proofOfTravel', maxCount: 1 },
+ { name: 'proofOfAccommodation', maxCount: 1 },
+ { name: 'proofOfAttendance', maxCount: 1 },
+ ...expenseProofFields,
+ ];
+
+ upload.fields(fields)(req, res, next);
+};
+
+
+export default uploadExpenses;
diff --git a/backend/src/middleware/verifyJwt.js b/backend/src/middleware/verifyJwt.js
new file mode 100644
index 0000000..502a964
--- /dev/null
+++ b/backend/src/middleware/verifyJwt.js
@@ -0,0 +1,97 @@
+import jwt from 'jsonwebtoken';
+import { applicantDesignations, validatorDesignations } from '../config/designations.js';
+
+const verifyApplicantToken = (req, res, next) => {
+
+ const token = req.cookies.access_token;
+
+ if (!token) {
+ return res.status(401).json({message: "No token found"});
+ }
+
+ jwt.verify(token, process.env.JWT_SECRET, (err,payload)=>{
+
+ if (err) {
+ return res.status(403).json({message:"Invalid Token"});
+ }
+
+ req.user = {
+ id : payload.id,
+ designation : payload.designation,
+ department : payload.department,
+ institute : payload.institute,
+ role : payload.role
+ };
+
+ if (req.user && applicantDesignations.includes(req.user.designation)) {
+ next();
+ } else {
+ return res.status(401).json({message : "Access denied. Not a applicant."});
+ }
+
+ })
+};
+
+const verifyValidatorToken = (req, res, next) => {
+
+ const token = req.cookies.access_token;
+
+ if (!token) {
+ return res.status(401).json({message: "No token found"});
+ }
+
+ jwt.verify(token, process.env.JWT_SECRET, (err,payload)=>{
+
+ if (err) {
+ return res.status(403).json({message:"Invalid Token"});
+ }
+
+ req.user = {
+ id : payload.id,
+ designation : payload.designation,
+ department : payload.department,
+ institute : payload.institute,
+ role : payload.role
+ }
+
+ if (req.user && validatorDesignations.includes(req.user.designation)) {
+ next();
+ } else {
+ return res.status(401).json({message:"Access denied. Not a validator."});
+ }
+
+ })
+};
+
+const verifyToken = (req, res, next) => {
+
+ const token = req.cookies.access_token;
+
+ if (!token) {
+ return res.status(401).json({message: "No token found"});
+ }
+
+ jwt.verify(token, process.env.JWT_SECRET, (err,payload)=>{
+
+ if (err) {
+ return res.status(403).json({message:"Invalid Token"});
+ }
+
+ req.user = {
+ id : payload.id,
+ designation : payload.designation,
+ department : payload.department,
+ institute : payload.institute,
+ role : payload.role
+ }
+
+ if (req.user && [...applicantDesignations ,...validatorDesignations].includes(req.user.designation)) {
+ next();
+ } else {
+ return res.status(401).json({message:"Access denied. Not a validator."});
+ }
+
+ })
+};
+
+export { verifyApplicantToken, verifyValidatorToken, verifyToken} ;
\ No newline at end of file
diff --git a/backend/src/routes/applicant.js b/backend/src/routes/applicant.js
new file mode 100644
index 0000000..b74ba6a
--- /dev/null
+++ b/backend/src/routes/applicant.js
@@ -0,0 +1,18 @@
+import express from 'express';
+import uploadFields from '../middleware/upload.js';
+import { createApplication, updateApplication } from '../controllers/applicantControllers.js';
+
+const router = express.Router();
+
+router.post("/create-application",
+ uploadFields,
+ createApplication
+);
+
+router.put("/resubmit-application",
+ uploadFields,
+ updateApplication
+);
+
+
+export default router;
diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js
new file mode 100644
index 0000000..3e56d6d
--- /dev/null
+++ b/backend/src/routes/auth.js
@@ -0,0 +1,11 @@
+import express from 'express';
+import { applicantLogin, logout, validatorLogin } from '../controllers/authControllers.js';
+
+const router = express.Router();
+
+router.post('/applicant-login', applicantLogin);
+router.post('/validator-login', validatorLogin);
+
+router.get('/logout', logout)
+
+export default router;
\ No newline at end of file
diff --git a/backend/src/routes/general.js b/backend/src/routes/general.js
new file mode 100644
index 0000000..d33580a
--- /dev/null
+++ b/backend/src/routes/general.js
@@ -0,0 +1,16 @@
+import express from 'express';
+import { dataRoot, getApplicationData, getApplicationsByStatus, getFile } from '../controllers/generalControllers.js';
+
+const router = express.Router();
+
+router.get("/dataRoot", dataRoot );
+
+router.get('/getApplications/:status', getApplicationsByStatus);
+
+router.get("/getApplicationData/:applicationId", getApplicationData);
+
+router.get("/getFile/:applicationId/:fileName", getFile)
+
+
+
+export default router;
\ No newline at end of file
diff --git a/backend/src/routes/validator.js b/backend/src/routes/validator.js
new file mode 100644
index 0000000..ac96c4b
--- /dev/null
+++ b/backend/src/routes/validator.js
@@ -0,0 +1,16 @@
+import express from 'express';
+import {applicationAction, expenseAction, getApplicantNames, getReportData} from '../controllers/validatorController.js'
+import multer from 'multer';
+
+const router = express.Router();
+const upload = multer();
+
+router.put("/statusAction", upload.none(), applicationAction)
+
+router.put("/expenseAction", expenseAction)
+
+router.get("/getApplicantNames", getApplicantNames)
+
+router.get("/getReportData", getReportData)
+
+export default router;
\ No newline at end of file
diff --git a/backend/src/server.js b/backend/src/server.js
new file mode 100644
index 0000000..af5a903
--- /dev/null
+++ b/backend/src/server.js
@@ -0,0 +1,9 @@
+import app from './app.js';
+import dotenv from 'dotenv';
+dotenv.config();
+
+const port = process.env.PORT || 3000;
+
+app.listen(port, () => {
+ console.log(`Server is running on port ${port}`);
+})
\ No newline at end of file
diff --git a/backend/src/services/generateToken.js b/backend/src/services/generateToken.js
new file mode 100644
index 0000000..d84d180
--- /dev/null
+++ b/backend/src/services/generateToken.js
@@ -0,0 +1,12 @@
+import jwt from 'jsonwebtoken';
+
+function generateToken(tokenObject) {
+
+ return jwt.sign(
+ tokenObject,
+ process.env.JWT_SECRET,
+ { expiresIn: '1h' }
+ );
+}
+
+export default generateToken;
\ No newline at end of file
diff --git a/backend/src/services/sendMail.js b/backend/src/services/sendMail.js
new file mode 100644
index 0000000..b423e47
--- /dev/null
+++ b/backend/src/services/sendMail.js
@@ -0,0 +1,74 @@
+import nodeMailer from 'nodemailer';
+
+export default async function sendMail({ emailId, link, type, status, designation }) {
+ if (!process.env.TravelPolicyEmail || !process.env.TravelPolicyEmailPass) {
+ return;
+ }
+
+ console.log("parametrs", emailId, link, type, status, designation);
+
+ const transporter = nodeMailer.createTransport({
+ service: 'gmail',
+ port: 465,
+ secure: true,
+ logger: true,
+ debug: true,
+ secureConnection: false,
+ auth: {
+ user: process.env.TravelPolicyEmail,
+ pass: process.env.TravelPolicyEmailPass,
+ },
+ tls: {
+ rejectUnauthorized: true,
+ },
+ });
+
+ let mailOptions;
+
+ switch (type) {
+ case 'validator':
+ mailOptions = {
+ from: process.env.TravelPolicyEmail,
+ to: emailId,
+ subject: 'You have a new travel policy application to review',
+ html: `
+
You have a new travel policy application to review. Please click on the link below to review the application:
+ Review Application
+ Thank you.
+ `,
+ };
+ break;
+ case 'applicant':
+ mailOptions = {
+ from: process.env.TravelPolicyEmail,
+ to: emailId,
+ subject: `Your travel policy application status: ${status}`,
+ html: `
+ Your travel policy application has been ${status} by ${designation}. Please click on the link below to view the status of your application:
+ View Application
+ Thank you.
+ `,
+ };
+ break;
+ case 'accounts':
+ mailOptions = {
+ from: process.env.TravelPolicyEmail,
+ to: emailId,
+ subject: 'Transfer money to the applicant',
+ html: `
+ Please transfer the travel policy amount to the applicant's account. Click on the link below to view the application:
`
+ }
+ break;
+ default:
+ throw new Error('Invalid email type');
+ }
+
+ try {
+ await transporter.sendMail(mailOptions);
+ console.log('Email sent successfully');
+ return true;
+ } catch (error) {
+ console.error('Error sending email:', error);
+ return { status: 'error', message: 'Verification code not sent' };
+ }
+}
\ No newline at end of file
diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs
new file mode 100644
index 0000000..3e212e1
--- /dev/null
+++ b/frontend/.eslintrc.cjs
@@ -0,0 +1,21 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ 'plugin:react/jsx-runtime',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
+ settings: { react: { version: '18.2' } },
+ plugins: ['react-refresh'],
+ rules: {
+ 'react/jsx-no-target-blank': 'off',
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ },
+}
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..c4c5017
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,27 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+# environment variables
+.env
\ No newline at end of file
diff --git a/frontend/README.md b/frontend/README.md
new file mode 100644
index 0000000..f768e33
--- /dev/null
+++ b/frontend/README.md
@@ -0,0 +1,8 @@
+# React + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
diff --git a/frontend/index.html b/frontend/index.html
new file mode 100644
index 0000000..b90892e
--- /dev/null
+++ b/frontend/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+ Vite + React
+
+
+
+
+
+
+
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
new file mode 100644
index 0000000..08ba80a
--- /dev/null
+++ b/frontend/package-lock.json
@@ -0,0 +1,7144 @@
+{
+ "name": "frontend",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "frontend",
+ "version": "0.0.0",
+ "dependencies": {
+ "@react-pdf/renderer": "^4.1.6",
+ "autoprefixer": "^10.4.20",
+ "axios": "^1.7.5",
+ "bootstrap": "^5.3.3",
+ "chart.js": "^4.4.7",
+ "chartjs-plugin-datalabels": "^2.2.0",
+ "formik": "^2.4.6",
+ "framer-motion": "^11.15.0",
+ "frontend": "file:",
+ "hamburger-react": "^2.5.1",
+ "pdfjs-dist": "^4.7.76",
+ "postcss": "^8.4.40",
+ "react": "^18.3.1",
+ "react-chartjs-2": "^5.2.0",
+ "react-dom": "^18.3.1",
+ "react-icons": "^5.2.1",
+ "react-pdf": "^9.1.1",
+ "react-router-dom": "^6.25.1",
+ "react-search-box": "^2.3.0",
+ "react-table": "^7.8.0",
+ "react-toastify": "^11.0.5",
+ "tailwindcss": "^3.4.7",
+ "yup": "^1.4.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "@vitejs/plugin-react": "^1.3.2",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react": "^7.34.3",
+ "eslint-plugin-react-hooks": "^4.6.2",
+ "eslint-plugin-react-refresh": "^0.4.7",
+ "vite": "^6.2.1"
+ }
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.25.0",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.0.tgz",
+ "integrity": "sha512-P4fwKI2mjEb3ZU5cnMJzvRsRKGBUcs8jvxIoRmr6ufAY9Xk2Bz7JubRTTivkw55c7WQJfTECeqYVa+HZ0FzREg==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz",
+ "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.9",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-module-transforms": "^7.24.9",
+ "@babel/helpers": "^7.24.8",
+ "@babel/parser": "^7.24.8",
+ "@babel/template": "^7.24.7",
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.9",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
+ "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.26.9",
+ "@babel/types": "^7.26.9",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
+ "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz",
+ "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==",
+ "dependencies": {
+ "@babel/compat-data": "^7.24.8",
+ "@babel/helper-validator-option": "^7.24.8",
+ "browserslist": "^4.23.1",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
+ "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.25.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.0.tgz",
+ "integrity": "sha512-bIkOa2ZJYn7FHnepzr5iX9Kmz8FjIz4UKzJ9zhX3dnYuVW0xul9RuR3skBfoLu+FPTQw90EHW9rJsSZhyLQ3fQ==",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.24.7",
+ "@babel/helper-simple-access": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "@babel/traverse": "^7.25.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz",
+ "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
+ "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
+ "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz",
+ "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz",
+ "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.1"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz",
+ "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz",
+ "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/plugin-syntax-jsx": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-development": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz",
+ "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-transform-react-jsx": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz",
+ "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz",
+ "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
+ "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
+ "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.26.2",
+ "@babel/generator": "^7.26.9",
+ "@babel/parser": "^7.26.9",
+ "@babel/template": "^7.26.9",
+ "@babel/types": "^7.26.9",
+ "debug": "^4.3.1",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
+ "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz",
+ "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/stylis": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
+ "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+ "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==",
+ "license": "MIT"
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+ "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+ "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+ "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+ "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+ "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+ "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+ "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+ "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+ "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+ "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+ "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+ "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+ "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+ "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+ "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+ "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+ "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+ "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+ "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+ "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
+ "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.11.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
+ "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==",
+ "dev": true,
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.14",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+ "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.2",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@kurkle/color": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+ "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+ "license": "MIT"
+ },
+ "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",
+ "optional": true,
+ "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/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==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
+ "node_modules/@react-pdf/fns": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/fns/-/fns-3.0.0.tgz",
+ "integrity": "sha512-ICbIWR93PE6+xf2Xd/fXYO1dAuiOAJaszEuGGv3wp5lLSeeelDXlEYLh6R05okxh28YqMzc0Qd85x6n6MtaLUQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13"
+ }
+ },
+ "node_modules/@react-pdf/font": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-3.0.1.tgz",
+ "integrity": "sha512-s+0xrQabGoYDDZwVpz8PXp1ylwabqiMhzfyetvxBqjDuQ15PuoSkmUkKUOkfDzauuAqs0MLMvt+Pcv+NioLfzw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/types": "^2.7.0",
+ "fontkit": "^2.0.2",
+ "is-url": "^1.2.4"
+ }
+ },
+ "node_modules/@react-pdf/image": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-3.0.1.tgz",
+ "integrity": "sha512-Hd5F1LzjuzG4bL/ytaOYxwN/5ip8oFBYDHdpccOfYY87J/Ca7AL31SsuneLk9DtnwNM1BSAKXtBo/WDFY3r57A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/png-js": "^3.0.0",
+ "jay-peg": "^1.1.0"
+ }
+ },
+ "node_modules/@react-pdf/layout": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-4.2.0.tgz",
+ "integrity": "sha512-/0jMhDKwZH0lQs3umNsOduaPtkK0IUpaBRUEv4udHVD9lB2VzYoSNeYsCu+MJMPJyByXj70OSWV7IMjWTCKwWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/fns": "3.0.0",
+ "@react-pdf/image": "^3.0.1",
+ "@react-pdf/pdfkit": "^4.0.0",
+ "@react-pdf/primitives": "^4.0.0",
+ "@react-pdf/stylesheet": "^5.2.0",
+ "@react-pdf/textkit": "^5.0.1",
+ "@react-pdf/types": "^2.7.0",
+ "emoji-regex": "^10.3.0",
+ "queue": "^6.0.1",
+ "yoga-layout": "^3.1.0"
+ }
+ },
+ "node_modules/@react-pdf/layout/node_modules/emoji-regex": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
+ "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
+ "license": "MIT"
+ },
+ "node_modules/@react-pdf/pdfkit": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-4.0.0.tgz",
+ "integrity": "sha512-HaaAoBpoRGJ6c1ZOANNQZ3q6Ehmagqa8n40x+OZ5s9HcmUviZ34SCm+QBa42s1o4299M+Lgw3UoqpW7sHv3/Hg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/png-js": "^3.0.0",
+ "browserify-zlib": "^0.2.0",
+ "crypto-js": "^4.2.0",
+ "fontkit": "^2.0.2",
+ "jay-peg": "^1.1.0",
+ "vite-compatible-readable-stream": "^3.6.1"
+ }
+ },
+ "node_modules/@react-pdf/png-js": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-3.0.0.tgz",
+ "integrity": "sha512-eSJnEItZ37WPt6Qv5pncQDxLJRK15eaRwPT+gZoujP548CodenOVp49GST8XJvKMFt9YqIBzGBV/j9AgrOQzVA==",
+ "license": "MIT",
+ "dependencies": {
+ "browserify-zlib": "^0.2.0"
+ }
+ },
+ "node_modules/@react-pdf/primitives": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-4.0.0.tgz",
+ "integrity": "sha512-yp4E0rDL03NaUp/CnDBz3HQNfH2Mzdlgku57yhTMGNzetwB0NJusXcjYg5XsTGIXnR7Tv80JKI4O4ajj+oaLeQ==",
+ "license": "MIT"
+ },
+ "node_modules/@react-pdf/reconciler": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@react-pdf/reconciler/-/reconciler-1.1.3.tgz",
+ "integrity": "sha512-4vqY0klmUH32kTFvuqdAszkOpwfZYKMLO4VpJ5xZWTsoUOLQSyhC2QM2QCj9eaxpB2Nd5Kl9uW+KfyutvZnMzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4.1.1",
+ "scheduler": "0.25.0-rc-603e6108-20241029"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@react-pdf/reconciler/node_modules/scheduler": {
+ "version": "0.25.0-rc-603e6108-20241029",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-603e6108-20241029.tgz",
+ "integrity": "sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==",
+ "license": "MIT"
+ },
+ "node_modules/@react-pdf/render": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-4.0.2.tgz",
+ "integrity": "sha512-5QJB9sS0uU5ALTLxrtT073VT1imZhrzuOun+7kvo0nykeAr9I4lv0Shmy8rS4QhpmXn8ASmhd17WjCVm4DcJlw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/fns": "3.0.0",
+ "@react-pdf/primitives": "^4.0.0",
+ "@react-pdf/textkit": "^5.0.1",
+ "@react-pdf/types": "^2.7.0",
+ "abs-svg-path": "^0.1.1",
+ "color-string": "^1.9.1",
+ "normalize-svg-path": "^1.1.0",
+ "parse-svg-path": "^0.1.2",
+ "svg-arc-to-cubic-bezier": "^3.2.0"
+ }
+ },
+ "node_modules/@react-pdf/renderer": {
+ "version": "4.1.6",
+ "resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-4.1.6.tgz",
+ "integrity": "sha512-hfQ0PsuVqfoYxkYgmkj+HFkylbB1QTpXY1rnlgnzJlrlSoNXjzPrCa/ty8jcHOwYA2lNoazIAoDatBIsc8K5pw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/font": "^3.0.1",
+ "@react-pdf/layout": "^4.2.0",
+ "@react-pdf/pdfkit": "^4.0.0",
+ "@react-pdf/primitives": "^4.0.0",
+ "@react-pdf/reconciler": "^1.1.3",
+ "@react-pdf/render": "^4.0.2",
+ "@react-pdf/types": "^2.7.0",
+ "events": "^3.3.0",
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.6.2",
+ "queue": "^6.0.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@react-pdf/stylesheet": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-5.2.0.tgz",
+ "integrity": "sha512-ST19VumM9iRG0z8EjDJnyQCG+NhPFtYUCAh5B8HY237MrsRGvMgzcwrpyyqcyuLwHHYy7S4iw8EY0mK9+Qa2XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/fns": "3.0.0",
+ "@react-pdf/types": "^2.7.0",
+ "color-string": "^1.9.1",
+ "hsl-to-hex": "^1.0.0",
+ "media-engine": "^1.0.3",
+ "postcss-value-parser": "^4.1.0"
+ }
+ },
+ "node_modules/@react-pdf/textkit": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-5.0.1.tgz",
+ "integrity": "sha512-4GdDiPA9l+If203hkh48slvRQmcmM3ecPLFTpXNMPrep/3retgvxUEXKMxI+xKclpw8tMzK/W6Z4hN9DgnxWMg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.20.13",
+ "@react-pdf/fns": "3.0.0",
+ "bidi-js": "^1.0.2",
+ "hyphen": "^1.6.4",
+ "unicode-properties": "^1.4.1"
+ }
+ },
+ "node_modules/@react-pdf/types": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.7.0.tgz",
+ "integrity": "sha512-7KrPPCpgRPKR+g+T127PE4bpw9Q84ZiY07EYRwXKVtTEVW9wJ5BZiF9smT9IvH19s+MQaDLmYRgjESsnqlyH0Q==",
+ "license": "MIT"
+ },
+ "node_modules/@remix-run/router": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.18.0.tgz",
+ "integrity": "sha512-L3jkqmqoSVBVKHfpGZmLrex0lxR5SucGA0sUfFzGctehw+S/ggL9L/0NnC5mw6P8HUWpFZ3nQw3cRApjjWx9Sw==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "estree-walker": "^2.0.1",
+ "picomatch": "^2.2.2"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz",
+ "integrity": "sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz",
+ "integrity": "sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz",
+ "integrity": "sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz",
+ "integrity": "sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz",
+ "integrity": "sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz",
+ "integrity": "sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz",
+ "integrity": "sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz",
+ "integrity": "sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz",
+ "integrity": "sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz",
+ "integrity": "sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz",
+ "integrity": "sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz",
+ "integrity": "sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz",
+ "integrity": "sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz",
+ "integrity": "sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz",
+ "integrity": "sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz",
+ "integrity": "sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz",
+ "integrity": "sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz",
+ "integrity": "sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz",
+ "integrity": "sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz",
+ "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.12",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
+ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
+ },
+ "node_modules/@types/react": {
+ "version": "18.3.3",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
+ "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.3.0",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
+ "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
+ "dev": true,
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
+ "dev": true
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz",
+ "integrity": "sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.17.10",
+ "@babel/plugin-transform-react-jsx": "^7.17.3",
+ "@babel/plugin-transform-react-jsx-development": "^7.16.7",
+ "@babel/plugin-transform-react-jsx-self": "^7.16.7",
+ "@babel/plugin-transform-react-jsx-source": "^7.16.7",
+ "@rollup/pluginutils": "^4.2.1",
+ "react-refresh": "^0.13.0",
+ "resolve": "^1.22.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react/node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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",
+ "optional": true
+ },
+ "node_modules/abs-svg-path": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz",
+ "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==",
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "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",
+ "optional": true,
+ "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",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "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==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "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",
+ "optional": true
+ },
+ "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",
+ "optional": true,
+ "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",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+ "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+ "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "is-string": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.findlast": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+ "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
+ "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
+ "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.tosorted": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+ "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
+ "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.22.3",
+ "es-errors": "^1.2.1",
+ "get-intrinsic": "^1.2.3",
+ "is-array-buffer": "^3.0.4",
+ "is-shared-array-buffer": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/autoprefixer": {
+ "version": "10.4.20",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
+ "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.23.3",
+ "caniuse-lite": "^1.0.30001646",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.0.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/babel-plugin-styled-components": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz",
+ "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.22.5",
+ "@babel/helper-module-imports": "^7.22.5",
+ "@babel/plugin-syntax-jsx": "^7.22.5",
+ "lodash": "^4.17.21",
+ "picomatch": "^2.3.1"
+ },
+ "peerDependencies": {
+ "styled-components": ">= 2"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bidi-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
+ "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
+ "license": "MIT",
+ "dependencies": {
+ "require-from-string": "^2.0.2"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bootstrap": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/twbs"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ }
+ ],
+ "peerDependencies": {
+ "@popperjs/core": "^2.11.8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "devOptional": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brotli": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
+ "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.1.2"
+ }
+ },
+ "node_modules/browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "license": "MIT",
+ "dependencies": {
+ "pako": "~1.0.5"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
+ "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001646",
+ "electron-to-chromium": "^1.5.4",
+ "node-releases": "^2.0.18",
+ "update-browserslist-db": "^1.1.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001695",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001695.tgz",
+ "integrity": "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/canvas": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
+ "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@mapbox/node-pre-gyp": "^1.0.0",
+ "nan": "^2.17.0",
+ "simple-get": "^3.0.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chart.js": {
+ "version": "4.4.7",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.7.tgz",
+ "integrity": "sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==",
+ "license": "MIT",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
+ "node_modules/chartjs-plugin-datalabels": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz",
+ "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "chart.js": ">=3.0.0"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "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",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+ },
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "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",
+ "optional": true,
+ "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",
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "devOptional": true
+ },
+ "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",
+ "optional": true
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "license": "MIT"
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+ "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+ "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+ "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
+ "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "mimic-response": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/deepmerge": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
+ "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "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",
+ "optional": true
+ },
+ "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"
+ }
+ },
+ "node_modules/dfa": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
+ "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
+ "license": "MIT"
+ },
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz",
+ "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA=="
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
+ },
+ "node_modules/es-abstract": {
+ "version": "1.23.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+ "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "arraybuffer.prototype.slice": "^1.0.3",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "data-view-buffer": "^1.0.1",
+ "data-view-byte-length": "^1.0.1",
+ "data-view-byte-offset": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-set-tostringtag": "^2.0.3",
+ "es-to-primitive": "^1.2.1",
+ "function.prototype.name": "^1.1.6",
+ "get-intrinsic": "^1.2.4",
+ "get-symbol-description": "^1.0.2",
+ "globalthis": "^1.0.3",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.0.3",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.0.7",
+ "is-array-buffer": "^3.0.4",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.1",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.1.4",
+ "is-shared-array-buffer": "^1.0.3",
+ "is-string": "^1.0.7",
+ "is-typed-array": "^1.1.13",
+ "is-weakref": "^1.0.2",
+ "object-inspect": "^1.13.1",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.5",
+ "regexp.prototype.flags": "^1.5.2",
+ "safe-array-concat": "^1.1.2",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.trim": "^1.2.9",
+ "string.prototype.trimend": "^1.0.8",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.2",
+ "typed-array-byte-length": "^1.0.1",
+ "typed-array-byte-offset": "^1.0.2",
+ "typed-array-length": "^1.0.6",
+ "unbox-primitive": "^1.0.2",
+ "which-typed-array": "^1.1.15"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-iterator-helpers": {
+ "version": "1.0.19",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz",
+ "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
+ "es-set-tostringtag": "^2.0.3",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "globalthis": "^1.0.3",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.0.3",
+ "has-symbols": "^1.0.3",
+ "internal-slot": "^1.0.7",
+ "iterator.prototype": "^1.1.2",
+ "safe-array-concat": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+ "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+ "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.4",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+ "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.0"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+ "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.0",
+ "@esbuild/android-arm": "0.25.0",
+ "@esbuild/android-arm64": "0.25.0",
+ "@esbuild/android-x64": "0.25.0",
+ "@esbuild/darwin-arm64": "0.25.0",
+ "@esbuild/darwin-x64": "0.25.0",
+ "@esbuild/freebsd-arm64": "0.25.0",
+ "@esbuild/freebsd-x64": "0.25.0",
+ "@esbuild/linux-arm": "0.25.0",
+ "@esbuild/linux-arm64": "0.25.0",
+ "@esbuild/linux-ia32": "0.25.0",
+ "@esbuild/linux-loong64": "0.25.0",
+ "@esbuild/linux-mips64el": "0.25.0",
+ "@esbuild/linux-ppc64": "0.25.0",
+ "@esbuild/linux-riscv64": "0.25.0",
+ "@esbuild/linux-s390x": "0.25.0",
+ "@esbuild/linux-x64": "0.25.0",
+ "@esbuild/netbsd-arm64": "0.25.0",
+ "@esbuild/netbsd-x64": "0.25.0",
+ "@esbuild/openbsd-arm64": "0.25.0",
+ "@esbuild/openbsd-x64": "0.25.0",
+ "@esbuild/sunos-x64": "0.25.0",
+ "@esbuild/win32-arm64": "0.25.0",
+ "@esbuild/win32-ia32": "0.25.0",
+ "@esbuild/win32-x64": "0.25.0"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+ "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+ "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.0",
+ "@humanwhocodes/config-array": "^0.11.14",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-plugin-react": {
+ "version": "7.35.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz",
+ "integrity": "sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.8",
+ "array.prototype.findlast": "^1.2.5",
+ "array.prototype.flatmap": "^1.3.2",
+ "array.prototype.tosorted": "^1.1.4",
+ "doctrine": "^2.1.0",
+ "es-iterator-helpers": "^1.0.19",
+ "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",
+ "prop-types": "^15.8.1",
+ "resolve": "^2.0.0-next.5",
+ "semver": "^6.3.1",
+ "string.prototype.matchall": "^4.0.11",
+ "string.prototype.repeat": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
+ "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.4.9",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.9.tgz",
+ "integrity": "sha512-QK49YrBAo5CLNLseZ7sZgvgTy21E6NEw22eZqc4teZfH8pxV3yXc9XXOYfUI6JNpw7mfHNkAeWtBxrTyykB6HA==",
+ "dev": true,
+ "peerDependencies": {
+ "eslint": ">=7"
+ }
+ },
+ "node_modules/eslint-plugin-react/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "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=="
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+ "dev": true
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fontkit": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
+ "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@swc/helpers": "^0.5.12",
+ "brotli": "^1.3.2",
+ "clone": "^2.1.2",
+ "dfa": "^1.2.0",
+ "fast-deep-equal": "^3.1.3",
+ "restructure": "^3.0.0",
+ "tiny-inflate": "^1.0.3",
+ "unicode-properties": "^1.4.0",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz",
+ "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/formik": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz",
+ "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://opencollective.com/formik"
+ }
+ ],
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "deepmerge": "^2.1.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "react-fast-compare": "^2.0.1",
+ "tiny-warning": "^1.0.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/framer-motion": {
+ "version": "11.15.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.15.0.tgz",
+ "integrity": "sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^11.14.3",
+ "motion-utils": "^11.14.3",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/frontend": {
+ "resolved": "",
+ "link": true
+ },
+ "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",
+ "optional": true,
+ "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",
+ "optional": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs-minipass/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",
+ "optional": true
+ },
+ "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==",
+ "devOptional": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+ "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "functions-have-names": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fuse.js": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.6.2.tgz",
+ "integrity": "sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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",
+ "optional": true,
+ "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/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",
+ "optional": true
+ },
+ "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",
+ "optional": true
+ },
+ "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",
+ "optional": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
+ "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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",
+ "devOptional": true,
+ "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/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graphemer": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+ "dev": true
+ },
+ "node_modules/hamburger-react": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/hamburger-react/-/hamburger-react-2.5.1.tgz",
+ "integrity": "sha512-XlTIinYeYzLu76q4Vd9olwOJP0hFgAeZfJFX6tTT/ufTLhmOjI77CGFYIwGc6gcDeeT86660ZoKx3/L67vdZEw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "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",
+ "optional": true
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hsl-to-hex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz",
+ "integrity": "sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==",
+ "license": "MIT",
+ "dependencies": {
+ "hsl-to-rgb-for-reals": "^1.1.0"
+ }
+ },
+ "node_modules/hsl-to-rgb-for-reals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/hsl-to-rgb-for-reals/-/hsl-to-rgb-for-reals-1.1.1.tgz",
+ "integrity": "sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==",
+ "license": "ISC"
+ },
+ "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",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/hyphen": {
+ "version": "1.10.6",
+ "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.10.6.tgz",
+ "integrity": "sha512-fXHXcGFTXOvZTSkPJuGOQf5Lv5T/R2itiiCVPg9LxAje5D00O0pP83yJShFq5V89Ly//Gt6acj7z8pbBr34stw==",
+ "license": "ISC"
+ },
+ "node_modules/ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "devOptional": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+ "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.0",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+ "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "license": "MIT"
+ },
+ "node_modules/is-async-function": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
+ "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "dev": true,
+ "dependencies": {
+ "has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+ "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+ "dev": true,
+ "dependencies": {
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finalizationregistry": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
+ "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "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==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-generator-function": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
+ "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
+ "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "dev": true,
+ "dependencies": {
+ "which-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+ "license": "MIT"
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+ "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
+ "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
+ },
+ "node_modules/iterator.prototype": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
+ "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "get-intrinsic": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "reflect.getprototypeof": "^1.0.4",
+ "set-function-name": "^2.0.1"
+ }
+ },
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/jay-peg": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/jay-peg/-/jay-peg-1.1.1.tgz",
+ "integrity": "sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==",
+ "license": "MIT",
+ "dependencies": {
+ "restructure": "^3.0.0"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "1.21.6",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
+ "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsx-ast-utils": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+ "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "object.assign": "^4.1.4",
+ "object.values": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "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-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/make-cancellable-promise": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz",
+ "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1"
+ }
+ },
+ "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",
+ "optional": true,
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-event-props": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz",
+ "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1"
+ }
+ },
+ "node_modules/media-engine": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz",
+ "integrity": "sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==",
+ "license": "MIT"
+ },
+ "node_modules/merge-refs": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.3.0.tgz",
+ "integrity": "sha512-nqXPXbso+1dcKDpPCXvwZyJILz+vSLqGGOnDrYHQYE+B8n9JTCekVLC65AfCpR4ggVyA/45Y0iR9LDyS2iI+zA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "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/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/mimic-response": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
+ "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "devOptional": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "engines": {
+ "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",
+ "optional": true,
+ "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",
+ "optional": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib/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",
+ "optional": true
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "license": "MIT",
+ "optional": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/motion-dom": {
+ "version": "11.14.3",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.14.3.tgz",
+ "integrity": "sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA==",
+ "license": "MIT"
+ },
+ "node_modules/motion-utils": {
+ "version": "11.14.3",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.14.3.tgz",
+ "integrity": "sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ==",
+ "license": "MIT"
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dependencies": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "node_modules/nan": {
+ "version": "2.22.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
+ "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "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",
+ "optional": true,
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
+ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g=="
+ },
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "license": "ISC",
+ "optional": true,
+ "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",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-svg-path": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz",
+ "integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==",
+ "license": "MIT",
+ "dependencies": {
+ "svg-arc-to-cubic-bezier": "^3.0.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",
+ "optional": true,
+ "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==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+ "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+ "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+ "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "devOptional": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
+ "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw=="
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "license": "(MIT AND Zlib)"
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-svg-path": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz",
+ "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==",
+ "license": "MIT"
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "devOptional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
+ },
+ "node_modules/path2d": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.1.tgz",
+ "integrity": "sha512-Fl2z/BHvkTNvkuBzYTpTuirHZg6wW9z8+4SND/3mDTEcYbbNKWAy21dz9D3ePNNwrrK8pqZO5vLPZ1hLF6T7XA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pdfjs-dist": {
+ "version": "4.7.76",
+ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.7.76.tgz",
+ "integrity": "sha512-8y6wUgC/Em35IumlGjaJOCm3wV4aY/6sqnIT3fVW/67mXsOZ9HWBn8GDKmJUK0GSzpbmX3gQqwfoFayp78Mtqw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "canvas": "^2.11.2",
+ "path2d": "^0.2.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+ "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-import/node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+ "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "lilconfig": "^3.0.0",
+ "yaml": "^2.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-load-config/node_modules/lilconfig": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
+ "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "postcss-selector-parser": "^6.1.1"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz",
+ "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
+ "license": "MIT"
+ },
+ "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",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
+ "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "~2.0.3"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-chartjs-2": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
+ "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "chart.js": "^4.1.1",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-fast-compare": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
+ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==",
+ "license": "MIT"
+ },
+ "node_modules/react-icons": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz",
+ "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "node_modules/react-pdf": {
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.1.1.tgz",
+ "integrity": "sha512-Cn3RTJZMqVOOCgLMRXDamLk4LPGfyB2Np3OwQAUjmHIh47EpuGW1OpAA1Z1GVDLoHx4d5duEDo/YbUkDbr4QFQ==",
+ "license": "MIT",
+ "dependencies": {
+ "clsx": "^2.0.0",
+ "dequal": "^2.0.3",
+ "make-cancellable-promise": "^1.3.1",
+ "make-event-props": "^1.6.0",
+ "merge-refs": "^1.3.0",
+ "pdfjs-dist": "4.4.168",
+ "tiny-invariant": "^1.0.0",
+ "warning": "^4.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/wojtekmaj/react-pdf?sponsor=1"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-pdf/node_modules/pdfjs-dist": {
+ "version": "4.4.168",
+ "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.4.168.tgz",
+ "integrity": "sha512-MbkAjpwka/dMHaCfQ75RY1FXX3IewBVu6NGZOcxerRFlaBiIkZmUoR0jotX5VUzYZEXAGzSFtknWs5xRKliXPA==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "canvas": "^2.11.2",
+ "path2d": "^0.2.0"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz",
+ "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-router": {
+ "version": "6.25.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.25.1.tgz",
+ "integrity": "sha512-u8ELFr5Z6g02nUtpPAggP73Jigj1mRePSwhS/2nkTrlPU5yEkH1vYzWNyvSnSzeeE2DNqWdH+P8OhIh9wuXhTw==",
+ "dependencies": {
+ "@remix-run/router": "1.18.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.25.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.25.1.tgz",
+ "integrity": "sha512-0tUDpbFvk35iv+N89dWNrJp+afLgd+y4VtorJZuOCXK0kkCWjEvb3vTJM++SYvMEpbVwXKf3FjeVveVEb6JpDQ==",
+ "dependencies": {
+ "@remix-run/router": "1.18.0",
+ "react-router": "6.25.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/react-search-box": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/react-search-box/-/react-search-box-2.3.0.tgz",
+ "integrity": "sha512-D/y51AAIIk+QUTUk7s3LEiJ3CnjjGmcA5U240ejItJFTnPX2mAjx9XZPnZCrwHDdhXSuYM4vhNFQUb6z1ksbLA==",
+ "license": "MIT",
+ "dependencies": {
+ "fuse.js": "^6.4.6",
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "styled-components": "^5.3.1"
+ }
+ },
+ "node_modules/react-search-box/node_modules/react": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-search-box/node_modules/react-dom": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1",
+ "scheduler": "^0.20.2"
+ },
+ "peerDependencies": {
+ "react": "17.0.2"
+ }
+ },
+ "node_modules/react-search-box/node_modules/scheduler": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "object-assign": "^4.1.1"
+ }
+ },
+ "node_modules/react-table": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
+ "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0"
+ }
+ },
+ "node_modules/react-toastify": {
+ "version": "11.0.5",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
+ "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==",
+ "license": "MIT",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19",
+ "react-dom": "^18 || ^19"
+ }
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dependencies": {
+ "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",
+ "optional": true,
+ "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",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
+ "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.1",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "globalthis": "^1.0.3",
+ "which-builtin-type": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+ "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "set-function-name": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "2.0.0-next.5",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+ "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/restructure": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz",
+ "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
+ "license": "MIT"
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "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",
+ "devOptional": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz",
+ "integrity": "sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.35.0",
+ "@rollup/rollup-android-arm64": "4.35.0",
+ "@rollup/rollup-darwin-arm64": "4.35.0",
+ "@rollup/rollup-darwin-x64": "4.35.0",
+ "@rollup/rollup-freebsd-arm64": "4.35.0",
+ "@rollup/rollup-freebsd-x64": "4.35.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.35.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.35.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.35.0",
+ "@rollup/rollup-linux-arm64-musl": "4.35.0",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.35.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.35.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.35.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.35.0",
+ "@rollup/rollup-linux-x64-gnu": "4.35.0",
+ "@rollup/rollup-linux-x64-musl": "4.35.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.35.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.35.0",
+ "@rollup/rollup-win32-x64-msvc": "4.35.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+ "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "get-intrinsic": "^1.2.4",
+ "has-symbols": "^1.0.3",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
+ "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.1.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "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/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",
+ "optional": true
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/shallowequal": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
+ "license": "MIT"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/simple-get": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
+ "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "decompress-response": "^4.2.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.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",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "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==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/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=="
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/string.prototype.matchall": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
+ "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "internal-slot": "^1.0.7",
+ "regexp.prototype.flags": "^1.5.2",
+ "set-function-name": "^2.0.2",
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.repeat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+ "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+ "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+ "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/styled-components": {
+ "version": "5.3.11",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz",
+ "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "@babel/traverse": "^7.4.5",
+ "@emotion/is-prop-valid": "^1.1.0",
+ "@emotion/stylis": "^0.8.4",
+ "@emotion/unitless": "^0.7.4",
+ "babel-plugin-styled-components": ">= 1.12.0",
+ "css-to-react-native": "^3.0.0",
+ "hoist-non-react-statics": "^3.0.0",
+ "shallowequal": "^1.1.0",
+ "supports-color": "^5.5.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/styled-components"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0",
+ "react-dom": ">= 16.8.0",
+ "react-is": ">= 16.8.0"
+ }
+ },
+ "node_modules/sucrase": {
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.2",
+ "commander": "^4.0.0",
+ "glob": "^10.3.10",
+ "lines-and-columns": "^1.1.6",
+ "mz": "^2.7.0",
+ "pirates": "^4.0.1",
+ "ts-interface-checker": "^0.1.9"
+ },
+ "bin": {
+ "sucrase": "bin/sucrase",
+ "sucrase-node": "bin/sucrase-node"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/sucrase/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sucrase/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/svg-arc-to-cubic-bezier": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
+ "integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==",
+ "license": "ISC"
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.4.7",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz",
+ "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.0",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.21.0",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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",
+ "optional": true,
+ "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",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar/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",
+ "optional": true
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dependencies": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "node_modules/thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "dependencies": {
+ "thenify": ">= 3.1.0 < 4"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+ "license": "MIT"
+ },
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
+ "license": "MIT"
+ },
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "license": "MIT"
+ },
+ "node_modules/tiny-warning": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
+ "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
+ "license": "MIT"
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/ts-interface-checker": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
+ "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
+ "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
+ "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+ "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+ "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.0.3",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unicode-properties": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
+ "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.0",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/unicode-trie": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
+ "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "pako": "^0.2.5",
+ "tiny-inflate": "^1.0.0"
+ }
+ },
+ "node_modules/unicode-trie/node_modules/pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
+ "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "node_modules/vite": {
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
+ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-compatible-readable-stream": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz",
+ "integrity": "sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/vite/node_modules/fdir": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "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",
+ "optional": true
+ },
+ "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",
+ "optional": true,
+ "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",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dev": true,
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz",
+ "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==",
+ "dev": true,
+ "dependencies": {
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.0.5",
+ "is-finalizationregistry": "^1.0.2",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.1.4",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.0.2",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.15"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+ "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "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",
+ "optional": true,
+ "dependencies": {
+ "string-width": "^1.0.2 || 2 || 3 || 4"
+ }
+ },
+ "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",
+ "optional": true
+ },
+ "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",
+ "optional": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.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",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/wrap-ansi-cjs/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=="
+ },
+ "node_modules/wrap-ansi-cjs/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==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "devOptional": true
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+ },
+ "node_modules/yaml": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz",
+ "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yoga-layout": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
+ "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
+ "license": "MIT"
+ },
+ "node_modules/yup": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz",
+ "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==",
+ "license": "MIT",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ },
+ "node_modules/yup/node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..d94201c
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite --host",
+ "build": "vite build",
+ "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@react-pdf/renderer": "^4.1.6",
+ "autoprefixer": "^10.4.20",
+ "axios": "^1.7.5",
+ "bootstrap": "^5.3.3",
+ "chart.js": "^4.4.7",
+ "chartjs-plugin-datalabels": "^2.2.0",
+ "formik": "^2.4.6",
+ "framer-motion": "^11.15.0",
+ "frontend": "file:",
+ "hamburger-react": "^2.5.1",
+ "pdfjs-dist": "^4.7.76",
+ "postcss": "^8.4.40",
+ "react": "^18.3.1",
+ "react-chartjs-2": "^5.2.0",
+ "react-dom": "^18.3.1",
+ "react-icons": "^5.2.1",
+ "react-pdf": "^9.1.1",
+ "react-router-dom": "^6.25.1",
+ "react-search-box": "^2.3.0",
+ "react-table": "^7.8.0",
+ "react-toastify": "^11.0.5",
+ "tailwindcss": "^3.4.7",
+ "yup": "^1.4.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "@vitejs/plugin-react": "^1.3.2",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react": "^7.34.3",
+ "eslint-plugin-react-hooks": "^4.6.2",
+ "eslint-plugin-react-refresh": "^0.4.7",
+ "vite": "^6.2.1"
+ }
+}
diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js
new file mode 100644
index 0000000..2e7af2b
--- /dev/null
+++ b/frontend/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/frontend/public/images/KJSCE-Logo.svg b/frontend/public/images/KJSCE-Logo.svg
new file mode 100644
index 0000000..0304aa0
--- /dev/null
+++ b/frontend/public/images/KJSCE-Logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/images/Trust.jpg b/frontend/public/images/Trust.jpg
new file mode 100644
index 0000000..e48d1f2
Binary files /dev/null and b/frontend/public/images/Trust.jpg differ
diff --git a/frontend/public/images/campus_bg.jpeg b/frontend/public/images/campus_bg.jpeg
new file mode 100644
index 0000000..660b421
Binary files /dev/null and b/frontend/public/images/campus_bg.jpeg differ
diff --git a/frontend/public/images/logo.jpeg b/frontend/public/images/logo.jpeg
new file mode 100644
index 0000000..7628248
Binary files /dev/null and b/frontend/public/images/logo.jpeg differ
diff --git a/frontend/src/App.css b/frontend/src/App.css
new file mode 100644
index 0000000..ce69dd1
--- /dev/null
+++ b/frontend/src/App.css
@@ -0,0 +1,25 @@
+#root {
+ margin: 0 auto;
+ padding: 0 auto;
+ text-align: center;
+}
+
+*::-webkit-scrollbar {
+ width: 10px;
+}
+
+*::-webkit-scrollbar-track {
+ background: #f1f1f1;
+}
+
+*::-webkit-scrollbar-thumb {
+ background: #888;
+}
+
+*::-webkit-scrollbar-thumb:hover {
+ background: #555;
+}
+
+.topLevelFormContainer::-webkit-scrollbar {
+ width: 0px;
+}
\ No newline at end of file
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
new file mode 100644
index 0000000..b8c5d06
--- /dev/null
+++ b/frontend/src/App.jsx
@@ -0,0 +1,76 @@
+import { createBrowserRouter, RouterProvider } from "react-router-dom";
+import React, { Suspense } from "react";
+import "./App.css";
+import { ToastContainer } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
+
+// Lazy loading the pages and components
+const Login = React.lazy(() => import("./pages/Login/Login"));
+const Root = React.lazy(() => import("./components/DashboardRoot/Root"));
+const Dashboard = React.lazy(() => import("./pages/Dashboard/Dashboard"));
+const Form = React.lazy(() => import("./pages/ApplicationForm/Form"));
+const About = React.lazy(() => import("./pages/About/About"));
+const Policy = React.lazy(() => import("./pages/Policy/Policy"));
+const Applications = React.lazy(() => import("./pages/Applications/Applications"));
+const Report = React.lazy(() => import("./pages/Report/Report"));
+const LoginRoot = React.lazy(() => import("./components/LoginRoot/LoginRoot"));
+const ContactUs = React.lazy(() => import("./pages/ContactUs/ContactUs"));
+const ApplicationView = React.lazy(() => import("./pages/ApplicationView/ApplicationView"));
+
+import userDataLoader from "./services/userDataLoader";
+import { upsertApplicationAction } from "./services/upsertApplicationAction";
+import { applicationStatusAction } from "./services/applicationStatusAction";
+import Loading from "./components/Loading";
+
+// Define the router with lazy-loaded components
+const router = createBrowserRouter([
+ {
+ path: "/",
+ element: ,
+ children: [
+ { index: true, element: },
+ { path: "about", element: },
+ { path: "policy", element: },
+ ],
+ },
+ {
+ path: "/applicant",
+ element: ,
+ id: "Applicant-Root",
+ loader: userDataLoader,
+ children: [
+ { path: "dashboard", element: },
+ { path: "dashboard/:status", element: },
+ { path: "dashboard/:status/:applicationId", element: , action: upsertApplicationAction },
+ { path: "form", element: , action: upsertApplicationAction },
+ { path: "contact-us", element: },
+ { path: "policy", element: },
+ ],
+ },
+ {
+ path: "/validator",
+ element: ,
+ id: "Validator-Root",
+ loader: userDataLoader,
+ children: [
+ { path: "dashboard", element: },
+ { path: "dashboard/:status", element: },
+ { path: "dashboard/:status/:applicationId", element: , action: applicationStatusAction },
+ { path: "report", element: },
+ { path: "policy", element: },
+ ],
+ },
+]);
+
+function App() {
+ return (
+ <>
+
+ }>
+
+
+ >
+ );
+}
+
+export default App;
diff --git a/frontend/src/assets/.keep b/frontend/src/assets/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/components/BaseData.jsx b/frontend/src/components/BaseData.jsx
new file mode 100644
index 0000000..58bf710
--- /dev/null
+++ b/frontend/src/components/BaseData.jsx
@@ -0,0 +1,141 @@
+const institutes = [
+ { label: "K J Somaiya Institute of Dharma Studies", value: "KJSIDS" },
+ { label: "S K Somaiya College", value: "SKSC" },
+ { label: "K J Somaiya College of Engineering", value: "KJSCE" },
+ { label: "Somaiya Institute for Research and Consultancy", value: "SIRC" },
+ { label: "K J Somaiya Institute of Management", value: "KJSIM" },
+ { label: "Somaiya Sports Academy", value: "SSA" },
+ { label: "K J Somaiya College of Education", value: "KJSCEd" },
+ { label: "Department of Library and Information Science", value: "DLIS" },
+ {
+ label: "Maya Somaiya School of Music and Performing Arts",
+ value: "MSSMPA",
+ },
+];
+
+const instituteDepartmentMapping = {
+ KJSIDS: [
+ { label: "Academics", value: "Academics" },
+ {
+ label: "Bharatiya Sanskriti Peetham",
+ value: "Bharatiya Sanskriti Peetham",
+ },
+ {
+ label: "Center for Studies in Jainism",
+ value: "Center for Studies in Jainism",
+ },
+ {
+ label: "Department of Ancient Indian History Culture and Archaeology",
+ value: "Department of Ancient Indian History Culture and Archaeology",
+ },
+ {
+ label: "Centre For Buddhist Studies",
+ value: "Centre For Buddhist Studies",
+ },
+ ],
+ SKSC: [
+ {
+ label: "Information Technology & Computer Science",
+ value: "Information Technology & Computer Science",
+ },
+ { label: "Mathematics & Statistics", value: "Mathematics & Statistics" },
+ { label: "Mass Communication", value: "Mass Communication" },
+ { label: "Life Science", value: "Life Science" },
+ { label: "Business Studies", value: "Business Studies" },
+ { label: "Polymer Science", value: "Polymer Science" },
+ {
+ label: "Commerce & Business Studies",
+ value: "Commerce & Business Studies",
+ },
+ { label: "Accounting & Finance", value: "Accounting & Finance" },
+ { label: "Commerce", value: "Commerce" },
+ { label: "Economics", value: "Economics" },
+ { label: "ENVIRONMENTAL SCIENCES", value: "ENVIRONMENTAL SCIENCES" },
+ { label: "Language & Literature", value: "Language & Literature" },
+ { label: "Computer Science & IT", value: "Computer Science & IT" },
+ { label: "SciSER", value: "SciSER" },
+ { label: "STATISTICS", value: "STATISTICS" },
+ { label: "International Studies", value: "International Studies" },
+ { label: "Banking & Finance", value: "Banking & Finance" },
+ { label: "Psychology", value: "Psychology" },
+ { label: "Financial Market", value: "Financial Market" },
+ { label: "NEUTRACEUTICALS", value: "NEUTRACEUTICALS" },
+ { label: "Faculty of Science - SVU", value: "Faculty of Science - SVU" },
+ ],
+ KJSCE: [
+ { label: "Mechanical", value: "Mechanical" },
+ { label: "Electronics", value: "Electronics" },
+ { label: "CBE", value: "CBE" },
+ {
+ label: "Electronics & Telecommunication",
+ value: "Electronics & Telecommunication",
+ },
+ { label: "Computer", value: "Computer" },
+ { label: "Information Technology", value: "Information Technology" },
+ { label: "Science & Humanities", value: "Science & Humanities" },
+ { label: "Admin", value: "Admin" },
+ { label: "Library", value: "Library" },
+ ],
+ SIRC: [
+ {
+ label: "Somaiya Institute for Research & Consultancy",
+ value: "Somaiya Institute for Research & Consultancy",
+ },
+ ],
+ KJSIM: [
+ {
+ label: "Marketing and International Business",
+ value: "Marketing and International Business",
+ },
+ {
+ label:
+ "General Management (Entrepreneurship, Business Communication, Strategy)",
+ value:
+ "General Management (Entrepreneurship, Business Communication, Strategy)",
+ },
+ { label: "IT", value: "IT" },
+ {
+ label: "Data Science and Technology",
+ value: "Data Science and Technology",
+ },
+ {
+ label: "HUMAN RESOURCES MANAGEMENT",
+ value: "HUMAN RESOURCES MANAGEMENT",
+ },
+ { label: "MBA-Sports Management", value: "MBA-Sports Management" },
+ { label: "HCM", value: "HCM" },
+ { label: "FINANCE AND LAW", value: "FINANCE AND LAW" },
+ { label: "Business Analytics", value: "Business Analytics" },
+ {
+ label: "PR, Social Media & Data Mining",
+ value: "PR, Social Media & Data Mining",
+ },
+ { label: "Economics", value: "Economics" },
+ {
+ label: "Operations and Supply Chain Management",
+ value: "Operations and Supply Chain Management",
+ },
+ { label: "Community Medicine", value: "Community Medicine" },
+ { label: "Accreditation", value: "Accreditation" },
+ { label: "Accounts & Finance", value: "Accounts & Finance" },
+ { label: "GENERAL ADMINISTRATION", value: "GENERAL ADMINISTRATION" },
+ { label: "Human Resource", value: "Human Resource" },
+ ],
+ SSA: [{ label: "Sports", value: "Sports" }],
+ KJSCEd: [{ label: "Education", value: "Education" }],
+ DLIS: [
+ {
+ label: "Department of Library & Information Science",
+ value: "Department of Library & Information Science",
+ },
+ ],
+ MSSMPA: [
+ {
+ label: "Maya Somaiya School of Music & Performing Art",
+ value: "Maya Somaiya School of Music & Performing Art",
+ },
+ ],
+ "": [],
+};
+
+export { institutes, instituteDepartmentMapping };
\ No newline at end of file
diff --git a/frontend/src/components/DashboardRoot/Navbar.jsx b/frontend/src/components/DashboardRoot/Navbar.jsx
new file mode 100644
index 0000000..2062cb1
--- /dev/null
+++ b/frontend/src/components/DashboardRoot/Navbar.jsx
@@ -0,0 +1,156 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import logo from "/images/logo.jpeg";
+import { IoNotifications, IoPerson } from "react-icons/io5";
+import Hamburger from "hamburger-react";
+import { FaSignOutAlt } from "react-icons/fa";
+
+const Navbar = ({ userData, sidebarIsVisible, setSidebarIsVisible }) => {
+ // Mouse cursor tracking for the pull-down effect
+ const [showNavbar, setShowNavbar] = useState(false);
+ const [isSmallScreen, setIsSmallScreen] = useState(false);
+
+ const handleLogout = async () => {
+ let res = await fetch(`${import.meta.env.VITE_APP_API_URL}/logout`, {
+ method: "GET",
+ credentials: "include",
+ });
+
+ return res;
+ };
+
+ const userDesignation = userData.designation;
+ const userName = userData.userName;
+
+ const [profileData] = useState({
+ name: userName,
+ university: "Somaiya Vidyavihar University",
+ role: userDesignation,
+ });
+
+ const links = [];
+
+ const handleResize = () => {
+ if (window.innerWidth < 768) {
+ setShowNavbar(true);
+ setIsSmallScreen(true);
+ } else {
+ setShowNavbar(false);
+ setIsSmallScreen(false);
+ }
+ };
+
+ useEffect(() => {
+ // Set initial visibility based on screen width
+ handleResize();
+
+ // Add event listener to handle resize
+ window.addEventListener("resize", handleResize);
+
+ // Cleanup the event listener on component unmount
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ };
+ }, []);
+
+ const handleMouseMove = (e) => {
+ if (e.clientY < 60 && !isSmallScreen) {
+ setShowNavbar(true);
+ } else {
+ setShowNavbar(false);
+ }
+ };
+
+ useEffect(() => {
+ // Add event listener for mousemove only for large screens
+ if (!isSmallScreen) {
+ window.addEventListener("mousemove", handleMouseMove);
+ }
+
+ // Clean up the event listener
+ return () => {
+ window.removeEventListener("mousemove", handleMouseMove);
+ };
+ }, [isSmallScreen]);
+
+ return (
+ <>
+
+ {/* Navbar with the pull-down effect */}
+
+
+
+ {/* Hamburger Menu for Mobile */}
+
+
+
+
+ {/* Logo for Desktop */}
+
+
+
+
+
+
+ {/* Navbar Links */}
+
+ {links?.map((link, index) => (
+
+
+ {link.label}
+
+ |
+
+ ))}
+
+
+ {/* Logout Button */}
+
+
+ {/* Logout icon */}
+
+ {/* Text hidden on small screens */}
+ Logout
+
+ |
+
+
+ {/* User Profile */}
+ {profileData.name && profileData.role && (
+
+
+
+
+ {profileData.name}
+
+
+ {`${userData.department} ${profileData.role} at ${userData.institute}`}
+
+
+
+ )}
+
+
+
+
+ >
+ );
+};
+
+export default Navbar;
diff --git a/frontend/src/components/DashboardRoot/Root.jsx b/frontend/src/components/DashboardRoot/Root.jsx
new file mode 100644
index 0000000..311e1d8
--- /dev/null
+++ b/frontend/src/components/DashboardRoot/Root.jsx
@@ -0,0 +1,46 @@
+import React, { useEffect, useState } from "react";
+import { Outlet, useLoaderData } from "react-router-dom";
+import Navbar from "./Navbar";
+import Sidebar from "./Sidebar";
+
+const Root = () => {
+ const { user, role } = useLoaderData()?.data;
+ const [sidebarIsVisible, setSidebarIsVisible] = useState(true)
+ const urlPath = window.location.pathname;
+
+
+ const handleResize = () => {
+ if (window.innerWidth < 768) {
+ setSidebarIsVisible(false); // Hide sidebar on small screens
+ } else {
+ setSidebarIsVisible(true); // Show sidebar on larger screens
+ }
+ };
+
+ useEffect(() => {
+ // Set initial visibility based on screen width
+ setSidebarIsVisible(window.innerWidth >= 768);
+
+ // Add event listener to handle resize
+ window.addEventListener("resize", handleResize);
+
+ // Cleanup the event listener on component unmount
+ return () => {
+ window.removeEventListener("resize", handleResize);
+ };
+ }, []);
+
+ return (
+
+
+
+ {sidebarIsVisible && !(urlPath.split("/").at(-1).includes("dashboard")) &&
}
+
+
+
+
+
+ );
+};
+
+export default Root;
diff --git a/frontend/src/components/DashboardRoot/Sidebar.jsx b/frontend/src/components/DashboardRoot/Sidebar.jsx
new file mode 100644
index 0000000..44f770f
--- /dev/null
+++ b/frontend/src/components/DashboardRoot/Sidebar.jsx
@@ -0,0 +1,258 @@
+import React from "react";
+import { FaSignOutAlt } from "react-icons/fa";
+import { Link, NavLink } from "react-router-dom";
+
+export const handleLogout = async () => {
+ let res = await fetch(`${import.meta.env.VITE_APP_API_URL}/logout`, {
+ method: "GET",
+ credentials: "include",
+ });
+
+ return res;
+};
+
+const Sidebar = ({ role }) => (
+
+
+
+
+ {`${role} Portal`}
+
+
+ Travel Policy SVU
+
+
+
+
+
+
+
+
+ `flex items-center text-gray-800 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-extrabold" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Dashboard
+
+
+
+
+
+
+ {" "}
+ Application Status
+
+
+
+
+ `flex items-center text-gray-600 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-black" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Pending
+
+
+
+
+ `flex items-center text-gray-600 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-black" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Accepted
+
+
+
+
+ `flex items-center text-gray-600 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-black" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Rejected
+
+
+
+
+
+ {role === "Applicant" ? (
+ <>
+
+
+ `flex items-center text-gray-800 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-extrabold" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Policy
+
+
+
+
+ `flex items-center text-gray-800 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-extrabold" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Contact Us
+
+
+ >
+ ) : (
+ //role = "Validator"
+ <>
+
+
+ `flex items-center text-gray-800 hover:text-white hover:bg-red-700 p-2 rounded ${
+ isActive ? "font-extrabold" : ""
+ }`
+ }
+ >
+
+
+ {" "}
+ Report
+
+
+ >
+ )}
+
+
+ {/* Spacer to push logout to the bottom */}
+
+
+
+ Logout
+
+
+
+);
+
+export default Sidebar;
diff --git a/frontend/src/components/ErrorComponent.jsx b/frontend/src/components/ErrorComponent.jsx
new file mode 100644
index 0000000..5cb95bb
--- /dev/null
+++ b/frontend/src/components/ErrorComponent.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { useRouteError } from 'react-router-dom';
+
+// Error component to display error messages
+const ErrorComponent = () => {
+ const error = useRouteError();
+ // Extracting status and message from the error
+ const status = error.status || 500;
+ const message = error.data.message || 'Something went wrong.';
+
+ return (
+
+
Error {status}
+
{message}
+
+ );
+};
+
+export default ErrorComponent;
diff --git a/frontend/src/components/Loading.jsx b/frontend/src/components/Loading.jsx
new file mode 100644
index 0000000..2e2bfae
--- /dev/null
+++ b/frontend/src/components/Loading.jsx
@@ -0,0 +1,13 @@
+import React from "react";
+import { TbLoader3 } from "react-icons/tb";
+
+function Loading() {
+ return (
+
+ );
+}
+
+export default Loading;
diff --git a/frontend/src/components/LoginRoot/LoginRoot.css b/frontend/src/components/LoginRoot/LoginRoot.css
new file mode 100644
index 0000000..269d670
--- /dev/null
+++ b/frontend/src/components/LoginRoot/LoginRoot.css
@@ -0,0 +1,94 @@
+/* login styles for the Navbar */
+.login-navbar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background-color: #f8f9fa;
+ padding: 10px 20px;
+ width: 100vw;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1000;
+}
+
+.login-navbar-brand .login-logo {
+ height: 45px;
+}
+
+@media (max-width: 768px) {
+ .login-navbar-brand .login-logo {
+ height: 25px;
+ }
+}
+
+.login-navbar-toggler {
+ display: none;
+ cursor: pointer;
+}
+
+.login-navbar-toggler-icon {
+ width: 30px;
+ height: 30px;
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+.login-navbar-collapse {
+ display: flex;
+ justify-content: flex-end;
+ flex-grow: 1;
+}
+
+.login-navbar-nav {
+ list-style: none;
+ display: flex;
+ margin: 0;
+ padding: 0;
+ justify-content: space-evenly;
+ align-items: center;
+}
+
+.login-nav-item {
+ margin-left: 20px;
+}
+
+.login-nav-link {
+ text-decoration: none;
+ color: #000;
+ font-size: 16px;
+}
+
+.login-nav-link.active {
+ font-weight: bold;
+ text-decoration: underline;
+}
+
+.login-trust-logo {
+ height: 40px;
+}
+
+@media (max-width: 768px) {
+ .login-navbar-toggler {
+ display: block;
+ }
+
+ .login-navbar-collapse {
+ display: none;
+ }
+
+ .login-navbar-collapse.show {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ }
+
+ .login-navbar-nav {
+ flex-direction: column;
+ width: 100%;
+ }
+
+ .login-nav-item {
+ margin-left: 0;
+ margin-bottom: 10px;
+ }
+}
diff --git a/frontend/src/components/LoginRoot/LoginRoot.jsx b/frontend/src/components/LoginRoot/LoginRoot.jsx
new file mode 100644
index 0000000..0bd7ad1
--- /dev/null
+++ b/frontend/src/components/LoginRoot/LoginRoot.jsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import { Outlet,NavLink } from 'react-router-dom';
+import './LoginRoot.css';
+
+//Navlinks to be used later & will be parent route for policy,services and login
+
+const LoginRoot = () => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ Policy
+
+
+ About
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+
+
+}
+
+export default LoginRoot;
diff --git a/frontend/src/components/Modal/Modal.jsx b/frontend/src/components/Modal/Modal.jsx
new file mode 100644
index 0000000..8396b61
--- /dev/null
+++ b/frontend/src/components/Modal/Modal.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+
+const Modal = ({ onClose, children }) => {
+ return (
+
+
e.stopPropagation()}
+ >
+
+
+ X
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export default Modal;
+
+
+
diff --git a/frontend/src/components/Pagination.jsx b/frontend/src/components/Pagination.jsx
new file mode 100644
index 0000000..bf868d6
--- /dev/null
+++ b/frontend/src/components/Pagination.jsx
@@ -0,0 +1,105 @@
+import React from 'react';
+
+function Pagination({ numOfItems, itemsPerPage = 10, currentPage, onPageChange }) {
+ const totalPages = Math.ceil(numOfItems / itemsPerPage);
+ const pages = Array.from({ length: totalPages }, (_, index) => index + 1);
+ const maxPageButtons = 5; // Maximum number of page buttons to display
+
+ const handlePrevious = () => {
+ if (currentPage > 1) onPageChange(currentPage - 1);
+ };
+
+ const handleNext = () => {
+ if (currentPage < totalPages) onPageChange(currentPage + 1);
+ };
+
+ const getPageButtons = () => {
+ if (totalPages <= maxPageButtons) {
+ return pages;
+ }
+
+ const half = Math.floor(maxPageButtons / 2);
+ let start = Math.max(1, currentPage - half);
+ let end = Math.min(totalPages, currentPage + half);
+
+ if (currentPage <= half) {
+ end = maxPageButtons;
+ } else if (currentPage + half >= totalPages) {
+ start = totalPages - maxPageButtons + 1;
+ }
+
+ return Array.from({ length: end - start + 1 }, (_, index) => start + index);
+ };
+
+ return (
+
+
+
+ Previous
+
+
+ Next
+
+
+
+
+
+
+ Showing {(currentPage - 1) * itemsPerPage + 1} to {Math.min(currentPage * itemsPerPage, numOfItems)} of {numOfItems} applications
+
+
+
+
+
+ Previous
+
+
+
+
+
+ {getPageButtons().map(page => (
+ onPageChange(page)}
+ aria-current={currentPage === page ? 'page' : undefined}
+ className={`relative inline-flex items-center px-4 py-2 text-sm font-semibold ${currentPage === page ? 'bg-red-700 text-white' : 'text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50'} focus:z-20 focus:outline-offset-0`}
+ >
+ {page}
+
+ ))}
+
+
+ Next
+
+
+
+
+
+
+
+
+ );
+}
+
+export default Pagination;
diff --git a/frontend/src/components/PdfViewer.jsx b/frontend/src/components/PdfViewer.jsx
new file mode 100644
index 0000000..53e9376
--- /dev/null
+++ b/frontend/src/components/PdfViewer.jsx
@@ -0,0 +1,25 @@
+// PdfViewer.js
+import React from "react";
+import Modal from "./Modal/Modal";
+
+function PdfViewer({ fileUrl, setIsModalOpen }) {
+ if (!fileUrl) {
+ return Loading PDF...
;
+ }
+
+ return (
+ setIsModalOpen(false)}>
+
+
+ PDF preview failed. Please{" "}
+
+ open the PDF
+ {" "}
+ in a new tab.
+
+
+
+ );
+}
+
+export default PdfViewer;
diff --git a/frontend/src/hooks/.keep b/frontend/src/hooks/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/index.css b/frontend/src/index.css
new file mode 100644
index 0000000..bd6213e
--- /dev/null
+++ b/frontend/src/index.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
new file mode 100644
index 0000000..54b39dd
--- /dev/null
+++ b/frontend/src/main.jsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.jsx'
+import './index.css'
+
+ReactDOM.createRoot(document.getElementById('root')).render(
+
+
+ ,
+)
diff --git a/frontend/src/pages/About/About.jsx b/frontend/src/pages/About/About.jsx
new file mode 100644
index 0000000..ce271e8
--- /dev/null
+++ b/frontend/src/pages/About/About.jsx
@@ -0,0 +1,145 @@
+import React from "react";
+
+const About = () => {
+ return (
+
+ {/* Hero Section */}
+
+
+
+
+ Welcome to Our Travel Policy
+
+
+ Structured, efficient, and research-focused travel planning.
+
+
+ Learn More
+
+
+
+
+ {/* Mission & Vision */}
+
+
+
Our Approach
+
+ Our travel policy for research students and associates ensures a
+ structured process for approvals and financial support, fostering
+ efficiency and alignment with academic and research objectives.
+
+
+
+
+
+
+
+ {/* Achievements & History */}
+
+
Policy Highlights
+
+ {[
+ {
+ title: "Travel Request Form",
+ description:
+ "Submit detailed forms including purpose, destination, budget, and supporting documentation.",
+ icon: "📄",
+ },
+ {
+ title: "Approval Process",
+ description:
+ "Supervisor, department head, and Office of Research must approve for major travels.",
+ icon: "✔️",
+ },
+ {
+ title: "Financial Support",
+ description:
+ "Eligibility depends on travel relevance, available funds, and research alignment.",
+ icon: "💰",
+ },
+ {
+ title: "Documentation",
+ description:
+ "Attach conference invitations or research collaboration letters for approval.",
+ icon: "📜",
+ },
+ {
+ title: "International Travel",
+ description:
+ "Managed through the Office of Research for additional oversight and funding.",
+ icon: "✈️",
+ },
+ {
+ title: "Funding Sources",
+ description:
+ "Includes department funds, institutional grants, or scholarships.",
+ icon: "🏛️",
+ },
+ ].map((item, index) => (
+
+
{item.icon}
+
{item.title}
+
{item.description}
+
+ ))}
+
+
+
+ {/* Why Choose Us */}
+
+
Why Our Policy Stands Out
+
+ {[
+ {
+ title: "Efficiency",
+ description: "Streamlined processes for quicker approvals.",
+ },
+ {
+ title: "Clarity",
+ description: "Clear guidelines for both students and staff.",
+ },
+ {
+ title: "Supportive",
+ description:
+ "Ensures financial and logistical aid for research-related travel.",
+ },
+ {
+ title: "Global Outlook",
+ description: "Facilitates international collaborations and exchanges.",
+ },
+ {
+ title: "Comprehensive",
+ description: "Covers all aspects of academic travel management.",
+ },
+ {
+ title: "Transparent",
+ description: "Approval criteria and funding sources clearly defined.",
+ },
+ ].map((item, index) => (
+
+
{item.title}
+
{item.description}
+
+ ))}
+
+
+
+ {/* Back to Top */}
+
+
+
+
+ );
+};
+
+export default About;
diff --git a/frontend/src/pages/ApplicationForm/Form.jsx b/frontend/src/pages/ApplicationForm/Form.jsx
new file mode 100644
index 0000000..f4b8fd0
--- /dev/null
+++ b/frontend/src/pages/ApplicationForm/Form.jsx
@@ -0,0 +1,204 @@
+import React, { useEffect, useState } from "react";
+import { Formik } from "formik";
+import Input from "./Input";
+import {
+ useSubmit,
+ useRouteLoaderData,
+ useNavigation,
+ useParams,
+} from "react-router-dom";
+import { studentFormFeilds, facultyFormFeilds } from "./FormFeilds";
+import * as yup from "yup";
+
+function Form({
+ prefilledData,
+ applicantDesignation,
+ resubmission = false,
+ onValuesChange,
+}) {
+ const { role, user } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+ const applicationId = useParams().applicationId || "";
+
+ const submit = useSubmit("upsertApplicationAction");
+ const navigation = useNavigation();
+ const isSubmittingNav = navigation.state === "submitting";
+ let formFeilds = [];
+ let toBeFormFeilds = [];
+ let designation;
+
+ const applicant = useRouteLoaderData("Applicant-Root");
+
+ if (applicantDesignation) {
+ designation = applicantDesignation;
+ } else {
+ designation = applicant?.data?.user?.designation; //Faculty or Student
+ }
+
+ if (designation === "STUDENT") {
+ toBeFormFeilds = studentFormFeilds;
+ } else {
+ toBeFormFeilds = facultyFormFeilds;
+ }
+
+ if (prefilledData) {
+ formFeilds = toBeFormFeilds?.map((section) => {
+ return {
+ ...section,
+ fields: section?.fields?.map((field) => ({
+ ...field,
+ disabled:
+ role === "Validator"
+ ? true
+ : resubmission && field?.name == "expenses"
+ ? false
+ : true,
+ })),
+ };
+ });
+ } else {
+ formFeilds = toBeFormFeilds;
+ }
+
+ const createIntialValuesScheme = (formFields) => {
+ const schema = {};
+
+ formFields?.forEach((section) => {
+ section?.fields?.forEach((field) => {
+ if (prefilledData) {
+ if (field.type === "miniForm") {
+ schema[field.name] = JSON.parse(prefilledData[field.name]);
+ } else if (field.type === "checkbox") {
+ schema[field.name] = JSON.parse(
+ prefilledData[field.name] || "false"
+ );
+ } else if (field.type === "number") {
+ schema[field.name] = parseInt(prefilledData[field.name]);
+ } else {
+ schema[field.name] = prefilledData[field.name];
+ }
+ } else if (field.type === "checkbox") {
+ schema[field.name] = false;
+ } else if (field.type === "miniForm") {
+ schema[field.name] = [];
+ } else {
+ schema[field.name] = "";
+ }
+ });
+ });
+
+ return schema;
+ };
+
+ const intialValuesSchema = createIntialValuesScheme(formFeilds);
+
+ const createValidationSchema = (formFields) => {
+ const schema = {};
+
+ formFields?.forEach((section) => {
+ section.fields?.forEach((field) => {
+ if (field.validation) {
+ schema[field.name] = field.validation;
+ }
+ });
+ });
+
+ return yup.object().shape(schema);
+ };
+
+ const validationSchema = createValidationSchema(formFeilds);
+
+ const handleSubmit = async (values, { setSubmitting }) => {
+ const formDataToSend = new FormData();
+
+ for (const key in values) {
+ if (key === "expenses") {
+ // Serialize the expenses array as a JSON string and append
+ const expenses = JSON.stringify(values[key]);
+ formDataToSend.append("expenses", expenses);
+
+ // Append expenseProof files separately (as file objects)
+ values[key].forEach((expense, index) => {
+ if (expense.expenseProof) {
+ formDataToSend.append(
+ `expenses[${index}].expenseProof`,
+ expense.expenseProof
+ );
+ }
+ });
+ } else {
+ // For other fields, just append normally
+ formDataToSend.append(key, values[key]);
+ }
+ }
+
+ formDataToSend.append("resubmission", resubmission);
+ formDataToSend.append("applicationId", applicationId);
+
+ try {
+ submit(formDataToSend, {
+ method: "POST",
+ encType: "multipart/form-data", // Specify the encoding type
+ });
+ } catch (error) {
+ console.error("Error uploading form:", error.message);
+ } finally {
+ setSubmitting(false); // Reset the submitting state after request is done
+ }
+ };
+
+ return (
+
+ {({
+ values,
+ errors,
+ touched,
+ handleChange,
+ handleBlur,
+ handleSubmit,
+ setFieldValue, // Use setFieldValue for file handling
+ isSubmitting,
+ }) => {
+ // Notify parent about values change
+ useEffect(() => {
+ if (onValuesChange) {
+ onValuesChange(values);
+ }
+ }, [values, onValuesChange]);
+
+ return (
+
+ );
+ }}
+
+ );
+}
+
+export default Form;
diff --git a/frontend/src/pages/ApplicationForm/FormFeilds.jsx b/frontend/src/pages/ApplicationForm/FormFeilds.jsx
new file mode 100644
index 0000000..31a3800
--- /dev/null
+++ b/frontend/src/pages/ApplicationForm/FormFeilds.jsx
@@ -0,0 +1,1107 @@
+import * as yup from "yup";
+import {
+ institutes,
+ instituteDepartmentMapping,
+} from "../../components/BaseData";
+
+const facultyFormFeilds = [
+ {
+ label: "Application Type",
+ fields: [
+ {
+ label: "Select Application Type",
+ name: "formName",
+ type: "dropdown",
+ options: {
+ "": [
+ {
+ label: "Travel Intimation Form",
+ value: "Travel Intimation Form",
+ },
+ { label: "Post Travel Form",
+ value: "Post Travel Form"
+ },
+ ],
+ },
+ validation: yup.string().notRequired("Application Type is notRequired"),
+ },
+ {
+ parent: { name: "formName", values: ["Travel Intimation Form"] },
+ label: "Advance Required",
+ name: "advanceRequired",
+ type: "checkbox",
+ },
+ {
+ parent: { name: "formName", values: ["Post Travel Form"] },
+ label: "Intimation Application ID",
+ name: "intimationApplicationID",
+ type: "text",
+ validation: yup.string().when("formName", {
+ is: "Post Travel Form",
+ then: (schema) => schema.required("Application ID is required"),
+ otherwise: (schema) => schema.notRequired(),
+ }),
+ },
+ ],
+ },
+ {
+ label: "Cadre Or Individual Application",
+ fields: [
+ {
+ label: "You are applying as Individual or Cadre?",
+ name: "applicationType",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Individual", value: "Individual" },
+ { label: "Cadre", value: "Cadre" },
+ ],
+ },
+ validation: yup.string().notRequired("Application Type is notRequired"),
+ },
+ {
+ parent: { name: "applicationType", values: ["Cadre"] },
+ label: "How many members are there in your cadre?",
+ name: "cadreSize",
+ type: "number",
+ max: 10,
+ min: 2,
+ validation: yup
+ .number()
+ .notRequired("Cadre Size is notRequired")
+ .min(2, "Cadre Size must be at least 2")
+ .max(10, "Cadre Size must be at most 10"),
+ },
+ ],
+ },
+ {
+ parent: { name: "applicationType", values: ["Individual"] },
+ label: "Personal and Academic Information",
+ fields: [
+ {
+ label: "Enter Full Name",
+ name: "applicantFullName",
+ type: "text",
+ validation: yup.string().notRequired("Full Name is notRequired"),
+ },
+ {
+ label: "Enter Age",
+ name: "applicantAge",
+ type: "number",
+ validation: yup
+ .number()
+ .notRequired("Age is notRequired")
+ .min(18, "Age must be at least 18"),
+ },
+ {
+ label: "Enter Contact Number",
+ name: "applicantContact",
+ type: "tel",
+ validation: yup
+ .string()
+ .notRequired("Contact Number is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ },
+ {
+ label: "Enter Address",
+ name: "applicantAddress",
+ type: "textarea",
+ validation: yup.string().notRequired("Address is notRequired"),
+ },
+ {
+ label: "Enter Email",
+ name: "applicantEmail",
+ type: "email",
+ validation: yup
+ .string()
+ .email("Invalid email format")
+ .notRequired("Email is notRequired"),
+ },
+ {
+ label: "Enter Faculty ID No",
+ name: "applicantIDNo",
+ type: "text",
+ validation: yup.string().notRequired("Roll No is notRequired"),
+ },
+ {
+ label: "Select Institute",
+ name: "applicantInstitute",
+ type: "dropdown",
+ options: {
+ "": institutes,
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ depend: "applicantInstitute",
+ label: "Select Department",
+ name: "applicantDepartment",
+ type: "dropdown",
+ options: instituteDepartmentMapping,
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ ],
+ },
+ ...Array.from({ length: 10 }, (_, i) => ({
+ parent: {
+ name: "cadreSize",
+ values: Array.from({ length: 10 }, (_, j) => Math.min(j + i + 1, 10)),
+ },
+ label: `Cadre Member ${i + 1} Personal and Academic Information`,
+ fields: [
+ {
+ label: `Enter Cadre Member ${i + 1} Full Name`,
+ name: `cadreMember${i + 1}FullName`,
+ type: "text",
+ validation: yup.string().notRequired("Full Name is notRequired"),
+ },
+ {
+ label: `Enter Cadre Member ${i + 1} Age`,
+ name: `cadreMember${i + 1}Age`,
+ type: "number",
+ validation: yup
+ .number()
+ .notRequired("Age is notRequired")
+ .min(18, "Age must be at least 18"),
+ },
+ {
+ label: `Enter Cadre Member ${i + 1} Contact Number`,
+ name: `cadreMember${i + 1}Contact`,
+ type: "tel",
+ validation: yup
+ .string()
+ .notRequired("Contact Number is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ },
+ {
+ label: `Enter Cadre Member ${i + 1} Address`,
+ name: `cadreMember${i + 1}Address`,
+ type: "textarea",
+ validation: yup.string().notRequired("Address is notRequired"),
+ },
+ {
+ label: `Enter Cadre Member ${i + 1} Email`,
+ name: `cadreMember${i + 1}Email`,
+ type: "email",
+ validation: yup
+ .string()
+ .email("Invalid email format")
+ .notRequired("Email is notRequired"),
+ },
+ {
+ label: `Enter Cadre Member ${i + 1} Faculty ID No`,
+ name: `cadreMember${i + 1}IDNo`,
+ type: "text",
+ validation: yup.string().notRequired("Roll No is notRequired"),
+ },
+ {
+ label: `Select Cadre Member ${i + 1} Institute`,
+ name: `cadreMember${i + 1}Institute`,
+ type: "dropdown",
+ options: {
+ "": institutes,
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ depend: `cadreMember${i + 1}Institute`,
+ label: `Select Cadre Member ${i + 1} Department`,
+ name: `cadreMember${i + 1}Department`,
+ type: "dropdown",
+ options: instituteDepartmentMapping,
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ ],
+ })),
+ {
+ label: "Travel Information",
+ fields: [
+ {
+ label: "Type of Travel",
+ name: "typeOfTravel",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Local", value: "Local" },
+ { label: "Domestic", value: "Domestic" },
+ { label: "International", value: "International" },
+ ],
+ },
+ validation: yup.string().notRequired("Type of Travel is not required"),
+ },
+ {
+ label: "Enter Purpose of Travel",
+ name: "purposeOfTravel",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Academic", value: "Academic" },
+ { label: "Conference", value: "Conference" },
+ { label: "Workshop", value: "Workshop" },
+ { label: "Research", value: "Research" },
+ { label: "Other", value: "Other" },
+ ],
+ },
+ validation: yup
+ .string()
+ .notRequired("Purpose of Travel is notRequired"),
+ },
+ {
+ parent: { name: "purposeOfTravel", values: ["Other"] },
+ label: "Enter Purpose of Travel (Other)",
+ name: "purposeOfTravelOther",
+ type: "text",
+ validation: yup.string().when("purposeOfTravel", {
+ is: "Other",
+ then: (schema) =>
+ schema.notRequired("Purpose of Travel (Other) is notRequired"),
+ }),
+ },
+ {
+ label: "Select Mode of Travel",
+ name: "modeOfTravel",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Air", value: "air" },
+ { label: "Train", value: "train" },
+ { label: "Bus", value: "bus" },
+ { label: "Car", value: "car" },
+ { label: "Other", value: "Other" },
+ ],
+ },
+ validation: yup.string().notRequired("Mode of Travel is notRequired"),
+ },
+ {
+ parent: { name: "modeOfTravel", values: ["Other"] },
+ label: "Enter Mode of Travel (Other)",
+ name: "modeOfTravelOther",
+ type: "text",
+ validation: yup.string().when("modeOfTravel", {
+ is: "Other",
+ then: (schema) =>
+ schema.notRequired("Mode of Travel (Other) is notRequired"),
+ }),
+ },
+ {
+ label: "Upload Proof of Travel",
+ name: "proofOfTravel",
+ type: "file",
+ validation: yup.mixed().notRequired("Proof of Travel is notRequired"),
+ // .test("fileType", "Only PDF files are allowed", (value) => {
+ // return value && value.type === "application/pdf";
+ // }),
+ },
+ {
+ label: "Travel Start Date",
+ name: "travelStartDate",
+ type: "date",
+ validation: yup
+ .date()
+ .notRequired("Start date is required")
+ .test(
+ "is-valid-start-date",
+ "Start date cannot be later than end date",
+ function (value) {
+ const { travelEndDate } = this.parent;
+ if (
+ travelEndDate &&
+ value &&
+ new Date(value) > new Date(travelEndDate)
+ ) {
+ return false;
+ }
+ return true;
+ }
+ ),
+ },
+ {
+ label: "Travel End Date",
+ name: "travelEndDate",
+ type: "date",
+ validation: yup
+ .date()
+ .notRequired("End date is required")
+ .test(
+ "is-valid-end-date",
+ "End date cannot be earlier than start date",
+ function (value) {
+ const { travelStartDate } = this.parent;
+ if (
+ travelStartDate &&
+ value &&
+ new Date(value) < new Date(travelStartDate)
+ ) {
+ return false;
+ }
+ return true;
+ }
+ ),
+ },
+ ],
+ },
+ {
+ label: "Accommodation Details",
+ fields: [
+ {
+ label: "Accommodation Opted?",
+ name: "accommodationOpted",
+ type: "checkbox",
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Select Type of Accommodation",
+ name: "typeOfAccommodation",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Hotel", value: "hotel" },
+ { label: "Guest House", value: "guest_house" },
+ { label: "Hostel", value: "hostel" },
+ {
+ label: "Own Arrangement (e.g., relative’s home)",
+ value: "private",
+ },
+ ],
+ },
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Type of Accommodation is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Enter Duration of Stay (In Days)",
+ name: "durationOfStay",
+ type: "number",
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Duration of Stay is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Enter Accommodation Address",
+ name: "accommodationAddress",
+ type: "textarea",
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Accommodation Address is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Upload Proof of Accommodation",
+ name: "proofOfAccommodation",
+ type: "file",
+ validation: yup.mixed().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Proof of Accommodation is notRequired"),
+ // .test("fileType", "Only PDF files are allowed", (value) => {
+ // return value && value.type === "application/pdf";
+ // }),
+ }),
+ },
+ ],
+ },
+ {
+ label: "Event/Conference Information",
+ fields: [
+ {
+ label: "Enter Event Name",
+ name: "eventName",
+ type: "text",
+ validation: yup.string().notRequired("Event Name is notRequired"),
+ },
+ {
+ label: "Enter Event Start Date",
+ name: "eventStartDate",
+ type: "date",
+ validation: yup.date().notRequired("Event Start Date is notRequired"),
+ },
+ {
+ label: "Enter Event End Date",
+ name: "eventEndDate",
+ type: "date",
+ validation: yup.date().notRequired("Event End Date is notRequired"),
+ },
+ {
+ label: "Enter Event Venue Address",
+ name: "eventVenue",
+ type: "textarea",
+ validation: yup.string().notRequired("Event Venue is notRequired"),
+ },
+ {
+ label: "Enter Event Website",
+ name: "eventWebsite",
+ type: "text",
+ validation: yup.string().notRequired("Event Website is notRequired"),
+ },
+ {
+ label: "Upload Proof of Attendance",
+ name: "proofOfAttendance",
+ type: "file",
+ validation: yup
+ .mixed()
+ .notRequired("Proof of Attendance is notRequired"),
+ // .test("fileType", "Only PDF files are allowed", (value) => {
+ // return value && value.type === "application/pdf";
+ // }),
+ },
+ ],
+ },
+ {
+ label: "Additional Information",
+ fields: [
+ {
+ label: "Enter Any Other Requirements",
+ name: "anyOtherRequirements",
+ type: "text",
+ validation: yup.string(),
+ },
+ ],
+ },
+ {
+ label: "Expense Details",
+ fields: [
+ {
+ label: "Total Expenses Incurred",
+ name: "expenses",
+ type: "miniForm",
+ validation: yup.array(),
+ },
+ ],
+ },
+];
+
+const studentFormFeilds = [
+ {
+ label: "Team Or Individual Application",
+ fields: [
+ {
+ label: "You are applying as Individual or Team?",
+ name: "applicationType",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Individual", value: "Individual" },
+ { label: "Team", value: "Team" },
+ ],
+ },
+ validation: yup.string().notRequired("Application Type is notRequired"),
+ },
+ {
+ parent: { name: "applicationType", values: ["Team"] },
+ label: "How many members are there in your team?",
+ name: "teamSize",
+ type: "number",
+ max: 10,
+ min: 2,
+ validation: yup
+ .number()
+ .notRequired("Team Size is notRequired")
+ .min(2, "Team Size must be at least 2")
+ .max(10, "Team Size must be at most 10"),
+ },
+ ],
+ },
+ {
+ parent: { name: "applicationType", values: ["Individual"] },
+ label: "Personal and Academic Information",
+ fields: [
+ {
+ label: "Enter Full Name",
+ name: "applicantFullName",
+ type: "text",
+ validation: yup.string().notRequired("Full Name is notRequired"),
+ },
+ {
+ label: "Enter Age",
+ name: "applicantAge",
+ type: "number",
+ validation: yup
+ .number()
+ .notRequired("Age is notRequired")
+ .min(0, "Age must be positive"),
+ },
+ {
+ label: "Enter Contact Number",
+ name: "applicantContact",
+ type: "tel",
+ validation: yup
+ .string()
+ .notRequired("Contact Number is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ },
+ {
+ label: "Enter Address",
+ name: "applicantAddress",
+ type: "text",
+ validation: yup.string().notRequired("Address is notRequired"),
+ },
+ {
+ label: "Select Course",
+ name: "applicantCourse",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "BTech", value: "BTech" },
+ { label: "MTech", value: "MTech" },
+ { label: "PHD", value: "PHD" },
+ ],
+ },
+ validation: yup.string().notRequired("Course selection is notRequired"),
+ },
+ {
+ depend: "applicantCourse",
+ label: "Enter Year of Study",
+ name: "applicantYearOfStudy",
+ type: "dropdown",
+ options: {
+ BTech: [
+ { label: "FY", value: "FY" },
+ { label: "SY", value: "SY" },
+ { label: "TY", value: "TY" },
+ { label: "LY", value: "LY" },
+ ],
+ MTech: [
+ { label: "FY", value: "FY" },
+ { label: "SY", value: "SY" },
+ ],
+ PHD: [],
+ "": [],
+ },
+ validation: yup.string().when("applicantCourse", {
+ is: "PHD",
+ then: (schema) => schema.notnotRequired(),
+ otherwise: (schema) =>
+ schema.notRequired("Year of Study is notRequired"),
+ }),
+ },
+ {
+ label: "Enter Email",
+ name: "applicantEmail",
+ type: "email",
+ validation: yup
+ .string()
+ .email("Invalid email format")
+ .notRequired("Email is notRequired"),
+ },
+ {
+ label: "Enter Roll No",
+ name: "applicantRollNo",
+ type: "text",
+ validation: yup
+ .string()
+ .notRequired("Roll No is notRequired")
+ .matches(/^\d{11}$/, "Roll No must be exactly 11 digits"),
+ },
+ {
+ label: "Select Institute",
+ name: "applicantInstitute",
+ type: "dropdown",
+ options: {
+ "": institutes.filter((institute) => institute?.value === "KJSCE"),
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ depend: "applicantInstitute",
+ label: "Select Department",
+ name: "applicantDepartment",
+ type: "dropdown",
+ options: instituteDepartmentMapping,
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ label: "Parental Consent?",
+ name: "parentalConsent",
+ type: "checkbox",
+ validation: yup.boolean().isFalse("Parent's Consent is notRequired"),
+ },
+ {
+ parent: { name: "parentalConsent", values: [true] },
+ label: "Enter Father's Full Name",
+ name: "fatherFullName",
+ type: "text",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Father's Full Name is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "parentalConsent", values: [true] },
+ label: "Enter Father's Contact",
+ name: "fatherContact",
+ type: "tel",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema
+ .notRequired("Father's Contact is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ }),
+ },
+ {
+ parent: { name: "parentalConsent", values: [true] },
+ label: "Enter Mother's Full Name",
+ name: "motherFullName",
+ type: "text",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Mother's Full Name is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "parentalConsent", values: [true] },
+ label: "Enter Mother's Contact",
+ name: "motherContact",
+ type: "tel",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema
+ .notRequired("Mother's Contact is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ }),
+ },
+ ],
+ },
+ ...Array.from({ length: 10 }, (_, i) => ({
+ parent: {
+ name: "teamSize",
+ values: Array.from({ length: 10 }, (_, j) => Math.min(j + i + 1, 10)),
+ },
+ label: `Team Member ${i + 1} Personal and Academic Information`,
+ fields: [
+ {
+ label: `Enter Team Member ${i + 1} Full Name`,
+ name: `teamMember${i + 1}FullName`,
+ type: "text",
+ validation: yup.string().notRequired("Full Name is notRequired"),
+ },
+ {
+ label: `Enter Team Member ${i + 1} Age`,
+ name: `teamMember${i + 1}Age`,
+ type: "number",
+ validation: yup
+ .number()
+ .notRequired("Age is notRequired")
+ .min(0, "Age must be positive"),
+ },
+ {
+ label: `Enter Team Member ${i + 1} Contact Number`,
+ name: `teamMember${i + 1}Contact`,
+ type: "tel",
+ validation: yup
+ .string()
+ .notRequired("Contact Number is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ },
+ {
+ label: `Enter Team Member ${i + 1} Address`,
+ name: `teamMember${i + 1}Address`,
+ type: "text",
+ validation: yup.string().notRequired("Address is notRequired"),
+ },
+ {
+ label: `Select Team Member ${i + 1} Course`,
+ name: `teamMember${i + 1}Course`,
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "BTech", value: "BTech" },
+ { label: "MTech", value: "MTech" },
+ { label: "PHD", value: "PHD" },
+ ],
+ },
+ validation: yup.string().notRequired("Course selection is notRequired"),
+ },
+ {
+ depend: `teamMember${i + 1}Course`,
+ label: `Enter Team Member ${i + 1} Year of Study`,
+ name: `teamMember${i + 1}YearOfStudy`,
+ type: "dropdown",
+ options: {
+ BTech: [
+ { label: "FY", value: "FY" },
+ { label: "SY", value: "SY" },
+ { label: "TY", value: "TY" },
+ { label: "LY", value: "LY" },
+ ],
+ MTech: [
+ { label: "FY", value: "FY" },
+ { label: "SY", value: "SY" },
+ ],
+ PHD: [],
+ "": [],
+ },
+ validation: yup.string().when(`teamMember${i + 1}Course`, {
+ is: "PHD",
+ then: (schema) => schema.notnotRequired(),
+ otherwise: (schema) =>
+ schema.notRequired("Year of Study is notRequired"),
+ }),
+ },
+ {
+ label: `Enter Team Member ${i + 1} Email`,
+ name: `teamMember${i + 1}Email`,
+ type: "email",
+ validation: yup
+ .string()
+ .email("Invalid email format")
+ .notRequired("Email is notRequired"),
+ },
+ {
+ label: `Enter Team Member ${i + 1} Roll No`,
+ name: `teamMember${i + 1}RollNo`,
+ type: "text",
+ validation: yup
+ .string()
+ .notRequired("Roll No is notRequired")
+ .matches(/^\d{11}$/, "Roll No must be exactly 11 digits"),
+ },
+ {
+ label: `Select Team Member ${i + 1} Institute`,
+ name: `teamMember${i + 1}Institute`,
+ type: "dropdown",
+ options: {
+ "": institutes.filter((institute) => institute?.value === "KJSCE"),
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ depend: `teamMember${i + 1}Institute`,
+ label: `Select Team Member ${i + 1} Department`,
+ name: `teamMember${i + 1}Department`,
+ type: "dropdown",
+ options: instituteDepartmentMapping,
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ label: `Parental Consent?`,
+ name: `parentalConsent${i + 1}`,
+ type: "checkbox",
+ validation: yup.boolean().isFalse("Parent's Consent is notRequired"),
+ },
+ {
+ parent: { name: `parentalConsent${i + 1}`, values: [true] },
+ label: `Enter Team Member ${i + 1} Father's Full Name`,
+ name: `teamMember${i + 1}FatherFullName`,
+ type: "text",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Father's Full Name is notRequired"),
+ }),
+ },
+ {
+ parent: { name: `parentalConsent${i + 1}`, values: [true] },
+ label: `Enter Team Member ${i + 1} Father's Contact`,
+ name: `teamMember${i + 1}FatherContact`,
+ type: "tel",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema
+ .notRequired("Father's Contact is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ }),
+ },
+ {
+ parent: { name: `parentalConsent${i + 1}`, values: [true] },
+ label: `Enter Team Member ${i + 1} Mother's Full Name`,
+ name: `teamMember${i + 1}MotherFullName`,
+ type: "text",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Mother's Full Name is notRequired"),
+ }),
+ },
+ {
+ parent: { name: `parentalConsent${i + 1}`, values: [true] },
+ label: `Enter Team Member ${i + 1} Mother's Contact`,
+ name: `teamMember${i + 1}MotherContact`,
+ type: "tel",
+ validation: yup.string().when("parentalConsent", {
+ is: true,
+ then: (schema) =>
+ schema
+ .notRequired("Mother's Contact is notRequired")
+ .matches(/^[0-9]{10}$/, "Contact Number must be 10 digits"),
+ }),
+ },
+ ],
+ })),
+ {
+ label: "Travel Information",
+ fields: [
+ {
+ label: "Enter Purpose of Travel",
+ name: "purposeOfTravel",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Academic", value: "Academic" },
+ { label: "Personal", value: "Personal" },
+ { label: "Research", value: "Research" },
+ { label: "Other", value: "Other" },
+ ],
+ },
+ validation: yup
+ .string()
+ .notRequired("Purpose of Travel is notRequired"),
+ },
+ {
+ parent: { name: "purposeOfTravel", values: ["Other"] },
+ label: "Enter Purpose of Travel (Other)",
+ name: "purposeOfTravelOther",
+ type: "text",
+ validation: yup.string().when("purposeOfTravel", {
+ is: "Other",
+ then: (schema) =>
+ schema.notRequired("Purpose of Travel (Other) is notRequired"),
+ }),
+ },
+ {
+ label: "Select Mode of Travel",
+ name: "modeOfTravel",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Air", value: "air" },
+ { label: "Train", value: "train" },
+ { label: "Bus", value: "bus" },
+ { label: "Car", value: "car" },
+ { label: "Other", value: "Other" },
+ ],
+ },
+ validation: yup.string().notRequired("Mode of Travel is notRequired"),
+ },
+ {
+ parent: { name: "modeOfTravel", values: ["Other"] },
+ label: "Enter Mode of Travel (Other)",
+ name: "modeOfTravelOther",
+ type: "text",
+ validation: yup.string().when("modeOfTravel", {
+ is: "Other",
+ then: (schema) =>
+ schema.notRequired("Mode of Travel (Other) is notRequired"),
+ }),
+ },
+ {
+ label: "Upload Proof of Travel",
+ name: "proofOfTravel",
+ type: "file",
+ validation: yup.mixed().notRequired("Proof of Travel is notRequired"),
+ },
+ {
+ label: "Travel Start Date",
+ name: "travelStartDate",
+ type: "date",
+ validation: yup
+ .date()
+ .notRequired("Start date is required")
+ .test(
+ "is-valid-start-date",
+ "Start date cannot be later than end date",
+ function (value) {
+ const { travelEndDate } = this.parent;
+ if (
+ travelEndDate &&
+ value &&
+ new Date(value) > new Date(travelEndDate)
+ ) {
+ return false;
+ }
+ return true;
+ }
+ ),
+ },
+ {
+ label: "Travel End Date",
+ name: "travelEndDate",
+ type: "date",
+ validation: yup
+ .date()
+ .notRequired("End date is required")
+ .test(
+ "is-valid-end-date",
+ "End date cannot be earlier than start date",
+ function (value) {
+ const { travelStartDate } = this.parent;
+ if (
+ travelStartDate &&
+ value &&
+ new Date(value) < new Date(travelStartDate)
+ ) {
+ return false;
+ }
+ return true;
+ }
+ ),
+ },
+ ],
+ },
+ {
+ label: "Accommodation Details",
+ fields: [
+ {
+ label: "Accommodation Opted?",
+ name: "accommodationOpted",
+ type: "checkbox",
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Select Type of Accommodation",
+ name: "typeOfAccommodation",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Hotel", value: "hotel" },
+ { label: "Guest House", value: "guest_house" },
+ { label: "Hostel", value: "hostel" },
+ {
+ label: "Own Arrangement (e.g., relative’s home)",
+ value: "private",
+ },
+ ],
+ },
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Type of Accommodation is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Enter Duration of Stay (In Days)",
+ name: "durationOfStay",
+ type: "number",
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Duration of Stay is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Enter Accommodation Address",
+ name: "accommodationAddress",
+ type: "textarea",
+ validation: yup.string().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Accommodation Address is notRequired"),
+ }),
+ },
+ {
+ parent: { name: "accommodationOpted", values: [true] },
+ label: "Upload Proof of Accommodation",
+ name: "proofOfAccommodation",
+ type: "file",
+ validation: yup.mixed().when("accommodationOpted", {
+ is: true,
+ then: (schema) =>
+ schema.notRequired("Proof of Accommodation is notRequired"),
+ // .test("fileType", "Only PDF files are allowed", (value) => {
+ // return value && value.type === "application/pdf";
+ // }),
+ }),
+ },
+ ],
+ },
+ {
+ label: "Event/Conference Information",
+ fields: [
+ {
+ label: "Enter Event Name",
+ name: "eventName",
+ type: "text",
+ validation: yup.string().notRequired("Event Name is notRequired"),
+ },
+ {
+ label: "Enter Event Start Date",
+ name: "eventStartDate",
+ type: "date",
+ validation: yup.date().notRequired("Event Start Date is notRequired"),
+ },
+ {
+ label: "Enter Event End Date",
+ name: "eventEndDate",
+ type: "date",
+ validation: yup.date().notRequired("Event End Date is notRequired"),
+ },
+ {
+ label: "Enter Event Venue Address",
+ name: "eventVenue",
+ type: "textarea",
+ validation: yup.string().notRequired("Event Venue is notRequired"),
+ },
+ {
+ label: "Enter Event Website",
+ name: "eventWebsite",
+ type: "text",
+ validation: yup.string().notRequired("Event Website is notRequired"),
+ },
+ {
+ label: "Upload Proof of Attendance",
+ name: "proofOfAttendance",
+ type: "file",
+ validation: yup
+ .mixed()
+ .notRequired("Proof of Attendance is notRequired"),
+ // .test("fileType", "Only PDF files are allowed", (value) => {
+ // return value && value.type === "application/pdf";
+ // }),
+ },
+ ],
+ },
+ {
+ label: "Additional Information",
+ fields: [
+ {
+ label: "Enter Any Other Requirements",
+ name: "anyOtherRequirements",
+ type: "text",
+ validation: yup.string(),
+ },
+ ],
+ },
+ {
+ label: "Expense Details",
+ fields: [
+ {
+ label: "Total Expenses Incurred",
+ name: "expenses",
+ type: "miniForm",
+ validation: yup.array(),
+ },
+ ],
+ },
+];
+
+export { studentFormFeilds, facultyFormFeilds };
diff --git a/frontend/src/pages/ApplicationForm/Input.jsx b/frontend/src/pages/ApplicationForm/Input.jsx
new file mode 100644
index 0000000..fcbe749
--- /dev/null
+++ b/frontend/src/pages/ApplicationForm/Input.jsx
@@ -0,0 +1,379 @@
+import React, { useEffect, useState } from "react";
+import { studentFormFeilds, facultyFormFeilds } from "./FormFeilds";
+import { useParams, useRouteLoaderData } from "react-router-dom";
+import ExpenseForm from "./components/ExpenseForm";
+import ExpenseTable from "./components/ExpenseTable";
+import PdfViewer from "../../components/PdfViewer";
+import PdfActions from "../ApplicationView/PdfActions";
+
+function Input({
+ values,
+ errors,
+ touched,
+ handleChange,
+ handleBlur,
+ setFieldValue,
+ formFeilds,
+}) {
+ const applicationId = useParams().applicationId;
+
+ const [showMiniFrom, setShowMiniForm] = useState(false);
+ const [expensesEditValues, setExpensesEditValues] = useState(null);
+ const [pdfIsVisible, setPdfIsVisible] = useState(false);
+ const [fileUrl, setFileUrl] = useState(null);
+
+ return formFeilds.map((section, sectionIndex) => {
+ if (
+ section?.parent?.name &&
+ !section?.parent?.values?.includes(values[section?.parent?.name])
+ ) {
+ section.fields.forEach((formFeild) => {
+ if (typeof values[formFeild?.name] === "boolean") {
+ values[formFeild.name] = false;
+ } else {
+ values[formFeild.name] = "";
+ }
+ });
+ return null;
+ }
+ return (
+
+
{section.label}
+
+ {section.fields.map((formFeild) => {
+ if (formFeild?.parent?.name) {
+ if (values[formFeild?.parent?.name] === false) {
+ typeof values[formFeild?.name] === "boolean"
+ ? (values[formFeild?.name] = false)
+ : (values[formFeild?.name] = "");
+ return null;
+ } else if (
+ typeof values[formFeild?.parent?.name] === "string" &&
+ !formFeild?.parent?.values.includes(
+ values[formFeild?.parent?.name]
+ )
+ ) {
+ typeof values[formFeild?.name] === "boolean"
+ ? (values[formFeild?.name] = false)
+ : (values[formFeild?.name] = "");
+ return null;
+ }
+ }
+
+ switch (formFeild.type) {
+ case "dropdown":
+ return (
+
+
+ {formFeild.label}
+
+
+
+ {formFeild.options[values[formFeild.depend] || ""].map(
+ (option) => (
+
+ {option.label}
+
+ )
+ )}
+
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+
+ );
+
+ case "checkbox":
+ return (
+
+
+
+ {formFeild.label}
+
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+
+ );
+
+ case "textarea":
+ return (
+
+
+ {formFeild.label}
+
+
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+
+ );
+
+ case "file":
+ return (
+
+
+ {formFeild.label}
+
+
+ {formFeild?.disabled ? (
+ values[formFeild.name] === "" ? (
+
No File Submitted
+ ) : (
+
+ )
+ ) : (
+ <>
+
{
+ setFieldValue(formFeild.name, e.target.files[0]);
+ }}
+ onBlur={handleBlur}
+ className="w-full bg-white px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-red-700 transition duration-300 ease-in-out"
+ />
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+ >
+ )}
+
+ );
+
+ case "miniForm":
+ return (
+
+ {pdfIsVisible && (
+
+ )}
+
+ {/* Label and Add Expense Button */}
+
+
+ {`${formFeild.label}: ₹${values[formFeild.name]
+ ?.reduce(
+ (total, rec) =>
+ total + parseFloat(rec.expenseAmount || 0),
+ 0
+ )
+ .toFixed(2)}`}
+ {/* {values[formFeild.name]
+ ?.reduce(
+ (total, rec) =>
+ total + parseFloat(rec.expenseAmount || 0),
+ 0
+ )
+ .toFixed(2) > 10000 && (
+ Warning: Limit Exceded
+ )} */}
+
+
+ {!formFeild?.disabled &&
+ (values[formFeild.name]?.length < 10 ? (
+
+ {setShowMiniForm(true); setExpensesEditValues(null)}}
+ >
+ Add Expense
+
+
+ ) : (
+
+ Cannot add more than 10 expenses
+
+ ))}
+
+
+ {/* Expense Form */}
+ {showMiniFrom && !formFeild?.disabled && (
+
setShowMiniForm(false)}
+ setExpenses={(newExpenses) =>
+ setFieldValue(formFeild.name, [
+ ...values[formFeild.name],
+ newExpenses,
+ ])
+ }
+ editExpense={(editedExpense) => {
+ setFieldValue(
+ formFeild.name,
+ values[formFeild.name].map((expense) =>
+ expense === expensesEditValues
+ ? editedExpense
+ : expense
+ )
+ );
+ }}
+ expenses={expensesEditValues}
+ />
+ )}
+
+ {/* Error Message */}
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+
+ {/* Display Expense Table */}
+ {values[formFeild.name]?.length > 0 && (
+
+
+ setFieldValue(
+ formFeild.name,
+ values[formFeild.name]?.filter(
+ (toDel) => toDel !== expense
+ )
+ )
+ }
+ editStatus={(expense, status) =>{
+ setFieldValue(
+ formFeild.name,
+ values[formFeild.name]?.map((toEdit) =>
+ toEdit === expense
+ ? { ...toEdit, proofStatus: status }
+ : toEdit
+ )
+ )}
+ }
+ editExpense={(expenseValues) => {setShowMiniForm(true); setExpensesEditValues(expenseValues)}}
+ disabled={formFeild?.disabled}
+ />
+
+ )}
+
+ );
+
+ default:
+ return (
+
+
+ {formFeild.label}
+
+
+
+ {errors[formFeild.name] &&
+ touched[formFeild.name] &&
+ errors[formFeild.name]}
+
+
+ );
+ }
+ })}
+
+
+ );
+ });
+}
+
+export default Input;
diff --git a/frontend/src/pages/ApplicationForm/components/ExpenseForm.jsx b/frontend/src/pages/ApplicationForm/components/ExpenseForm.jsx
new file mode 100644
index 0000000..610506e
--- /dev/null
+++ b/frontend/src/pages/ApplicationForm/components/ExpenseForm.jsx
@@ -0,0 +1,243 @@
+import React, { useEffect, useRef, useState } from "react";
+import Modal from "../../../components/Modal/Modal"; // Ensure your Modal is correctly imported
+
+// Validation function (manually written)
+const validateForm = (values) => {
+ const errors = {};
+
+ // Validate Expense Category
+ if (!values.expenseName) {
+ errors.expenseName = "Expense Category is required";
+ }
+
+ // Validate Expense Name
+ if (!values.expenseDetails) {
+ errors.expenseDetails = "Expense Name is required";
+ }
+
+ // Validate Expense Amount
+ if (!values.expenseAmount) {
+ errors.expenseAmount = "Expense Amount is required";
+ } else if (values.expenseAmount <= 0) {
+ errors.expenseAmount = "Amount must be positive";
+ } else if (values.expenseAmount < 1) {
+ errors.expenseAmount = "Amount must be at least 1";
+ }
+
+ // Validate Expense Proof
+ if (!values.expenseProof) {
+ errors.expenseProof = "Expense Proof is required";
+ } else {
+ // Validate file size and type
+ if (values.expenseProof.size > 1024 * 1024) {
+ errors.expenseProof = "File size too large (max 1MB)";
+ } else if (
+ !["image/jpeg", "image/png", "application/pdf"].includes(values.expenseProof.type)
+ ) {
+ errors.expenseProof = "Invalid file type. Only JPEG, PNG, and PDF are allowed.";
+ }
+ }
+
+ return errors;
+};
+
+const ExpenseForm = ({ onClose, setExpenses, editExpense, expenses = null }) => {
+ const fileInputRef = useRef(null);
+
+ const [values, setValues] = useState({
+ expenseName: "",
+ expenseDetails: "",
+ expenseAmount: "",
+ expenseProof: null,
+ });
+ const [errors, setErrors] = useState({});
+ const [touched, setTouched] = useState({
+ expenseName: false,
+ expenseDetails: false,
+ expenseAmount: false,
+ expenseProof: false,
+ });
+
+ useEffect(() => {
+ if (expenses) {
+ // If the expenses object contains a File, set it to the input
+ if (expenses.expenseProof && expenses.expenseProof instanceof File) {
+ const dataTransfer = new DataTransfer();
+ dataTransfer.items.add(expenses.expenseProof); // Add the file from expenses to DataTransfer
+ fileInputRef.current.files = dataTransfer.files; // Set files to the input
+ }
+
+ setValues(expenses); // Set the rest of the form data
+ }
+ }, [expenses]);
+
+ // Handle form input changes with error checking on each keystroke
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setValues((prevValues) => {
+ const updatedValues = { ...prevValues, [name]: value };
+
+ // Validate the field on every change
+ const validationErrors = validateForm(updatedValues);
+ setErrors(validationErrors);
+
+ return updatedValues;
+ });
+ };
+
+ // Handle file input change
+ const handleFileChange = (e) => {
+ const file = e.target.files[0];
+ setValues((prevValues) => {
+ const updatedValues = { ...prevValues, expenseProof: file };
+
+ // Validate the file field on change
+ const validationErrors = validateForm(updatedValues);
+ setErrors(validationErrors);
+
+ return updatedValues;
+ });
+ };
+
+ // Handle blur (mark field as touched)
+ const handleBlur = (e) => {
+ const { name } = e.target;
+ setTouched((prevTouched) => ({
+ ...prevTouched,
+ [name]: true,
+ }));
+ };
+
+ // Handle form submission
+ const handleSubmit = () => {
+ // Validate form before submission
+ const validationErrors = validateForm(values);
+ setErrors(validationErrors);
+
+ // If no errors, proceed with submission
+ if (Object.keys(validationErrors).length === 0) {
+ if (expenses) {
+ editExpense({
+ expenseId: expenses.expenseId,
+ expenseName: values.expenseName,
+ expenseDetails: values.expenseDetails,
+ expenseAmount: values.expenseAmount,
+ expenseProof: values.expenseProof,
+ })
+ } else {
+ setExpenses({
+ expenseId: crypto.randomUUID(),
+ expenseName: values.expenseName,
+ expenseDetails: values.expenseDetails,
+ expenseAmount: values.expenseAmount,
+ expenseProof: values.expenseProof,
+ });
+ }
+ onClose(); // Close the modal after submission
+ }
+ };
+
+ return (
+
+
+ {/* Expense Category */}
+
+
+ Expense Name
+
+
+ Select Category
+ Travel
+ Lodging
+ Boarding
+ Local Conveyance
+ Transportation
+ Registration
+ Miscellaneous
+
+ {errors.expenseName && (
+
{errors.expenseName}
+ )}
+
+
+ {/* Expense Name */}
+
+
+ Expense Details
+
+
+ {errors.expenseDetails && (
+
{errors.expenseDetails}
+ )}
+
+
+ {/* Expense Amount */}
+
+
+ Expense Amount
+
+
+ {errors.expenseAmount && (
+
{errors.expenseAmount}
+ )}
+
+
+ {/* Expense Proof (File Upload) */}
+
+
+ Expense Proof (Upload File)
+
+
+ {errors.expenseProof && (
+
{errors.expenseProof}
+ )}
+
+
+ {/* Submit Button */}
+
+
+ {expenses ? "Update" : "Add"} Expense
+
+
+
+
+ );
+};
+
+export default ExpenseForm;
diff --git a/frontend/src/pages/ApplicationForm/components/ExpenseTable.jsx b/frontend/src/pages/ApplicationForm/components/ExpenseTable.jsx
new file mode 100644
index 0000000..24f1f17
--- /dev/null
+++ b/frontend/src/pages/ApplicationForm/components/ExpenseTable.jsx
@@ -0,0 +1,277 @@
+import React, { useState } from "react";
+import { useTable } from "react-table";
+import axios from "axios";
+import {
+ MdDangerous,
+ MdDeleteOutline,
+ MdEdit,
+ MdVerified
+} from "react-icons/md";
+import PdfActions from "../../ApplicationView/PdfActions";
+import { useParams, useRouteLoaderData } from "react-router-dom";
+
+const ExpenseTable = ({
+ expenses,
+ setPdfIsVisible,
+ setFileUrl,
+ deleteExpense,
+ editExpense,
+ editStatus,
+ disabled,
+}) => {
+ const applicationId = useParams().applicationId;
+ const applicationStatus = useParams().status;
+ const { role } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+
+ // const handleExpenseAction = async (expense, action) => {
+ // try {
+ // await axios.put(
+ // `${import.meta.env.VITE_APP_API_URL}/validator/expenseAction`,
+ // { expense, action, applicationId },
+ // { withCredentials: true }
+ // );
+ // alert(`Proof ${action}`);
+ // window.location.reload();
+ // } catch (error) {
+ // console.error("Error performing expense action:", error);
+ // }
+ // };
+
+ const columns = React.useMemo(() => {
+ // Common columns
+ const baseColumns = [
+ {
+ Header: "Expense Name",
+ accessor: "expenseName",
+ },
+ {
+ Header: "Expense Details",
+ accessor: "expenseDetails",
+ },
+ {
+ Header: "Amount",
+ accessor: "expenseAmount",
+ Cell: ({ value }) => `₹${value}`,
+ },
+ {
+ Header: "Expense Proof",
+ accessor: "expenseProof",
+ Cell: ({ value, row }) => {
+ if (applicationId) {
+ return (
+
+ );
+ } else if (value && value.name) {
+ return (
+ {
+ setPdfIsVisible(true);
+ setFileUrl(URL.createObjectURL(value));
+ }}
+ className="text-blue-600 hover:text-blue-700 focus:outline-none"
+ >
+ View Document
+
+ );
+ }
+ return "No Document";
+ },
+ },
+ ];
+
+ // Add the "Delete" column only if 'disabled' is false
+ if (role === "Applicant" && !disabled) {
+ baseColumns.push({
+ Header: "Actions",
+ accessor: "actions",
+ Cell: ({ row }) => (
+ row?.original?.proofStatus != "verified" ?(
+
+
+ deleteExpense(row.original)}
+ className="bg-red-600 text-white py-2 px-3 rounded-lg hover:bg-red-700 transition-colors focus:outline-none"
+ >
+
+
+
+
+ editExpense(row.original)}
+ className="bg-blue-600 text-white py-2 px-3 rounded-lg hover:bg-blue-700 transition-colors focus:outline-none"
+ >
+
+
+
+
) : Approved
+ ),
+ });
+ }
+
+ if (role === "Validator") {
+ baseColumns.push({
+ Header: "Approval",
+ accessor: "approval",
+ Cell: ({ row }) => {
+ const isVerified = row?.original?.proofStatus === "verified";
+ const isRejected = row?.original?.proofStatus === "rejected";
+ const status = isVerified ? "verified" : isRejected ? "rejected" : "pending";
+ const [hoverSide, setHoverSide] = useState(null);
+
+ return (
+
+
+ {/* Status indicator text */}
+
+ Approved
+ Pending
+ Rejected
+
+
+ {/* Track background with hover effect */}
+
+ {/* Hover indicators */}
+ {hoverSide === 'left' && (
+
+ )}
+ {hoverSide === 'right' && (
+
+ )}
+
+ {/* Sliding knob */}
+
+ {status === "verified" && }
+ {status === "rejected" && }
+ {status === "pending" && ? }
+
+
+
+ {/* Clickable buttons overlaid on top */}
+
editStatus(row.original, "verified")}
+ onMouseEnter={() => setHoverSide('left')}
+ onMouseLeave={() => setHoverSide(null)}
+ className="absolute left-0 w-1/2 h-full opacity-0 z-20"
+ aria-label="Approve"
+ disabled={applicationStatus != "pending"}
+ />
+ editStatus(row.original, "rejected")}
+ onMouseEnter={() => setHoverSide('right')}
+ onMouseLeave={() => setHoverSide(null)}
+ className="absolute right-0 w-1/2 h-full opacity-0 z-20"
+ aria-label="Reject"
+ disabled={applicationStatus != "pending"}
+ />
+
+
+ {/* Status text */}
+
+ {status === "verified" ? "Expense Approved" :
+ status === "rejected" ? "Expense Rejected" :
+ "Click to change status"}
+
+
+ );
+ },
+ });
+ }
+
+ return baseColumns;
+ }, [deleteExpense, setPdfIsVisible, setFileUrl, disabled]);
+
+ // Using the useTable hook to create the table instance
+ const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
+ useTable({
+ columns,
+ data: expenses || [], // Data passed to the table
+ });
+
+ return (
+
+
+ Expense Breakdown
+
+
+ {/* Wrapping the table inside a scrollable div for responsiveness */}
+
+
+ {/* Table header */}
+
+ {headerGroups.map((headerGroup) => {
+ const { key, ...restHeaderProps } =
+ headerGroup.getHeaderGroupProps(); // Destructure `key` here
+ return (
+
+ {headerGroup.headers.map((column) => {
+ const { key, ...restColumnProps } = column.getHeaderProps(); // Destructure `key` here
+ return (
+
+ {column.render("Header")}
+
+ );
+ })}
+
+ );
+ })}
+
+
+ {/* Table body */}
+
+ {rows.map((row) => {
+ prepareRow(row);
+ const { key, ...restRowProps } = row.getRowProps(); // Destructure `key` here
+ return (
+
+ {row.cells.map((cell) => {
+ const { key, ...restCellProps } = cell.getCellProps(); // Destructure `key` here
+ return (
+
+ {cell.render("Cell")}
+
+ );
+ })}
+
+ );
+ })}
+
+
+
+
+ );
+};
+
+export default ExpenseTable;
diff --git a/frontend/src/pages/ApplicationView/AcceptChoice.jsx b/frontend/src/pages/ApplicationView/AcceptChoice.jsx
new file mode 100644
index 0000000..a6badbf
--- /dev/null
+++ b/frontend/src/pages/ApplicationView/AcceptChoice.jsx
@@ -0,0 +1,127 @@
+import React from "react";
+import Modal from "../../components/Modal/Modal";
+
+function AcceptChoice({
+ onClose,
+ onSubmit,
+ designation,
+ applicantDesignation,
+}) {
+ const handleSubmit = (toVC = false) => {
+ onSubmit(toVC);
+ onClose();
+ };
+
+ return (
+
+
+
+ Confirm Application Approval
+
+
+ {(() => {
+ switch (designation) {
+ case "FACULTY":
+ return "By approving, you will forward this application to the Head of Department (HOD).";
+ case "HOD":
+ return "By approving, you will forward this application to the Head of Institute (HOI).";
+ case "HOI":
+ if (applicantDesignation === "STUDENT") {
+ return "By approving, you will forward this application to Accounts.";
+ } else {
+ return "By approving, you can forward this application to either the Vice Chancellor (VC) or Accounts.";
+ }
+ case "VC":
+ return "By approving, you will forward this application to Accounts.";
+ case "ACCOUNTS":
+ return "By approving, you confirm that the given expenses will be paid by the institute.";
+ default:
+ return "";
+ }
+ })()}
+
+
+
+ {/* Cancel Button */}
+
+ Cancel
+
+
+ {(() => {
+ switch (designation) {
+ case "FACULTY":
+ return (
+
+ Approve
+
+ );
+ case "HOD":
+ return (
+
+ Approve
+
+ );
+ case "HOI":
+ return (
+
+ {applicantDesignation !== "STUDENT" && (
+ handleSubmit(true)}
+ type="button"
+ className="px-4 py-2 bg-blue-700 text-white rounded-lg hover:bg-blue-800 focus:outline-none"
+ >
+ Forward to VC
+
+ )}
+ handleSubmit(false)}
+ type="button"
+ className="px-4 py-2 bg-green-700 text-white rounded-lg hover:bg-green-800 focus:outline-none"
+ >
+ Forward to Accounts
+
+
+ );
+ case "VC":
+ return (
+
+ Forward to Accounts
+
+ );
+ case "ACCOUNTS":
+ return (
+
+ Approve
+
+ );
+ default:
+ return null;
+ }
+ })()}
+
+
+
+ );
+}
+
+export default AcceptChoice;
diff --git a/frontend/src/pages/ApplicationView/ApplicationView.jsx b/frontend/src/pages/ApplicationView/ApplicationView.jsx
new file mode 100644
index 0000000..9600193
--- /dev/null
+++ b/frontend/src/pages/ApplicationView/ApplicationView.jsx
@@ -0,0 +1,246 @@
+import React, { useEffect, useState } from "react";
+import {
+ useNavigate,
+ useParams,
+ useRouteLoaderData,
+ useSubmit,
+} from "react-router-dom";
+import ValidationStatus from "./ValidationStatus";
+import Form from "../ApplicationForm/Form";
+import RejectionFeedback from "./RejectionFeedback";
+import { TbLoader3 } from "react-icons/tb";
+import AcceptChoice from "./AcceptChoice";
+import { FaCopy } from "react-icons/fa";
+
+function ApplicationView() {
+ const { role, user } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+ const submit = useSubmit();
+ const navigate = useNavigate();
+
+ const [loading, setLoading] = useState(false);
+ const [applicationDisplay, setApplicationDisplay] = useState(null);
+ const [rejectionFeedbackPopUp, setRejectionFeedbackPopUp] = useState(false);
+ const [acceptChoicePopUp, setAcceptChoicePopUp] = useState(false);
+ const [copySuccess, setCopySuccess] = useState(false);
+
+ const [formValues, setFormValues] = useState({});
+
+ const applicationId = useParams().applicationId;
+ const statusParam = useParams().status;
+
+ const getFullApplication = async (applicationId) => {
+ try {
+ setLoading(true);
+ const response = await fetch(
+ `${
+ import.meta.env.VITE_APP_API_URL
+ }/general/getApplicationData/${applicationId}`,
+ {
+ method: "GET",
+ credentials: "include",
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(
+ `Failed to fetch application data: ${response.status} ${response.statusText}`
+ );
+ }
+ const fullApplication = await response.json();
+ setApplicationDisplay(fullApplication?.data);
+ } catch (error) {
+ console.error("Error fetching application data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const handleSubmit = (
+ applicationId,
+ action,
+ rejectionFeedback = "",
+ toVC = false,
+ resubmission = false
+ ) => {
+ try {
+ setLoading(true);
+ const formData = new FormData();
+ formData.append("applicationId", applicationId);
+ formData.append("action", action);
+ formData.append("rejectionFeedback", rejectionFeedback);
+ formData.append("toVC", toVC);
+ formData.append("resubmission", resubmission);
+
+ if (formValues && formValues?.expenses) {
+ formData.append("expenses", JSON.stringify(formValues.expenses));
+ }
+
+ submit(formData, {
+ method: "PUT",
+ encType: "multipart/form-data", // Specify the encoding type
+ });
+ } catch (error) {
+ console.error("Error during submit:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ // Navigation for status change
+ let currentStatus = applicationDisplay?.currentStatus?.toLowerCase();
+
+ useEffect(() => {
+ getFullApplication(applicationId);
+ }, [applicationId]);
+
+ useEffect(() => {
+ if (
+ (statusParam !== currentStatus && currentStatus) ||
+ (applicationId !== applicationDisplay?.applicationId &&
+ applicationDisplay?.applicationId)
+ ) {
+ const location = window.location.pathname;
+ const newPath = location.split("/").slice(0, -2).join("/");
+ navigate(
+ `${newPath}/${currentStatus}/${applicationDisplay?.applicationId}`
+ );
+ }
+ }, [statusParam, currentStatus, applicationDisplay]);
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ let title = applicationDisplay?.formData?.eventName;
+
+ if (!applicationDisplay) return null;
+
+ const copyToClipboard = () => {
+ navigator.clipboard.writeText(applicationId)
+ .then(() => {
+ setCopySuccess(true);
+ setTimeout(() => setCopySuccess(false), 2000);
+ })
+ .catch(err => {
+ console.error("Failed to copy application ID: ", err);
+ alert("Failed to copy application ID. Please try again.");
+ });
+ };
+
+ // Check if this is a Travel Intimation Form
+ const isTravelIntimationForm = applicationDisplay?.formData?.formName === "Travel Intimation Form";
+
+ return (
+
+
+
+
{title}
+
+ {isTravelIntimationForm && (
+
+ {copySuccess ? (
+ <>
+ ✓
+ Copied!
+ >
+ ) : (
+ <>
+
+ Copy ID
+ >
+ )}
+
+ )}
+
+
+
+
+
+ );
+}
+
+export default ApplicationView;
diff --git a/frontend/src/pages/ApplicationView/PdfActions.jsx b/frontend/src/pages/ApplicationView/PdfActions.jsx
new file mode 100644
index 0000000..3c209e6
--- /dev/null
+++ b/frontend/src/pages/ApplicationView/PdfActions.jsx
@@ -0,0 +1,81 @@
+// PdfActions.js
+import React, { useState } from "react";
+import axios from "axios";
+import Modal from "../../components/Modal/Modal.jsx";
+import PdfViewer from "../../components/PdfViewer.jsx";
+import { FaFileDownload } from "react-icons/fa";
+
+function PdfActions({ fileName, applicationId }) {
+ const [fileUrl, setFileUrl] = useState(null);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+
+ const fetchFileBlob = async () => {
+ try {
+ const response = await axios.get(
+ `${
+ import.meta.env.VITE_APP_API_URL
+ }/general/getFile/${applicationId}/${fileName}`,
+ {
+ responseType: "blob",
+ withCredentials: true,
+ }
+ );
+
+ if (response.data.type !== "application/pdf") {
+ throw new Error("Invalid file format received.");
+ }
+
+ const blob = new Blob([response.data], { type: "application/pdf" });
+ const url = URL.createObjectURL(blob);
+ setFileUrl(url);
+
+ return () => URL.revokeObjectURL(url); // Clean up URL when component unmounts
+ } catch (error) {
+ console.error("Error fetching PDF:", error);
+ }
+ };
+
+ const handleView = async () => {
+ if (!fileUrl) await fetchFileBlob(); // Only fetch if fileUrl is not set
+ setIsModalOpen(true);
+ };
+
+ const handleDownload = async () => {
+ if (!fileUrl) await fetchFileBlob(); // Only fetch if fileUrl is not set
+
+ const link = document.createElement("a");
+ link.href = fileUrl;
+ link.setAttribute("download", `${fileName}.pdf`);
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
+
+ return (
+
+
+ View PDF
+
+
+
+
+ Download PDF
+
+
+ {/* Modal to view PDF */}
+ {isModalOpen && fileUrl && (
+
+ )}
+
+ );
+}
+
+export default PdfActions;
diff --git a/frontend/src/pages/ApplicationView/RejectionFeedback.jsx b/frontend/src/pages/ApplicationView/RejectionFeedback.jsx
new file mode 100644
index 0000000..89e63b9
--- /dev/null
+++ b/frontend/src/pages/ApplicationView/RejectionFeedback.jsx
@@ -0,0 +1,58 @@
+import React, { useState } from 'react';
+import Modal from '../../components/Modal/Modal';
+import { MdOutlineSettingsInputHdmi } from 'react-icons/md';
+
+function RejectionFeedback({ onClose, onSubmit }) {
+ const [reason, setReason] = useState('');
+
+ const handleChange = (e) => {
+ setReason(e.target.value);
+ };
+
+ const handleSubmit = (e, resubmission = false) => {
+ e.preventDefault();
+ onSubmit(reason, resubmission);
+ onClose();
+ };
+
+ return (
+
+
+
Confirm Application Rejection
+
+ Please provide a reason for rejecting the application. This will help the applicant to improve future applications.
+
+
+
+
+
+ );
+}
+
+export default RejectionFeedback;
diff --git a/frontend/src/pages/ApplicationView/ValidationStatus.jsx b/frontend/src/pages/ApplicationView/ValidationStatus.jsx
new file mode 100644
index 0000000..9efb5eb
--- /dev/null
+++ b/frontend/src/pages/ApplicationView/ValidationStatus.jsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { MdWarning } from "react-icons/md";
+
+function ValidationStatus({ validations, rejectionFeedback }) {
+
+ const roles = [
+ { name: "FACULTY", status: validations.facultyValidation },
+ { name: "HOD", status: validations.hodValidation },
+ { name: "HOI", status: validations.hoiValidation },
+ { name: "VC", status: validations.vcValidation },
+ { name: "ACCOUNTS", status: validations.accountsValidation },
+ ];
+
+ const getStatusColor = (status) => {
+ switch (status) {
+ case "ACCEPTED":
+ return "bg-green-300";
+ case "REJECTED":
+ return "bg-red-300";
+ default:
+ return "bg-yellow-300";
+ }
+ };
+
+ return (
+
+
+ {roles
+ .filter((role) => role.status !== null) // Exclude roles with null status
+ .map((role, index) => (
+
+ ))}
+
+
+ {rejectionFeedback && (
+
+
+
{rejectionFeedback}
+
+ )}
+
+ );
+}
+
+export default ValidationStatus;
diff --git a/frontend/src/pages/Applications/Applications.jsx b/frontend/src/pages/Applications/Applications.jsx
new file mode 100644
index 0000000..91cd52a
--- /dev/null
+++ b/frontend/src/pages/Applications/Applications.jsx
@@ -0,0 +1,112 @@
+import React, { useState, useEffect, useCallback } from "react";
+import { useParams, useRouteLoaderData } from "react-router-dom";
+import ApplicationTable from "../Applications/components/ApplicationTable";
+import Pagination from "../../components/Pagination";
+import axios from "axios";
+import ApplicationView from "../ApplicationView/ApplicationView";
+import ApplicationsStatusDescription from "./components/ApplicationsStatusDescription";
+import Search from "./components/Search";
+import Modal from "../../components/Modal/Modal";
+import Root from "../../components/DashboardRoot/Root";
+import { TbLoader3 } from "react-icons/tb";
+
+const Applications = () => {
+ const { role } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+ const [numOfApplications, setNumOfApplications] = useState(0);
+ const [applications, setApplications] = useState([]);
+ const [applicantName, setApplicantName] = useState("");
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [applicationDisplay, setApplicationDisplay] = useState(null);
+ const [currentPage, setCurrentPage] = useState(1);
+ const itemsPerPage = 4;
+ const { status } = useParams();
+
+ // Reset currentPage when status changes
+ useEffect(() => {
+ setCurrentPage(1);
+ }, [status]);
+
+ // Fetch applications based on status, pagination, and search criteria
+ useEffect(() => {
+ const fetchApplications = async () => {
+ setLoading(true);
+ try {
+ const skip = (currentPage - 1) * itemsPerPage;
+ const res = await axios.get(
+ `${
+ import.meta.env.VITE_APP_API_URL
+ }/general/getApplications/${status}?take=${itemsPerPage}&skip=${skip}${
+ applicantName
+ ? `&sortBy=applicantName&sortValue=${applicantName}`
+ : ""
+ }`,
+ { withCredentials: true }
+ );
+ setNumOfApplications(res.data.totalApplications);
+ setApplications(res.data.applications);
+ } catch (err) {
+ console.error(err);
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+ fetchApplications();
+ }, [status, currentPage, applicantName]);
+
+ const handlePageChange = (page) => {
+ setCurrentPage(page);
+ };
+
+ const handleSelect = useCallback((selection) => {
+ setApplicantName(selection); // Update search criteria only when selection is finalized
+ }, []);
+
+ const renderTable = () =>
+ applications.length > 0 ? (
+
+ ) : (
+
+ No {status.toLowerCase()} applications found.
+
+ );
+
+ if (loading) {
+ return (
+
+ );
+ }
+ if (error) return Error: {error}
;
+
+ return (
+
+
+
+
+ {role === "Validator" && (
+
+ )}
+ {renderTable()}
+
+
+
+ );
+};
+
+export default Applications;
diff --git a/frontend/src/pages/Applications/components/ApplicationTable.jsx b/frontend/src/pages/Applications/components/ApplicationTable.jsx
new file mode 100644
index 0000000..472353e
--- /dev/null
+++ b/frontend/src/pages/Applications/components/ApplicationTable.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+
+const ApplicationTable = ({ title, applications,}) => {
+
+ const navigate = useNavigate();
+
+ return (
+
+ {/*
{title} */}
+
+
+
+ Topic
+ Name
+ Submitted
+ Branch
+ Status
+
+
+
+ {applications.map((app, index) => (
+ onRowClick({ ...app, currentStatus: title.split(" ")[0] })}
+ onClick={() => {
+ const location = window.location.pathname;
+ const newPath = location.split('/').slice(0, -1).join('/');
+ navigate(`${newPath}/${title.split(" ")[0]?.toLowerCase()}/${app.applicationId}`);
+ }}
+ className="odd:bg-gray-50 even:bg-white hover:bg-gray-200 cursor-pointer"
+ style={{ height: '50px' }}
+ >
+ {app.formData.eventName}
+ {app.applicantName}
+ {formatDateToDDMMYYYY(app.createdAt)}
+ {app.formData.applicantDepartment}
+ {title.split(" ")[0]}
+
+ ))}
+
+
+
+ );
+};
+
+export default ApplicationTable;
+
+function formatDateToDDMMYYYY(dateString) {
+ // Convert the ISO string to a Date object
+ const date = new Date(dateString);
+
+ // Extract the day, month, and year
+ const day = String(date.getDate()).padStart(2, '0'); // Ensures two-digit format
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-based, so add 1
+ const year = date.getFullYear();
+
+ // Format the date as dd/mm/yyyy
+ return `${day}/${month}/${year}`;
+}
diff --git a/frontend/src/pages/Applications/components/ApplicationsStatusDescription.jsx b/frontend/src/pages/Applications/components/ApplicationsStatusDescription.jsx
new file mode 100644
index 0000000..f80ea6b
--- /dev/null
+++ b/frontend/src/pages/Applications/components/ApplicationsStatusDescription.jsx
@@ -0,0 +1,51 @@
+import React from "react";
+import { useNavigate, useParams, useRouteLoaderData } from "react-router-dom";
+
+function ApplicationsStatusDescription() {
+ const { role } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+ const navigate = useNavigate();
+ const { status } = useParams();
+
+ return (
+
+
+
+ {`${status.toUpperCase()} APPLICATIONS`}
+
+ {role === "Applicant" && (
+
navigate("../form")}
+ className="flex items-center bg-gradient-to-r from-red-600 to-red-800 hover:from-red-800 hover:to-red-600 text-white font-semibold py-2 px-4 rounded-lg shadow-lg transform transition duration-300 ease-in-out hover:scale-105"
+ >
+
+
+
+ Create New Application
+
+ )}
+
+
+ Easily track the details and statuses of all your submitted applications
+ in one place.
+
+ Stay updated and manage your applications with ease.
+
+
+ );
+}
+
+export default ApplicationsStatusDescription;
diff --git a/frontend/src/pages/Applications/components/Search.jsx b/frontend/src/pages/Applications/components/Search.jsx
new file mode 100644
index 0000000..ef419f6
--- /dev/null
+++ b/frontend/src/pages/Applications/components/Search.jsx
@@ -0,0 +1,59 @@
+import React, { useEffect, useState } from "react";
+import ReactSearchBox from "react-search-box";
+import axios from "axios";
+
+let applicantNamesCache = null;
+
+const Search = ({ value, setValue }) => {
+ const [applicantNames, setApplicantNames] = useState([
+ { key: "", value: "" },
+ ]);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ async function getApplicants() {
+ setIsLoading(true);
+ if (!applicantNamesCache) {
+ try {
+ const res = await axios.get(
+ `${import.meta.env.VITE_APP_API_URL}/validator/getApplicantNames`,
+ { withCredentials: true }
+ );
+ if (res.status === 200) {
+ applicantNamesCache = res.data;
+ }
+ } catch (error) {
+ console.error("Error fetching applicant names:", error);
+ }
+ }
+ setApplicantNames(applicantNamesCache);
+ setIsLoading(false);
+ }
+ getApplicants();
+ }, []);
+
+ if (isLoading) return Loading search suggestions...
;
+
+ return (
+
+
+
+ setValue(record.item.value)}
+ clearOnSelect={false}
+ inputFontSize="large"
+ fuseConfigs={{ ignoreLocation: true, threshold: 0.3 }}
+ />
+
+
setValue("")}>
+ Clear
+
+
+ {value !== "" &&
{`Showing Results for ${value}`}
}
+
+ );
+};
+
+export default Search;
diff --git a/frontend/src/pages/ContactUs/ContactUs.jsx b/frontend/src/pages/ContactUs/ContactUs.jsx
new file mode 100644
index 0000000..1deb146
--- /dev/null
+++ b/frontend/src/pages/ContactUs/ContactUs.jsx
@@ -0,0 +1,124 @@
+import React, { useState } from "react";
+
+function ContactUs() {
+ const [formSubmitted, setFormSubmitted] = useState(false);
+ const [formError, setFormError] = useState(false);
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ // Simulating form submission
+ setTimeout(() => {
+ setFormSubmitted(true);
+ }, 1000);
+ };
+
+ return (
+
+ {/* Hero Section */}
+
+
+
+
Get in Touch with Us
+
We’re eager to hear from prospective students, parents, and alumni.
+
Contact Us
+
+
+
+ {/* Contact Form */}
+
+
+ {/* Location Map */}
+
+
+ {/* Contact Details */}
+
+
+
+
Contact Details
+
+ Address: K. J. Somaiya College of Engineering, Vidya Nagar, Mumbai, India
+
+
+ Phone: (022) 6728 8000
+
+
+ Email: info@somaiya.edu
+
+
+
+
+
+
+ );
+}
+
+export default ContactUs;
\ No newline at end of file
diff --git a/frontend/src/pages/Dashboard/Dashboard.jsx b/frontend/src/pages/Dashboard/Dashboard.jsx
new file mode 100644
index 0000000..a350872
--- /dev/null
+++ b/frontend/src/pages/Dashboard/Dashboard.jsx
@@ -0,0 +1,167 @@
+import React from "react";
+import { useNavigate, useRouteLoaderData } from "react-router-dom";
+
+function Dashboard() {
+ const { role, user } =
+ useRouteLoaderData("Applicant-Root")?.data ||
+ useRouteLoaderData("Validator-Root")?.data;
+
+ const navigate = useNavigate();
+
+ const { userName, designation, department, institute } = user;
+
+ // Personalized greeting message (updated for professionalism and animation)
+ const greetingLine1 = `Hello, ${userName}!`;
+ const greetingLine2 = `${designation} in ${department} Department, ${institute}`;
+
+ return (
+
+ {/* Hero Section */}
+
+
+
+
+ {greetingLine1}
+
+
+ {greetingLine2}
+
+
+
+ {role === "Applicant"
+ ? "Submit and track your funding applications with ease."
+ : "Review, validate, and manage applications efficiently."}
+
+
+ {role === "Applicant" && (
+
navigate("../form")}
+ className="px-3 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-white text-red-700 font-bold text-lg sm:text-base md:text-lg rounded-lg shadow-xl hover:bg-red-100 hover:scale-110 transition-all transform"
+ >
+ Start a New Application
+
+ )}
+ {role === "Validator" && (
+
navigate("../dashboard/pending")}
+ className="px-3 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-white text-red-700 font-bold text-lg sm:text-base md:text-lg rounded-lg shadow-xl hover:bg-red-100 hover:scale-110 transition-all transform"
+ >
+ Check For New Applications
+
+ )}
+
+
+
+
+ {/* Features Section */}
+
+
+ Our Key Features
+
+
+ {/* Feature 1 */}
+
+
🔍
+
+ View Your Applications
+
+
+ {role === "Applicant"
+ ? "Manage and track the status of your funding applications. Review feedback and make necessary updates."
+ : "Review and validate applications submitted by applicants. Approve or reject based on eligibility and guidelines."}
+
+
+ navigate("../dashboard/pending")
+ }
+ className="px-6 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-red-700 text-white font-semibold text-lg sm:text-base md:text-lg rounded-lg hover:bg-red-600 transition-all transform hover:scale-110 shadow-md"
+ >
+ {role === "Applicant" ? "View Status" : "Review Application"}
+
+
+
+ {/* Feature 2 */}
+ {role === "Validator" && (
+
+
📊
+
+ View Insights
+
+
+ Analyze and gain insights about funding and related data.
+
+
navigate("../report")}
+ className="px-6 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-red-700 text-white font-semibold text-lg sm:text-base md:text-lg rounded-lg hover:bg-red-600 transition-all transform hover:scale-110 shadow-md"
+ >
+ View Insights
+
+
+ )}
+
+ {/* Feature 3 */}
+ {role === "Applicant" && (
+
+
📝
+
+ Create New Application
+
+
+ Start your application process to apply for funding and
+ financial assistance.
+
+
navigate("../form")}
+ className="px-6 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-red-700 text-white font-semibold text-lg sm:text-base md:text-lg rounded-lg hover:bg-red-600 transition-all transform hover:scale-110 shadow-md"
+ >
+ Start Application
+
+
+ )}
+
+ {/* Feature 4 */}
+
+
📚
+
+ Understand the Policy
+
+
+ Learn about the eligibility, funding process, and guidelines for
+ financial assistance.
+
+
navigate("../policy")}
+ className="px-6 py-3 sm:px-5 sm:py-2 md:px-6 md:py-3 bg-red-700 text-white font-semibold text-lg sm:text-base md:text-lg rounded-lg hover:bg-red-600 transition-all transform hover:scale-110 shadow-md"
+ >
+ Learn More
+
+
+
+
+
+ {/* Footer Section */}
+
+
+ );
+}
+
+export default Dashboard;
diff --git a/frontend/src/pages/Login/Login.css b/frontend/src/pages/Login/Login.css
new file mode 100644
index 0000000..65e4966
--- /dev/null
+++ b/frontend/src/pages/Login/Login.css
@@ -0,0 +1,33 @@
+/* General styles for login page */
+.login-page {
+ position: relative;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.login {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+}
+
+.loginPage_bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ object-fit:cover;
+ z-index: -1;
+ opacity: 0.6;
+}
+
+.login-container {
+ margin: 2rem;
+}
diff --git a/frontend/src/pages/Login/Login.jsx b/frontend/src/pages/Login/Login.jsx
new file mode 100644
index 0000000..e8d6b28
--- /dev/null
+++ b/frontend/src/pages/Login/Login.jsx
@@ -0,0 +1,37 @@
+import React, { useState } from 'react';
+
+import './Login.css';
+import loginPageBg from '/images/campus_bg.jpeg';
+import 'bootstrap/dist/css/bootstrap.min.css';
+import ApplicantLogin from './components/ApplicantLogin';
+import ValidatorLogin from './components/ValidatorLogin';
+
+const Login = () => {
+ const [isApplicant, setIsApplicant] = useState(true);
+
+ const toggleRole = () => {
+ setIsApplicant(!isApplicant);
+ };
+
+ return (
+
+
+
+
+ {isApplicant ? (
+ <>
+
+ >
+ ) : (
+ <>
+
+ >
+ )
+ }
+
+
+
+ );
+};
+
+export default Login;
diff --git a/frontend/src/pages/Login/components/ApplicantLogin.jsx b/frontend/src/pages/Login/components/ApplicantLogin.jsx
new file mode 100644
index 0000000..060214d
--- /dev/null
+++ b/frontend/src/pages/Login/components/ApplicantLogin.jsx
@@ -0,0 +1,138 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import './LoginAnimation.css';
+
+function ApplicantLogin({ changeRole }) {
+ const [credentials, setCredentials] = useState({ email: 'faculty.computer.kjsce@example.com', password: 'securePassword123' });
+ const [animate, setAnimate] = useState(false);
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false); // Loading state
+
+ const handleChangeRole = () => {
+ setAnimate(true);
+ setTimeout(() => {
+ changeRole();
+ }, 800); // Match this timeout duration to your animation duration
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ // Basic Validation
+ if (!credentials.email || !credentials.password) {
+ setError('Please enter both email and password.');
+ return;
+ }
+ if (!/\S+@\S+\.\S+/.test(credentials.email)) {
+ setError('Please enter a valid email address.');
+ return;
+ }
+
+ setLoading(true); // Show loading state
+ setError(''); // Reset previous errors
+
+ try {
+ const response = await fetch(`${import.meta.env.VITE_APP_API_URL}/applicant-login`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify(credentials),
+ });
+
+ const result = await response.json();
+ if (response.ok) {
+ window.location.href = '/applicant/dashboard';
+ } else {
+ setError(result.message || 'Invalid login credentials.');
+ }
+ } catch (error) {
+ console.error('Error during login:', error);
+ setError('An error occurred. Please try again later.');
+ } finally {
+ setLoading(false); // Hide loading state
+ }
+ };
+
+ return (
+
+
+
Travel Policy
+
+ Our web application simplifies the process of requesting, approving, and managing financial support for research students and associates.
+
+
Validator?
+
Go to Validator’s Sign in
+
+ Click Here
+
+
+
+
+
Login for Applicants👋
+
+
+
+
+
+
+
+ Login With Google
+
+
or use email
+
+ {/* Display Error Message */}
+ {error &&
{error}
}
+
+
+ setCredentials(prev => ({ ...prev, email: event.target.value }))}
+ />
+ setCredentials(prev => ({ ...prev, password: event.target.value }))}
+ />
+
+
+ {loading ? 'Logging in...' : 'Log in'}
+
+
+
+
+ );
+}
+
+export default ApplicantLogin;
diff --git a/frontend/src/pages/Login/components/LoginAnimation.css b/frontend/src/pages/Login/components/LoginAnimation.css
new file mode 100644
index 0000000..eb7945e
--- /dev/null
+++ b/frontend/src/pages/Login/components/LoginAnimation.css
@@ -0,0 +1,143 @@
+/**
+ * ----------------------------------------
+ * animation slide-out-right
+ * ----------------------------------------
+ */
+@-webkit-keyframes slide-out-right {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(1000px);
+ transform: translateX(1000px);
+ opacity: 0;
+ }
+}
+
+@keyframes slide-out-right {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(1000px);
+ transform: translateX(1000px);
+ opacity: 0;
+ }
+}
+
+/* Apply animation to the specific class */
+.slide-out-right {
+ -webkit-animation: slide-out-right 1s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+ animation: slide-out-right 1s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+}
+
+
+/**
+ * ----------------------------------------
+ * animation slide-out-left
+ * ----------------------------------------
+ */
+ @-webkit-keyframes slide-out-left {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(-1000px);
+ transform: translateX(-1000px);
+ opacity: 0;
+ }
+}
+@keyframes slide-out-left {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(-1000px);
+ transform: translateX(-1000px);
+ opacity: 0;
+ }
+}
+
+/* Apply animation to the specific class */
+.slide-out-left {
+ -webkit-animation: slide-out-left 1s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+ animation: slide-out-left 1s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+}
+
+
+
+/**
+ * ----------------------------------------
+ * animation text-blur-out
+ * ----------------------------------------
+ */
+ @-webkit-keyframes text-blur-out {
+ 0% {
+ -webkit-filter: blur(0.01);
+ filter: blur(0.01);
+ }
+ 100% {
+ -webkit-filter: blur(12px) opacity(0%);
+ filter: blur(12px) opacity(0%);
+ }
+}
+@keyframes text-blur-out {
+ 0% {
+ -webkit-filter: blur(0.01);
+ filter: blur(0.01);
+ }
+ 100% {
+ -webkit-filter: blur(12px) opacity(0%);
+ filter: blur(12px) opacity(0%);
+ }
+}
+
+/* Apply animation to the specific class */
+.text-blur-out {
+ -webkit-animation: text-blur-out 0.7s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+ animation: text-blur-out 0.7s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
+}
+
+/**
+ * ----------------------------------------
+ * animation fade-in-fwd
+ * ----------------------------------------
+ */
+ @-webkit-keyframes fade-in-fwd {
+ 0% {
+ -webkit-transform: translateZ(-80px);
+ transform: translateZ(-80px);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ opacity: 1;
+ }
+}
+@keyframes fade-in-fwd {
+ 0% {
+ -webkit-transform: translateZ(-80px);
+ transform: translateZ(-80px);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ opacity: 1;
+ }
+}
+
+/* Apply animation to the specific class */
+.fade-in-fwd {
+ -webkit-animation: fade-in-fwd 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
+ animation: fade-in-fwd 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;
+}
\ No newline at end of file
diff --git a/frontend/src/pages/Login/components/ValidatorLogin.jsx b/frontend/src/pages/Login/components/ValidatorLogin.jsx
new file mode 100644
index 0000000..8d073c8
--- /dev/null
+++ b/frontend/src/pages/Login/components/ValidatorLogin.jsx
@@ -0,0 +1,143 @@
+import React, { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import './LoginAnimation.css';
+
+function ValidatorLogin({ changeRole }) {
+ const [credentials, setCredentials] = useState({ email: 'hod.computer.kjsce@example.com', password: 'securePassword123' });
+ const [animate, setAnimate] = useState(false);
+ const [error, setError] = useState('');
+ const [loading, setLoading] = useState(false); // Loading state
+
+ const handleChangeRole = () => {
+ setAnimate(true);
+ setTimeout(() => {
+ changeRole();
+ }, 800); // Ensure this matches your CSS animation duration
+ };
+
+ // Basic email validation
+ const validateEmail = (email) => {
+ const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
+ return emailRegex.test(email);
+ };
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ // Basic validation
+ if (!credentials.email || !credentials.password) {
+ setError('Please enter both email and password.');
+ return;
+ }
+
+ // Validate email format
+ if (!validateEmail(credentials.email)) {
+ setError('Please enter a valid email address.');
+ return;
+ }
+
+ setLoading(true); // Show loading state
+ setError(''); // Reset previous errors
+
+ try {
+ const response = await fetch(`${import.meta.env.VITE_APP_API_URL}/validator-login`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ credentials: 'include',
+ body: JSON.stringify(credentials),
+ });
+
+ const result = await response.json();
+ if (response.ok) {
+ // Handle successful login (navigate, store tokens, etc.)
+ window.location.href = '/validator/dashboard';
+ } else {
+ setError(result.message || 'Invalid login credentials.');
+ }
+ } catch (error) {
+ console.error('Error during login:', error);
+ setError('An error occurred. Please try again later.');
+ } finally {
+ setLoading(false); // Hide loading state
+ }
+ };
+
+ return (
+
+
+
Login for Validator👋
+
+
+
+
+
+
+
+ Login With Google
+
+
or use email
+
+ {/* Display Error Message */}
+ {error &&
{error}
}
+
+
+ setCredentials(prev => ({ ...prev, email: event.target.value }))}
+ />
+
+ setCredentials(prev => ({ ...prev, password: event.target.value }))}
+ />
+
+
+
+
+ {loading ? 'Logging in...' : 'Log in'}
+
+
+
+
+
+
Travel Policy
+
+ Our web application simplifies the process of requesting, approving, and managing financial support for research students and associates.
+
+
Applicant?
+
Go to Applicant’s Sign in
+
Click Here
+
+
+ );
+}
+
+export default ValidatorLogin;
diff --git a/frontend/src/pages/Policy/Policy.css b/frontend/src/pages/Policy/Policy.css
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/pages/Policy/Policy.jsx b/frontend/src/pages/Policy/Policy.jsx
new file mode 100644
index 0000000..cdb0076
--- /dev/null
+++ b/frontend/src/pages/Policy/Policy.jsx
@@ -0,0 +1,11 @@
+import React from 'react'
+
+function Policy() {
+ return (
+
+ Policy
+
+ )
+}
+
+export default Policy
diff --git a/frontend/src/pages/Report/Data.js b/frontend/src/pages/Report/Data.js
new file mode 100644
index 0000000..6a6c576
--- /dev/null
+++ b/frontend/src/pages/Report/Data.js
@@ -0,0 +1,30 @@
+export const CardsData = [
+ {
+ title: "Total Funds Deployed",
+ color: {
+ backGround: "linear-gradient(#93A5CF, #E4EfE9)",
+ boxShadow: "0px 10px 20px 0px rgba(0, 0, 0, 0.1)",
+ },
+ value: "12,23,234",
+ series: [
+ {
+ name: "Funds",
+ data: [20134, 1200, 23532, 23543, 12564,23346,23454,54634,45364,45634,45745,564],
+ },
+ ],
+ },
+ {
+ title: "Enrollment rate",
+ color: {
+ backGround: "linear-gradient(#93A5CF, #E4EfE9)",
+ boxShadow: "0px 10px 20px 0px rgba(0, 0, 0, 0.1)",
+ },
+ value: "90%",
+ series: [
+ {
+ name: "Enrollment Trends",
+ data: [200, 145, 232, 543, 564,342,635,345,346,123,543],
+ },
+ ],
+ },
+];
diff --git a/frontend/src/pages/Report/Report.jsx b/frontend/src/pages/Report/Report.jsx
new file mode 100644
index 0000000..c3fca9e
--- /dev/null
+++ b/frontend/src/pages/Report/Report.jsx
@@ -0,0 +1,22 @@
+import React, { useState } from "react";
+import Loading from "../../components/Loading";
+import Charts from "../Report/components/charts";
+import FilterDataForm from "./components/FilterDataForm";
+
+function Report() {
+ const [reportData, setReportData] = useState({
+ data: [],
+ query: {},
+ });
+ const [loading, setLoading] = useState(false);
+ return (
+
+
+
+ {loading ? : }
+
+
+ );
+}
+
+export default Report;
diff --git a/frontend/src/pages/Report/components/FilterDataForm.jsx b/frontend/src/pages/Report/components/FilterDataForm.jsx
new file mode 100644
index 0000000..4a3903d
--- /dev/null
+++ b/frontend/src/pages/Report/components/FilterDataForm.jsx
@@ -0,0 +1,152 @@
+import React, { useEffect } from "react";
+import { Formik } from "formik";
+import { useSubmit, useRouteLoaderData, useNavigation } from "react-router-dom";
+import { filterDataFormFeilds } from "./FilterDataFormFeilds";
+import * as yup from "yup";
+import Input from "../../ApplicationForm/Input";
+import axios from "axios";
+
+function FilterDataForm({ setReportData, setLoading }) {
+ const { role, user } = useRouteLoaderData("Validator-Root")?.data;
+
+ const navigation = useNavigation();
+ const isSubmittingNav = navigation.state === "submitting";
+
+ const prefilledData =
+ user?.institute || user?.department
+ ? {
+ institute: user?.institute,
+ department: user?.department,
+ }
+ : null;
+
+ const formFields = prefilledData
+ ? filterDataFormFeilds.map((section) => ({
+ ...section,
+ fields: section.fields.map((field) => ({
+ ...field,
+ disabled: prefilledData[field.name],
+ })),
+ }))
+ : filterDataFormFeilds;
+
+ const createInitialValuesScheme = (formFields) => {
+ const schema = {};
+
+ formFields?.forEach((section) => {
+ section?.fields?.forEach((field) => {
+ if (prefilledData) {
+ if (field.type === "miniForm" || field.type === "checkbox") {
+ schema[field.name] = JSON.parse(prefilledData[field.name]);
+ } else {
+ schema[field.name] = prefilledData[field.name];
+ }
+ } else if (field.type === "checkbox") {
+ schema[field.name] = false;
+ } else if (field.type === "miniForm") {
+ schema[field.name] = [];
+ } else {
+ schema[field.name] = "";
+ }
+ });
+ });
+
+ return schema;
+ };
+
+ const initialValuesSchema = createInitialValuesScheme(formFields);
+
+ const createValidationSchema = (formFields) => {
+ const schema = {};
+
+ formFields?.forEach((section) => {
+ section.fields?.forEach((field) => {
+ if (field.validation) {
+ schema[field.name] = field.validation;
+ }
+ });
+ });
+
+ return yup.object().shape(schema);
+ };
+
+ const validationSchema = createValidationSchema(formFields);
+
+ const handleSubmit = async (values, { setSubmitting, setErrors }) => {
+ const { institute, department, year, applicationType } = values;
+ try {
+ setLoading(true);
+ const queryParams = new URLSearchParams();
+ if (institute) queryParams.append("institute", institute);
+ if (department) queryParams.append("department", department);
+ if (year) queryParams.append("year", year);
+ if (applicationType) queryParams.append("applicationType", applicationType);
+
+ const res = await axios.get(
+ `http://localhost:3000/validator/getReportData?${queryParams.toString()}`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ withCredentials: true,
+ }
+ );
+ setReportData({data: res.data, query: values});
+ } catch (error) {
+ if (error.response && error.response.data) {
+ setErrors({ submit: error.response.data.message });
+ } else {
+ setErrors({ submit: "An unexpected error occurred" });
+ }
+ } finally {
+ setLoading(false);
+ setSubmitting(false);
+ }
+ };
+
+ useEffect(() => {
+ // Trigger form submission on first render
+ handleSubmit(initialValuesSchema, { setSubmitting: () => {}, setErrors: () => {} });
+ }, []);
+
+ return (
+
+ {({
+ values,
+ errors,
+ touched,
+ handleChange,
+ handleBlur,
+ handleSubmit,
+ setFieldValue, // Use setFieldValue for file handling
+ isSubmitting,
+ }) => (
+
+
+
+
+ {isSubmitting || isSubmittingNav ? "Gettting Data" : "Get Data"}
+
+
+ )}
+
+ );
+}
+
+export default FilterDataForm;
diff --git a/frontend/src/pages/Report/components/FilterDataFormFeilds.jsx b/frontend/src/pages/Report/components/FilterDataFormFeilds.jsx
new file mode 100644
index 0000000..bb1583b
--- /dev/null
+++ b/frontend/src/pages/Report/components/FilterDataFormFeilds.jsx
@@ -0,0 +1,65 @@
+import * as yup from "yup";
+import {
+ institutes,
+ instituteDepartmentMapping,
+} from "../../../components/BaseData";
+
+const currentYear = new Date().getFullYear();
+const yearOptions = [];
+for (let year = 2018; year <= currentYear; year++) {
+ yearOptions.push({ label: year.toString(), value: year.toString() });
+}
+
+const filterDataFormFeilds = [
+ {
+ label: "Travel Polciy Report",
+ fields: [
+ {
+ label: "Select Institute",
+ name: "institute",
+ type: "dropdown",
+ options: {
+ "": institutes,
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ depend: "institute",
+ label: "Select Department",
+ name: "department",
+ type: "dropdown",
+ options: instituteDepartmentMapping,
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ label: "Select Application Type",
+ name: "applicationType",
+ type: "dropdown",
+ options: {
+ "": [
+ { label: "Student Applications", value: "STUDENT" },
+ { label: "Faculty Applications", value: "FACULTY" },
+ ],
+ },
+ validation: yup
+ .string()
+ .notRequired("Department selection is notRequired"),
+ },
+ {
+ label: "Select Year",
+ name: "year",
+ type: "dropdown",
+ options: {
+ "": yearOptions,
+ },
+ validation: yup.string().notRequired("Year is required"),
+ },
+ ],
+ },
+];
+
+export { filterDataFormFeilds };
diff --git a/frontend/src/pages/Report/components/OverTheYearsLine.jsx b/frontend/src/pages/Report/components/OverTheYearsLine.jsx
new file mode 100644
index 0000000..2100f30
--- /dev/null
+++ b/frontend/src/pages/Report/components/OverTheYearsLine.jsx
@@ -0,0 +1,90 @@
+import { Line } from "react-chartjs-2";
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend,
+} from "chart.js";
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ Title,
+ Tooltip,
+ Legend
+);
+
+function OverTheYearsLine() {
+ const options = {
+ responsive: true, // Make the chart responsive to window resizing
+ maintainAspectRatio: false, // Allow chart size to change dynamically (optional)
+
+ // Title configuration
+ plugins: {
+ title: {
+ display: true,
+ text: "Applications Over the Years", // Set a title for the chart
+ font: {
+ size: 16,
+ },
+ },
+ tooltip: {
+ // Customize tooltips
+ callbacks: {
+ label: function (context) {
+ // Format tooltip labels
+ return `${context.dataset.label}: ${context.raw} steps`;
+ },
+ },
+ },
+ legend: {
+ display: true,
+ position: "top", // Legend position: 'top', 'left', 'bottom', 'right'
+ },
+ },
+
+ // Scales configuration (e.g., setting up x and y axes)
+ scales: {
+ x: {
+ // X-axis configuration (labels are auto-set)
+ title: {
+ display: true,
+ text: "Year", // Label for the X-axis
+ },
+ },
+ y: {
+ // Y-axis configuration
+ title: {
+ display: true,
+ text: "Number of Applications", // Label for the Y-axis
+ },
+ // ticks: {
+ // // Custom tick marks
+ // beginAtZero: true, // Start Y-axis from 0
+ // stepSize: 9000, // Tick step size for Y-axis
+ // },
+ },
+ },
+ };
+
+ const data = {
+ labels: [2020, 2021, 2022, 2023, 2024],
+ datasets: [
+ {
+ label: "Steps",
+ data: [30, 50, 45, 90, 35],
+ borderColor: "rgb(75, 192, 192)",
+ },
+ ],
+ };
+
+ return ;
+}
+
+export default OverTheYearsLine;
diff --git a/frontend/src/pages/Report/components/OverTheYearsPie.jsx b/frontend/src/pages/Report/components/OverTheYearsPie.jsx
new file mode 100644
index 0000000..56af1c2
--- /dev/null
+++ b/frontend/src/pages/Report/components/OverTheYearsPie.jsx
@@ -0,0 +1,65 @@
+import { Pie } from "react-chartjs-2";
+import {
+ Chart as ChartJS,
+ ArcElement,
+ Tooltip,
+ Legend,
+} from "chart.js";
+
+// Register chart components
+ChartJS.register(ArcElement, Tooltip, Legend);
+
+function OverTheYearsPie() {
+ const options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ title: {
+ display: true,
+ text: "Steps Distribution Over Years",
+ font: {
+ size: 16,
+ },
+ },
+ tooltip: {
+ callbacks: {
+ label: function (context) {
+ return `${context.label}: ${context.raw} steps`;
+ },
+ },
+ },
+ legend: {
+ display: true,
+ position: "top",
+ },
+ },
+ };
+
+ const data = {
+ labels: ["2020", "2021", "2022", "2023", "2024"], // Labels for the pie slices
+ datasets: [
+ {
+ data: [3000, 5000, 4500, 9000, 12000], // Data for the pie chart
+ backgroundColor: [
+ "rgba(75, 192, 192, 0.5)", // Color for the 2020 slice
+ "rgba(255, 99, 132, 0.5)", // Color for the 2021 slice
+ "rgba(54, 162, 235, 0.5)", // Color for the 2022 slice
+ "rgba(153, 102, 255, 0.5)", // Color for the 2023 slice
+ "rgba(255, 159, 64, 0.5)", // Color for the 2024 slice
+ ],
+ borderColor: [
+ "rgb(75, 192, 192)",
+ "rgb(255, 99, 132)",
+ "rgb(54, 162, 235)",
+ "rgb(153, 102, 255)",
+ "rgb(255, 159, 64)",
+ ],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ return ;
+}
+
+export default OverTheYearsPie;
diff --git a/frontend/src/pages/Report/components/ReportPDF.jsx b/frontend/src/pages/Report/components/ReportPDF.jsx
new file mode 100644
index 0000000..3f2f879
--- /dev/null
+++ b/frontend/src/pages/Report/components/ReportPDF.jsx
@@ -0,0 +1,166 @@
+import React from "react";
+import {
+ Page,
+ Text,
+ View,
+ Document,
+ StyleSheet,
+ Image,
+} from "@react-pdf/renderer";
+
+// Create styles
+const styles = StyleSheet.create({
+ page: {
+ flexDirection: "column",
+ backgroundColor: "white",
+ padding: 20,
+ },
+ sectionTitle: {
+ textAlign: "center",
+ fontSize: 16,
+ fontWeight: "bold",
+ marginBottom: 10,
+ },
+ section: {
+ margin: 10,
+ padding: 10,
+ },
+ viewer: {
+ width: "75vw", // Full width
+ height: "100vh", // Full height
+ },
+ cardContainer: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ marginVertical: 10,
+ },
+ card: {
+ width: "45%",
+ padding: 10,
+ backgroundColor: "#f8e7d1",
+ borderRadius: 5,
+ textAlign: "center",
+ fontSize: 14,
+ fontWeight: "bold",
+ },
+ chartContainer: {
+ marginVertical: 20,
+ textAlign: "center",
+ },
+ table: {
+ display: "table",
+ width: "auto",
+ borderStyle: "solid",
+ borderWidth: 1,
+ borderColor: "#bfbfbf",
+ borderBottomWidth: 0,
+ borderRightWidth: 0,
+ },
+ tableRow: {
+ flexDirection: "row",
+ },
+ tableColHeader: {
+ width: "25%",
+ borderStyle: "solid",
+ borderColor: "#bfbfbf",
+ borderRightWidth: 1,
+ borderBottomWidth: 1,
+ backgroundColor: "#f2f2f2",
+ padding: 5,
+ textAlign: "center",
+ },
+ tableCol: {
+ width: "25%",
+ borderStyle: "solid",
+ borderColor: "#bfbfbf",
+ borderRightWidth: 1,
+ borderBottomWidth: 1,
+ padding: 5,
+ textAlign: "center",
+ },
+ tableCellHeader: {
+ margin: 5,
+ fontSize: 12,
+ fontWeight: "bold",
+ },
+ tableCell: {
+ margin: 5,
+ fontSize: 10,
+ },
+ image: {
+ width: 400,
+ height: 300,
+ },
+});
+
+// Create Document Component
+const ReportPDF = ({ tableData, chartImages }) => {
+ return (
+
+
+ {/* Title */}
+ Travel Policy Report
+
+ {/* Summary Cards */}
+ {/*
+
+ Total Funds Deployed
+ 12,23,234
+
+
+ Enrollment Rate
+ 90%
+
+ */}
+
+ {/* Table */}
+
+
+
+ ID
+
+
+ Stream
+
+
+ Scholarship
+
+
+ Funds
+
+
+ {tableData?.map((row) => (
+
+
+ {row.id}
+
+
+ {row.Stream}
+
+
+ {row.Scholarship}
+
+
+ {row.Funds}
+
+
+ ))}
+
+
+ {/* Charts */}
+ {chartImages?.barChart && (
+
+ )}
+ {chartImages?.pieChart1 && (
+
+ )}
+
+ {chartImages?.pieChart2 && (
+
+ )}
+
+
+ );
+};
+
+export default ReportPDF;
diff --git a/frontend/src/pages/Report/components/Table.jsx b/frontend/src/pages/Report/components/Table.jsx
new file mode 100644
index 0000000..2d56750
--- /dev/null
+++ b/frontend/src/pages/Report/components/Table.jsx
@@ -0,0 +1,37 @@
+import React from "react";
+
+const Table = ({ tableData }) => {
+
+ return (
+
+
+
+
+ ID
+ Stream
+ Scholarship
+ Funds
+
+
+
+ {tableData?.map((row) => (
+
+ {row.id}
+ {row.Stream}
+ {row.Scholarship}
+ {row.Funds}
+
+ ))}
+
+
+
+ );
+};
+
+export default Table;
diff --git a/frontend/src/pages/Report/components/approved.jsx b/frontend/src/pages/Report/components/approved.jsx
new file mode 100644
index 0000000..47170cf
--- /dev/null
+++ b/frontend/src/pages/Report/components/approved.jsx
@@ -0,0 +1,146 @@
+import React, { useState } from "react";
+import { Bar } from "react-chartjs-2";
+
+const ChartWithDropdown = () => {
+ // Chart data options for faculty, students, HOI, and HOD
+ const chartDataOptions = {
+ faculty: {
+ approved: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Approved Applications (Faculty)",
+ data: [100, 150, 200, 250, 300,400,900,132,920,1000,890 ,100],
+ backgroundColor: "rgba(75, 192, 192, 0.5)",
+ borderColor: "rgb(75, 192, 192)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ rejected: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Rejected Applications (Faculty)",
+ data: [50, 60, 70, 80, 20,40,90,78,23,29,98,33],
+ backgroundColor: "rgba(255, 99, 132, 0.5)",
+ borderColor: "rgb(255, 99, 132)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ },
+ HOI: {
+ approved: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Approved Applications (HOI)",
+ data: [1200, 1500, 1800, 2200, 2500,2000,1999,3453,2345,5633,2345,5647],
+ backgroundColor: "rgba(54, 162, 235, 0.5)",
+ borderColor: "rgb(54, 162, 235)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ rejected: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Rejected Applications (HOI)",
+ data: [200, 300, 400, 500, 450, 350, 320, 410, 360, 430, 300, 250],
+ backgroundColor: "rgba(255, 159, 64, 0.5)",
+ borderColor: "rgb(255, 159, 64)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ },
+ HOD: {
+ approved: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Approved Applications (HOD)",
+ data: [300, 400, 500, 450, 400, 350, 300, 250, 200, 150, 100, 50],
+ backgroundColor: "rgba(153, 102, 255, 0.5)",
+ borderColor: "rgb(153, 102, 255)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ rejected: {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"],
+ datasets: [
+ {
+ label: "Rejected Applications (HOD)",
+ data: [30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140],
+ backgroundColor: "rgba(255, 206, 86, 0.5)",
+ borderColor: "rgb(255, 206, 86)",
+ borderWidth: 1,
+ },
+ ],
+ },
+ },
+ };
+
+ const chartOptions = {
+ responsive: true,
+ plugins: {
+ legend: { display: true },
+ title: { display: true, text: "Applications Over the Years" },
+ },
+ scales: {
+ x: { title: { display: true, text: "Year" } },
+ y: { title: { display: true, text: "Number of Applications" }, beginAtZero: true },
+ },
+ };
+
+ const [category, setCategory] = useState("faculty"); // Faculty, HOI, or HOD
+ const [applicationType, setApplicationType] = useState("approved"); // Approved or Rejected
+
+ // Fetch the data based on the selected category and application type
+ const data =
+ chartDataOptions[category]?.[applicationType] ||
+ chartDataOptions["faculty"]["approved"];
+
+ return (
+
+ {/* Dropdown for selecting category */}
+
+
+ Select Category:
+
+ setCategory(e.target.value)}
+ style={{ padding: "5px", fontSize: "16px", marginRight: "20px", borderRadius: "15px", textAlign: "center", border: "2px solid black" }}
+ >
+ Faculty
+ HOI
+ HOD
+
+
+ {/* Dropdown for selecting application type */}
+
+ Select Application Type:
+
+ setApplicationType(e.target.value)}
+ style={{ padding: "5px", fontSize: "16px", borderRadius: "15px", textAlign: "center", border: "2px solid black" }}
+ >
+ Approved Applications
+ Rejected Applications
+
+
+
+ {/* Chart */}
+ {data &&
}
+
+ );
+};
+
+export default ChartWithDropdown;
\ No newline at end of file
diff --git a/frontend/src/pages/Report/components/card.jsx b/frontend/src/pages/Report/components/card.jsx
new file mode 100644
index 0000000..d1d20ee
--- /dev/null
+++ b/frontend/src/pages/Report/components/card.jsx
@@ -0,0 +1,143 @@
+ import React, { useState } from "react";
+ import { motion } from "framer-motion";
+ import "./cards.css";
+ import { Bar } from "react-chartjs-2";
+ import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend,
+ } from "chart.js";
+
+ // Register chart.js components
+ ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend
+ );
+
+ const Card = (props) => {
+ const [expanded, setExpanded] = useState(false);
+
+ return (
+
+ setExpanded(!expanded)} // Toggle the state
+ className="motion_card"
+ >
+ {!expanded && ( // Render CompactCard when NOT expanded
+
+
+
+ )}
+
+ {expanded && ( // Render ExpandedCard when expanded
+
+
+
+ )}
+
+
+ );
+ };
+
+ // Compact Card Component
+ function CompactCard({ param }) {
+ return (
+
+
+
{param.title}
+
+
{param.value}
+
+ );
+ }
+
+ // Expanded Card Component
+ function ExpandedCard({ param }) {
+ const barOptions = {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: "Number of Applications Over the Years ",
+ },
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: "Year",
+ },
+ },
+ y: {
+ title: {
+ display: true,
+ text: "Number of Applications",
+ },
+ ticks: {
+ beginAtZero: true,
+ },
+ },
+ },
+ };
+
+ const chartData = {
+ labels: ["Jan", "Feb", "Mar", "April", "May","June","July","Aug","Sep","Nov","Dec"], // Example years
+ datasets: [
+ {
+ label: param.series[0].name, // e.g., "Applications"
+ data: param.series[0].data, // e.g., [100, 150, 200, 250, 300]
+ backgroundColor: "rgba(75, 192, 192, 0.6)", // Bar color
+ },
+ ],
+ };
+
+ return (
+
+
+
+
{param.title}
+
+
+
{param.value}
+
+
+ )
+ }
+
+ export default Card;
diff --git a/frontend/src/pages/Report/components/cards.css b/frontend/src/pages/Report/components/cards.css
new file mode 100644
index 0000000..5c34990
--- /dev/null
+++ b/frontend/src/pages/Report/components/cards.css
@@ -0,0 +1,63 @@
+.generalInfo{
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ width: 30%;
+ padding: 10px;
+}
+
+.cards{
+ display: flex;
+ gap: 10px;
+ padding: 10px;
+ flex-direction: row;
+
+}
+.Cards{
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ margin: 20px;
+}
+.CompactCard{
+ display: flex;
+ flex-direction: row;
+ padding: 20px;
+ width: 300px;
+ height: 200px;
+ align-items: center;
+ gap: 20px;
+ cursor: pointer;
+ background-color: antiquewhite;
+ border-width: 5px;
+ border-color: rgb(85, 85, 85);
+ border-radius: 5px;
+ filter: drop-shadow(2px 4px 6px rgb(114, 114, 114));
+}
+.CompactCard:hover
+{
+ filter: drop-shadow(2px 4px 6px rgb(255, 255, 255));
+}
+.data>h1
+{
+ font-size: large;
+ font-weight: 1000;
+}
+.CompactCard>span
+{
+ display: flex;
+ flex-direction: row;
+ align-items: end;
+}
+
+.motionCard{
+gap: 20px;
+}
+.h{
+
+ display: flex;
+ flex-direction: row;
+ margin: 10px;
+ gap: 10px;
+
+}
\ No newline at end of file
diff --git a/frontend/src/pages/Report/components/cards.jsx b/frontend/src/pages/Report/components/cards.jsx
new file mode 100644
index 0000000..4809d5e
--- /dev/null
+++ b/frontend/src/pages/Report/components/cards.jsx
@@ -0,0 +1,28 @@
+import './cards.css'
+import React from 'react'
+import Card from './card'
+import { CardsData } from '../Data';
+
+const Cards= () =>{
+ return(
+
+ {CardsData.map((card , id)=>{
+ return(
+
+
+
+
+ )
+
+ })}
+
+
+ );
+}
+export default Cards
\ No newline at end of file
diff --git a/frontend/src/pages/Report/components/charts.jsx b/frontend/src/pages/Report/components/charts.jsx
new file mode 100644
index 0000000..518dd88
--- /dev/null
+++ b/frontend/src/pages/Report/components/charts.jsx
@@ -0,0 +1,440 @@
+import React, { useEffect, useRef, useState } from "react";
+import ChartWithDropdown from "./approved";
+import Cards from "./cards";
+import "./cards.css";
+import { Bar, Pie } from "react-chartjs-2";
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ BarElement,
+ ArcElement,
+ Title,
+ Tooltip,
+ Legend,
+} from "chart.js";
+import ChartDataLabels from 'chartjs-plugin-datalabels';
+import Table from "./Table";
+import { PDFDownloadLink, PDFViewer } from "@react-pdf/renderer";
+import ApprovalVsRejectionTrends from "./map";
+import ReportPDF from "./reportPDF";
+
+// Register chart components for all three types (Line, Bar, Pie)
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ PointElement,
+ LineElement,
+ BarElement,
+ ArcElement,
+ Title,
+ Tooltip,
+ Legend,
+ ChartDataLabels
+);
+
+function Charts({ reportData }) {
+ const { data, query } = reportData;
+
+ if (!data) {
+ return (
+
+ No Data Found
+
+ );
+ }
+
+ const { acceptedApplications, rejectedApplications, pendingApplications } = data;
+
+ const tableData = [];
+ const groupedData = {};
+ if (acceptedApplications) {
+ for (const item of acceptedApplications) {
+ const { institute, department, formData } = item;
+ const { totalExpense } = formData;
+
+ if (!groupedData[institute]) {
+ groupedData[institute] = {};
+ }
+
+ if (query.institute) {
+ if (!groupedData[institute][department]) {
+ groupedData[institute][department] = {
+ totalExpense: 0,
+ applications: 0,
+ };
+ }
+
+ // Aggregate the data
+ groupedData[institute][department].totalExpense +=
+ parseFloat(totalExpense); // Summing the expenses
+ groupedData[institute][department].applications += 1;
+ } else {
+ if (!groupedData[institute].applications) {
+ groupedData[institute] = {
+ totalExpense: 0,
+ applications: 0,
+ };
+ }
+
+ // Aggregate the data
+ groupedData[institute].totalExpense += parseFloat(totalExpense); // Summing the expenses
+ groupedData[institute].applications += 1;
+ }
+ }
+ }
+
+ // Step 2: Transform grouped data into desired table format
+ if (query.institute) {
+ for (const institute in groupedData) {
+ for (const department in groupedData[institute]) {
+ const departmentData = groupedData[institute][department];
+
+ tableData.push({
+ id: tableData.length + 1,
+ Stream: department,
+ Scholarship: departmentData.applications, // Assuming each application is one scholarship
+ Purpose_of_Travel: departmentData.purposeOfTravel,
+ Funds: departmentData.totalExpense.toFixed(2), // Formatting funds to 2 decimal places
+ });
+ }
+ }
+ } else {
+ for (const institute in groupedData) {
+ const instituteData = groupedData[institute];
+
+ tableData.push({
+ id: tableData.length + 1,
+ Stream: institute,
+ Scholarship: instituteData.applications, // Assuming each application is one scholarship
+ Purpose_of_Travel: instituteData.purposeOfTravel,
+ Funds: instituteData.totalExpense.toFixed(2), // Formatting funds to 2 decimal places
+ });
+ }
+ }
+
+ const [chartImages, setChartImages] = useState({
+ barChart: null,
+ pieChart1: null,
+ pieChart2: null,
+ isLoading: false,
+ });
+
+ // Line Chart Data and Options
+ const lineOptions = {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: "Number of Applications Over the Years ",
+ },
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: "Year",
+ },
+ },
+ y: {
+ title: {
+ display: true,
+ text: "Number of Applications",
+ },
+ ticks: {
+ beginAtZero: true,
+ },
+ },
+ },
+ };
+
+ const lineData = {
+ labels: [2020, 2021, 2022, 2023, 2024],
+ datasets: [
+ {
+ label: "Applications",
+ data: [1200, 1500, 1800, 2200, 2500], // Updated data for number of applications
+ borderColor: "rgb(75, 192, 192)",
+ fill: false,
+ tension: 0.1,
+ },
+ ],
+ };
+
+ // Bar Chart Data and Options
+ const barOptions = {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: "Number of Applications Over the Years ",
+ },
+ },
+ scales: {
+ x: {
+ title: {
+ display: true,
+ text: "Month",
+ },
+ },
+ y: {
+ title: {
+ display: true,
+ text: "Number of Applications",
+ },
+ ticks: {
+ beginAtZero: true,
+ },
+ },
+ },
+ };
+
+ const barData = {
+ labels: [
+ "Jan",
+ "Feb",
+ "Mar",
+ "April",
+ "May",
+ "June",
+ "July",
+ "Aug",
+ "Sep",
+ "Nov",
+ "Dec",
+ ],
+ datasets: [
+ {
+ label: "Applications",
+ data: [
+ 1200, 1500, 1800, 2200, 200, 800, 1235, 604, 2345, 2523, 3453, 6453,
+ ], // Updated data for number of applications
+ backgroundColor: "rgba(75, 192, 192, 0.5)",
+ borderColor: "rgb(75, 192, 192)",
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ // Pie Chart Data and Options
+ const pieOptions = {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: "Purpose of Travel",
+ },
+ },
+ };
+
+ const pieData = {
+ labels: ["Academic", "Research", "Personal", "Other"],
+ datasets: [
+ {
+ data: [1200, 1500, 1800, 2200], // Updated data for number of applications
+ backgroundColor: [
+ "rgba(75, 192, 192, 0.5)",
+ "rgba(255, 99, 132, 0.5)",
+ "rgba(54, 162, 235, 0.5)",
+ "rgba(153, 102, 255, 0.5)",
+ ],
+ borderColor: [
+ "rgb(75, 192, 192)",
+ "rgb(255, 99, 132)",
+ "rgb(54, 162, 235)",
+ "rgb(153, 102, 255)",
+ ],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ const pie_Options = {
+ responsive: true,
+ plugins: {
+ title: {
+ display: true,
+ text: "Travel",
+ },
+ },
+ };
+
+ const pie_Data = {
+ labels: ["Domestic", "International", "Local"],
+ datasets: [
+ {
+ data: [1200, 1500, 1800], // Updated data for number of applications
+ backgroundColor: [
+ "rgba(79, 246, 96, 0.5)",
+ "rgba(255, 99, 132, 0.5)",
+ "rgba(54, 162, 235, 0.5)",
+ ],
+ borderColor: [
+ "rgb(79, 246, 96)",
+ "rgb(255, 99, 132)",
+ "rgb(54, 162, 235)",
+ ],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ // const barChartRef = useRef();
+ // const pieChartRef1 = useRef();
+ // const pieChartRef2 = useRef();
+
+ // const loadChartsInPdf = () => {
+ // const barChartInstance = barChartRef.current;
+ // const pieChartInstance1 = pieChartRef1.current;
+ // const pieChartInstance2 = pieChartRef2.current;
+
+ // if (barChartInstance) {
+ // const barBase64Image = barChartInstance.toBase64Image();
+ // setChartImages((prevImages) => ({
+ // ...prevImages,
+ // barChart: barBase64Image,
+ // }));
+ // }
+
+ // if (pieChartInstance1) {
+ // const pieBase64Image = pieChartInstance1.toBase64Image();
+ // setChartImages((prevImages) => ({
+ // ...prevImages,
+ // pieChart1: pieBase64Image,
+ // }));
+ // }
+
+ // if (pieChartInstance2) {
+ // const pieBase64Image = pieChartInstance2.toBase64Image();
+ // setChartImages((prevImages) => ({
+ // ...prevImages,
+ // pieChart2: pieBase64Image,
+ // }));
+ // }
+ // };
+
+ // useEffect(() => {
+ // setChartImages((prevImages) => ({ ...prevImages, isLoading: true }));
+
+ // const handleRender = () => {
+ // loadChartsInPdf();
+ // setChartImages((prevImages) => ({ ...prevImages, isLoading: false }));
+ // };
+
+ // const barChartInstance = barChartRef.current;
+ // const pieChartInstance1 = pieChartRef1.current;
+ // const pieChartInstance2 = pieChartRef2.current;
+
+ // if (barChartInstance) {
+ // barChartInstance.options.animation.onComplete = handleRender;
+ // }
+
+ // if (pieChartInstance1) {
+ // pieChartInstance1.options.animation.onComplete = handleRender;
+ // }
+
+ // if (pieChartInstance2) {
+ // pieChartInstance2.options.animation.onComplete = handleRender;
+ // }
+
+ // return () => {
+ // if (barChartInstance) {
+ // barChartInstance.options.animation.onComplete = null;
+ // }
+ // if (pieChartInstance1) {
+ // pieChartInstance1.options.animation.onComplete = null;
+ // }
+ // if (pieChartInstance2) {
+ // pieChartInstance2.options.animation.onComplete = null;
+ // }
+ // };
+ // }, []);
+
+ return (
+
+
Travel Policy Report
+
+ {/* Container for all three charts */}
+ {/*
*/}
+
+ {/*
*/}
+
+ {/*
*/}
+
+ {/* Line Chart */}
+ {/*
+
*/}
+
+
+
+ {chartImages.isLoading ? (
+
+ Generating PDF Report...
+
+ ) : (
+
+
+ }
+ fileName={`report_${query.institute || "allInstitutes"}_${
+ query.department || "allDepartments"
+ }_${query.year || "allYears"}_${
+ query.applicationType || "allApplications"
+ }.pdf`}
+ >
+ {({ blob, url, loading, error }) =>
+ loading ? (
+
+ Getting Your PDF Report Ready...
+
+ ) : (
+
+ Download PDF
+
+ )
+ }
+
+
+
+
+
+
+ )}
+
+ );
+}
+
+export default Charts;
diff --git a/frontend/src/pages/Report/components/map.jsx b/frontend/src/pages/Report/components/map.jsx
new file mode 100644
index 0000000..30af923
--- /dev/null
+++ b/frontend/src/pages/Report/components/map.jsx
@@ -0,0 +1,92 @@
+import React, { useState } from "react";
+import { Line } from "react-chartjs-2";
+import { Chart as ChartJS, LineElement, CategoryScale, LinearScale, PointElement, Title, Tooltip, Legend, Filler } from "chart.js";
+
+// Register required Chart.js components
+ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement, Title, Tooltip, Legend, Filler);
+
+const ApprovalVsRejectionTrends = () => {
+ // Sample data for Approved and Rejected Applications
+ const applicationData = {
+ faculty: {
+ approved: [100, 150, 200, 250, 300, 400, 500, 450, 600, 550, 700, 650],
+ rejected: [50, 60, 70, 80, 100, 90, 120, 110, 130, 100, 140, 120],
+ },
+ HOI: {
+ approved: [500, 600, 700, 800, 750, 700, 900, 850, 1000, 950, 1100, 1050],
+ rejected: [100, 120, 140, 150, 130, 110, 180, 150, 200, 170, 220, 190],
+ },
+ HOD: {
+ approved: [300, 400, 350, 450, 500, 480, 550, 520, 600, 580, 650, 620],
+ rejected: [80, 90, 100, 110, 120, 100, 140, 130, 150, 140, 160, 150],
+ },
+ };
+
+ const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
+
+ // State for selected category
+ const [category, setCategory] = useState("faculty");
+
+ // Data for the Line Chart
+ const lineChartData = {
+ labels: months,
+ datasets: [
+ {
+ label: "Approved Applications",
+ data: applicationData[category].approved,
+ borderColor: "rgb(75, 192, 192)",
+ backgroundColor: "rgba(75, 192, 192, 0.2)",
+ tension: 0.4, // For a smooth curve
+ fill: true,
+ },
+ {
+ label: "Rejected Applications",
+ data: applicationData[category].rejected,
+ borderColor: "rgb(255, 99, 132)",
+ backgroundColor: "rgba(255, 99, 132, 0.2)",
+ tension: 0.4,
+ fill: true,
+ },
+ ],
+ };
+
+ const lineChartOptions = {
+ responsive: true,
+ plugins: {
+ legend: { display: true, position: "top" },
+ title: { display: true, text: "Approval vs. Rejection Trends" },
+ },
+ scales: {
+ x: { title: { display: true, text: "Months" } },
+ y: { title: { display: true, text: "Number of Applications" }, beginAtZero: true },
+ },
+ };
+
+ return (
+
+
Approval vs. Rejection Trends
+
+ {/* Dropdown to select category */}
+
+
+ Select Category:
+
+ setCategory(e.target.value)}
+ style={{ padding: "5px", fontSize: "16px", borderRadius: "8px", border: "1px solid #ccc" }}
+ >
+ Faculty
+ HOI
+ HOD
+
+
+
+ {/* Line Chart */}
+
+
+ );
+};
+
+export default ApprovalVsRejectionTrends;
diff --git a/frontend/src/pages/index.js b/frontend/src/pages/index.js
new file mode 100644
index 0000000..9089911
--- /dev/null
+++ b/frontend/src/pages/index.js
@@ -0,0 +1,8 @@
+export { default as Login } from './login/Login'
+export { default as Dashboard } from './Dashboard/Dashboard'
+export { default as Applications } from './Applications/Applications'
+export { default as Form } from './ApplicationForm/Form'
+export { default as ApplicationView } from './ApplicationView/ApplicationView'
+export { default as About } from './about/About'
+export { default as Policy } from './policy/Policy'
+export { default as Report } from './Report/Report'
\ No newline at end of file
diff --git a/frontend/src/services/applicationStatusAction.js b/frontend/src/services/applicationStatusAction.js
new file mode 100644
index 0000000..c685220
--- /dev/null
+++ b/frontend/src/services/applicationStatusAction.js
@@ -0,0 +1,52 @@
+import { json } from "react-router-dom";
+import { toastSuccess, toastError, toastWarning } from "../utils/toast";
+
+export async function applicationStatusAction({ request, params }) {
+ const formData = await request.formData();
+ const action = formData.get("action")
+
+ try {
+ if (action === "accepted") {
+ const expenses = JSON.parse(formData.get("expenses"));
+ const hasUnverifiedExpense = expenses.some(item => item?.proofStatus !== "verified");
+
+ if (hasUnverifiedExpense) {
+ toastWarning("Please verify all the proofs before approving");
+ return json(
+ { message: "Please verify all the proofs before approving" },
+ { status: 400 }
+ );
+ }
+ }
+
+ const res = await fetch(
+ `${
+ import.meta.env.VITE_APP_API_URL
+ }/validator/statusAction`,
+ {
+ method: "PUT",
+ credentials: "include",
+ body: formData,
+ }
+ );
+
+ if (res.status === 401) {
+ return json({ message: "Unauthorized access" }, { status: res.status });
+ }
+
+ if (!res.ok) {
+ toastError(res.statusText);
+ return json({ message: res.statusText }, { status: res.status });
+ }
+
+ toastSuccess(`Application ${action.slice(0, 1).toUpperCase() + action.slice(1).toLowerCase()} Successfully`);
+
+ window.location.reload()
+
+ return null;
+
+ } catch (error) {
+ console.error("Fetch error:", error);
+ throw json({ message: error.message }, { status: error.status || 500 });
+ }
+}
diff --git a/frontend/src/services/upsertApplicationAction.js b/frontend/src/services/upsertApplicationAction.js
new file mode 100644
index 0000000..da855ea
--- /dev/null
+++ b/frontend/src/services/upsertApplicationAction.js
@@ -0,0 +1,49 @@
+import { json, redirect } from 'react-router-dom';
+import { toastSuccess, toastError, toastSecurityAlert } from '../utils/toast';
+
+export async function upsertApplicationAction({ request }) {
+ const formData = await request.formData();
+
+ const resubmission = JSON.parse(formData.get('resubmission'));
+ formData.delete('resubmission');
+
+ try {
+ let res;
+ if (resubmission) {
+ res = await fetch(`${import.meta.env.VITE_APP_API_URL}/applicant/resubmit-application`, {
+ method: 'PUT',
+ credentials: 'include',
+ body: formData
+ });
+ } else {
+ res = await fetch(`${import.meta.env.VITE_APP_API_URL}/applicant/create-application`, {
+ method: 'POST',
+ credentials: 'include',
+ body: formData
+ });
+ }
+
+ if (res.status === 401) {
+ return json({ message: 'Unauthorized access' }, { status: res.status });
+ }
+
+ if (!res.ok) {
+ const errorData = await res.text();
+
+ // Check for field tampering attempt
+ if (errorData.includes("Forbidden: Field") && errorData.includes("Tampering detected")) {
+ toastSecurityAlert("SECURITY ALERT: Your submission was blocked because form tampering was detected. Disabled fields cannot be modified. This incident has been logged.");
+ } else {
+ toastError(errorData);
+ }
+
+ return json({ message: errorData }, { status: res.status });
+ }
+
+ toastSuccess("Application Submitted Successfully");
+ return redirect("../dashboard/pending");
+ } catch (error) {
+ console.error('Fetch error:', error);
+ return json({ message: error.message || 'An unexpected error occurred' }, { status: error.status || 500 });
+ }
+}
diff --git a/frontend/src/services/userDataLoader.js b/frontend/src/services/userDataLoader.js
new file mode 100644
index 0000000..1dfcfda
--- /dev/null
+++ b/frontend/src/services/userDataLoader.js
@@ -0,0 +1,58 @@
+import axios from "axios";
+import { json, redirect } from "react-router-dom";
+import { toastError } from "../utils/toast";
+
+async function userDataLoader({ params, request }) {
+ try {
+ const res = await axios.get(`${import.meta.env.VITE_APP_API_URL}/general/dataRoot`, {
+ withCredentials: true,
+ });
+
+ if (res.status === 401 || res.status === 403) {
+ toastError("Unauthorized Access. Please Login.");
+ return redirect("/"); // Redirect to login page
+ }
+
+ const userRole = res.data.role;
+ const url = new URL(request.url);
+ const userRoleInURL = url.pathname.split("/")[1];
+
+ // Role-based route protection
+ if (userRoleInURL === "applicant" && userRole !== "Applicant") {
+ toastError("Access Denied: Applicant Role Required.");
+ return redirect("/");
+ }
+
+ if (userRoleInURL === "validator" && userRole !== "Validator") {
+ toastError("Access Denied: Validator Role Required.");
+ return redirect("/");
+ }
+
+ return { data: res.data };
+
+ } catch (error) {
+ // Handle errors during the request
+ if (error.response && (error.response.status === 401 || error.response.status === 403)) {
+ toastError(error.response?.data?.message || "Unauthorized Access.");
+
+ // Log out the user if unauthorized or forbidden
+ await fetch(`${import.meta.env.VITE_APP_API_URL}/logout`, {
+ method: 'GET',
+ credentials: 'include', // Include credentials (cookies) for logout
+ });
+
+ return redirect("/"); // Redirect to login page
+ }
+
+ // If the error isn't related to authorization, return a network error
+ throw json(
+ {
+ message: error.response?.data?.message || "Network error. Please try again later.",
+ status: error.response?.status || 500,
+ },
+ { status: error.response?.status || 500 }
+ );
+ }
+}
+
+export default userDataLoader;
diff --git a/frontend/src/styles/.keep b/frontend/src/styles/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/src/utils/toast.js b/frontend/src/utils/toast.js
new file mode 100644
index 0000000..9968afb
--- /dev/null
+++ b/frontend/src/utils/toast.js
@@ -0,0 +1,46 @@
+import { toast } from 'react-toastify';
+
+// Default toast configuration
+const defaultConfig = {
+ position: "top-center",
+ autoClose: 4000,
+ hideProgressBar: false,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true
+};
+
+// Pre-configured toast functions
+export const toastSuccess = (message) => {
+ return toast.success(message, {
+ ...defaultConfig,
+ autoClose: 3000
+ });
+};
+
+export const toastError = (message) => {
+ return toast.error(message, {
+ ...defaultConfig,
+ autoClose: 5000
+ });
+};
+
+export const toastInfo = (message) => {
+ return toast.info(message, {
+ ...defaultConfig
+ });
+};
+
+export const toastWarning = (message) => {
+ return toast.warning(message, {
+ ...defaultConfig
+ });
+};
+
+export const toastSecurityAlert = (message) => {
+ return toast.error(message, {
+ ...defaultConfig,
+ icon: "🔐",
+ autoClose: 7000
+ });
+};
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
new file mode 100644
index 0000000..dc1013c
--- /dev/null
+++ b/frontend/tailwind.config.js
@@ -0,0 +1,11 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: [
+ "./index.html",
+ "./src/**/*.{js,ts,jsx,tsx}",
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
\ No newline at end of file
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 0000000..0dc4615
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,18 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ server: {
+ proxy: {
+ '/applicant-login': process.env.VITE_APP_API_URL,
+ '/validator-login': process.env.VITE_APP_API_URL,
+ '/verify-applicant': process.env.VITE_APP_API_URL,
+ '/verify-validator': process.env.VITE_APP_API_URL,
+ '/submit': process.env.VITE_APP_API_URL,
+ },
+ host: true,
+ port: 5173,
+ },
+})