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 e03dd4b..5f60a6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,25 @@ "name": "client", "version": "0.1.0", "dependencies": { + "@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", + "@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", + "react-router-dom": "^6.8.0", "react-scripts": "5.0.1", + "react-toastify": "^9.1.1", "web-vitals": "^2.1.4" } }, @@ -2124,6 +2137,239 @@ "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", + "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 +3214,398 @@ "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/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", + "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.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.7", + "@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.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.8", + "@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/@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", @@ -3077,6 +3715,46 @@ } } }, + "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/@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", + "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", @@ -3735,6 +4413,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", @@ -4073,6 +4760,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", @@ -4139,6 +4842,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", @@ -4953,6 +5661,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", @@ -5642,6 +6373,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 +7309,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 +8715,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 +9348,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", @@ -11986,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", @@ -13925,6 +14705,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", @@ -14219,12 +15004,85 @@ "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", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "engines": { - "node": ">=0.10.0" + "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": { @@ -14299,6 +15157,33 @@ } } }, + "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", + "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", @@ -14354,6 +15239,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", @@ -14496,6 +15397,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", @@ -14612,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", @@ -15422,6 +16336,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", @@ -16085,6 +17004,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", @@ -18463,6 +19390,170 @@ "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", + "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 +20179,184 @@ "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/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", + "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.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.7", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", + "prop-types": "^15.8.1" + } + }, + "@mui/system": { + "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.8", + "@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==" + } + } + }, + "@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", @@ -19151,6 +20420,27 @@ "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==" + }, + "@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", + "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", @@ -19622,6 +20912,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", @@ -19907,6 +21206,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", @@ -19973,6 +21288,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", @@ -20556,6 +21876,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", @@ -21070,6 +22412,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 +23090,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 +24145,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 +24570,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", @@ -25663,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", @@ -26877,6 +28263,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", @@ -27088,11 +28479,48 @@ "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", "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 +28576,25 @@ "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", + "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", @@ -27191,6 +28638,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", @@ -27302,6 +28763,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", @@ -27373,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", @@ -27970,6 +29442,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", @@ -28457,6 +29934,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 866d594..b5be625 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,25 @@ "version": "0.1.0", "private": true, "dependencies": { + "@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", + "@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", + "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 3784575..064965c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,24 +1,74 @@ -import logo from './logo.svg'; -import './App.css'; +import React, { Fragment, useEffect } from "react"; +import { Route, Routes } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; + +import { ToastContainer } from "react-toastify"; + +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 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/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) { + + sendRequest( + { + url: "auth/users/me/", + }, + (data) => { + dispatch(setCredentials(data)); + } + ); + } + }, [dispatch, authToken, sendRequest]); + return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
+ + + }> + } /> + } /> + + } /> + } /> + + }> + } /> + } /> + + + + + ); } diff --git a/src/components/PrivateRoute.jsx b/src/components/PrivateRoute.jsx new file mode 100644 index 0000000..b802868 --- /dev/null +++ b/src/components/PrivateRoute.jsx @@ -0,0 +1,11 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { Navigate, Outlet } from "react-router-dom"; + +const PrivateRoute = () => { + const { authToken } = useSelector((state) => state.user); + + return authToken ? : ; +}; + +export default PrivateRoute; diff --git a/src/components/forms/BookLoanForm.jsx b/src/components/forms/BookLoanForm.jsx new file mode 100644 index 0000000..3889b92 --- /dev/null +++ b/src/components/forms/BookLoanForm.jsx @@ -0,0 +1,134 @@ +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 { DesktopDatePicker } from "@mui/x-date-pickers/DesktopDatePicker"; +import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; +import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment"; + +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(null); + const [dateBorrowed, setDateBorrowed] = useState(null); + const [dateDue, setDateDue] = useState(null); + const [dateReturned, setDateReturned] = useState(null); + const { sendRequest, isLoading } = useHttp(); + + const handleStatusChange = (event) => { + setStatus(event.target.value); + }; + + const handleSubmit = (event) => { + event.preventDefault(); + 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 ( + + + Book Loan Form + + + + + + Status + + + + + + } + /> + + + } + /> + + + { + setDateReturned(value); + }} + renderInput={(params) => } + /> + + + + + + + ); +}; + +export default BookLoanForm; diff --git a/src/components/forms/LibBookRequestForm.jsx b/src/components/forms/LibBookRequestForm.jsx new file mode 100644 index 0000000..b08c511 --- /dev/null +++ b/src/components/forms/LibBookRequestForm.jsx @@ -0,0 +1,100 @@ +import React, { useState } from "react"; + +import Button from "@mui/material/Button"; +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 TextareaAutosize from "@mui/base/TextareaAutosize"; +import InputLabel from "@mui/material/InputLabel"; + +import { toast } from "react-toastify"; +import { bookRequestStatusOptions } from "../../constants"; +import useHttp from "../../hooks/use-https"; + +const BookLoanForm = ({ defaultValue, handleClose }) => { + const [status, setStatus] = useState(null); + const [reason, setReason] = useState(null); + const { sendRequest, isLoading } = useHttp(); + + const handleStatusChange = (event) => { + setStatus(event.target.value); + }; + + const handleSubmit = (event) => { + event.preventDefault(); + + 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(); + } + ); + }; + + 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..c29d72d --- /dev/null +++ b/src/components/forms/UserBookRequestForm.jsx @@ -0,0 +1,81 @@ +import React 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 { 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) { + sendRequest( + { + url: `book_requests/${defaultValue.id}/`, + method: "PUT", + body: { + book_name: data.get("book_name"), + }, + }, + (data) => { + toast.success("Book request updated successfully."); + handleClose(); + } + ); + } else { + sendRequest( + { + url: "book_requests/", + method: "POST", + body: { book_name: data.get("book_name") }, + }, + (data) => { + toast.success("Book request created successfully."); + handleClose(); + } + ); + } + }; + + return ( + + + Request A Book + + + + + + + + + + + ); +}; + +export default UserBookRequestForm; diff --git a/src/components/layout/Layout.jsx b/src/components/layout/Layout.jsx new file mode 100644 index 0000000..31aa1ba --- /dev/null +++ b/src/components/layout/Layout.jsx @@ -0,0 +1,21 @@ +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 ( + + + + + + + + ); +}; + +export default Layout; diff --git a/src/components/navbar/Navbar.jsx b/src/components/navbar/Navbar.jsx new file mode 100644 index 0000000..aaf20ce --- /dev/null +++ b/src/components/navbar/Navbar.jsx @@ -0,0 +1,94 @@ +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 Container from "@mui/material/Container"; +import Button from "@mui/material/Button"; +import AdbIcon from "@mui/icons-material/Adb"; + +import { logout } from "../../store/slices/userSlice"; + +const userPages = [ + { 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" }, +]; + +function ResponsiveAppBar() { + const [pages, setPages] = useState([]); + const { userInfo } = useSelector((state) => state.user); + + const dispatch = useDispatch(); + const navigate = useNavigate(); + + useEffect(() => { + if (userInfo?.isLibrarian) { + setPages(librarianPages); + } else if (userInfo) { + setPages(userPages); + } else { + setPages([]); + } + }, [userInfo]); + + return ( + + + + + + + + {pages.map((page) => ( + + ))} + + + + {userInfo ? ( + + ) : ( + + + + + )} + + + + + ); +} +export default ResponsiveAppBar; 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/index.js b/src/index.js index d563c0f..0103966 100644 --- a/src/index.js +++ b/src/index.js @@ -1,17 +1,22 @@ -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')); +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..d1408ba --- /dev/null +++ b/src/interceptor/interceptor.js @@ -0,0 +1,32 @@ +import axios from "axios"; + +const httpIntercept = (props) => { + axios.interceptors.request.use( + (request) => { + const authToken = localStorage.getItem("authToken"); + if ( + request.url.includes(process.env.REACT_APP_BACKEND_URL) && + authToken + ) { + request.headers.Authorization = + "JWT " + 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/book_loans/BookLoans.jsx b/src/pages/book_loans/BookLoans.jsx new file mode 100644 index 0000000..da3c690 --- /dev/null +++ b/src/pages/book_loans/BookLoans.jsx @@ -0,0 +1,130 @@ +import React, { useEffect, useState } from "react"; + +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"; +import { toast } from "react-toastify"; +import useHttp from "../../hooks/use-https"; + +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 { sendRequest } = useHttp(); + + const handleOpen = () => setOpen(true); + const handleClose = () => { + setOpen(false); + setReload(Math.random()); + }; + + useEffect(() => { + sendRequest( + { + url: "loans", + }, + (data) => { + setLoans(data); + } + ); + }, [reload, sendRequest]); + + const handleRemind = (id) => { + sendRequest( + { + url: `loans/${id}/`, + }, + (data) => { + toast.success("Reminder email sent."); + } + ); + }; + 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/book_requests/BookRequests.jsx b/src/pages/book_requests/BookRequests.jsx new file mode 100644 index 0000000..d74b4da --- /dev/null +++ b/src/pages/book_requests/BookRequests.jsx @@ -0,0 +1,128 @@ +import React, { useEffect, useState } from "react"; + +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"; +import useHttp from "../../hooks/use-https"; + +const MyRequests = () => { + const [requests, setRequests] = useState([]); + const [defaultValue, setDefaultValue] = useState(null); + const [reload, setReload] = useState(0); + const [open, setOpen] = useState(false); + + const { sendRequest } = useHttp(); + + const { userInfo } = useSelector((state) => state.user); + + const handleOpen = () => setOpen(true); + const handleClose = () => { + setDefaultValue(null); + setOpen(false); + setReload(Math.random()); + }; + + useEffect(() => { + sendRequest({ url: "book_requests/" }, (data) => { + setRequests(data); + }); + }, [reload, sendRequest]); + return ( + + + + + + + + + + {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")} + + + + + + + ))} + +
+
+
+ + + + {userInfo?.is_librarian && defaultValue ? ( + + ) : ( + + )} + + +
+ ); +}; + +export default MyRequests; diff --git a/src/pages/home/Home.jsx b/src/pages/home/Home.jsx new file mode 100644 index 0000000..567d4d9 --- /dev/null +++ b/src/pages/home/Home.jsx @@ -0,0 +1,93 @@ +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 { toast } from "react-toastify"; +import { useSelector } from "react-redux"; +import useHttp from "../../hooks/use-https"; + +const Home = () => { + const [books, setBooks] = useState([]); + const { authToken } = useSelector((state) => state.user); + const { sendRequest } = useHttp(); + + useEffect(() => { + sendRequest({ url: "books/" }, (data) => { + setBooks(data); + }); + }, [sendRequest]); + + const handleLoan = (bookId) => { + sendRequest( + { + url: "loans/", + method: "POST", + body: { + book: bookId, + status: "requested", + }, + }, + (data) => { + toast.success( + 'Book loan successful. You can track your loan in "Book Loans".' + ); + } + ); + }; + return ( + + + {books.map((item) => ( + + + + + + {item.name} + + + {item.author} - {item.publisher} - {item.stock} available + + + + {authToken && ( + + )} + + + + ))} + + + ); +}; + +export default Home; diff --git a/src/pages/login/Login.jsx b/src/pages/login/Login.jsx new file mode 100644 index 0000000..4bd9496 --- /dev/null +++ b/src/pages/login/Login.jsx @@ -0,0 +1,102 @@ +import React, { useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import { useDispatch, useSelector } from "react-redux"; + +import Avatar from "@mui/material/Avatar"; +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 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) { + console.log("first") + navigate("/"); + } + }, [navigate, userInfo]); + + const handleSubmit = (event) => { + event.preventDefault(); + const data = new FormData(event.currentTarget); + 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"} + + + + + + ); +} diff --git a/src/pages/register/Register.jsx b/src/pages/register/Register.jsx new file mode 100644 index 0000000..2891343 --- /dev/null +++ b/src/pages/register/Register.jsx @@ -0,0 +1,152 @@ +import React, { useState } 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"; + +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 { sendRequest } = useHttp(); + + const handleChange = (event) => { + setGender(event.target.value); + }; + const handleSubmit = (event) => { + event.preventDefault(); + const data = new FormData(event.currentTarget); + 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 ( + + + + + + + + Sign up + + + + + + + + + + + + + + + + + + + + + Gender + + + + + + + + + Already have an account? Sign in + + + + + + + ); +} 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..1c91cec --- /dev/null +++ b/src/store/actions/userActions.jsx @@ -0,0 +1,25 @@ +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) { + console.log("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;