diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 824d16c..9aa8618 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -18,9 +18,12 @@ "axios": "^0.27.2", "classnames": "^2.3.1", "daisyui": "^2.15.2", + "luxon": "^3.0.4", "react": "^18.1.0", + "react-big-calendar": "^1.5.0", "react-dom": "^18.1.0", "react-hook-form": "^7.31.3", + "react-modal": "^3.16.1", "react-query": "^3.39.0", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", @@ -29,6 +32,9 @@ "web-vitals": "^2.1.4" }, "devDependencies": { + "@types/luxon": "^3.0.2", + "@types/react-big-calendar": "^0.38.2", + "@types/react-modal": "^3.13.1", "autoprefixer": "^10.4.7", "postcss": "^8.4.14", "tailwindcss": "^3.0.24" @@ -1799,9 +1805,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -3068,6 +3074,26 @@ } } }, + "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/@restart/hooks": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz", + "integrity": "sha512-ZbjlEHcG+FQtpDPHd7i4FzNNvJf2enAwZfJbpM8CW7BhmOAbsHpZe3tsHwfQUrBuyrxWqPYp2x5UMnilWcY22A==", + "dependencies": { + "dequal": "^2.0.2" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3795,6 +3821,12 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/luxon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz", + "integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -3845,6 +3877,16 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-big-calendar": { + "version": "0.38.2", + "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-0.38.2.tgz", + "integrity": "sha512-YbJ88I6QOEt1JEb1U5nvJsIy47zgBbXcyPRYaT3n4AJLv49AZsdsIk6akEIuuGouosfMEwUAUktjL8R0Y63yTA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz", @@ -3853,6 +3895,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-modal": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.13.1.tgz", + "integrity": "sha512-iY/gPvTDIy6Z+37l+ibmrY+GTV4KQTHcCyR5FIytm182RQS69G5ps4PH2FxtC7bAQ2QRHXMevsBgck7IQruHNg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", @@ -3922,6 +3973,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/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -5450,6 +5506,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", @@ -6223,6 +6287,11 @@ "node": ">=10" } }, + "node_modules/date-arithmetic": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", + "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6325,6 +6394,14 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -7492,6 +7569,11 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -8249,6 +8331,11 @@ "which": "bin/which" } }, + "node_modules/globalize": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/globalize/-/globalize-0.1.1.tgz", + "integrity": "sha512-5e01v8eLGfuQSOvx2MsDMOWS0GFtCx1wPzQSmcHw4hkxFzrQDBO3Xwg/m8Hr/7qXMrHeOIE29qWVzyv06u1TZA==" + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -8757,6 +8844,14 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ipaddr.js": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", @@ -11376,6 +11471,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -11431,6 +11531,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==", + "engines": { + "node": ">=12" + } + }, "node_modules/lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", @@ -11703,6 +11811,25 @@ "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/moment-timezone": { + "version": "0.5.38", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.38.tgz", + "integrity": "sha512-nMIrzGah4+oYZPflDvLZUgoVUO4fvAqHstvG3xAUnMolWncuAiLDWNnJZj6EwJGMGfb1ZcuTFE6GI3hNOVWI/Q==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -13688,6 +13815,45 @@ "node": ">=14" } }, + "node_modules/react-big-calendar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.5.0.tgz", + "integrity": "sha512-/BAJqufxtIf4oR51+7LBtPnqTrghzszzYCGlLaaLlxvVxXBVvTWRcKuyR6KMSuo0zQ/8b94JMG75hiPRe3DWlw==", + "dependencies": { + "@babel/runtime": "^7.18.6", + "clsx": "^1.2.1", + "date-arithmetic": "^4.1.0", + "dom-helpers": "^5.2.1", + "globalize": "^0.1.1", + "invariant": "^2.2.4", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "luxon": "^2.4.0", + "memoize-one": "^6.0.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.34", + "prop-types": "^15.8.1", + "react-overlays": "^5.2.0", + "uncontrollable": "^7.2.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17 || ^18", + "react-dom": "^16.14.0 || ^17 || ^18" + } + }, + "node_modules/react-big-calendar/node_modules/luxon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz", + "integrity": "sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A==", + "engines": { + "node": ">=12" + } + }, + "node_modules/react-big-calendar/node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -13842,6 +14008,48 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "dependencies": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" + } + }, + "node_modules/react-overlays": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz", + "integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==", + "dependencies": { + "@babel/runtime": "^7.13.8", + "@popperjs/core": "^2.11.6", + "@restart/hooks": "^0.4.7", + "@types/warning": "^3.0.0", + "dom-helpers": "^5.2.0", + "prop-types": "^15.7.2", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, "node_modules/react-query": { "version": "3.39.0", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.0.tgz", @@ -15691,6 +15899,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -15878,6 +16100,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -17945,9 +18175,9 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -18839,6 +19069,19 @@ "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==" + }, + "@restart/hooks": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz", + "integrity": "sha512-ZbjlEHcG+FQtpDPHd7i4FzNNvJf2enAwZfJbpM8CW7BhmOAbsHpZe3tsHwfQUrBuyrxWqPYp2x5UMnilWcY22A==", + "requires": { + "dequal": "^2.0.2" + } + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -19373,6 +19616,12 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "@types/luxon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz", + "integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -19423,6 +19672,16 @@ "csstype": "^3.0.2" } }, + "@types/react-big-calendar": { + "version": "0.38.2", + "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-0.38.2.tgz", + "integrity": "sha512-YbJ88I6QOEt1JEb1U5nvJsIy47zgBbXcyPRYaT3n4AJLv49AZsdsIk6akEIuuGouosfMEwUAUktjL8R0Y63yTA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/react": "*" + } + }, "@types/react-dom": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz", @@ -19431,6 +19690,15 @@ "@types/react": "*" } }, + "@types/react-modal": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.13.1.tgz", + "integrity": "sha512-iY/gPvTDIy6Z+37l+ibmrY+GTV4KQTHcCyR5FIytm182RQS69G5ps4PH2FxtC7bAQ2QRHXMevsBgck7IQruHNg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-transition-group": { "version": "4.4.4", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", @@ -19500,6 +19768,11 @@ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==" }, + "@types/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", + "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==" + }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -20627,6 +20900,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", @@ -21188,6 +21466,11 @@ "whatwg-url": "^8.0.0" } }, + "date-arithmetic": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz", + "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -21258,6 +21541,11 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" + }, "destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -22112,6 +22400,11 @@ "strip-final-newline": "^2.0.0" } }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -22663,6 +22956,11 @@ } } }, + "globalize": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/globalize/-/globalize-0.1.1.tgz", + "integrity": "sha512-5e01v8eLGfuQSOvx2MsDMOWS0GFtCx1wPzQSmcHw4hkxFzrQDBO3Xwg/m8Hr/7qXMrHeOIE29qWVzyv06u1TZA==" + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -23035,6 +23333,14 @@ "side-channel": "^1.0.4" } }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "ipaddr.js": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", @@ -24924,6 +25230,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -24973,6 +25284,11 @@ "yallist": "^4.0.0" } }, + "luxon": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==" + }, "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", @@ -25174,6 +25490,19 @@ "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==" + }, + "moment-timezone": { + "version": "0.5.38", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.38.tgz", + "integrity": "sha512-nMIrzGah4+oYZPflDvLZUgoVUO4fvAqHstvG3xAUnMolWncuAiLDWNnJZj6EwJGMGfb1ZcuTFE6GI3hNOVWI/Q==", + "requires": { + "moment": ">= 2.9.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -26462,6 +26791,40 @@ "whatwg-fetch": "^3.6.2" } }, + "react-big-calendar": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.5.0.tgz", + "integrity": "sha512-/BAJqufxtIf4oR51+7LBtPnqTrghzszzYCGlLaaLlxvVxXBVvTWRcKuyR6KMSuo0zQ/8b94JMG75hiPRe3DWlw==", + "requires": { + "@babel/runtime": "^7.18.6", + "clsx": "^1.2.1", + "date-arithmetic": "^4.1.0", + "dom-helpers": "^5.2.1", + "globalize": "^0.1.1", + "invariant": "^2.2.4", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "luxon": "^2.4.0", + "memoize-one": "^6.0.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.34", + "prop-types": "^15.8.1", + "react-overlays": "^5.2.0", + "uncontrollable": "^7.2.1" + }, + "dependencies": { + "luxon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.5.0.tgz", + "integrity": "sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A==" + }, + "memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" + } + } + }, "react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -26573,6 +26936,37 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "requires": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + } + }, + "react-overlays": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz", + "integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==", + "requires": { + "@babel/runtime": "^7.13.8", + "@popperjs/core": "^2.11.6", + "@restart/hooks": "^0.4.7", + "@types/warning": "^3.0.0", + "dom-helpers": "^5.2.0", + "prop-types": "^15.7.2", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + } + }, "react-query": { "version": "3.39.0", "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.0.tgz", @@ -27950,6 +28344,17 @@ "which-boxed-primitive": "^1.0.2" } }, + "uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "requires": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -28094,6 +28499,14 @@ "makeerror": "1.0.12" } }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 45a3eaf..0ff5e33 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,9 +13,12 @@ "axios": "^0.27.2", "classnames": "^2.3.1", "daisyui": "^2.15.2", + "luxon": "^3.0.4", "react": "^18.1.0", + "react-big-calendar": "^1.5.0", "react-dom": "^18.1.0", "react-hook-form": "^7.31.3", + "react-modal": "^3.16.1", "react-query": "^3.39.0", "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", @@ -48,6 +51,9 @@ ] }, "devDependencies": { + "@types/luxon": "^3.0.2", + "@types/react-big-calendar": "^0.38.2", + "@types/react-modal": "^3.13.1", "autoprefixer": "^10.4.7", "postcss": "^8.4.14", "tailwindcss": "^3.0.24" diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 193bd43..671091d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2,6 +2,7 @@ import React from 'react' import { QueryClient, QueryClientProvider } from 'react-query' import { Navigate, Route, Routes } from 'react-router-dom' import './App.css' +import 'react-big-calendar/lib/css/react-big-calendar.css' import AddGroup from './views/coordinator/AddGroup' import AddStudent from './views/coordinator/AddStudent' import AddLeader from './views/coordinator/AddLeader' @@ -12,6 +13,9 @@ import Students from './views/coordinator/Students' import Login from './views/Login' import Enrollment from './views/student/Enrollment' import Student from './views/student/Student' +import Supervisor from './views/supervisor/Supervisor' +import Schedules from './views/coordinator/Schedules' +import Schedule from './views/coordinator/Schedule' const queryClient = new QueryClient({ defaultOptions: { @@ -35,11 +39,17 @@ function App() { } /> } /> } /> + } /> + } /> }> } /> } /> + }> + } /> + } /> + diff --git a/frontend/src/api/schedule.ts b/frontend/src/api/schedule.ts new file mode 100644 index 0000000..bea7547 --- /dev/null +++ b/frontend/src/api/schedule.ts @@ -0,0 +1,74 @@ +import axiosInstance from './axiosInstance' + +export const getEvents = (scheduleId: number) => { + return axiosInstance.get<{ + enrollments: { + id: number + start_date: string + end_date: string + title: string + }[] + }>( + `http://127.0.0.1:5000/api/examination_schedule/enrollments/${scheduleId}/coordinator-view/?per_page=10000`, + ) +} + +export const getSchedules = () => { + return axiosInstance.get<{ + examination_schedules: { + id: number + start_date: string + end_date: string + title: string + mode: boolean + }[] + }>( + 'http://127.0.0.1:5000/api/coordinator/examination_schedule/?per_page=10000', + ) +} + +export const createEvent = ({ + start_date, + end_date, + scheduleId, +}: { + start_date: string + end_date: string + scheduleId: number +}) => { + return axiosInstance.post( + `http://127.0.0.1:5000/api/coordinator/enrollments/${scheduleId}/`, + { + start_date, + end_date, + }, + ) +} + +export const createSchedule = (title: string) => { + return axiosInstance.post( + 'http://127.0.0.1:5000/api/coordinator/examination_schedule/', + { + title, + mode: true, + }, + ) +} + +export const setEventDate = ({ + id, + start_date, + end_date, +}: { + id: number + start_date: string + end_date: string +}) => { + return axiosInstance.put( + `http://127.0.0.1:5000/api/coordinator/examination_schedule/${id}/date`, + { + start_date, + end_date, + }, + ) +} diff --git a/frontend/src/index.css b/frontend/src/index.css index b2bc267..b72b595 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -8,4 +8,7 @@ body { sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; +} +.rbc-calendar .rbc-row-content { + z-index: 0; } \ No newline at end of file diff --git a/frontend/src/views/coordinator/Coordinator.tsx b/frontend/src/views/coordinator/Coordinator.tsx index 90dbc05..f7a5663 100644 --- a/frontend/src/views/coordinator/Coordinator.tsx +++ b/frontend/src/views/coordinator/Coordinator.tsx @@ -9,6 +9,7 @@ const Coordinator = () => { { name: 'Grupy', path: '/coordinator/groups' }, { name: 'Studenci', path: '/coordinator/students' }, { name: 'Opiekunowie', path: '/coordinator/leaders' }, + { name: 'Harmonogram', path: '/coordinator/schedule' }, ]} />
diff --git a/frontend/src/views/coordinator/Schedule.tsx b/frontend/src/views/coordinator/Schedule.tsx new file mode 100644 index 0000000..237c836 --- /dev/null +++ b/frontend/src/views/coordinator/Schedule.tsx @@ -0,0 +1,172 @@ +import { Calendar, luxonLocalizer, Views } from 'react-big-calendar' +import { DateTime, Settings } from 'luxon' +import { useCallback, useState } from 'react' +import { useMutation, useQuery } from 'react-query' +import { createEvent, getEvents } from '../../api/schedule' +import { useParams } from 'react-router-dom' +import Modal from 'react-modal' +import { useForm } from 'react-hook-form' + +const customStyles = { + content: { + top: '50%', + left: '50%', + right: 'auto', + bottom: 'auto', + marginRight: '-50%', + transform: 'translate(-50%, -50%)', + }, +} + +const Schedule = () => { + Settings.defaultZone = DateTime.local().zoneName + Settings.defaultLocale = 'pl' + + const { id } = useParams<{ id: string }>() + const [events, setEvents] = useState< + { + id: number + title: string + start: Date + end: Date + }[] + >([]) + const [selectedDate, setSelectedDate] = useState<{ + start: Date + end: Date + title: string + id: number + }>() + const [view, setView] = useState(Views.MONTH) + const onView = useCallback((newView: any) => setView(newView), [setView]) + + const [isModalOpen, setIsModalOpen] = useState(false) + Modal.setAppElement('#root') + + const { register, handleSubmit, reset } = useForm<{ + from: string + to: string + }>({ mode: 'onBlur' }) + + const { refetch } = useQuery(['schedules'], () => getEvents(Number(id)), { + onSuccess: (data) => { + setEvents( + data.data.enrollments.map( + ({ id, start_date, end_date, title = 'Obrona' }) => { + return { + id, + title, + start: new Date(start_date), + end: new Date(end_date), + } + }, + ), + ) + }, + }) + const { mutateAsync: mutateCreateEvent } = useMutation( + ['createEvent'], + (data: { start_date: string; end_date: string; scheduleId: number }) => + createEvent(data), + ) + + const handleSelectSlot = async (event: any) => { + setSelectedDate(event) + if (view === Views.MONTH) { + setIsModalOpen(true) + } else { + await mutateCreateEvent({ + start_date: DateTime.fromJSDate(event.start).toFormat( + 'yyyy-LL-dd HH:mm:ss', + ), + end_date: DateTime.fromJSDate(event.end).toFormat( + 'yyyy-LL-dd HH:mm:ss', + ), + scheduleId: Number(id), + }) + refetch() + } + } + + const handleSelectEvent = useCallback( + (event: { id: number; title: string; start: Date; end: Date }) => + window.alert(event.title), + [], + ) + + function closeModal() { + setIsModalOpen(false) + } + const onSubmit = async (data: any) => { + if (selectedDate && view === Views.MONTH) { + const from = data.from.split(':') + const to = data.to.split(':') + await mutateCreateEvent({ + start_date: DateTime.fromJSDate(selectedDate.start) + .set({ hour: from[0], minute: from[1] }) + .toFormat('yyyy-LL-dd HH:mm:ss'), + end_date: DateTime.fromJSDate(selectedDate.start) + .set({ hour: to[0], minute: to[1] }) + .toFormat('yyyy-LL-dd HH:mm:ss'), + scheduleId: Number(id), + }) + refetch() + reset() + closeModal() + } + } + + return ( +
+ + + +
+

Dostępne godziny

+
+ + + + +
+ +
+
+
+ ) +} + +export default Schedule diff --git a/frontend/src/views/coordinator/Schedules.tsx b/frontend/src/views/coordinator/Schedules.tsx new file mode 100644 index 0000000..2d669bb --- /dev/null +++ b/frontend/src/views/coordinator/Schedules.tsx @@ -0,0 +1,60 @@ +import { useMutation, useQuery } from 'react-query' +import { createSchedule, getSchedules } from '../../api/schedule' +import { useForm } from 'react-hook-form' +import { Link } from 'react-router-dom' + +const Schedules = () => { + const { register, handleSubmit } = useForm<{ title: string }>({ + mode: 'onBlur', + }) + + const { data: schedules, refetch } = useQuery(['getSchedules'], () => + getSchedules(), + ) + + const { mutate: mutateCreateSchedule } = useMutation( + ['createSchedule'], + ({ title }: { title: string }) => createSchedule(title), + { + onSuccess: () => { + refetch() + }, + }, + ) + + const onSubmit = (data: any) => { + mutateCreateSchedule(data) + } + + return ( +
+
+
+ + +
+ +
+ {schedules && + schedules?.data?.examination_schedules.map((schedule) => ( +

+ + {schedule.title} + +

+ ))} +
+ ) +} + +export default Schedules diff --git a/frontend/src/views/supervisor/Supervisor.tsx b/frontend/src/views/supervisor/Supervisor.tsx new file mode 100644 index 0000000..be1b8a9 --- /dev/null +++ b/frontend/src/views/supervisor/Supervisor.tsx @@ -0,0 +1,15 @@ +import { Outlet } from 'react-router-dom' +import TopBar from '../../components/TopBar' + +const Supervisor = () => { + return ( + <> + +
+ +
+ + ) +} + +export default Supervisor diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index c0b9ebc..49032df 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -3,5 +3,8 @@ module.exports = { theme: { extend: {}, }, + daisyui: { + themes: ['light'], + }, plugins: [require('daisyui')], }