diff --git a/my-app/package-lock.json b/my-app/package-lock.json index b5f916d..360afab 100644 --- a/my-app/package-lock.json +++ b/my-app/package-lock.json @@ -9,8 +9,11 @@ "version": "0.0.0", "dependencies": { "@dagrejs/dagre": "^1.1.4", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@headlessui/react": "^2.2.1", "@heroicons/react": "^2.2.0", + "@mui/material": "^7.1.0", "@tailwindcss/vite": "^4.0.17", "@xyflow/react": "^12.5.5", "autoprefixer": "^10.4.21", @@ -62,7 +65,6 @@ "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -118,7 +120,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.27.0", @@ -152,7 +153,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -194,7 +194,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -204,7 +203,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -238,7 +236,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.0" @@ -282,11 +279,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -301,7 +305,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -320,7 +323,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -330,7 +332,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -368,6 +369,152 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "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.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "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.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", + "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", @@ -1722,7 +1869,6 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -1737,7 +1883,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1747,7 +1892,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1757,14 +1901,12 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1786,6 +1928,216 @@ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", "license": "MIT" }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.0.tgz", + "integrity": "sha512-E0OqhZv548Qdc0PwWhLVA2zmjJZSTvaL4ZhoswmI8NJEC1tpW2js6LLP827jrW9MEiXYdz3QS6+hask83w74yQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.1.0.tgz", + "integrity": "sha512-ahUJdrhEv+mCp4XHW+tHIEYzZMSRLg8z4AjUOsj44QpD1ZaMxQoVOG2xiHvLFdcsIPbgSRx1bg1eQSheHBgvtg==", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/core-downloads-tracker": "^7.1.0", + "@mui/system": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.1.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.1.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==" + }, + "node_modules/@mui/private-theming": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.1.0.tgz", + "integrity": "sha512-4Kck4jxhqF6YxNwJdSae1WgDfXVg0lIH6JVJ7gtuFfuKcQCgomJxPvUEOySTFRPz1IZzwz5OAcToskRdffElDA==", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/utils": "^7.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.1.0.tgz", + "integrity": "sha512-m0mJ0c6iRC+f9hMeRe0W7zZX1wme3oUX0+XTVHjPG7DJz6OdQ6K/ggEOq7ZdwilcpdsDUwwMfOmvO71qDkYd2w==", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.1.0.tgz", + "integrity": "sha512-iedAWgRJMCxeMHvkEhsDlbvkK+qKf9me6ofsf7twk/jfT4P1ImVf7Rwb5VubEA0sikrVL+1SkoZM41M4+LNAVA==", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/private-theming": "^7.1.0", + "@mui/styled-engine": "^7.1.0", + "@mui/types": "^7.4.2", + "@mui/utils": "^7.1.0", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.2.tgz", + "integrity": "sha512-edRc5JcLPsrlNFYyTPxds+d5oUovuUxnnDtpJUbP6WMeV4+6eaX/mqai1ZIWT62lCOe0nlrON0s9HDiv5en5bA==", + "dependencies": { + "@babel/runtime": "^7.27.1" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.1.0.tgz", + "integrity": "sha512-/OM3S8kSHHmWNOP+NH9xEtpYSG10upXeQ0wLZnfDgmgadTAk5F4MQfFLyZ5FCRJENB3eRzltMmaNl6UtDnPovw==", + "dependencies": { + "@babel/runtime": "^7.27.1", + "@mui/types": "^7.4.2", + "@types/prop-types": "^15.7.14", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==" + }, "node_modules/@napi-rs/canvas": { "version": "0.1.69", "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.69.tgz", @@ -1968,6 +2320,15 @@ "node": ">= 10" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -3107,11 +3468,20 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" + }, "node_modules/@types/react": { "version": "19.1.2", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", - "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -3127,6 +3497,14 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@vitejs/plugin-react": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.4.0.tgz", @@ -3362,6 +3740,39 @@ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "license": "MIT" }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3444,7 +3855,15 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "license": "MIT", "engines": { "node": ">=6" @@ -3667,6 +4086,29 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3686,7 +4128,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, "license": "MIT" }, "node_modules/d3-color": { @@ -3869,6 +4310,15 @@ "node": ">=8" } }, + "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/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -3905,6 +4355,14 @@ "node": ">=10.13.0" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/esbuild": { "version": "0.25.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", @@ -3958,7 +4416,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -4319,6 +4776,11 @@ "node": ">=16.0.0" } }, + "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", @@ -4459,6 +4921,14 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/fuse.js": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", @@ -4582,6 +5052,25 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/http-parser-js": { "version": "0.5.10", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", @@ -4635,7 +5124,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -4834,6 +5322,25 @@ "node": ">=4" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -4931,7 +5438,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -4947,6 +5453,11 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -5258,6 +5769,11 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, "node_modules/lint": { "version": "0.8.19", "resolved": "https://registry.npmjs.org/lint/-/lint-0.8.19.tgz", @@ -5901,7 +6417,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -5910,6 +6425,23 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5939,6 +6471,19 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, "node_modules/pdfjs-dist": { "version": "5.1.91", "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.1.91.tgz", @@ -6209,6 +6754,21 @@ "react-dom": ">=18" } }, + "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/reactflow": { "version": "11.11.4", "resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.4.tgz", @@ -6539,7 +7099,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6837,6 +7396,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6850,6 +7414,17 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", diff --git a/my-app/package.json b/my-app/package.json index fa84172..0a596d5 100644 --- a/my-app/package.json +++ b/my-app/package.json @@ -11,8 +11,11 @@ }, "dependencies": { "@dagrejs/dagre": "^1.1.4", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@headlessui/react": "^2.2.1", "@heroicons/react": "^2.2.0", + "@mui/material": "^7.1.0", "@tailwindcss/vite": "^4.0.17", "@xyflow/react": "^12.5.5", "autoprefixer": "^10.4.21", diff --git a/my-app/src/index.jsx b/my-app/src/index.jsx index 546ffb1..6d8d65a 100644 --- a/my-app/src/index.jsx +++ b/my-app/src/index.jsx @@ -11,11 +11,8 @@ import { JsonToDatabase } from "./presenters/Tests/JsonToDatabase"; import { AllCoursesPresenter } from "./presenters/Tests/AllCoursesPresenter.jsx"; -/** - * This file contains the bootstrapping, as well as the router used in our webapp. - */ +configure({ enforceActions: "never", reactionScheduler: (f) => setTimeout(f, 0),}); -configure({ enforceActions: "observed", reactionScheduler: (f) => setTimeout(f, 0),}); const reactiveModel = makeAutoObservable(model); connectToFirebase(reactiveModel); diff --git a/my-app/src/model.js b/my-app/src/model.js index 538ed25..1dab325 100644 --- a/my-app/src/model.js +++ b/my-app/src/model.js @@ -1,311 +1,299 @@ -import { - addCourse, - addReviewForCourse, - getReviewsForCourse, - uploadDepartmentsAndLocations, -} from "../firebase"; - -/** - * The model contains the data and "business logic" of the application. - * It manages the state of the application and contains getter / setter to manipulate the state. - * "firebase.js" is used to fetch data from the Firebase database, which are then stored in the model. - * In the application the model is used as a singleton, so that all components can access the same data. - * Initializing the model happens on top of the application tree in the "index.jsx". - */ +import { query } from "firebase/database"; +import { addCourse, addReviewForCourse, getReviewsForCourse, uploadDepartmentsAndLocations } from "../firebase"; + + export const model = { - user: undefined, - //add searchChange: false, //this is for reworking the searchbar presenter, so that it triggers as a model, - //instead of passing searchcouses lambda function down into the searchbarview. - /* courses returned from SearchbarPresenter (search is applied on top of filteredCourses[]) to be shown in the ListView */ - currentSearch: [], - - sidebarIsOpen: true, - /* current query text */ - currentSearchText: "", - scrollPosition: 0, - /* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */ - courses: [], - departments: [], - locations: [], - // indexes: 0 -> overall rating; 1 -> difficulty; 2->teacher rating - avgRatings: [], - // model.avgRatings["IK1203"][0] - /* courses the user selected as their favourite */ - favourites: [], - searchHistory: [], - isReady: false, - /* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */ - filtersChange: false, - /* this is a flag showing if the filteredCourses[] has changed (since FilterPresenter recalculated it), so now SearchBarPresenter needs to + user: undefined, + //add searchChange: false, //this is for reworking the searchbar presenter, so that it triggers as a model, + //instead of passing searchcouses lambda function down into the searchbarview. + /* courses returned from SearchbarPresenter (search is applied on top of filteredCourses[]) to be shown in the ListView */ + currentSearch: [], + + sidebarIsOpen: true, + /* current query text */ + currentSearchText: "", + scrollPosition: 0, + /* list of all course objects downloaded from the Firebase realtime database and stored locally as JSON object in this array */ + courses: [], + departments: [], + locations: [], + // indexes: 0 -> overall rating; 1 -> difficulty; 2->teacher rating + avgRatings: [], + // model.avgRatings["IK1203"][0] + /* courses the user selected as their favourite */ + favourites: [], + searchHistory: [], + isReady: false, + /* this is a boolean flag showing that filtering options in the UI have changed, triggering the FilterPresenter to recalculate the filteredCourses[] */ + filtersChange: false, + /* this is a flag showing if the filteredCourses[] has changed (since FilterPresenter recalculated it), so now SearchBarPresenter needs to recalculate currentSearch[] depending this updated list of courses */ - filtersCalculated: false, - /* this is the array that FilterPresenter fills up with course objects, filtered from the model.courses[] */ - filteredCourses: [], - /* JSON object containing all important parameters the FilterPresenter needs to calculate the filtered list of courses */ - filterOptions: { - //apply-X-Filter boolean triggering flag wether corresponding filtering functions should run or not - //different arrays require different data, some uses string arrays, some boolean values, and so on - applyTranscriptFilter: false, - eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong" - applyLevelFilter: true, - level: ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" - applyLanguageFilter: false, - language: "none", //the possible values for the string are: "none"/"english"/"swedish"/"both" - applyLocationFilter: false, - location: [], //the possible values for the array are: 'KTH Campus', 'KTH Kista', 'AlbaNova', 'KTH Flemingsberg', 'KTH Solna', 'KTH Södertälje', 'Handelshögskolan', 'KI Solna', 'Stockholms universitet', 'KONSTFACK' - applyCreditsFilter: true, - creditMin: 0, - creditMax: 45, - applyDepartmentFilter: false, - department: [], - applyRemoveNullCourses: false, - period: [true, true, true, true], - applyPeriodFilter: true, - }, - isPopupOpen: false, - selectedCourse: null, - searchQueryModel: "", - - _coursesListeners: [], // internal list of listeners - - onCoursesSet(callback) { - this._coursesListeners.push(callback); - }, - - urlStackPointer: 0, - - setUser(user) { - if (!this.user) this.user = user; - }, - - setCurrentSearch(searchResults) { - this.currentSearch = searchResults; - }, - - setCurrentSearchText(text) { - this.currentSearchText = text; - }, - - setScrollPosition(position) { - this.scrollPosition = position; - }, - - setCourses(courses) { - this.courses = courses; - this._coursesListeners.forEach((cb) => cb(courses)); - }, - - async addCourse(course) { - try { - await addCourse(course); - this.courses = [...this.courses, course]; - } catch (error) { - console.error("Error adding course:", error); - } - }, - addHistoryItem(course_id) { - try { - this.searchHistory = [...this.searchHistory, course_id]; - } catch (error) { - console.error("Error adding course code to the history:", error); - } - }, - setDepartments(departments) { - this.departments = departments; - }, - setLocations(locations) { - this.locations = locations; - }, - setAverageRatings(ratings) { - this.avgRatings = ratings; - }, - updateAverageRating(courseCode, rating) { - if (this.avgRatings != null) this.avgRatings[courseCode] = rating; - }, - setFavourite(favorites) { - this.favourites = favorites; - }, - - addFavourite(course) { - this.favourites = [...this.favourites, course]; - }, - - removeFavourite(course) { - this.favourites = (this.favourites || []).filter( - (fav) => fav.code !== course.code - ); - }, - - getCourse(courseID) { - return this.courses.find((course) => course.code === courseID); - }, - - getCourseNames(courseID_array) { - let return_obj = {}; - for (let course of this.courses) { - if (courseID_array.includes(course.code)) { - return_obj[course.code] = course.name; - } - } - return return_obj; - }, - - /** - * An admin function to populate the database with courses, - * Currently used in the Tests/JsonToDatabase Test file to trigger. - * @param {data} data to populate the database with. Can be read from a JSON - * @returns void - */ - populateDatabase(data) { - if (!data || !this) { - console.log("no model or data"); - return; - } - // use sets to avoid duplicates - const dep = new Set(); - const loc = new Set(); - const entries = Object.entries(data); - entries.forEach((entry) => { - const course = { - code: entry[1].code, - name: entry[1]?.name ?? null, - location: entry[1]?.location ?? null, - department: entry[1]?.department ?? null, - language: entry[1]?.language ?? null, - description: entry[1]?.description ?? null, - academicLevel: entry[1]?.academic_level ?? null, - periods: entry[1]?.periods ?? null, - credits: entry[1]?.credits ?? 0, - prerequisites: entry[1]?.prerequisites ?? null, - prerequisites_text: entry[1]?.prerequisites_text ?? null, - learning_outcomes: entry[1]?.learning_outcomes ?? null, - }; - this.addCourse(course); - dep.add(course.department); - loc.add(course.location); - }); - this.departments = Array.from(dep); - this.locations = Array.from(loc); - uploadDepartmentsAndLocations(this.departments, this.locations); - }, - //for reviews - async addReview(courseCode, review) { - try { - await addReviewForCourse(courseCode, review); - return true; - } catch (error) { - console.error("Error adding review:", error); - return false; - } - }, - - async getReviews(courseCode) { - try { - const rawReviews = await getReviewsForCourse(courseCode); - if (!Array.isArray(rawReviews)) return []; - - const enriched = rawReviews.map((review) => { - return { - ...review, - uid: review.uid || review.id || "", - courseCode: courseCode || "", - }; - }); - - return enriched; - } catch (error) { - console.error("Error fetching reviews:", error); - return []; - } - }, - //for filters - - setFiltersChange() { - this.filtersChange = true; - }, - - setFiltersCalculated() { - this.filtersCalculated = true; - }, - - setFilterOptions(options) { - this.filterOptions = options; // do we want to set the flags? What about useEffect? - }, - - setApplyRemoveNullCourses() { - this.filterOptions.applyRemoveNullCourses = - !this.filterOptions.applyRemoveNullCourses; - this.setFiltersChange(); - }, - - updateLevelFilter(level) { - this.filterOptions.level = level; - console.log(level); - }, - updateLanguageFilter(languages) { - this.filterOptions.language = languages; - }, - updateLocationFilter(location) { - this.filterOptions.location = location; - }, - updateCreditsFilter(creditLimits) { - this.filterOptions.creditMin = creditLimits[0]; - this.filterOptions.creditMax = creditLimits[1]; - }, - updateTranscriptElegibilityFilter(eligibility) { - this.filterOptions.eligibility = eligibility; - }, - - updatePeriodFilter(period) { - this.filterOptions.period = period; - }, - - setApplyTranscriptFilter(transcriptFilterState) { - this.filterOptions.applyTranscriptFilter = transcriptFilterState; - }, - setApplyLevelFilter(levelFilterState) { - this.filterOptions.applyLevelFilter = levelFilterState; - }, - setApplyLanguageFilter(languageFilterState) { - this.filterOptions.applyLanguageFilter = languageFilterState; - }, - setApplyLocationFilter(locationFilterState) { - this.filterOptions.applyLocationFilter = locationFilterState; - }, - setApplyCreditsFilter(creditsFilterState) { - this.filterOptions.applyCreditsFilter = creditsFilterState; - }, - setApplyDepartmentFilter(departmentFilterState) { - this.filterOptions.applyDepartmentFilter = departmentFilterState; - }, - setApplyPeriodFilter(periodfilterState) { - this.filterOptions.applyPeriodFilter = periodfilterState; - }, - //for better display we would like the departments in a structured format based on school - formatDepartments() { - const grouped = this.departments?.reduce((acc, item) => { - const [school, department] = item.split("/"); - if (!acc[school]) { - acc[school] = []; - } - acc[school].push(department?.trim()); - return acc; - }, {}); - const sortedGrouped = Object.keys(grouped) - .sort() - .reduce((acc, key) => { - acc[key] = grouped[key].sort(); - return acc; - }, {}); - const fields = Object.entries(sortedGrouped).map( - ([school, departments], index) => ({ - id: index + 1, - label: school, - subItems: departments, - }) - ); - return fields; - }, + filtersCalculated: false, + /* this is the array that FilterPresenter fills up with course objects, filtered from the model.courses[] */ + filteredCourses: [], + /* JSON object containing all important parameters the FilterPresenter needs to calculate the filtered list of courses */ + filterOptions: { + //apply-X-Filter boolean triggering flag wether corresponding filtering functions should run or not + //different arrays require different data, some uses string arrays, some boolean values, and so on + applyTranscriptFilter: false, + eligibility: "weak", //the possible values for the string are: "weak"/"moderate"/"strong" + applyLevelFilter: false, + level: ["PREPARATORY", "BASIC", "ADVANCED", "RESEARCH"], //the possible values for the array are: "PREPARATORY", "BASIC", "ADVANCED", "RESEARCH" + applyLanguageFilter: false, + language: "none", //the possible values for the string are: "none"/"english"/"swedish"/"both" + applyLocationFilter: false, + location: [], //the possible values for the array are: 'KTH Campus', 'KTH Kista', 'AlbaNova', 'KTH Flemingsberg', 'KTH Solna', 'KTH Södertälje', 'Handelshögskolan', 'KI Solna', 'Stockholms universitet', 'KONSTFACK' + applyCreditsFilter: false, + creditMin: 0, + creditMax: 45, + applyDepartmentFilter: false, + department: [], + applyRemoveNullCourses: false, + period: [true, true, true, true], + applyPeriodFilter: false, + }, + isPopupOpen: false, + selectedCourse: null, + searchQueryModel: "", + + _coursesListeners: [], // internal list of listeners + + onCoursesSet(callback) { + this._coursesListeners.push(callback); + }, + + _coursesListeners: [], // internal list of listeners + urlStackPointer: 0, + + onCoursesSet(callback) { + this._coursesListeners.push(callback); + }, + + setUser(user) { + if (!this.user) + this.user = user; + }, + + setCurrentSearch(searchResults) { + this.currentSearch = searchResults; + }, + + setCurrentSearchText(text) { + this.currentSearchText = text; + }, + + setScrollPosition(position) { + this.scrollPosition = position; + }, + + setCourses(courses) { + this.courses = courses; + this._coursesListeners.forEach(cb => cb(courses)); + }, + + async addCourse(course) { + try { + await addCourse(course); + this.courses = [...this.courses, course]; + } catch (error) { + console.error("Error adding course:", error); + } + }, + addHistoryItem(course_id) { + try { + this.searchHistory = [...this.searchHistory, course_id]; + } catch (error) { + console.error("Error adding course code to the history:", error); + } + }, + setDepartments(departments) { + this.departments = departments; + }, + setLocations(locations) { + this.locations = locations; + }, + setAverageRatings(ratings) { + this.avgRatings = ratings; + }, + updateAverageRating(courseCode, rating) { + if (this.avgRatings != null) + this.avgRatings[courseCode] = rating; + }, + setFavourite(favorites) { + this.favourites = favorites; + }, + + addFavourite(course) { + this.favourites = [...this.favourites, course]; + }, + + removeFavourite(course) { + this.favourites = (this.favourites || []).filter(fav => fav.code !== course.code); + }, + + getCourse(courseID) { + return this.courses.find(course => course.code === courseID); + }, + + getCourseNames(courseID_array) { + let return_obj = {}; + for (let course of this.courses) { + if (courseID_array.includes(course.code)) { + return_obj[course.code] = course.name; + } + } + return return_obj; + }, + + populateDatabase(data) { + if (!data || !this) { + console.log("no model or data"); + return; + } + const dep = new Set(); + const loc = new Set(); + const entries = Object.entries(data); + entries.forEach(entry => { + const course = { + code: entry[1].code, + name: entry[1]?.name ?? null, + location: entry[1]?.location ?? null, + department: entry[1]?.department ?? null, + language: entry[1]?.language ?? null, + description: entry[1]?.description ?? null, + academicLevel: entry[1]?.academic_level ?? null, + periods: entry[1]?.periods ?? null, + credits: entry[1]?.credits ?? 0, + prerequisites: entry[1]?.prerequisites ?? null, + prerequisites_text: entry[1]?.prerequisites_text ?? null, + learning_outcomes: entry[1]?.learning_outcomes ?? null + }; + this.addCourse(course); + dep.add(course.department); + loc.add(course.location); + }); + this.departments = Array.from(dep); + this.locations = Array.from(loc); + uploadDepartmentsAndLocations(this.departments, this.locations); + + }, + //for reviews + async addReview(courseCode, review) { + try { + await addReviewForCourse(courseCode, review); + return true; + } catch (error) { + console.error("Error adding review:", error); + return false; + } + }, + + async getReviews(courseCode) { + try { + return await getReviewsForCourse(courseCode); + } catch (error) { + console.error("Error fetching reviews:", error); + return []; + } + }, + //for filters + + setFiltersChange() { + this.filtersChange = true; + }, + + setFiltersCalculated() { + this.filtersCalculated = true; + }, + + setFilterOptions(options) { + this.filterOptions = options; // do we want to set the flags? What about useEffect? + }, + + setApplyRemoveNullCourses() { + this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses; + this.setFiltersChange(); + }, + + setApplyRemoveNullCourses() { + this.filterOptions.applyRemoveNullCourses = !this.filterOptions.applyRemoveNullCourses; + this.setFiltersChange(); + }, + + updateLevelFilter(level) { + this.filterOptions.level = level; + }, + + updateDepartmentFilter(department) { + this.filterOptions.department = department; + }, + + updateLanguageFilter(languages) { + this.filterOptions.language = languages; + }, + updateLocationFilter(location) { + this.filterOptions.location = location; + }, + updateCreditsFilter(creditLimits) { + this.filterOptions.creditMin = creditLimits[0]; + this.filterOptions.creditMax = creditLimits[1]; + }, + updateTranscriptElegibilityFilter(eligibility) { + this.filterOptions.eligibility = eligibility; + }, + + updateDepartmentFilter(department) { + this.filterOptions.department = department; + }, + + updatePeriodFilter(period) { + this.filterOptions.period = period; + }, + + setApplyTranscriptFilter(transcriptFilterState) { + this.filterOptions.applyTranscriptFilter = transcriptFilterState; + }, + setApplyLevelFilter(levelFilterState) { + this.filterOptions.applyLevelFilter = levelFilterState; + }, + setApplyLanguageFilter(languageFilterState) { + this.filterOptions.applyLanguageFilter = languageFilterState; + }, + setApplyLocationFilter(locationFilterState) { + this.filterOptions.applyLocationFilter = locationFilterState; + }, + setApplyCreditsFilter(creditsFilterState) { + this.filterOptions.applyCreditsFilter = creditsFilterState; + }, + setApplyDepartmentFilter(departmentFilterState) { + this.filterOptions.applyDepartmentFilter = departmentFilterState; + }, + setApplyPeriodFilter(periodfilterState) { + this.filterOptions.applyPeriodFilter = periodfilterState; + }, + //for better display we would like the departments in a structured format based on school + formatDepartments() { + const grouped = this?.departments.reduce((acc, item) => { + const [school, department] = item.split("/"); + if (!acc[school]) { + acc[school] = []; + } + acc[school].push(department?.trim()); + return acc; + }, {}); + const sortedGrouped = Object.keys(grouped) + .sort() + .reduce((acc, key) => { + acc[key] = grouped[key].sort(); + return acc; + }, {}); + const fields = Object.entries(sortedGrouped).map(([school, departments], index) => ({ + id: index + 1, + label: school, + subItems: departments, + })); + return fields; + }, async getAverageRating(courseCode, option) { const reviews = await getReviewsForCourse(courseCode); if (!reviews || reviews.length === 0) return null; @@ -346,54 +334,58 @@ export const model = { return (total / validReviews).toFixed(1); }, - setPopupOpen(isOpen) { - if (!isOpen) { - let current_url = window.location.href; - let end_index = indexOfNth(current_url, "/", 3); - if (end_index + 1 != current_url.length) { - window.history.back(); - } - } - - this.isPopupOpen = isOpen; - }, - - setSelectedCourse(course) { - this.selectedCourse = course; - }, - - toggleSidebarIsOpen() { - this.sidebarIsOpen = !this.sidebarIsOpen; - }, - - handleUrlChange() { - let current_url = window.location.href; - - let start_idx = indexOfNth(current_url, "/", 3) + 2; - - if (start_idx > 0 && start_idx < current_url.length) { - let course_code = current_url.slice(start_idx); - let course = this.getCourse(course_code); - if (course) { - this.setSelectedCourse(course); - this.setPopupOpen(true); - } - this.urlStackPointer++; - } else if (start_idx > 0) { - this.setPopupOpen(false); - } - }, + setPopupOpen(isOpen) { + if (!isOpen) { + let current_url = window.location.href; + let end_index = indexOfNth(current_url, '/', 3); + if (end_index + 1 != current_url.length) { + window.history.back(); + } + } + + this.isPopupOpen = isOpen; + }, + + setSelectedCourse(course) { + this.selectedCourse = course; + }, + + + toggleSidebarIsOpen() { + this.sidebarIsOpen = !this.sidebarIsOpen; + }, + + handleUrlChange() { + let current_url = window.location.href; + + let start_idx = indexOfNth(current_url, '/', 3) + 2; + + if (start_idx > 0 && start_idx < current_url.length) { + + let course_code = current_url.slice(start_idx); + let course = this.getCourse(course_code); + if (course) { + this.setSelectedCourse(course); + this.setPopupOpen(true); + } + this.urlStackPointer++; + } else if (start_idx > 0) { + this.setPopupOpen(false); + } + } + }; + function indexOfNth(string, char, n) { - let count = 0; - for (let i = 0; i < string.length; i++) { - if (string[i] == char) { - count++; - } - if (count == n) { - return i; - } - } - return -1; -} + let count = 0; + for (let i = 0; i < string.length; i++) { + if (string[i] == char) { + count++; + } + if (count == n) { + return i; + } + } + return -1; +} \ No newline at end of file diff --git a/my-app/src/pages/App.jsx b/my-app/src/pages/App.jsx index 3e6f124..0799e06 100644 --- a/my-app/src/pages/App.jsx +++ b/my-app/src/pages/App.jsx @@ -1,7 +1,7 @@ -import React, { useState } from "react"; -import { SidebarPresenter } from "../presenters/SidebarPresenter.jsx"; -import { SearchbarPresenter } from "../presenters/SearchbarPresenter.jsx"; -import { ListViewPresenter } from "../presenters/ListViewPresenter.jsx"; +import React, { useState, useEffect } from 'react'; +import { SidebarPresenter } from '../presenters/SidebarPresenter.jsx'; +import { SearchbarPresenter } from '../presenters/SearchbarPresenter.jsx'; +import { ListViewPresenter } from '../presenters/ListViewPresenter.jsx'; import { FilterPresenter } from "../presenters/FilterPresenter.jsx"; import { slide as Menu } from "react-burger-menu"; @@ -15,6 +15,18 @@ import { slide as Menu } from "react-burger-menu"; function App({ model }) { const [sidebarIsOpen, setSidebarIsOpen] = useState(model.sidebarIsOpen); + useEffect(() => { + const clearStorageOnUnload = () => { + localStorage.clear(); + }; + + window.addEventListener("unload", clearStorageOnUnload); + + return () => { + window.removeEventListener("unload", clearStorageOnUnload); + }; + }, []); + return ( /* The sidebar styling(under the menu)*/
diff --git a/my-app/src/presenters/SidebarPresenter.jsx b/my-app/src/presenters/SidebarPresenter.jsx index c62615a..1d7691f 100644 --- a/my-app/src/presenters/SidebarPresenter.jsx +++ b/my-app/src/presenters/SidebarPresenter.jsx @@ -3,22 +3,16 @@ import { observer } from "mobx-react-lite"; import SidebarView from "../views/SidebarView.jsx"; import transcriptScraperFunction from "./UploadTranscriptPresenter.jsx"; import { useState } from "react"; +import { use } from 'react'; const SidebarPresenter = observer(({ model }) => { - - let currentLanguageSet = model.filterOptions.language; - let currentLevelSet = model.filterOptions.level; - let currentPeriodSet = model.filterOptions.period; - let currentDepartmentSet = model.filterOptions.department; - let currentLocationSet = model.filterOptions.location; - - useEffect(() => { model.setFiltersChange(); },[model]); function handleLanguageFilterChange(param) { + let currentLanguageSet = model.filterOptions.language; if (param === "English") { switch (currentLanguageSet) { case "none": @@ -57,7 +51,9 @@ const SidebarPresenter = observer(({ model }) => { model.updateLanguageFilter(currentLanguageSet); } function handleLevelFilterChange(param) { - + + let currentLevelSet = model.filterOptions.level; + if (!currentLevelSet.includes(param)) { currentLevelSet.push(param); } else { @@ -70,6 +66,9 @@ const SidebarPresenter = observer(({ model }) => { } function handleDepartmentFilterChange(param) { + + let currentDepartmentSet = model.filterOptions.department; + if (currentDepartmentSet.includes(param)) { const index = currentDepartmentSet.indexOf(param); if (index > -1) { @@ -83,12 +82,18 @@ const SidebarPresenter = observer(({ model }) => { } function handlePeriodFilterChange(param) { + + let currentPeriodSet = model.filterOptions.period; + currentPeriodSet[param] = !currentPeriodSet[param]; model.updatePeriodFilter(currentPeriodSet); model.setFiltersChange(); } function handleLocationFilterChange(param) { + + let currentLocationSet = model.filterOptions.location; + if (currentLocationSet.includes(param)) { const index = currentLocationSet.indexOf(param); if (index > -1) { @@ -226,6 +231,11 @@ const SidebarPresenter = observer(({ model }) => { }; + + const [initialSliderValues, setInitialSliderValues] = useState([0.5,45]); + useEffect(()=>{ + setInitialSliderValues([model.filterOptions.creditMin, model.filterOptions.creditMax]); + }, []) //========================================================== return ( @@ -237,20 +247,20 @@ const SidebarPresenter = observer(({ model }) => { initialApplyTranscriptFilter={model.filterOptions.applyTranscriptFilter} initialTranscriptElegiblityValue={model.filterOptions.eligibility} - initialLanguageFilterOptions={currentLanguageSet} + initialLanguageFilterOptions={model.filterOptions.language} initialLanguageFilterEnable={model.filterOptions.applyLanguageFilter} - initialLevelFilterOptions={currentLevelSet} + initialLevelFilterOptions={model.filterOptions.level} initialLevelFilterEnable={model.filterOptions.applyLevelFilter} - initialPeriodFilterOptions={currentPeriodSet} + initialPeriodFilterOptions={model.filterOptions.period} initialPeriodFilterEnable={model.filterOptions.applyPeriodFilter} - initialDepartmentFilterOptions={formatDepartmentSet(currentDepartmentSet.filter(item => item !== "undefined/undefined"))} + initialDepartmentFilterOptions={formatDepartmentSet(model.filterOptions.department.filter(item => item !== "undefined/undefined"))} initialDepartmentFilterEnable={model.filterOptions.applyDepartmentFilter} DepartmentFilterField = {model.formatDepartments()} - initialLocationFilterOptions={currentLocationSet} + initialLocationFilterOptions={model.filterOptions.location} initialLocationFilterEnable={model.filterOptions.applyLocationFilter} LocationFilterField = {model.locations} diff --git a/my-app/src/views/Components/SideBarComponents/ResetButtonField.jsx b/my-app/src/views/Components/SideBarComponents/ResetButtonField.jsx new file mode 100644 index 0000000..f157ed9 --- /dev/null +++ b/my-app/src/views/Components/SideBarComponents/ResetButtonField.jsx @@ -0,0 +1,24 @@ +import { useState } from "react"; +import { useRef, useEffect } from "react"; +import FilterEnableCheckbox from "./FilterEnableCheckbox"; +import Tooltip from "./ToolTip"; + +export default function DropDownField(props) { + + const resetFiltersFunction = () => { + console.log("meow."); + }; + + return( +
+ +
+ ); + + +} \ No newline at end of file diff --git a/my-app/src/views/Components/SideBarComponents/SliderField.jsx b/my-app/src/views/Components/SideBarComponents/SliderField.jsx index 82ccd65..d929550 100644 --- a/my-app/src/views/Components/SideBarComponents/SliderField.jsx +++ b/my-app/src/views/Components/SideBarComponents/SliderField.jsx @@ -1,6 +1,7 @@ -import React, { useState, useRef, useEffect, useMemo } from "react"; +import React, { useState, useRef, useEffect, useMemo, useCallback } from "react"; import FilterEnableCheckbox from "./FilterEnableCheckbox"; import Tooltip from "./ToolTip"; +import Slider from '@mui/material/Slider'; /** @@ -11,20 +12,33 @@ import Tooltip from "./ToolTip"; export default function UploadField(props) { let paramFieldType = "slider"; - const values = useMemo(() => [ - 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, + 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 7, 7.5, 8, 8.5, 9, 10, 11, 12, 13.5, 14, 15, 20, 22.5, 30, 45 ], []); + const [value, setValue] = useState([0,values.length-1]); + const [minIndex, setMinIndex] = useState(0); const [maxIndex, setMaxIndex] = useState(values.length - 1); const [filterEnabled, setFilterEnabled] = useState(props.filterEnable); const sliderRef = useRef(null); const checkboxRef = useRef(null); - useEffect(() => { + const [isChanging, setChanging] = useState(false); + + useEffect(()=>{ + + if (!isChanging && props.initialValues && props.initialValues[0] != 0) { + console.log(props.initialValues); + setValue([values.indexOf(values.find((c) => c == props.initialValues[0])), values.indexOf(values.find((c) => c == props.initialValues[1]))]); + setChanging(true); + } + }, [props.initialValues, isChanging]) + + /* useState(() => { + setValue(props.initialValues); for (let i = 0; i < values.length; i++) { if (values[i] === props?.initialValues[0]) { setMinIndex(i); @@ -33,9 +47,22 @@ export default function UploadField(props) { setMaxIndex(i); } } - }, [props?.initialValues, values]); // Empty dependency array ensures this runs only once + + }, [props.initialValues]); // Empty dependency array ensures this runs only once*/ + const handleChange = (event, newValue) => { + setValue(newValue); + const [min, max] = [...newValue]; + setMinIndex(min); + setMaxIndex(max); + }; + + const handleCommit = (event, newValue) => { + const [minIndex, maxIndex] = newValue; + props.HandleFilterChange([paramFieldType, props.filterName, [values[minIndex], values[maxIndex]]]); + }; + const handleDrag = (e, thumbType) => { const slider = sliderRef.current; @@ -86,83 +113,42 @@ export default function UploadField(props) { }}>
- Credits: {values[minIndex]} – {values[maxIndex]} + Credits: {(values[minIndex]==props.initialValues[0]) ? values[minIndex] : props.initialValues[0]} – {(values[maxIndex]==props.initialValues[1]) ? values[maxIndex] : props.initialValues[1]}
{/* SLIDER */} -
handleDrag(e, "bar")} - onTouchStart={(e) => handleDrag(e, "bar")} - > - {/* Selected range bar */} -
- - {/* Min thumb */} -
{ - e.stopPropagation(); - const move = (ev) => handleDrag(ev, "min"); - const up = () => { - window.removeEventListener("mousemove", move); - window.removeEventListener("mouseup", up); - //props.HandleFilterChange([paramFieldType, props.filterName, [values[minIndex], values[maxIndex]]]); - }; - window.addEventListener("mousemove", move); - window.addEventListener("mouseup", up); - }} - onTouchStart={() => { - const move = (ev) => handleDrag(ev, "min"); - const end = () => { - window.removeEventListener("touchmove", move); - window.removeEventListener("touchend", end); - //props.HandleFilterChange([paramFieldType, props.filterName, [values[minIndex], values[maxIndex]]]); - }; - window.addEventListener("touchmove", move); - window.addEventListener("touchend", end); - }} - onMouseUp={() => props.HandleFilterChange([paramFieldType, props.filterName, [values[minIndex], values[maxIndex]]])} - className="absolute top-1/2 -translate-y-1/2 bg-violet-600 h-4 w-4 rounded-full z-20" - style={{ - left: `calc(${(minIndex / (values.length - 1)) * 100}% - 8px)` - }} - /> - - {/* Max thumb */} -
{ - e.stopPropagation(); - const move = (ev) => handleDrag(ev, "max"); - const up = () => { - window.removeEventListener("mousemove", move); - window.removeEventListener("mouseup", up); - }; - window.addEventListener("mousemove", move); - window.addEventListener("mouseup", up); - }} - onTouchStart={() => { - const move = (ev) => handleDrag(ev, "max"); - const end = () => { - window.removeEventListener("touchmove", move); - window.removeEventListener("touchend", end); - }; - window.addEventListener("touchmove", move); - window.addEventListener("touchend", end); - }} - onMouseUp={() => props.HandleFilterChange([paramFieldType, props.filterName, [values[minIndex], values[maxIndex]]])} - className="absolute top-1/2 -translate-y-1/2 bg-violet-600 h-4 w-4 rounded-full z-20" - style={{ - left: `calc(${(maxIndex / (values.length - 1)) * 100}% - 8px)` - }} - /> -
+ 'Temperature range'} + value={value} + min={0} + max={values.length - 1} + onChange={handleChange} + onChangeCommitted={handleCommit} + + marks={values.slice(0, 45 + 1).map((_, idx) => ({ value: idx }))} + step={1} + + + sx={{ + boxSizing: 'border-box', + width: '100%', + color: '#8e51ff', + height: 8, + '& .MuiSlider-thumb': { + width: 20, + height: 20, + backgroundColor: '#8e51ff', + }, + '& .MuiSlider-track': { + border: 'none', + }, + '& .MuiSlider-rail': { + opacity: 0.3, + backgroundColor: '#8e51ff', + }, + }} + />
diff --git a/my-app/src/views/Components/SideBarComponents/ToggleField.jsx b/my-app/src/views/Components/SideBarComponents/ToggleField.jsx index 78709a0..1c0e19a 100644 --- a/my-app/src/views/Components/SideBarComponents/ToggleField.jsx +++ b/my-app/src/views/Components/SideBarComponents/ToggleField.jsx @@ -12,9 +12,9 @@ export default function ToggleField(props) { let paramFieldType = "toggle"; const [filterEnabled, setFilterEnabled] = useState(props.filterEnable); - // eslint-disable-next-line no-unused-vars - const [prop1Set, setprop1Set] = useState((props.initialValues=="both") || (props.initialValues==String(props.fields[0]).charAt(0).toLowerCase() + String(props.fields[0]).slice(1))); - // eslint-disable-next-line no-unused-vars + //eslint-disable-next-line @typescript-eslint/no-unused-vars + const [prop1Set, setprop1Set] = useState((props.initialValues == "both") || (props.initialValues == String(props.fields[0]).charAt(0).toLowerCase() + String(props.fields[0]).slice(1))); + //eslint-disable-next-line @typescript-eslint/no-unused-vars const [prop2Set, setprop2Set] = useState((props.initialValues=="both") || (props.initialValues==String(props.fields[1]).charAt(0).toLowerCase() + String(props.fields[1]).slice(1))); const checkboxRef = useRef(null); diff --git a/my-app/src/views/Components/SideBarComponents/UploadField.jsx b/my-app/src/views/Components/SideBarComponents/UploadField.jsx index ee91630..0c74c82 100644 --- a/my-app/src/views/Components/SideBarComponents/UploadField.jsx +++ b/my-app/src/views/Components/SideBarComponents/UploadField.jsx @@ -15,7 +15,7 @@ export default function UploadField(props) { const [isDragging, setIsDragging] = useState(false); const [filterEnabled, setFilterEnabled] = useState(props.filterEnable); - const [fileUploaded, setfileUploaded] = useState(false); + const [fileUploaded, setfileUploaded] = useState(localStorage.getItem("completedCourses")); const checkboxRef = useRef(null); diff --git a/my-app/src/views/ListView.jsx b/my-app/src/views/ListView.jsx index 33a1868..b5b2337 100644 --- a/my-app/src/views/ListView.jsx +++ b/my-app/src/views/ListView.jsx @@ -111,7 +111,7 @@ function ListView(props) {
) : ( -
+

Found diff --git a/my-app/src/views/SidebarView.jsx b/my-app/src/views/SidebarView.jsx index 39a85ee..0b679e0 100644 --- a/my-app/src/views/SidebarView.jsx +++ b/my-app/src/views/SidebarView.jsx @@ -6,6 +6,7 @@ import CollapsibleCheckboxes from './Components/SideBarComponents/CollapsibleChe import Tooltip from './Components/SideBarComponents/ToolTip.jsx'; import UploadField from './Components/SideBarComponents/UploadField'; import MultipleChoiceButtons from './Components/SideBarComponents/MultipleChoiceButtons.jsx'; +import ResetButtonField from "./Components/SideBarComponents/ResetButtonField.jsx"; /** @@ -46,6 +47,9 @@ function SidebarView(props) { initialValue={props.initialTranscriptElegiblityValue} />

+ {/**/}
- + +
- +
-
);