From efbb6cfe39add4818f38bddb5faf6448a3baa68e Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Thu, 2 Feb 2023 15:56:26 +0500
Subject: [PATCH 1/6] feat: architecture and login
---
package-lock.json | 885 +++++++++++++++++++++++++++++++
package.json | 5 +
src/App.js | 29 +-
src/components/PrivateRoute.jsx | 10 +
src/components/Routes.jsx | 12 +
src/components/layout/Layout.jsx | 17 +
src/index.js | 17 +-
src/pages/login/Login.jsx | 93 ++++
8 files changed, 1043 insertions(+), 25 deletions(-)
create mode 100644 src/components/PrivateRoute.jsx
create mode 100644 src/components/Routes.jsx
create mode 100644 src/components/layout/Layout.jsx
create mode 100644 src/pages/login/Login.jsx
diff --git a/package-lock.json b/package-lock.json
index e03dd4b..d575520 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,11 +8,16 @@
"name": "client",
"version": "0.1.0",
"dependencies": {
+ "@emotion/react": "^11.10.5",
+ "@emotion/styled": "^11.10.5",
+ "@mui/icons-material": "^5.11.0",
+ "@mui/material": "^5.11.7",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-router-dom": "^6.8.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
@@ -2124,6 +2129,170 @@
"postcss-selector-parser": "^6.0.10"
}
},
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
+ "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/plugin-syntax-jsx": "^7.17.12",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.0",
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/serialize": "^1.1.1",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.1.3"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@emotion/babel-plugin/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==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@emotion/babel-plugin/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz",
+ "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==",
+ "dependencies": {
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/sheet": "^1.2.1",
+ "@emotion/utils": "^1.2.0",
+ "@emotion/weak-memoize": "^0.3.0",
+ "stylis": "4.1.3"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz",
+ "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ=="
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
+ "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
+ "dependencies": {
+ "@emotion/memoize": "^0.8.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
+ "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
+ "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.10.5",
+ "@emotion/cache": "^11.10.5",
+ "@emotion/serialize": "^1.1.1",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+ "@emotion/utils": "^1.2.0",
+ "@emotion/weak-memoize": "^0.3.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz",
+ "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==",
+ "dependencies": {
+ "@emotion/hash": "^0.9.0",
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/unitless": "^0.8.0",
+ "@emotion/utils": "^1.2.0",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz",
+ "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
+ },
+ "node_modules/@emotion/styled": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
+ "integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.10.5",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@emotion/serialize": "^1.1.1",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+ "@emotion/utils": "^1.2.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0",
+ "@emotion/react": "^11.0.0-rc.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
+ "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz",
+ "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz",
+ "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw=="
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz",
+ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg=="
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -2968,6 +3137,262 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
+ "node_modules/@mui/base": {
+ "version": "5.0.0-alpha.116",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.116.tgz",
+ "integrity": "sha512-VwhifWdrfHc4/ZdqRZ4Gf+7P39sovNN24By1YVZdvJ9fvp0Sr8sNftGUCjYXXz+xCXVBQDXvhfxMwZrj2MvJvA==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@popperjs/core": "^2.11.6",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/base/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
+ "node_modules/@mui/core-downloads-tracker": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.7.tgz",
+ "integrity": "sha512-lZgX7XQTk0zVcpwEa80r+T4y09dosnUxWvFPSikU/2Hh5wnyNOek8WfJwGCNsaRiXJHMi5eHY+z8oku4u5lgNw==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ }
+ },
+ "node_modules/@mui/icons-material": {
+ "version": "5.11.0",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.0.tgz",
+ "integrity": "sha512-I2LaOKqO8a0xcLGtIozC9xoXjZAto5G5gh0FYUMAlbsIHNHIjn4Xrw9rvjY20vZonyiGrZNMAlAXYkY6JvhF6A==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.6"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@mui/material": "^5.0.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.7.tgz",
+ "integrity": "sha512-wDv7Pc6kMe9jeWkmCLt4JChd1lPc2u23JQHpB35L2VwQowpNFoDfIwqi0sYCnZTMKlRc7lza8LqwSwHl2G52Rw==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/base": "5.0.0-alpha.116",
+ "@mui/core-downloads-tracker": "^5.11.7",
+ "@mui/system": "^5.11.7",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@types/react-transition-group": "^4.4.5",
+ "clsx": "^1.2.1",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
+ "node_modules/@mui/private-theming": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz",
+ "integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/utils": "^5.11.7",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/styled-engine": {
+ "version": "5.11.0",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.0.tgz",
+ "integrity": "sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.6",
+ "@emotion/cache": "^11.10.5",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/system": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.7.tgz",
+ "integrity": "sha512-uGB6hBxGlAdlmbLdTtUZYNPXkgQGGnKxHdkRATqsu7UlCxNsc/yS5NCEWy/3c4pnelD1LDLD39WrntP9mwhfkQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/private-theming": "^5.11.7",
+ "@mui/styled-engine": "^5.11.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "clsx": "^1.2.1",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/types": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz",
+ "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==",
+ "peerDependencies": {
+ "@types/react": "*"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz",
+ "integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@types/prop-types": "^15.7.5",
+ "@types/react-is": "^16.7.1 || ^17.0.0",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/@mui/utils/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -3077,6 +3502,23 @@
}
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.6",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
+ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
+ "node_modules/@remix-run/router": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.1.tgz",
+ "integrity": "sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -4073,6 +4515,22 @@
"@types/react": "*"
}
},
+ "node_modules/@types/react-is": {
+ "version": "17.0.3",
+ "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
+ "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
+ "node_modules/@types/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==",
+ "dependencies": {
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -5642,6 +6100,14 @@
"wrap-ansi": "^7.0.0"
}
},
+ "node_modules/clsx": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+ "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -6570,6 +7036,15 @@
"utila": "~0.4"
}
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
@@ -7967,6 +8442,11 @@
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
}
},
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -8595,6 +9075,19 @@
"he": "bin/he"
}
},
+ "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==",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/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/hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@@ -14227,6 +14720,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.0.tgz",
+ "integrity": "sha512-760bk7y3QwabduExtudhWbd88IBbuD1YfwzpuDUAlJUJ7laIIcqhMvdhSVh1Fur1PE8cGl84L0dxhR3/gvHF7A==",
+ "dependencies": {
+ "@remix-run/router": "1.3.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.0.tgz",
+ "integrity": "sha512-hQouduSTywGJndE86CXJ2h7YEy4HYC6C/uh19etM+79FfQ6cFFFHnHyDlzO4Pq0eBUI96E4qVE5yUjA00yJZGQ==",
+ "dependencies": {
+ "@remix-run/router": "1.3.1",
+ "react-router": "6.8.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -14299,6 +14822,21 @@
}
}
},
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -15422,6 +15960,11 @@
"postcss": "^8.2.15"
}
},
+ "node_modules/stylis": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",
+ "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA=="
+ },
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -18463,6 +19006,133 @@
"integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==",
"requires": {}
},
+ "@emotion/babel-plugin": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
+ "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
+ "requires": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/plugin-syntax-jsx": "^7.17.12",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.0",
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/serialize": "^1.1.1",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.1.3"
+ },
+ "dependencies": {
+ "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=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
+ }
+ }
+ },
+ "@emotion/cache": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz",
+ "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==",
+ "requires": {
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/sheet": "^1.2.1",
+ "@emotion/utils": "^1.2.0",
+ "@emotion/weak-memoize": "^0.3.0",
+ "stylis": "4.1.3"
+ }
+ },
+ "@emotion/hash": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz",
+ "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ=="
+ },
+ "@emotion/is-prop-valid": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
+ "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
+ "requires": {
+ "@emotion/memoize": "^0.8.0"
+ }
+ },
+ "@emotion/memoize": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
+ "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
+ },
+ "@emotion/react": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
+ "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.10.5",
+ "@emotion/cache": "^11.10.5",
+ "@emotion/serialize": "^1.1.1",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+ "@emotion/utils": "^1.2.0",
+ "@emotion/weak-memoize": "^0.3.0",
+ "hoist-non-react-statics": "^3.3.1"
+ }
+ },
+ "@emotion/serialize": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz",
+ "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==",
+ "requires": {
+ "@emotion/hash": "^0.9.0",
+ "@emotion/memoize": "^0.8.0",
+ "@emotion/unitless": "^0.8.0",
+ "@emotion/utils": "^1.2.0",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@emotion/sheet": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz",
+ "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
+ },
+ "@emotion/styled": {
+ "version": "11.10.5",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
+ "integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
+ "requires": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.10.5",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@emotion/serialize": "^1.1.1",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+ "@emotion/utils": "^1.2.0"
+ }
+ },
+ "@emotion/unitless": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
+ "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
+ },
+ "@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz",
+ "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==",
+ "requires": {}
+ },
+ "@emotion/utils": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz",
+ "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw=="
+ },
+ "@emotion/weak-memoize": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz",
+ "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg=="
+ },
"@eslint/eslintrc": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -19088,6 +19758,128 @@
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
},
+ "@mui/base": {
+ "version": "5.0.0-alpha.116",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.116.tgz",
+ "integrity": "sha512-VwhifWdrfHc4/ZdqRZ4Gf+7P39sovNN24By1YVZdvJ9fvp0Sr8sNftGUCjYXXz+xCXVBQDXvhfxMwZrj2MvJvA==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@popperjs/core": "^2.11.6",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
+ "@mui/core-downloads-tracker": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.7.tgz",
+ "integrity": "sha512-lZgX7XQTk0zVcpwEa80r+T4y09dosnUxWvFPSikU/2Hh5wnyNOek8WfJwGCNsaRiXJHMi5eHY+z8oku4u5lgNw=="
+ },
+ "@mui/icons-material": {
+ "version": "5.11.0",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.0.tgz",
+ "integrity": "sha512-I2LaOKqO8a0xcLGtIozC9xoXjZAto5G5gh0FYUMAlbsIHNHIjn4Xrw9rvjY20vZonyiGrZNMAlAXYkY6JvhF6A==",
+ "requires": {
+ "@babel/runtime": "^7.20.6"
+ }
+ },
+ "@mui/material": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.7.tgz",
+ "integrity": "sha512-wDv7Pc6kMe9jeWkmCLt4JChd1lPc2u23JQHpB35L2VwQowpNFoDfIwqi0sYCnZTMKlRc7lza8LqwSwHl2G52Rw==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/base": "5.0.0-alpha.116",
+ "@mui/core-downloads-tracker": "^5.11.7",
+ "@mui/system": "^5.11.7",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@types/react-transition-group": "^4.4.5",
+ "clsx": "^1.2.1",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0",
+ "react-transition-group": "^4.4.5"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
+ "@mui/private-theming": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz",
+ "integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/utils": "^5.11.7",
+ "prop-types": "^15.8.1"
+ }
+ },
+ "@mui/styled-engine": {
+ "version": "5.11.0",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.0.tgz",
+ "integrity": "sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==",
+ "requires": {
+ "@babel/runtime": "^7.20.6",
+ "@emotion/cache": "^11.10.5",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1"
+ }
+ },
+ "@mui/system": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.7.tgz",
+ "integrity": "sha512-uGB6hBxGlAdlmbLdTtUZYNPXkgQGGnKxHdkRATqsu7UlCxNsc/yS5NCEWy/3c4pnelD1LDLD39WrntP9mwhfkQ==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/private-theming": "^5.11.7",
+ "@mui/styled-engine": "^5.11.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "clsx": "^1.2.1",
+ "csstype": "^3.1.1",
+ "prop-types": "^15.8.1"
+ }
+ },
+ "@mui/types": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz",
+ "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==",
+ "requires": {}
+ },
+ "@mui/utils": {
+ "version": "5.11.7",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz",
+ "integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@types/prop-types": "^15.7.5",
+ "@types/react-is": "^16.7.1 || ^17.0.0",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
"@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -19151,6 +19943,16 @@
"source-map": "^0.7.3"
}
},
+ "@popperjs/core": {
+ "version": "2.11.6",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
+ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
+ },
+ "@remix-run/router": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.1.tgz",
+ "integrity": "sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw=="
+ },
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -19907,6 +20709,22 @@
"@types/react": "*"
}
},
+ "@types/react-is": {
+ "version": "17.0.3",
+ "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
+ "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
"@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -21070,6 +21888,11 @@
"wrap-ansi": "^7.0.0"
}
},
+ "clsx": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+ "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
+ },
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -21743,6 +22566,15 @@
"utila": "~0.4"
}
},
+ "dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "requires": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"dom-serializer": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
@@ -22789,6 +23621,11 @@
"pkg-dir": "^4.1.0"
}
},
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+ },
"find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -23209,6 +24046,21 @@
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
+ "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==",
+ "requires": {
+ "react-is": "^16.7.0"
+ },
+ "dependencies": {
+ "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=="
+ }
+ }
+ },
"hoopy": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
@@ -27093,6 +27945,23 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
},
+ "react-router": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.0.tgz",
+ "integrity": "sha512-760bk7y3QwabduExtudhWbd88IBbuD1YfwzpuDUAlJUJ7laIIcqhMvdhSVh1Fur1PE8cGl84L0dxhR3/gvHF7A==",
+ "requires": {
+ "@remix-run/router": "1.3.1"
+ }
+ },
+ "react-router-dom": {
+ "version": "6.8.0",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.0.tgz",
+ "integrity": "sha512-hQouduSTywGJndE86CXJ2h7YEy4HYC6C/uh19etM+79FfQ6cFFFHnHyDlzO4Pq0eBUI96E4qVE5yUjA00yJZGQ==",
+ "requires": {
+ "@remix-run/router": "1.3.1",
+ "react-router": "6.8.0"
+ }
+ },
"react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -27148,6 +28017,17 @@
"workbox-webpack-plugin": "^6.4.1"
}
},
+ "react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "requires": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ }
+ },
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -27970,6 +28850,11 @@
"postcss-selector-parser": "^6.0.4"
}
},
+ "stylis": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",
+ "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA=="
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
diff --git a/package.json b/package.json
index 866d594..4a00bd2 100644
--- a/package.json
+++ b/package.json
@@ -3,11 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@emotion/react": "^11.10.5",
+ "@emotion/styled": "^11.10.5",
+ "@mui/icons-material": "^5.11.0",
+ "@mui/material": "^5.11.7",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-router-dom": "^6.8.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
diff --git a/src/App.js b/src/App.js
index 3784575..1d7608a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,24 +1,17 @@
-import logo from './logo.svg';
-import './App.css';
+import { Route, Routes } from "react-router-dom";
+import PrivateRoute from "./components/PrivateRoute";
+
+import Layout from "./components/layout/Layout";
+import Login from "./pages/login/Login";
function App() {
return (
-
+
+ } />
+ }>
+ } />
+
+
);
}
diff --git a/src/components/PrivateRoute.jsx b/src/components/PrivateRoute.jsx
new file mode 100644
index 0000000..f3af732
--- /dev/null
+++ b/src/components/PrivateRoute.jsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { Navigate, Outlet } from 'react-router-dom';
+
+const PrivateRoute = () => {
+ const auth = null; // TODO: determine if authorized, from redux later.
+
+ return auth ? : ;
+}
+
+export default PrivateRoute;
diff --git a/src/components/Routes.jsx b/src/components/Routes.jsx
new file mode 100644
index 0000000..ac22b2b
--- /dev/null
+++ b/src/components/Routes.jsx
@@ -0,0 +1,12 @@
+import React from "react";
+import { Route, Routes, Navigate } from "react-router-dom";
+
+const AppRoutes = () => {
+ return (
+
+ } />
+
+ );
+};
+
+export default AppRoutes;
diff --git a/src/components/layout/Layout.jsx b/src/components/layout/Layout.jsx
new file mode 100644
index 0000000..672e84e
--- /dev/null
+++ b/src/components/layout/Layout.jsx
@@ -0,0 +1,17 @@
+import React from "react";
+import AppRoutes from "../Routes";
+import { Route } from "react-router-dom";
+
+const Layout = () => {
+ return (
+ (
+
+ )}
+ />
+ );
+};
+
+export default Layout;
diff --git a/src/index.js b/src/index.js
index d563c0f..b390529 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,13 +1,16 @@
-import React from 'react';
-import ReactDOM from 'react-dom/client';
-import './index.css';
-import App from './App';
-import reportWebVitals from './reportWebVitals';
+import React from "react";
+import ReactDOM from "react-dom/client";
+import "./index.css";
+import App from "./App";
+import reportWebVitals from "./reportWebVitals";
+import { BrowserRouter } from "react-router-dom";
-const root = ReactDOM.createRoot(document.getElementById('root'));
+const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
-
+
+
+
);
diff --git a/src/pages/login/Login.jsx b/src/pages/login/Login.jsx
new file mode 100644
index 0000000..8de0fab
--- /dev/null
+++ b/src/pages/login/Login.jsx
@@ -0,0 +1,93 @@
+import * as React from "react";
+import Avatar from "@mui/material/Avatar";
+import Button from "@mui/material/Button";
+import CssBaseline from "@mui/material/CssBaseline";
+import TextField from "@mui/material/TextField";
+import FormControlLabel from "@mui/material/FormControlLabel";
+import Checkbox from "@mui/material/Checkbox";
+import Link from "@mui/material/Link";
+import Grid from "@mui/material/Grid";
+import Box from "@mui/material/Box";
+import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
+import Typography from "@mui/material/Typography";
+import Container from "@mui/material/Container";
+import { createTheme, ThemeProvider } from "@mui/material/styles";
+
+const theme = createTheme();
+
+export default function SignIn() {
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ const data = new FormData(event.currentTarget);
+ console.log({
+ email: data.get("email"),
+ password: data.get("password"),
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ Sign in
+
+
+
+
+
+
+
+
+
+ {"Don't have an account? Sign Up"}
+
+
+
+
+
+
+
+ );
+}
From b7100f6cfe46a516a010c4401f497a7e67aa56c4 Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Tue, 7 Feb 2023 17:20:12 +0500
Subject: [PATCH 2/6] add navbar
---
src/App.js | 18 ++--
src/components/navbar/Navbar.jsx | 174 +++++++++++++++++++++++++++++++
src/pages/home/Home.jsx | 9 ++
src/pages/login/Login.jsx | 19 ++--
src/pages/register/Register.jsx | 130 +++++++++++++++++++++++
5 files changed, 332 insertions(+), 18 deletions(-)
create mode 100644 src/components/navbar/Navbar.jsx
create mode 100644 src/pages/home/Home.jsx
create mode 100644 src/pages/register/Register.jsx
diff --git a/src/App.js b/src/App.js
index 1d7608a..c7f04f6 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,15 +3,21 @@ import PrivateRoute from "./components/PrivateRoute";
import Layout from "./components/layout/Layout";
import Login from "./pages/login/Login";
+import Register from "./pages/register/Register";
+import Navbar from "./components/navbar/Navbar";
function App() {
return (
-
- } />
- }>
- } />
-
-
+ <>
+
+
+ } />
+ } />
+ }>
+ } />
+
+
+ >
);
}
diff --git a/src/components/navbar/Navbar.jsx b/src/components/navbar/Navbar.jsx
new file mode 100644
index 0000000..22e7d79
--- /dev/null
+++ b/src/components/navbar/Navbar.jsx
@@ -0,0 +1,174 @@
+import React, { useEffect, useState } from "react";
+import AppBar from "@mui/material/AppBar";
+import Box from "@mui/material/Box";
+import Toolbar from "@mui/material/Toolbar";
+import IconButton from "@mui/material/IconButton";
+import Typography from "@mui/material/Typography";
+import Menu from "@mui/material/Menu";
+import MenuIcon from "@mui/icons-material/Menu";
+import Container from "@mui/material/Container";
+import Avatar from "@mui/material/Avatar";
+import Button from "@mui/material/Button";
+import Tooltip from "@mui/material/Tooltip";
+import MenuItem from "@mui/material/MenuItem";
+import AdbIcon from "@mui/icons-material/Adb";
+
+const userPages = ["Books", "My Books", "My Requests"];
+const librarianPages = ["Books", "Books Loans", "Book Requests"];
+const anonPages = ["Books"];
+const settings = ["Profile", "Account", "Dashboard", "Logout"];
+
+function ResponsiveAppBar() {
+ const [anchorElNav, setAnchorElNav] = useState(null);
+ const [anchorElUser, setAnchorElUser] = useState(null);
+ const [pages, setPages] = useState(anonPages);
+ const [user] = useState({ isAuth: false, isLibrarian: false });
+
+ useEffect(() => {
+ if (user.isLibrarian) {
+ setPages(librarianPages);
+ } else if (user.isAuth) {
+ setPages(userPages);
+ }
+ }, [user]);
+
+ const handleOpenNavMenu = (event) => {
+ setAnchorElNav(event.currentTarget);
+ };
+ const handleOpenUserMenu = (event) => {
+ setAnchorElUser(event.currentTarget);
+ };
+
+ const handleCloseNavMenu = () => {
+ setAnchorElNav(null);
+ };
+
+ const handleCloseUserMenu = () => {
+ setAnchorElUser(null);
+ };
+
+ return (
+
+
+
+
+
+ LOGO
+
+
+
+
+
+
+
+
+
+
+ LMS
+
+
+ {pages.map((page) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+export default ResponsiveAppBar;
diff --git a/src/pages/home/Home.jsx b/src/pages/home/Home.jsx
new file mode 100644
index 0000000..96c5535
--- /dev/null
+++ b/src/pages/home/Home.jsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const Home = () => {
+ return (
+ Home
+ )
+}
+
+export default Home
\ No newline at end of file
diff --git a/src/pages/login/Login.jsx b/src/pages/login/Login.jsx
index 8de0fab..63b98c6 100644
--- a/src/pages/login/Login.jsx
+++ b/src/pages/login/Login.jsx
@@ -1,19 +1,16 @@
-import * as React from "react";
+import React from "react";
import Avatar from "@mui/material/Avatar";
import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
import TextField from "@mui/material/TextField";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Checkbox from "@mui/material/Checkbox";
import Link from "@mui/material/Link";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";
-import { createTheme, ThemeProvider } from "@mui/material/styles";
-const theme = createTheme();
+
export default function SignIn() {
const handleSubmit = (event) => {
@@ -26,7 +23,6 @@ export default function SignIn() {
};
return (
-
-
+
{"Don't have an account? Sign Up"}
@@ -88,6 +84,5 @@ export default function SignIn() {
-
);
}
diff --git a/src/pages/register/Register.jsx b/src/pages/register/Register.jsx
new file mode 100644
index 0000000..e86d4f3
--- /dev/null
+++ b/src/pages/register/Register.jsx
@@ -0,0 +1,130 @@
+import React from "react";
+import Avatar from "@mui/material/Avatar";
+import Button from "@mui/material/Button";
+import CssBaseline from "@mui/material/CssBaseline";
+import TextField from "@mui/material/TextField";
+
+import Link from "@mui/material/Link";
+import Grid from "@mui/material/Grid";
+import Box from "@mui/material/Box";
+import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
+import Typography from "@mui/material/Typography";
+import Container from "@mui/material/Container";
+import Select from "@mui/material/Select";
+import MenuItem from "@mui/material/MenuItem";
+import FormControl from "@mui/material/FormControl";
+import InputLabel from "@mui/material/InputLabel";
+
+export default function SignUp() {
+ const [gender, setGender] = React.useState("");
+
+ const handleChange = (event) => {
+ setGender(event.target.value);
+ };
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ const data = new FormData(event.currentTarget);
+ console.log({
+ email: data.get("email"),
+ password: data.get("password"),
+ });
+ };
+
+ return (
+
+
+
+
+
+
+
+ Sign up
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gender
+
+
+
+
+
+
+
+
+ Already have an account? Sign in
+
+
+
+
+
+
+ );
+}
From 886754f47305fca01155e0fd1c072e43c2025309 Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Wed, 8 Feb 2023 18:47:39 +0500
Subject: [PATCH 3/6] setup user redux
---
.env | 1 +
package-lock.json | 406 +++++++++++++++++++++++++--
package.json | 5 +
src/App.css | 38 ---
src/App.js | 64 ++++-
src/components/PrivateRoute.jsx | 11 +-
src/components/Routes.jsx | 12 -
src/components/layout/Layout.jsx | 24 +-
src/components/navbar/Navbar.jsx | 185 ++++--------
src/index.js | 10 +-
src/interceptor/interceptor.js | 28 ++
src/pages/404/PageNotFound.jsx | 9 +
src/pages/login/Login.jsx | 151 +++++-----
src/pages/my_books/MyBooks.jsx | 9 +
src/pages/my_requests/MyRequests.jsx | 9 +
src/store/Store.js | 8 +
src/store/actions/userActions.jsx | 24 ++
src/store/slices/userSlice.jsx | 51 ++++
18 files changed, 748 insertions(+), 297 deletions(-)
create mode 100644 .env
delete mode 100644 src/App.css
delete mode 100644 src/components/Routes.jsx
create mode 100644 src/interceptor/interceptor.js
create mode 100644 src/pages/404/PageNotFound.jsx
create mode 100644 src/pages/my_books/MyBooks.jsx
create mode 100644 src/pages/my_requests/MyRequests.jsx
create mode 100644 src/store/Store.js
create mode 100644 src/store/actions/userActions.jsx
create mode 100644 src/store/slices/userSlice.jsx
diff --git a/.env b/.env
new file mode 100644
index 0000000..29b0abf
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+REACT_APP_BACKEND_URL=http://localhost:8000
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index d575520..298c884 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,14 +11,19 @@
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@mui/icons-material": "^5.11.0",
+ "@mui/lab": "^5.0.0-alpha.119",
"@mui/material": "^5.11.7",
+ "@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-redux": "^8.0.5",
"react-router-dom": "^6.8.0",
"react-scripts": "5.0.1",
+ "react-toastify": "^9.1.1",
"web-vitals": "^2.1.4"
}
},
@@ -3208,6 +3213,84 @@
}
}
},
+ "node_modules/@mui/lab": {
+ "version": "5.0.0-alpha.119",
+ "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.119.tgz",
+ "integrity": "sha512-74l+gA7fybcB2zyOLjWsPbOxt2F4ydu4t0a5rEC/Y4v6q0wDKaW1El1S/+zuE5Xw/fQmiwNrQ+Do5fDbRZDAsw==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/base": "5.0.0-alpha.117",
+ "@mui/system": "^5.11.8",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@mui/material": "^5.0.0",
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/lab/node_modules/@mui/base": {
+ "version": "5.0.0-alpha.117",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.117.tgz",
+ "integrity": "sha512-3GlRSZdSrvDQ4k03dSV2rM+97JbNWimFOqGsE7n7Mi8WuBSYCgnPe56bQp3E5cShOrTn11dGH8FRCmVMcCEXqQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.20.7",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@popperjs/core": "^2.11.6",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0",
+ "react": "^17.0.0 || ^18.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/lab/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
"node_modules/@mui/material": {
"version": "5.11.7",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.7.tgz",
@@ -3284,11 +3367,11 @@
}
},
"node_modules/@mui/styled-engine": {
- "version": "5.11.0",
- "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.0.tgz",
- "integrity": "sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==",
+ "version": "5.11.8",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz",
+ "integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==",
"dependencies": {
- "@babel/runtime": "^7.20.6",
+ "@babel/runtime": "^7.20.7",
"@emotion/cache": "^11.10.5",
"csstype": "^3.1.1",
"prop-types": "^15.8.1"
@@ -3315,13 +3398,13 @@
}
},
"node_modules/@mui/system": {
- "version": "5.11.7",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.7.tgz",
- "integrity": "sha512-uGB6hBxGlAdlmbLdTtUZYNPXkgQGGnKxHdkRATqsu7UlCxNsc/yS5NCEWy/3c4pnelD1LDLD39WrntP9mwhfkQ==",
+ "version": "5.11.8",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz",
+ "integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==",
"dependencies": {
"@babel/runtime": "^7.20.7",
"@mui/private-theming": "^5.11.7",
- "@mui/styled-engine": "^5.11.0",
+ "@mui/styled-engine": "^5.11.8",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.7",
"clsx": "^1.2.1",
@@ -3511,6 +3594,29 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.2.tgz",
+ "integrity": "sha512-5ZAZ7hwAKWSii5T6NTPmgIBUqyVdlDs+6JjThz6J6dmHLDm6zCzv2OjHIFAi3Vvs1qjmXU0bm6eBojukYXjVMQ==",
+ "dependencies": {
+ "immer": "^9.0.16",
+ "redux": "^4.2.0",
+ "redux-thunk": "^2.4.2",
+ "reselect": "^4.1.7"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18",
+ "react-redux": "^7.2.1 || ^8.0.2"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@remix-run/router": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.1.tgz",
@@ -4177,6 +4283,15 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -4597,6 +4712,11 @@
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+ },
"node_modules/@types/ws": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
@@ -5411,6 +5531,29 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.2.tgz",
+ "integrity": "sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==",
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/axios/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==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -14418,6 +14561,11 @@
"node": ">= 0.10"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -14712,6 +14860,49 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
+ "node_modules/react-redux": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+ "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.1",
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "@types/use-sync-external-store": "^0.0.3",
+ "hoist-non-react-statics": "^3.3.2",
+ "react-is": "^18.0.0",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8 || ^17.0 || ^18.0",
+ "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0",
+ "react-native": ">=0.59",
+ "redux": "^4"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-redux/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ },
"node_modules/react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
@@ -14822,6 +15013,18 @@
}
}
},
+ "node_modules/react-toastify": {
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.1.tgz",
+ "integrity": "sha512-pkFCla1z3ve045qvjEmn2xOJOy4ZciwRXm1oMPULVkELi5aJdHCN/FHnuqXq8IwGDLB7PPk2/J6uP9D8ejuiRw==",
+ "dependencies": {
+ "clsx": "^1.1.1"
+ },
+ "peerDependencies": {
+ "react": ">=16",
+ "react-dom": ">=16"
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -14892,6 +15095,22 @@
"node": ">=8"
}
},
+ "node_modules/redux": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+ "peerDependencies": {
+ "redux": "^4"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -15034,6 +15253,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
+ "node_modules/reselect": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
+ "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
+ },
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -16628,6 +16852,14 @@
"requires-port": "^1.0.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -19793,6 +20025,43 @@
"@babel/runtime": "^7.20.6"
}
},
+ "@mui/lab": {
+ "version": "5.0.0-alpha.119",
+ "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.119.tgz",
+ "integrity": "sha512-74l+gA7fybcB2zyOLjWsPbOxt2F4ydu4t0a5rEC/Y4v6q0wDKaW1El1S/+zuE5Xw/fQmiwNrQ+Do5fDbRZDAsw==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@mui/base": "5.0.0-alpha.117",
+ "@mui/system": "^5.11.8",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ },
+ "dependencies": {
+ "@mui/base": {
+ "version": "5.0.0-alpha.117",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.117.tgz",
+ "integrity": "sha512-3GlRSZdSrvDQ4k03dSV2rM+97JbNWimFOqGsE7n7Mi8WuBSYCgnPe56bQp3E5cShOrTn11dGH8FRCmVMcCEXqQ==",
+ "requires": {
+ "@babel/runtime": "^7.20.7",
+ "@emotion/is-prop-valid": "^1.2.0",
+ "@mui/types": "^7.2.3",
+ "@mui/utils": "^5.11.7",
+ "@popperjs/core": "^2.11.6",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^18.2.0"
+ }
+ },
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
"@mui/material": {
"version": "5.11.7",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.7.tgz",
@@ -19830,24 +20099,24 @@
}
},
"@mui/styled-engine": {
- "version": "5.11.0",
- "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.0.tgz",
- "integrity": "sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==",
+ "version": "5.11.8",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz",
+ "integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==",
"requires": {
- "@babel/runtime": "^7.20.6",
+ "@babel/runtime": "^7.20.7",
"@emotion/cache": "^11.10.5",
"csstype": "^3.1.1",
"prop-types": "^15.8.1"
}
},
"@mui/system": {
- "version": "5.11.7",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.7.tgz",
- "integrity": "sha512-uGB6hBxGlAdlmbLdTtUZYNPXkgQGGnKxHdkRATqsu7UlCxNsc/yS5NCEWy/3c4pnelD1LDLD39WrntP9mwhfkQ==",
+ "version": "5.11.8",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz",
+ "integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==",
"requires": {
"@babel/runtime": "^7.20.7",
"@mui/private-theming": "^5.11.7",
- "@mui/styled-engine": "^5.11.0",
+ "@mui/styled-engine": "^5.11.8",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.7",
"clsx": "^1.2.1",
@@ -19948,6 +20217,17 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
},
+ "@reduxjs/toolkit": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.2.tgz",
+ "integrity": "sha512-5ZAZ7hwAKWSii5T6NTPmgIBUqyVdlDs+6JjThz6J6dmHLDm6zCzv2OjHIFAi3Vvs1qjmXU0bm6eBojukYXjVMQ==",
+ "requires": {
+ "immer": "^9.0.16",
+ "redux": "^4.2.0",
+ "redux-thunk": "^2.4.2",
+ "reselect": "^4.1.7"
+ }
+ },
"@remix-run/router": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.1.tgz",
@@ -20424,6 +20704,15 @@
"@types/node": "*"
}
},
+ "@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "requires": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -20791,6 +21080,11 @@
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
},
+ "@types/use-sync-external-store": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
+ "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
+ },
"@types/ws": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
@@ -21374,6 +21668,28 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
"integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg=="
},
+ "axios": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.2.tgz",
+ "integrity": "sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==",
+ "requires": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ },
+ "dependencies": {
+ "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==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
+ }
+ },
"axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -27729,6 +28045,11 @@
}
}
},
+ "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=="
+ },
"psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -27940,6 +28261,26 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
+ "react-redux": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
+ "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "@types/use-sync-external-store": "^0.0.3",
+ "hoist-non-react-statics": "^3.3.2",
+ "react-is": "^18.0.0",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+ }
+ }
+ },
"react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
@@ -28017,6 +28358,14 @@
"workbox-webpack-plugin": "^6.4.1"
}
},
+ "react-toastify": {
+ "version": "9.1.1",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.1.tgz",
+ "integrity": "sha512-pkFCla1z3ve045qvjEmn2xOJOy4ZciwRXm1oMPULVkELi5aJdHCN/FHnuqXq8IwGDLB7PPk2/J6uP9D8ejuiRw==",
+ "requires": {
+ "clsx": "^1.1.1"
+ }
+ },
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -28071,6 +28420,20 @@
"strip-indent": "^3.0.0"
}
},
+ "redux": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
+ "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "redux-thunk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
+ "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
+ "requires": {}
+ },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -28182,6 +28545,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
},
+ "reselect": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.7.tgz",
+ "integrity": "sha512-Zu1xbUt3/OPwsXL46hvOOoQrap2azE7ZQbokq61BQfiXvhewsKDwhMeZjTX9sX0nvw1t/U5Audyn1I9P/m9z0A=="
+ },
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -29342,6 +29710,12 @@
"requires-port": "^1.0.0"
}
},
+ "use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "requires": {}
+ },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index 4a00bd2..625565a 100644
--- a/package.json
+++ b/package.json
@@ -6,14 +6,19 @@
"@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5",
"@mui/icons-material": "^5.11.0",
+ "@mui/lab": "^5.0.0-alpha.119",
"@mui/material": "^5.11.7",
+ "@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
+ "axios": "^1.3.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-redux": "^8.0.5",
"react-router-dom": "^6.8.0",
"react-scripts": "5.0.1",
+ "react-toastify": "^9.1.1",
"web-vitals": "^2.1.4"
},
"scripts": {
diff --git a/src/App.css b/src/App.css
deleted file mode 100644
index 74b5e05..0000000
--- a/src/App.css
+++ /dev/null
@@ -1,38 +0,0 @@
-.App {
- text-align: center;
-}
-
-.App-logo {
- height: 40vmin;
- pointer-events: none;
-}
-
-@media (prefers-reduced-motion: no-preference) {
- .App-logo {
- animation: App-logo-spin infinite 20s linear;
- }
-}
-
-.App-header {
- background-color: #282c34;
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- font-size: calc(10px + 2vmin);
- color: white;
-}
-
-.App-link {
- color: #61dafb;
-}
-
-@keyframes App-logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/App.js b/src/App.js
index c7f04f6..287c94b 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,23 +1,69 @@
+import React, { Fragment, useEffect } from "react";
import { Route, Routes } from "react-router-dom";
-import PrivateRoute from "./components/PrivateRoute";
+import { useDispatch, useSelector } from "react-redux";
+
+import { ToastContainer } from "react-toastify";
+import axios from "axios";
+
+import "react-toastify/dist/ReactToastify.css";
+import PrivateRoute from "./components/PrivateRoute";
import Layout from "./components/layout/Layout";
import Login from "./pages/login/Login";
import Register from "./pages/register/Register";
-import Navbar from "./components/navbar/Navbar";
+import PageNotFound from "./pages/404/PageNotFound";
+import httpIntercept from "./interceptor/interceptor";
+import { setCredentials } from "./store/slices/userSlice";
+import Home from "./pages/home/Home";
+import MyBooks from "./pages/my_books/MyBooks";
+import MyRequests from "./pages/my_requests/MyRequests";
function App() {
+ httpIntercept();
+
+ const { authToken } = useSelector((state) => state.user);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ const token = localStorage.getItem("authToken");
+ if (token) {
+ axios
+ .get(`${process.env.REACT_APP_BACKEND_URL}/auth/users/me`)
+ .then(({ data }) => {
+ dispatch(setCredentials(data));
+ });
+ }
+ }, [dispatch, authToken]);
+
return (
- <>
-
+
- } />
- } />
- }>
- } />
+ }>
+ } />
+ }/>
+
+ } />
+ } />
+
+ }>
+ } />
+ } />
+
- >
+
+
);
}
diff --git a/src/components/PrivateRoute.jsx b/src/components/PrivateRoute.jsx
index f3af732..b802868 100644
--- a/src/components/PrivateRoute.jsx
+++ b/src/components/PrivateRoute.jsx
@@ -1,10 +1,11 @@
-import React from 'react';
-import { Navigate, Outlet } from 'react-router-dom';
+import React from "react";
+import { useSelector } from "react-redux";
+import { Navigate, Outlet } from "react-router-dom";
const PrivateRoute = () => {
- const auth = null; // TODO: determine if authorized, from redux later.
+ const { authToken } = useSelector((state) => state.user);
- return auth ? : ;
-}
+ return authToken ? : ;
+};
export default PrivateRoute;
diff --git a/src/components/Routes.jsx b/src/components/Routes.jsx
deleted file mode 100644
index ac22b2b..0000000
--- a/src/components/Routes.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from "react";
-import { Route, Routes, Navigate } from "react-router-dom";
-
-const AppRoutes = () => {
- return (
-
- } />
-
- );
-};
-
-export default AppRoutes;
diff --git a/src/components/layout/Layout.jsx b/src/components/layout/Layout.jsx
index 672e84e..31aa1ba 100644
--- a/src/components/layout/Layout.jsx
+++ b/src/components/layout/Layout.jsx
@@ -1,16 +1,20 @@
-import React from "react";
-import AppRoutes from "../Routes";
-import { Route } from "react-router-dom";
+import React, { Fragment } from "react";
+import { Outlet } from "react-router-dom";
+
+import Container from "@mui/material/Container";
+import CssBaseline from "@mui/material/CssBaseline";
+
+import Navbar from "../navbar/Navbar";
const Layout = () => {
return (
- (
-
- )}
- />
+
+
+
+
+
+
+
);
};
diff --git a/src/components/navbar/Navbar.jsx b/src/components/navbar/Navbar.jsx
index 22e7d79..4eea8f9 100644
--- a/src/components/navbar/Navbar.jsx
+++ b/src/components/navbar/Navbar.jsx
@@ -1,170 +1,87 @@
import React, { useEffect, useState } from "react";
+import { useNavigate } from "react-router-dom";
+import { useDispatch, useSelector } from "react-redux";
+
import AppBar from "@mui/material/AppBar";
import Box from "@mui/material/Box";
import Toolbar from "@mui/material/Toolbar";
-import IconButton from "@mui/material/IconButton";
-import Typography from "@mui/material/Typography";
-import Menu from "@mui/material/Menu";
-import MenuIcon from "@mui/icons-material/Menu";
import Container from "@mui/material/Container";
-import Avatar from "@mui/material/Avatar";
import Button from "@mui/material/Button";
-import Tooltip from "@mui/material/Tooltip";
-import MenuItem from "@mui/material/MenuItem";
import AdbIcon from "@mui/icons-material/Adb";
-const userPages = ["Books", "My Books", "My Requests"];
-const librarianPages = ["Books", "Books Loans", "Book Requests"];
-const anonPages = ["Books"];
-const settings = ["Profile", "Account", "Dashboard", "Logout"];
+import { logout } from "../../store/slices/userSlice";
+
+const userPages = [
+ { name: "My Books", path: "lms/mybooks" },
+ { name: "My Requests", path: "lms/myrequests" },
+];
+const librarianPages = ["Books Loans", "Book Requests"];
function ResponsiveAppBar() {
- const [anchorElNav, setAnchorElNav] = useState(null);
- const [anchorElUser, setAnchorElUser] = useState(null);
- const [pages, setPages] = useState(anonPages);
- const [user] = useState({ isAuth: false, isLibrarian: false });
+ const [pages, setPages] = useState([]);
+ const { userInfo } = useSelector((state) => state.user);
+
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
useEffect(() => {
- if (user.isLibrarian) {
+ if (userInfo?.isLibrarian) {
setPages(librarianPages);
- } else if (user.isAuth) {
+ } else if (userInfo) {
setPages(userPages);
+ } else {
+ setPages([]);
}
- }, [user]);
-
- const handleOpenNavMenu = (event) => {
- setAnchorElNav(event.currentTarget);
- };
- const handleOpenUserMenu = (event) => {
- setAnchorElUser(event.currentTarget);
- };
-
- const handleCloseNavMenu = () => {
- setAnchorElNav(null);
- };
-
- const handleCloseUserMenu = () => {
- setAnchorElUser(null);
- };
+ }, [userInfo]);
return (
- navigate("/")}
+ sx={{ my: 2, color: "white", display: "block" }}
>
- LOGO
-
+ Home
+
-
-
-
-
-
-
-
-
- LMS
-
{pages.map((page) => (
))}
-
-
-
-
-
-
+ {userInfo ? (
+
+ ) : (
+
+
+
+
+ )}
diff --git a/src/index.js b/src/index.js
index b390529..0103966 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,16 +5,18 @@ import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
+import { store } from "./store/Store";
+import { Provider } from "react-redux";
+
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
-
+
+
+
);
-// If you want to start measuring performance in your app, pass a function
-// to log results (for example: reportWebVitals(console.log))
-// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
diff --git a/src/interceptor/interceptor.js b/src/interceptor/interceptor.js
new file mode 100644
index 0000000..f9134a0
--- /dev/null
+++ b/src/interceptor/interceptor.js
@@ -0,0 +1,28 @@
+import axios from "axios";
+
+const httpIntercept = (props) => {
+ axios.interceptors.request.use(
+ (request) => {
+ if (request.url.includes(process.env.REACT_APP_BACKEND_URL)) {
+ request.headers.Authorization =
+ "JWT " + localStorage.getItem("authToken");
+ }
+ return request;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+ );
+
+ axios.interceptors.response.use(
+ (response) => {
+ // Edit response config
+ return response;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+ );
+};
+
+export default httpIntercept;
diff --git a/src/pages/404/PageNotFound.jsx b/src/pages/404/PageNotFound.jsx
new file mode 100644
index 0000000..362b116
--- /dev/null
+++ b/src/pages/404/PageNotFound.jsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const PageNotFound = () => {
+ return (
+ PageNotFound
+ )
+}
+
+export default PageNotFound
\ No newline at end of file
diff --git a/src/pages/login/Login.jsx b/src/pages/login/Login.jsx
index 63b98c6..8ef42bd 100644
--- a/src/pages/login/Login.jsx
+++ b/src/pages/login/Login.jsx
@@ -1,88 +1,101 @@
-import React from "react";
+import React, { useEffect } from "react";
+import { useNavigate } from "react-router-dom";
+import { useDispatch, useSelector } from "react-redux";
+
import Avatar from "@mui/material/Avatar";
-import Button from "@mui/material/Button";
-import CssBaseline from "@mui/material/CssBaseline";
import TextField from "@mui/material/TextField";
import Link from "@mui/material/Link";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
import Typography from "@mui/material/Typography";
-import Container from "@mui/material/Container";
-
+import LoadingButton from "@mui/lab/LoadingButton";
+import Alert from "@mui/material/Alert";
+import { userLogin } from "../../store/actions/userActions";
export default function SignIn() {
+ const { loading, userInfo, error } = useSelector((state) => state.user);
+
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ // redirect authenticated user to profile screen
+ useEffect(() => {
+ if (userInfo) {
+ navigate("/");
+ }
+ }, [navigate, userInfo]);
+
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
- console.log({
- email: data.get("email"),
- password: data.get("password"),
- });
+ dispatch(
+ userLogin({
+ username: data.get("username"),
+ password: data.get("password"),
+ })
+ );
};
return (
-
-
-
+
+
+
+
+ Sign in
+
+
+
+
+ {error?.detail && (
+
+ {error?.detail}
+
+ )}
+
-
-
-
-
- Sign in
-
-
-
-
-
-
-
-
-
- {"Don't have an account? Sign Up"}
-
-
-
-
-
-
+ Sign In
+
+
+
+
+ {"Don't have an account? Sign Up"}
+
+
+
+
+
);
}
diff --git a/src/pages/my_books/MyBooks.jsx b/src/pages/my_books/MyBooks.jsx
new file mode 100644
index 0000000..d3c07e4
--- /dev/null
+++ b/src/pages/my_books/MyBooks.jsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const MyBooks = () => {
+ return (
+ MyBooks
+ )
+}
+
+export default MyBooks
\ No newline at end of file
diff --git a/src/pages/my_requests/MyRequests.jsx b/src/pages/my_requests/MyRequests.jsx
new file mode 100644
index 0000000..dd1c124
--- /dev/null
+++ b/src/pages/my_requests/MyRequests.jsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const MyRequests = () => {
+ return (
+ MyRequests
+ )
+}
+
+export default MyRequests
\ No newline at end of file
diff --git a/src/store/Store.js b/src/store/Store.js
new file mode 100644
index 0000000..1835217
--- /dev/null
+++ b/src/store/Store.js
@@ -0,0 +1,8 @@
+import { configureStore } from '@reduxjs/toolkit'
+import userReducer from './slices/userSlice'
+
+export const store = configureStore({
+ reducer: {
+ user: userReducer,
+ },
+})
diff --git a/src/store/actions/userActions.jsx b/src/store/actions/userActions.jsx
new file mode 100644
index 0000000..1309505
--- /dev/null
+++ b/src/store/actions/userActions.jsx
@@ -0,0 +1,24 @@
+import axios from "axios";
+import { createAsyncThunk } from "@reduxjs/toolkit";
+import { toast } from "react-toastify";
+
+export const userLogin = createAsyncThunk(
+ "auth/login",
+ async ({ username, password }, { rejectWithValue }) => {
+ try {
+ const { data } = await axios.post(
+ `${process.env.REACT_APP_BACKEND_URL}/auth/jwt/create`,
+ { username, password }
+ );
+ localStorage.setItem("authToken", data.access);
+ return data;
+ } catch (error) {
+ if (error.response && error.response.data.detail) {
+ return rejectWithValue(error.response.data);
+ } else {
+ toast.error(error.message);
+ return rejectWithValue(error.message);
+ }
+ }
+ }
+);
diff --git a/src/store/slices/userSlice.jsx b/src/store/slices/userSlice.jsx
new file mode 100644
index 0000000..b36bc84
--- /dev/null
+++ b/src/store/slices/userSlice.jsx
@@ -0,0 +1,51 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+import { userLogin } from "../actions/userActions";
+
+const authToken = localStorage.getItem("authToken")
+ ? localStorage.getItem("authToken")
+ : null;
+
+const initialState = {
+ loading: false,
+ userInfo: null,
+ authToken,
+ error: null,
+ success: false,
+};
+
+export const userSlice = createSlice({
+ name: "user",
+ initialState,
+ reducers: {
+ logout: (state, { payload }) => {
+ localStorage.removeItem("authToken");
+ state.loading = false
+ state.userInfo = null
+ state.authToken = null
+ state.error = null
+ },
+ setCredentials: (state, { payload }) => {
+ state.userInfo = payload;
+ },
+ },
+ extraReducers: {
+ // login user
+ [userLogin.pending]: (state) => {
+ state.loading = true;
+ state.error = null;
+ },
+ [userLogin.fulfilled]: (state, { payload }) => {
+ state.loading = false;
+ state.authToken = payload.access;
+ },
+ [userLogin.rejected]: (state, { payload }) => {
+ state.loading = false;
+ state.error = payload;
+ },
+ },
+});
+
+
+export const { logout, setCredentials } = userSlice.actions
+export default userSlice.reducer;
From ad4a0ec54f2621668147e58cb5451ba53b7b23b3 Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Tue, 28 Feb 2023 18:11:05 +0500
Subject: [PATCH 4/6] add home page and book loans
---
package-lock.json | 224 ++++++++++++++++++
package.json | 3 +
src/App.js | 4 +-
src/components/forms/BookLoanForm.jsx | 127 ++++++++++
src/components/navbar/Navbar.jsx | 9 +-
src/pages/book_loans/BookLoans.jsx | 103 ++++++++
.../BookRequests.jsx} | 0
src/pages/home/Home.jsx | 86 ++++++-
src/pages/my_books/MyBooks.jsx | 9 -
9 files changed, 546 insertions(+), 19 deletions(-)
create mode 100644 src/components/forms/BookLoanForm.jsx
create mode 100644 src/pages/book_loans/BookLoans.jsx
rename src/pages/{my_requests/MyRequests.jsx => book_requests/BookRequests.jsx} (100%)
delete mode 100644 src/pages/my_books/MyBooks.jsx
diff --git a/package-lock.json b/package-lock.json
index 298c884..5f60a6c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,11 +13,14 @@
"@mui/icons-material": "^5.11.0",
"@mui/lab": "^5.0.0-alpha.119",
"@mui/material": "^5.11.7",
+ "@mui/x-date-pickers": "^5.0.20",
"@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.3.2",
+ "moment": "^2.29.4",
+ "momentjs": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
@@ -2134,6 +2137,75 @@
"postcss-selector-parser": "^6.0.10"
}
},
+ "node_modules/@date-io/core": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.16.0.tgz",
+ "integrity": "sha512-DYmSzkr+jToahwWrsiRA2/pzMEtz9Bq1euJwoOuYwuwIYXnZFtHajY2E6a1VNVDc9jP8YUXK1BvnZH9mmT19Zg=="
+ },
+ "node_modules/@date-io/date-fns": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.16.0.tgz",
+ "integrity": "sha512-bfm5FJjucqlrnQcXDVU5RD+nlGmL3iWgkHTq3uAZWVIuBu6dDmGa3m8a6zo2VQQpu8ambq9H22UyUpn7590joA==",
+ "dependencies": {
+ "@date-io/core": "^2.16.0"
+ },
+ "peerDependencies": {
+ "date-fns": "^2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "date-fns": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@date-io/dayjs": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.16.0.tgz",
+ "integrity": "sha512-y5qKyX2j/HG3zMvIxTobYZRGnd1FUW2olZLS0vTj7bEkBQkjd2RO7/FEwDY03Z1geVGlXKnzIATEVBVaGzV4Iw==",
+ "dependencies": {
+ "@date-io/core": "^2.16.0"
+ },
+ "peerDependencies": {
+ "dayjs": "^1.8.17"
+ },
+ "peerDependenciesMeta": {
+ "dayjs": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@date-io/luxon": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.16.1.tgz",
+ "integrity": "sha512-aeYp5K9PSHV28946pC+9UKUi/xMMYoaGelrpDibZSgHu2VWHXrr7zWLEr+pMPThSs5vt8Ei365PO+84pCm37WQ==",
+ "dependencies": {
+ "@date-io/core": "^2.16.0"
+ },
+ "peerDependencies": {
+ "luxon": "^1.21.3 || ^2.x || ^3.x"
+ },
+ "peerDependenciesMeta": {
+ "luxon": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@date-io/moment": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.16.1.tgz",
+ "integrity": "sha512-JkxldQxUqZBfZtsaCcCMkm/dmytdyq5pS1RxshCQ4fHhsvP5A7gSqPD22QbVXMcJydi3d3v1Y8BQdUKEuGACZQ==",
+ "dependencies": {
+ "@date-io/core": "^2.16.0"
+ },
+ "peerDependencies": {
+ "moment": "^2.24.0"
+ },
+ "peerDependenciesMeta": {
+ "moment": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@emotion/babel-plugin": {
"version": "11.10.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
@@ -3476,6 +3548,64 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
+ "node_modules/@mui/x-date-pickers": {
+ "version": "5.0.20",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.20.tgz",
+ "integrity": "sha512-ERukSeHIoNLbI1C2XRhF9wRhqfsr+Q4B1SAw2ZlU7CWgcG8UBOxgqRKDEOVAIoSWL+DWT6GRuQjOKvj6UXZceA==",
+ "dependencies": {
+ "@babel/runtime": "^7.18.9",
+ "@date-io/core": "^2.15.0",
+ "@date-io/date-fns": "^2.15.0",
+ "@date-io/dayjs": "^2.15.0",
+ "@date-io/luxon": "^2.15.0",
+ "@date-io/moment": "^2.15.0",
+ "@mui/utils": "^5.10.3",
+ "@types/react-transition-group": "^4.4.5",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.7.2",
+ "react-transition-group": "^4.4.5",
+ "rifm": "^0.12.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.4.1",
+ "@mui/system": "^5.4.1",
+ "date-fns": "^2.25.0",
+ "dayjs": "^1.10.7",
+ "luxon": "^1.28.0 || ^2.0.0 || ^3.0.0",
+ "moment": "^2.29.1",
+ "react": "^17.0.2 || ^18.0.0",
+ "react-dom": "^17.0.2 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -12622,6 +12752,20 @@
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/momentjs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/momentjs/-/momentjs-2.0.0.tgz",
+ "integrity": "sha512-GYMUxLyCwVhECkJR1/LMHEyb9gWYSPRnXi+elGN0m5bet7ngQOxU4QLWUI/eBzgN4N/T194n6yP7lQiE+Udw9A==",
+ "deprecated": "WARNING: The correct package name for Moment.js is 'moment', not 'momentjs'."
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -15374,6 +15518,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/rifm": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz",
+ "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==",
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -19238,6 +19390,43 @@
"integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==",
"requires": {}
},
+ "@date-io/core": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.16.0.tgz",
+ "integrity": "sha512-DYmSzkr+jToahwWrsiRA2/pzMEtz9Bq1euJwoOuYwuwIYXnZFtHajY2E6a1VNVDc9jP8YUXK1BvnZH9mmT19Zg=="
+ },
+ "@date-io/date-fns": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.16.0.tgz",
+ "integrity": "sha512-bfm5FJjucqlrnQcXDVU5RD+nlGmL3iWgkHTq3uAZWVIuBu6dDmGa3m8a6zo2VQQpu8ambq9H22UyUpn7590joA==",
+ "requires": {
+ "@date-io/core": "^2.16.0"
+ }
+ },
+ "@date-io/dayjs": {
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.16.0.tgz",
+ "integrity": "sha512-y5qKyX2j/HG3zMvIxTobYZRGnd1FUW2olZLS0vTj7bEkBQkjd2RO7/FEwDY03Z1geVGlXKnzIATEVBVaGzV4Iw==",
+ "requires": {
+ "@date-io/core": "^2.16.0"
+ }
+ },
+ "@date-io/luxon": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.16.1.tgz",
+ "integrity": "sha512-aeYp5K9PSHV28946pC+9UKUi/xMMYoaGelrpDibZSgHu2VWHXrr7zWLEr+pMPThSs5vt8Ei365PO+84pCm37WQ==",
+ "requires": {
+ "@date-io/core": "^2.16.0"
+ }
+ },
+ "@date-io/moment": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.16.1.tgz",
+ "integrity": "sha512-JkxldQxUqZBfZtsaCcCMkm/dmytdyq5pS1RxshCQ4fHhsvP5A7gSqPD22QbVXMcJydi3d3v1Y8BQdUKEuGACZQ==",
+ "requires": {
+ "@date-io/core": "^2.16.0"
+ }
+ },
"@emotion/babel-plugin": {
"version": "11.10.5",
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
@@ -20149,6 +20338,25 @@
}
}
},
+ "@mui/x-date-pickers": {
+ "version": "5.0.20",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.20.tgz",
+ "integrity": "sha512-ERukSeHIoNLbI1C2XRhF9wRhqfsr+Q4B1SAw2ZlU7CWgcG8UBOxgqRKDEOVAIoSWL+DWT6GRuQjOKvj6UXZceA==",
+ "requires": {
+ "@babel/runtime": "^7.18.9",
+ "@date-io/core": "^2.15.0",
+ "@date-io/date-fns": "^2.15.0",
+ "@date-io/dayjs": "^2.15.0",
+ "@date-io/luxon": "^2.15.0",
+ "@date-io/moment": "^2.15.0",
+ "@mui/utils": "^5.10.3",
+ "@types/react-transition-group": "^4.4.5",
+ "clsx": "^1.2.1",
+ "prop-types": "^15.7.2",
+ "react-transition-group": "^4.4.5",
+ "rifm": "^0.12.1"
+ }
+ },
"@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -26831,6 +27039,16 @@
"minimist": "^1.2.6"
}
},
+ "moment": {
+ "version": "2.29.4",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+ },
+ "momentjs": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/momentjs/-/momentjs-2.0.0.tgz",
+ "integrity": "sha512-GYMUxLyCwVhECkJR1/LMHEyb9gWYSPRnXi+elGN0m5bet7ngQOxU4QLWUI/eBzgN4N/T194n6yP7lQiE+Udw9A=="
+ },
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -28621,6 +28839,12 @@
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
},
+ "rifm": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/rifm/-/rifm-0.12.1.tgz",
+ "integrity": "sha512-OGA1Bitg/dSJtI/c4dh90svzaUPt228kzFsUkJbtA2c964IqEAwWXeL9ZJi86xWv3j5SMqRvGULl7bA6cK0Bvg==",
+ "requires": {}
+ },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
diff --git a/package.json b/package.json
index 625565a..b5be625 100644
--- a/package.json
+++ b/package.json
@@ -8,11 +8,14 @@
"@mui/icons-material": "^5.11.0",
"@mui/lab": "^5.0.0-alpha.119",
"@mui/material": "^5.11.7",
+ "@mui/x-date-pickers": "^5.0.20",
"@reduxjs/toolkit": "^1.9.2",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.3.2",
+ "moment": "^2.29.4",
+ "momentjs": "^2.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
diff --git a/src/App.js b/src/App.js
index 287c94b..ed52e70 100644
--- a/src/App.js
+++ b/src/App.js
@@ -15,8 +15,8 @@ import PageNotFound from "./pages/404/PageNotFound";
import httpIntercept from "./interceptor/interceptor";
import { setCredentials } from "./store/slices/userSlice";
import Home from "./pages/home/Home";
-import MyBooks from "./pages/my_books/MyBooks";
-import MyRequests from "./pages/my_requests/MyRequests";
+import MyBooks from "./pages/book_loans/BookLoans";
+import MyRequests from "./pages/book_requests/BookRequests";
function App() {
httpIntercept();
diff --git a/src/components/forms/BookLoanForm.jsx b/src/components/forms/BookLoanForm.jsx
new file mode 100644
index 0000000..b0acf0f
--- /dev/null
+++ b/src/components/forms/BookLoanForm.jsx
@@ -0,0 +1,127 @@
+import React, { useEffect, useState } from "react";
+
+import Button from "@mui/material/Button";
+import TextField from "@mui/material/TextField";
+import Grid from "@mui/material/Grid";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import Select from "@mui/material/Select";
+import MenuItem from "@mui/material/MenuItem";
+import FormControl from "@mui/material/FormControl";
+import InputLabel from "@mui/material/InputLabel";
+import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
+import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
+import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
+
+import axios from "axios";
+import { toast } from "react-toastify";
+import moment from "moment";
+
+const BookLoanForm = ({ bookLoan, handleClose }) => {
+ const [status, setStatus] = useState("");
+ const [dateBorrowed, setDateBorrowed] = useState(null);
+ const [dateDue, setDateDue] = useState(null);
+ const [dateReturned, setDateReturned] = useState(null);
+
+ useEffect(() => {
+ console.log(bookLoan);
+ setStatus(bookLoan.status);
+ setDateBorrowed(bookLoan.date_borrowed);
+ setDateDue(bookLoan.date_due);
+ setDateReturned(bookLoan.date_returned);
+ }, [bookLoan]);
+
+ const handleStatusChange = (event) => {
+ setStatus(event.target.value);
+ };
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ axios
+ .put(`${process.env.REACT_APP_BACKEND_URL}/loans/${bookLoan.id}/`, {
+ book: bookLoan.book.id,
+ status: status,
+ date_borrowed: moment(dateBorrowed).format("YYYY-MM-DD"),
+ date_due: moment(dateDue).format("YYYY-MM-DD"),
+ date_returned: moment(dateReturned).format("YYYY-MM-DD"),
+ })
+ .then(({ data }) => {
+ toast.success("Book loan updated successfully.");
+ })
+ .catch((err) => {
+ toast.error(err.msg);
+ });
+ handleClose()
+ };
+
+ return (
+
+
+ Sign up
+
+
+
+
+
+ Status
+
+
+
+
+
+ }
+ />
+
+
+ }
+ />
+
+
+ {
+ setDateReturned(value);
+ }}
+ renderInput={(params) => }
+ />
+
+
+
+
+
+
+ );
+};
+
+export default BookLoanForm;
diff --git a/src/components/navbar/Navbar.jsx b/src/components/navbar/Navbar.jsx
index 4eea8f9..aaf20ce 100644
--- a/src/components/navbar/Navbar.jsx
+++ b/src/components/navbar/Navbar.jsx
@@ -12,10 +12,13 @@ import AdbIcon from "@mui/icons-material/Adb";
import { logout } from "../../store/slices/userSlice";
const userPages = [
- { name: "My Books", path: "lms/mybooks" },
- { name: "My Requests", path: "lms/myrequests" },
+ { name: "Book Loans", path: "lms/mybooks" },
+ { name: "Book Requests", path: "lms/myrequests" },
+];
+const librarianPages = [
+ { name: "Book Loans", path: "lms/mybooks" },
+ { name: "Book Requests", path: "lms/myrequests" },
];
-const librarianPages = ["Books Loans", "Book Requests"];
function ResponsiveAppBar() {
const [pages, setPages] = useState([]);
diff --git a/src/pages/book_loans/BookLoans.jsx b/src/pages/book_loans/BookLoans.jsx
new file mode 100644
index 0000000..1fe8b81
--- /dev/null
+++ b/src/pages/book_loans/BookLoans.jsx
@@ -0,0 +1,103 @@
+import React, { useEffect, useState } from "react";
+import axios from "axios";
+
+import Table from "@mui/material/Table";
+import TableBody from "@mui/material/TableBody";
+import TableCell from "@mui/material/TableCell";
+import TableContainer from "@mui/material/TableContainer";
+import TableHead from "@mui/material/TableHead";
+import TableRow from "@mui/material/TableRow";
+import Paper from "@mui/material/Paper";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogContent from "@mui/material/DialogContent";
+
+import { useSelector } from "react-redux";
+
+import BookLoanForm from "../../components/forms/BookLoanForm";
+
+
+const MyBooks = () => {
+ const [loans, setLoans] = useState([]);
+ const [defaultValue, setDefaultValue] = useState(null);
+ const [open, setOpen] = useState(false);
+
+ const { userInfo } = useSelector((state) => state.user);
+
+ const handleOpen = () => setOpen(true);
+ const handleClose = () => setOpen(false);
+
+ useEffect(() => {
+ axios.get(`${process.env.REACT_APP_BACKEND_URL}/loans`).then(({ data }) => {
+ setLoans(data);
+ });
+ }, []);
+ return (
+
+
+
+
+
+ Book
+ Status
+ Loaned
+ Due
+ Returned
+ {userInfo?.is_librarian && (
+ Actions
+ )}
+
+
+
+ {loans.map((row) => (
+
+
+ {row.book.name}
+
+ {row.status}
+ {row.date_borrowed}
+ {row.date_due}
+
+ {row.date_returned ?? "N/A"}
+
+ {userInfo?.is_librarian && (
+
+ {" "}
+
+
+ )}
+
+ ))}
+
+
+
+
+
+ );
+};
+
+export default MyBooks;
diff --git a/src/pages/my_requests/MyRequests.jsx b/src/pages/book_requests/BookRequests.jsx
similarity index 100%
rename from src/pages/my_requests/MyRequests.jsx
rename to src/pages/book_requests/BookRequests.jsx
diff --git a/src/pages/home/Home.jsx b/src/pages/home/Home.jsx
index 96c5535..c5dd1ba 100644
--- a/src/pages/home/Home.jsx
+++ b/src/pages/home/Home.jsx
@@ -1,9 +1,85 @@
-import React from 'react'
+import React, { useEffect, useState } from "react";
+import Box from "@mui/material/Box";
+import Grid from "@mui/material/Grid";
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import CardMedia from "@mui/material/CardMedia";
+import CardActions from "@mui/material/CardActions";
+import Button from "@mui/material/Button";
+import Typography from "@mui/material/Typography";
+import axios from "axios";
+import { toast } from "react-toastify";
const Home = () => {
+ const [books, setBooks] = useState([]);
+ useEffect(() => {
+ axios.get(`${process.env.REACT_APP_BACKEND_URL}/books`).then(({ data }) => {
+ setBooks(data);
+ });
+ }, []);
+
+ const handleLoan = (bookId) => {
+ axios
+ .post(`${process.env.REACT_APP_BACKEND_URL}/loans/`, {
+ book: bookId,
+ status: "requested",
+ })
+ .then(({ data }) => {
+ toast.success(
+ 'Book loan successful. You can track your loan in "Book Loans".'
+ );
+ })
+ .catch((err) => {
+ toast.error(err.msg);
+ });
+ };
return (
- Home
- )
-}
+
+
+ {books.map((item) => (
+
+
+
+
+
+ {item.name}
+
+
+ {item.author} - {item.publisher} - {item.stock} available
+
+
+
+
+
+
+
+ ))}
+
+
+ );
+};
-export default Home
\ No newline at end of file
+export default Home;
diff --git a/src/pages/my_books/MyBooks.jsx b/src/pages/my_books/MyBooks.jsx
deleted file mode 100644
index d3c07e4..0000000
--- a/src/pages/my_books/MyBooks.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react'
-
-const MyBooks = () => {
- return (
- MyBooks
- )
-}
-
-export default MyBooks
\ No newline at end of file
From 9a1cb1d1bb20f942fcaf0723bcec9b48954e9e9c Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Wed, 1 Mar 2023 17:29:20 +0500
Subject: [PATCH 5/6] feat: add book requests module
---
src/components/forms/BookLoanForm.jsx | 3 +-
src/components/forms/LibBookRequestForm.jsx | 97 ++++++++++++++
src/components/forms/UserBookRequestForm.jsx | 81 ++++++++++++
src/interceptor/interceptor.js | 8 +-
src/pages/book_loans/BookLoans.jsx | 36 ++++--
src/pages/book_requests/BookRequests.jsx | 129 ++++++++++++++++++-
src/pages/home/Home.jsx | 23 ++--
src/pages/register/Register.jsx | 44 +++++--
8 files changed, 382 insertions(+), 39 deletions(-)
create mode 100644 src/components/forms/LibBookRequestForm.jsx
create mode 100644 src/components/forms/UserBookRequestForm.jsx
diff --git a/src/components/forms/BookLoanForm.jsx b/src/components/forms/BookLoanForm.jsx
index b0acf0f..68c3479 100644
--- a/src/components/forms/BookLoanForm.jsx
+++ b/src/components/forms/BookLoanForm.jsx
@@ -24,7 +24,6 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
const [dateReturned, setDateReturned] = useState(null);
useEffect(() => {
- console.log(bookLoan);
setStatus(bookLoan.status);
setDateBorrowed(bookLoan.date_borrowed);
setDateDue(bookLoan.date_due);
@@ -63,7 +62,7 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
}}
>
- Sign up
+ Book Loan Form
diff --git a/src/components/forms/LibBookRequestForm.jsx b/src/components/forms/LibBookRequestForm.jsx
new file mode 100644
index 0000000..ca6a46e
--- /dev/null
+++ b/src/components/forms/LibBookRequestForm.jsx
@@ -0,0 +1,97 @@
+import React, { useEffect, useState } from "react";
+
+import Button from "@mui/material/Button";
+import TextField from "@mui/material/TextField";
+import Grid from "@mui/material/Grid";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import Select from "@mui/material/Select";
+import MenuItem from "@mui/material/MenuItem";
+import FormControl from "@mui/material/FormControl";
+import InputLabel from "@mui/material/InputLabel";
+import TextareaAutosize from "@mui/base/TextareaAutosize";
+
+import axios from "axios";
+import { toast } from "react-toastify";
+
+const BookLoanForm = ({ defaultValue, handleClose }) => {
+ const [status, setStatus] = useState(defaultValue?.status);
+ const [reason, setReason] = useState(defaultValue?.reason);
+
+ const handleStatusChange = (event) => {
+ setStatus(event.target.value);
+ };
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ const data = new FormData(event.currentTarget);
+
+ axios
+ .patch(
+ `${process.env.REACT_APP_BACKEND_URL}/book_requests/${defaultValue.id}/`,
+ {
+ // ...defaultValue,
+ status,
+ reason,
+ }
+ )
+ .then(({ data }) => {
+ toast.success("Book request updated successfully.");
+ handleClose();
+ })
+ .catch((err) => {
+ toast.error(err.detail);
+ });
+ };
+
+ return (
+
+
+ Book Request
+
+
+
+
+
+ Status
+
+
+
+
+ setReason(event.target.value)}
+ />
+
+
+
+
+
+ );
+};
+
+export default BookLoanForm;
diff --git a/src/components/forms/UserBookRequestForm.jsx b/src/components/forms/UserBookRequestForm.jsx
new file mode 100644
index 0000000..8080940
--- /dev/null
+++ b/src/components/forms/UserBookRequestForm.jsx
@@ -0,0 +1,81 @@
+import React, { useEffect } from "react";
+
+import Button from "@mui/material/Button";
+import TextField from "@mui/material/TextField";
+import Grid from "@mui/material/Grid";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+
+import axios from "axios";
+import { toast } from "react-toastify";
+
+const UserBookRequestForm = ({ defaultValue, handleClose }) => {
+
+ const handleSubmit = (event) => {
+ event.preventDefault();
+ const data = new FormData(event.currentTarget);
+
+ if (defaultValue) {
+ axios
+ .put(
+ `${process.env.REACT_APP_BACKEND_URL}/book_requests/${defaultValue.id}/`,
+ {
+ book_name: data.get("book_name"),
+ }
+ )
+ .then(({ data }) => {
+ toast.success("Book request updated successfully.");
+ handleClose();
+ })
+ .catch((err) => {
+ toast.error(err.detail);
+ });
+ } else {
+ axios
+ .post(`${process.env.REACT_APP_BACKEND_URL}/book_requests/`, {
+ book_name: data.get("book_name"),
+ })
+ .then(({ data }) => {
+ toast.success("Book request created successfully.");
+ handleClose();
+ })
+ .catch((err) => {
+ toast.error(err.detail);
+ });
+ }
+ };
+
+ return (
+
+
+ Request A Book
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default UserBookRequestForm;
diff --git a/src/interceptor/interceptor.js b/src/interceptor/interceptor.js
index f9134a0..d1408ba 100644
--- a/src/interceptor/interceptor.js
+++ b/src/interceptor/interceptor.js
@@ -3,9 +3,13 @@ import axios from "axios";
const httpIntercept = (props) => {
axios.interceptors.request.use(
(request) => {
- if (request.url.includes(process.env.REACT_APP_BACKEND_URL)) {
+ const authToken = localStorage.getItem("authToken");
+ if (
+ request.url.includes(process.env.REACT_APP_BACKEND_URL) &&
+ authToken
+ ) {
request.headers.Authorization =
- "JWT " + localStorage.getItem("authToken");
+ "JWT " + authToken;
}
return request;
},
diff --git a/src/pages/book_loans/BookLoans.jsx b/src/pages/book_loans/BookLoans.jsx
index 1fe8b81..7f413ea 100644
--- a/src/pages/book_loans/BookLoans.jsx
+++ b/src/pages/book_loans/BookLoans.jsx
@@ -16,23 +16,35 @@ import DialogContent from "@mui/material/DialogContent";
import { useSelector } from "react-redux";
import BookLoanForm from "../../components/forms/BookLoanForm";
-
+import { toast } from "react-toastify";
const MyBooks = () => {
const [loans, setLoans] = useState([]);
const [defaultValue, setDefaultValue] = useState(null);
+ const [reload, setReload] = useState(0);
const [open, setOpen] = useState(false);
const { userInfo } = useSelector((state) => state.user);
-
+
const handleOpen = () => setOpen(true);
- const handleClose = () => setOpen(false);
+ const handleClose = () => {
+ setOpen(false);
+ setReload(Math.random());
+ };
useEffect(() => {
axios.get(`${process.env.REACT_APP_BACKEND_URL}/loans`).then(({ data }) => {
setLoans(data);
});
- }, []);
+ }, [reload]);
+
+ const handleRemind = (id) => {
+ axios
+ .get(`${process.env.REACT_APP_BACKEND_URL}/loans/${id}/`)
+ .then((data) => {
+ toast.success("Reminder email sent.");
+ });
+ };
return (
{
{userInfo?.is_librarian && (
- {" "}
+
)}
@@ -93,7 +111,7 @@ const MyBooks = () => {
diff --git a/src/pages/book_requests/BookRequests.jsx b/src/pages/book_requests/BookRequests.jsx
index dd1c124..22ad040 100644
--- a/src/pages/book_requests/BookRequests.jsx
+++ b/src/pages/book_requests/BookRequests.jsx
@@ -1,9 +1,128 @@
-import React from 'react'
+import React, { useEffect, useState } from "react";
+import axios from "axios";
+
+import Table from "@mui/material/Table";
+import TableBody from "@mui/material/TableBody";
+import TableCell from "@mui/material/TableCell";
+import TableContainer from "@mui/material/TableContainer";
+import TableHead from "@mui/material/TableHead";
+import TableRow from "@mui/material/TableRow";
+import Paper from "@mui/material/Paper";
+import Grid from "@mui/material/Grid";
+import Button from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import DialogContent from "@mui/material/DialogContent";
+
+import { useSelector } from "react-redux";
+
+import UserBookRequestForm from "../../components/forms/UserBookRequestForm";
+import LibBookRequestForm from "../../components/forms/LibBookRequestForm";
+import moment from "moment";
const MyRequests = () => {
+ const [requests, setRequests] = useState([]);
+ const [defaultValue, setDefaultValue] = useState(null);
+ const [reload, setReload] = useState(0);
+ const [open, setOpen] = useState(false);
+
+ const { userInfo } = useSelector((state) => state.user);
+
+ const handleOpen = () => setOpen(true);
+ const handleClose = () => {
+ setDefaultValue(null);
+ setOpen(false);
+ setReload(Math.random());
+ };
+
+ useEffect(() => {
+ axios
+ .get(`${process.env.REACT_APP_BACKEND_URL}/book_requests`)
+ .then(({ data }) => {
+ setRequests(data);
+ });
+ }, [reload]);
return (
- MyRequests
- )
-}
+
+
+
+
+
+
+
+
+
+ {userInfo?.is_librarian && (
+ User
+ )}
+ Book
+ Status
+ Reason
+ Created At
+ Actions
+
+
+
+ {requests.map((row) => (
+
+ {userInfo?.is_librarian && (
+ {row.user}
+ )}
+
+ {row.book_name}
+
+ {row.status}
+ {row.reason ?? "N/A"}
+
+ {moment(row.created_at).format("ll")}
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+ );
+};
-export default MyRequests
\ No newline at end of file
+export default MyRequests;
diff --git a/src/pages/home/Home.jsx b/src/pages/home/Home.jsx
index c5dd1ba..f44c47f 100644
--- a/src/pages/home/Home.jsx
+++ b/src/pages/home/Home.jsx
@@ -9,9 +9,12 @@ import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import axios from "axios";
import { toast } from "react-toastify";
+import { useSelector } from "react-redux";
const Home = () => {
const [books, setBooks] = useState([]);
+ const { authToken } = useSelector((state) => state.user);
+
useEffect(() => {
axios.get(`${process.env.REACT_APP_BACKEND_URL}/books`).then(({ data }) => {
setBooks(data);
@@ -64,15 +67,17 @@ const Home = () => {
-
+ {authToken && (
+
+ )}
diff --git a/src/pages/register/Register.jsx b/src/pages/register/Register.jsx
index e86d4f3..aa40b13 100644
--- a/src/pages/register/Register.jsx
+++ b/src/pages/register/Register.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, {useState} from "react";
import Avatar from "@mui/material/Avatar";
import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
@@ -15,8 +15,13 @@ import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
+import axios from "axios";
+import {toast} from 'react-toastify'
+import { useNavigate } from "react-router-dom";
+
export default function SignUp() {
- const [gender, setGender] = React.useState("");
+ const [gender, setGender] = useState("");
+ const navigate = useNavigate()
const handleChange = (event) => {
setGender(event.target.value);
@@ -24,9 +29,15 @@ export default function SignUp() {
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
- console.log({
- email: data.get("email"),
- password: data.get("password"),
+ var newUser = Object.fromEntries(data)
+ newUser.gender = gender
+ axios.post(
+ `${process.env.REACT_APP_BACKEND_URL}/auth/users/`,
+ newUser
+ ).then(({data})=>{
+ console.log(data)
+ toast.success("Welcome to the greatest library ever! try logging in.")
+ navigate("/login");
});
};
@@ -47,15 +58,15 @@ export default function SignUp() {
Sign up
-
+
@@ -64,12 +75,21 @@ export default function SignUp() {
+
+
+
-
-
+
+
From b8a1396738e618b6eab29dec53a59833427b5045 Mon Sep 17 00:00:00 2001
From: Ahmed Khalid <106074266+ahmed-arb@users.noreply.github.com>
Date: Mon, 6 Mar 2023 14:29:18 +0500
Subject: [PATCH 6/6] change all requests to custom hook
---
src/App.js | 25 ++++---
src/components/forms/BookLoanForm.jsx | 78 +++++++++++---------
src/components/forms/LibBookRequestForm.jsx | 57 +++++++-------
src/components/forms/UserBookRequestForm.jsx | 44 +++++------
src/constants.js | 18 +++++
src/hooks/use-https.jsx | 32 ++++++++
src/pages/book_loans/BookLoans.jsx | 27 ++++---
src/pages/book_requests/BookRequests.jsx | 14 ++--
src/pages/home/Home.jsx | 29 ++++----
src/pages/login/Login.jsx | 1 +
src/pages/register/Register.jsx | 36 ++++-----
src/store/actions/userActions.jsx | 1 +
12 files changed, 222 insertions(+), 140 deletions(-)
create mode 100644 src/constants.js
create mode 100644 src/hooks/use-https.jsx
diff --git a/src/App.js b/src/App.js
index ed52e70..064965c 100644
--- a/src/App.js
+++ b/src/App.js
@@ -3,7 +3,6 @@ import { Route, Routes } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { ToastContainer } from "react-toastify";
-import axios from "axios";
import "react-toastify/dist/ReactToastify.css";
@@ -17,37 +16,43 @@ import { setCredentials } from "./store/slices/userSlice";
import Home from "./pages/home/Home";
import MyBooks from "./pages/book_loans/BookLoans";
import MyRequests from "./pages/book_requests/BookRequests";
+import useHttp from "./hooks/use-https";
function App() {
httpIntercept();
const { authToken } = useSelector((state) => state.user);
const dispatch = useDispatch();
+ const { sendRequest } = useHttp();
useEffect(() => {
const token = localStorage.getItem("authToken");
if (token) {
- axios
- .get(`${process.env.REACT_APP_BACKEND_URL}/auth/users/me`)
- .then(({ data }) => {
+
+ sendRequest(
+ {
+ url: "auth/users/me/",
+ },
+ (data) => {
dispatch(setCredentials(data));
- });
+ }
+ );
}
- }, [dispatch, authToken]);
+ }, [dispatch, authToken, sendRequest]);
return (
}>
} />
- }/>
+ } />
} />
} />
- }>
- } />
- } />
+ }>
+ } />
+ } />
diff --git a/src/components/forms/BookLoanForm.jsx b/src/components/forms/BookLoanForm.jsx
index 68c3479..3889b92 100644
--- a/src/components/forms/BookLoanForm.jsx
+++ b/src/components/forms/BookLoanForm.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
@@ -13,22 +13,17 @@ import { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment";
-import axios from "axios";
import { toast } from "react-toastify";
import moment from "moment";
+import { bookLoanStatusOptions } from "../../constants";
+import useHttp from "../../hooks/use-https";
const BookLoanForm = ({ bookLoan, handleClose }) => {
- const [status, setStatus] = useState("");
+ const [status, setStatus] = useState(null);
const [dateBorrowed, setDateBorrowed] = useState(null);
const [dateDue, setDateDue] = useState(null);
const [dateReturned, setDateReturned] = useState(null);
-
- useEffect(() => {
- setStatus(bookLoan.status);
- setDateBorrowed(bookLoan.date_borrowed);
- setDateDue(bookLoan.date_due);
- setDateReturned(bookLoan.date_returned);
- }, [bookLoan]);
+ const { sendRequest, isLoading } = useHttp();
const handleStatusChange = (event) => {
setStatus(event.target.value);
@@ -36,21 +31,29 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
const handleSubmit = (event) => {
event.preventDefault();
- axios
- .put(`${process.env.REACT_APP_BACKEND_URL}/loans/${bookLoan.id}/`, {
- book: bookLoan.book.id,
- status: status,
- date_borrowed: moment(dateBorrowed).format("YYYY-MM-DD"),
- date_due: moment(dateDue).format("YYYY-MM-DD"),
- date_returned: moment(dateReturned).format("YYYY-MM-DD"),
- })
- .then(({ data }) => {
- toast.success("Book loan updated successfully.");
- })
- .catch((err) => {
- toast.error(err.msg);
- });
- handleClose()
+ sendRequest(
+ {
+ url: `loans/${bookLoan.id}/`,
+ method: "PUT",
+ body: {
+ book: bookLoan.book.id,
+ status: status ?? bookLoan.status,
+ date_borrowed: dateBorrowed
+ ? moment(dateBorrowed).format("YYYY-MM-DD")
+ : bookLoan.date_borrowed,
+ date_due: dateDue
+ ? moment(dateDue).format("YYYY-MM-DD")
+ : bookLoan.date_due,
+ date_returned: dateReturned
+ ? moment(dateReturned).format("YYYY-MM-DD")
+ : bookLoan.date_returned,
+ },
+ },
+ (data) => {
+ toast.success("yay");
+ handleClose();
+ }
+ );
};
return (
@@ -62,7 +65,7 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
}}
>
- Book Loan Form
+ Book Loan Form
@@ -72,23 +75,23 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
}
/>
@@ -97,7 +100,7 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
}
/>
@@ -106,7 +109,7 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
{
setDateReturned(value);
}}
@@ -115,7 +118,12 @@ const BookLoanForm = ({ bookLoan, handleClose }) => {
-
diff --git a/src/components/forms/LibBookRequestForm.jsx b/src/components/forms/LibBookRequestForm.jsx
index ca6a46e..b08c511 100644
--- a/src/components/forms/LibBookRequestForm.jsx
+++ b/src/components/forms/LibBookRequestForm.jsx
@@ -1,22 +1,23 @@
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import Button from "@mui/material/Button";
-import TextField from "@mui/material/TextField";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Select from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
-import InputLabel from "@mui/material/InputLabel";
import TextareaAutosize from "@mui/base/TextareaAutosize";
+import InputLabel from "@mui/material/InputLabel";
-import axios from "axios";
import { toast } from "react-toastify";
+import { bookRequestStatusOptions } from "../../constants";
+import useHttp from "../../hooks/use-https";
const BookLoanForm = ({ defaultValue, handleClose }) => {
- const [status, setStatus] = useState(defaultValue?.status);
- const [reason, setReason] = useState(defaultValue?.reason);
+ const [status, setStatus] = useState(null);
+ const [reason, setReason] = useState(null);
+ const { sendRequest, isLoading } = useHttp();
const handleStatusChange = (event) => {
setStatus(event.target.value);
@@ -24,24 +25,21 @@ const BookLoanForm = ({ defaultValue, handleClose }) => {
const handleSubmit = (event) => {
event.preventDefault();
- const data = new FormData(event.currentTarget);
- axios
- .patch(
- `${process.env.REACT_APP_BACKEND_URL}/book_requests/${defaultValue.id}/`,
- {
- // ...defaultValue,
- status,
- reason,
- }
- )
- .then(({ data }) => {
+ sendRequest(
+ {
+ url: `book_requests/${defaultValue.id}/`,
+ method: "PATCH",
+ body: {
+ status: status ?? defaultValue.status,
+ reason: reason ?? defaultValue.reason,
+ },
+ },
+ (data) => {
toast.success("Book request updated successfully.");
handleClose();
- })
- .catch((err) => {
- toast.error(err.detail);
- });
+ }
+ );
};
return (
@@ -63,13 +61,13 @@ const BookLoanForm = ({ defaultValue, handleClose }) => {
@@ -80,13 +78,18 @@ const BookLoanForm = ({ defaultValue, handleClose }) => {
minRows={10}
placeholder="Reason for rejection"
style={{ width: 400 }}
- value={reason}
+ value={reason ?? defaultValue?.reason}
disabled={status !== "rejected"}
onChange={(event) => setReason(event.target.value)}
/>
-
+
Update
diff --git a/src/components/forms/UserBookRequestForm.jsx b/src/components/forms/UserBookRequestForm.jsx
index 8080940..c29d72d 100644
--- a/src/components/forms/UserBookRequestForm.jsx
+++ b/src/components/forms/UserBookRequestForm.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import React from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
@@ -6,42 +6,42 @@ import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
-import axios from "axios";
import { toast } from "react-toastify";
+import useHttp from "../../hooks/use-https";
const UserBookRequestForm = ({ defaultValue, handleClose }) => {
+ const { sendRequest } = useHttp();
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
if (defaultValue) {
- axios
- .put(
- `${process.env.REACT_APP_BACKEND_URL}/book_requests/${defaultValue.id}/`,
- {
+ sendRequest(
+ {
+ url: `book_requests/${defaultValue.id}/`,
+ method: "PUT",
+ body: {
book_name: data.get("book_name"),
- }
- )
- .then(({ data }) => {
+ },
+ },
+ (data) => {
toast.success("Book request updated successfully.");
handleClose();
- })
- .catch((err) => {
- toast.error(err.detail);
- });
+ }
+ );
} else {
- axios
- .post(`${process.env.REACT_APP_BACKEND_URL}/book_requests/`, {
- book_name: data.get("book_name"),
- })
- .then(({ data }) => {
+ sendRequest(
+ {
+ url: "book_requests/",
+ method: "POST",
+ body: { book_name: data.get("book_name") },
+ },
+ (data) => {
toast.success("Book request created successfully.");
handleClose();
- })
- .catch((err) => {
- toast.error(err.detail);
- });
+ }
+ );
}
};
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 0000000..b591b86
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,18 @@
+export const userGenderOptions = [
+ { value: 0, display: "Male" },
+ { value: 1, display: "Female" },
+ { value: 2, display: "Other" },
+];
+
+export const bookRequestStatusOptions = [
+ { value: 0, display: "Pending" },
+ { value: 1, display: "Approved" },
+ { value: 2, display: "Rejected" },
+];
+
+export const bookLoanStatusOptions = [
+ { value: 0, display: "Requested" },
+ { value: 1, display: "Issued" },
+ { value: 2, display: "Rejected" },
+ { value: 3, display: "Returned" },
+];
diff --git a/src/hooks/use-https.jsx b/src/hooks/use-https.jsx
new file mode 100644
index 0000000..6b49f43
--- /dev/null
+++ b/src/hooks/use-https.jsx
@@ -0,0 +1,32 @@
+import { useState, useCallback } from "react";
+import axios from "axios";
+import { toast } from "react-toastify";
+
+const useHttp = () => {
+ const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const sendRequest = useCallback(async (requestConfig, applyData) => {
+ setIsLoading(true);
+ setError(null);
+ try {
+ const response = await axios(`${process.env.REACT_APP_BACKEND_URL}/${requestConfig.url}`, {
+ method: requestConfig.method ?? "GET",
+ data: requestConfig.body ?? null,
+ });
+
+ applyData(response.data);
+ setIsLoading(false);
+ } catch (err) {
+ toast.error(err.message || "Something went wrong!");
+ setError(err.message || "Something went wrong!");
+ }
+ }, []);
+
+ return {
+ isLoading,
+ error,
+ sendRequest,
+ };
+};
+
+export default useHttp;
diff --git a/src/pages/book_loans/BookLoans.jsx b/src/pages/book_loans/BookLoans.jsx
index 7f413ea..da3c690 100644
--- a/src/pages/book_loans/BookLoans.jsx
+++ b/src/pages/book_loans/BookLoans.jsx
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from "react";
-import axios from "axios";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
@@ -17,6 +16,7 @@ import { useSelector } from "react-redux";
import BookLoanForm from "../../components/forms/BookLoanForm";
import { toast } from "react-toastify";
+import useHttp from "../../hooks/use-https";
const MyBooks = () => {
const [loans, setLoans] = useState([]);
@@ -25,6 +25,7 @@ const MyBooks = () => {
const [open, setOpen] = useState(false);
const { userInfo } = useSelector((state) => state.user);
+ const { sendRequest } = useHttp();
const handleOpen = () => setOpen(true);
const handleClose = () => {
@@ -33,17 +34,25 @@ const MyBooks = () => {
};
useEffect(() => {
- axios.get(`${process.env.REACT_APP_BACKEND_URL}/loans`).then(({ data }) => {
- setLoans(data);
- });
- }, [reload]);
+ sendRequest(
+ {
+ url: "loans",
+ },
+ (data) => {
+ setLoans(data);
+ }
+ );
+ }, [reload, sendRequest]);
const handleRemind = (id) => {
- axios
- .get(`${process.env.REACT_APP_BACKEND_URL}/loans/${id}/`)
- .then((data) => {
+ sendRequest(
+ {
+ url: `loans/${id}/`,
+ },
+ (data) => {
toast.success("Reminder email sent.");
- });
+ }
+ );
};
return (
{
const [requests, setRequests] = useState([]);
@@ -25,6 +25,8 @@ const MyRequests = () => {
const [reload, setReload] = useState(0);
const [open, setOpen] = useState(false);
+ const { sendRequest } = useHttp();
+
const { userInfo } = useSelector((state) => state.user);
const handleOpen = () => setOpen(true);
@@ -35,12 +37,10 @@ const MyRequests = () => {
};
useEffect(() => {
- axios
- .get(`${process.env.REACT_APP_BACKEND_URL}/book_requests`)
- .then(({ data }) => {
- setRequests(data);
- });
- }, [reload]);
+ sendRequest({ url: "book_requests/" }, (data) => {
+ setRequests(data);
+ });
+ }, [reload, sendRequest]);
return (
{
const [books, setBooks] = useState([]);
const { authToken } = useSelector((state) => state.user);
+ const { sendRequest } = useHttp();
useEffect(() => {
- axios.get(`${process.env.REACT_APP_BACKEND_URL}/books`).then(({ data }) => {
+ sendRequest({ url: "books/" }, (data) => {
setBooks(data);
});
- }, []);
+ }, [sendRequest]);
const handleLoan = (bookId) => {
- axios
- .post(`${process.env.REACT_APP_BACKEND_URL}/loans/`, {
- book: bookId,
- status: "requested",
- })
- .then(({ data }) => {
+ sendRequest(
+ {
+ url: "loans/",
+ method: "POST",
+ body: {
+ book: bookId,
+ status: "requested",
+ },
+ },
+ (data) => {
toast.success(
'Book loan successful. You can track your loan in "Book Loans".'
);
- })
- .catch((err) => {
- toast.error(err.msg);
- });
+ }
+ );
};
return (
{
if (userInfo) {
+ console.log("first")
navigate("/");
}
}, [navigate, userInfo]);
diff --git a/src/pages/register/Register.jsx b/src/pages/register/Register.jsx
index aa40b13..2891343 100644
--- a/src/pages/register/Register.jsx
+++ b/src/pages/register/Register.jsx
@@ -1,4 +1,4 @@
-import React, {useState} from "react";
+import React, { useState } from "react";
import Avatar from "@mui/material/Avatar";
import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
@@ -15,13 +15,15 @@ import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
-import axios from "axios";
-import {toast} from 'react-toastify'
+import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
+import { userGenderOptions } from "../../constants";
+import useHttp from "../../hooks/use-https";
export default function SignUp() {
const [gender, setGender] = useState("");
- const navigate = useNavigate()
+ const navigate = useNavigate();
+ const { sendRequest } = useHttp();
const handleChange = (event) => {
setGender(event.target.value);
@@ -29,16 +31,16 @@ export default function SignUp() {
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
- var newUser = Object.fromEntries(data)
- newUser.gender = gender
- axios.post(
- `${process.env.REACT_APP_BACKEND_URL}/auth/users/`,
- newUser
- ).then(({data})=>{
- console.log(data)
- toast.success("Welcome to the greatest library ever! try logging in.")
- navigate("/login");
- });
+ var newUser = Object.fromEntries(data);
+ newUser.gender = gender;
+
+ sendRequest(
+ { url: "auth/users/", method: "POST", body: newUser },
+ (data) => {
+ toast.success("Welcome to the greatest library ever! try logging in.");
+ navigate("/login");
+ }
+ );
};
return (
@@ -121,9 +123,9 @@ export default function SignUp() {
label="Gender"
onChange={handleChange}
>
-
-
-
+ {userGenderOptions.map((option) => (
+
+ ))}
diff --git a/src/store/actions/userActions.jsx b/src/store/actions/userActions.jsx
index 1309505..1c91cec 100644
--- a/src/store/actions/userActions.jsx
+++ b/src/store/actions/userActions.jsx
@@ -13,6 +13,7 @@ export const userLogin = createAsyncThunk(
localStorage.setItem("authToken", data.access);
return data;
} catch (error) {
+ console.log("error")
if (error.response && error.response.data.detail) {
return rejectWithValue(error.response.data);
} else {