From a416f8a83427050d29fff211e00d32414c9e063d Mon Sep 17 00:00:00 2001 From: a-thansen <102360418+a-thansen@users.noreply.github.com> Date: Sun, 5 Nov 2023 13:22:30 +0100 Subject: [PATCH] MultiSelector (Condition Type Filter) --- frontend/package-lock.json | 426 ++++++++++-------- frontend/package.json | 12 +- .../Components/Conditions/ConditionsMap.tsx | 19 +- .../src/Components/Map/Inputs/MonthFilter.tsx | 4 + .../Components/Map/Inputs/MultiSelector.tsx | 50 ++ frontend/src/Components/Map/Inputs/Search.tsx | 42 +- frontend/src/css/multiselector.css | 31 ++ frontend/src/models/conditions.ts | 27 ++ frontend/src/pages/Main.tsx | 76 +++- 9 files changed, 437 insertions(+), 250 deletions(-) create mode 100644 frontend/src/Components/Map/Inputs/MultiSelector.tsx create mode 100644 frontend/src/css/multiselector.css diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8026e705..2efb13c8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,9 +15,7 @@ "chartjs-plugin-zoom": "^2.0.1", "d3": "^7.8.5", "leaflet": "^1.9.4", - "multiselect-react-dropdown": "^2.0.25", "react": "^18.2.0", - "react-burger-menu": "^3.0.9", "react-chartjs-2": "^5.2.0", "react-datepicker": "^4.19.0", "react-dom": "^18.2.0", @@ -26,6 +24,7 @@ "react-leaflet-hotline": "^1.4.12", "react-router-dom": "^6.16.0", "react-scripts": "^5.0.1", + "react-select": "^5.7.7", "react-slider": "^2.0.6", "react-split": "^2.0.14", "typescript": "^4.9.5", @@ -42,7 +41,6 @@ "@types/leaflet": "^1.9.4", "@types/node": "^20.6.2", "@types/react": "^18.2.21", - "@types/react-burger-menu": "^2.8.5", "@types/react-datepicker": "^4.15.1", "@types/react-dom": "^18.2.7", "@types/react-router-dom": "^5.3.3", @@ -2329,6 +2327,128 @@ "postcss-selector-parser": "^6.0.10" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", + "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/serialize": "^1.1.2", + "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/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", + "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + }, + "node_modules/@emotion/react": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", + "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", + "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "dependencies": { + "@emotion/hash": "^0.9.1", + "@emotion/memoize": "^0.8.1", + "@emotion/unitless": "^0.8.1", + "@emotion/utils": "^1.2.1", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", + "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -2422,6 +2542,28 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", + "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", + "dependencies": { + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", + "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", + "dependencies": { + "@floating-ui/core": "^1.4.2", + "@floating-ui/utils": "^0.1.3" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", + "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" + }, "node_modules/@geoapify/geocoder-autocomplete": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@geoapify/geocoder-autocomplete/-/geocoder-autocomplete-1.5.1.tgz", @@ -4126,8 +4268,7 @@ "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/q": { "version": "1.5.6", @@ -4148,22 +4289,12 @@ "version": "18.2.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", - "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, - "node_modules/@types/react-burger-menu": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/@types/react-burger-menu/-/react-burger-menu-2.8.5.tgz", - "integrity": "sha512-2VCnDyg4JGzaTByh17qwu2rVnjylF+L5Lzw9CwiiDmcYBMlW9XE8+q0ZChV+9qiBW6SNjBiz/KH+bOyv28THAQ==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-datepicker": { "version": "4.15.1", "resolved": "https://registry.npmjs.org/@types/react-datepicker/-/react-datepicker-4.15.1.tgz", @@ -4224,6 +4355,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.8.tgz", + "integrity": "sha512-QmQ22q+Pb+HQSn04NL3HtrqHwYMf4h3QKArOy5F8U5nEVMaihBs3SR10WiOM1iwPz5jIo8x/u11al+iEGZZrvg==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4240,8 +4379,7 @@ "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, "node_modules/@types/semver": { "version": "7.5.1", @@ -5057,15 +5195,6 @@ "ajv": "^6.9.1" } }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "optional": true, - "engines": { - "node": ">=0.4.2" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -5316,76 +5445,6 @@ "util": "0.10.3" } }, - "node_modules/ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha512-e/JfLiSoakfmL4wmTGPjv0HpTICVmxwXgYOB8x+mzozHL8v+dSfCbrJ8J8hJ0YBP0XcYu1aLZ6b/3TnxNK3P2A==", - "dependencies": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" - } - }, - "node_modules/ast-transform/node_modules/escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha512-yLy3Cc+zAC0WSmoT2fig3J87TpQ8UaZGx8ahCAs9FL8qNbyV7CVyPKS74DG4bsHiL5ew9sxdYx131OkBQMFnvA==", - "dependencies": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "optionalDependencies": { - "source-map": "~0.1.30" - } - }, - "node_modules/ast-transform/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ast-transform/node_modules/estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ast-transform/node_modules/esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ast-transform/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", - "optional": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/ast-types": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", @@ -5967,37 +6026,6 @@ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" }, - "node_modules/browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dependencies": { - "resolve": "1.1.7" - } - }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==" - }, - "node_modules/browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha512-VrhjbZ+Ba5mDiSYEuPelekQMfTbhcA2DhLk2VQWqdcCROWeFqlTcXZ7yfRkXCIl8E+g4gINJYJiRB7WEtfomAQ==", - "dependencies": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" - } - }, - "node_modules/browserify-optional/node_modules/ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha512-RIOpVnVlltB6PcBJ5BMLx+H+6JJ/zjDGU0t7f0L6c2M1dqcK92VQopLBlPQ9R80AVXelfqYgjcPLtHtDbNFg0Q==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/browserslist": { "version": "4.21.10", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", @@ -7369,8 +7397,7 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/d3": { "version": "7.8.5", @@ -8266,6 +8293,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -9434,11 +9470,6 @@ "node": ">= 0.6" } }, - "node_modules/eve": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/eve/-/eve-0.5.4.tgz", - "integrity": "sha512-aqprQ9MAOh1t66PrHxDFmMXPlgNO6Uv1uqvxmwjprQV50jaQ2RqO7O1neY4PJwC+hMnkyMDphu2AQPOPZdjQog==" - }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -9890,6 +9921,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -10596,6 +10632,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -13675,6 +13724,11 @@ "node": ">= 4.0.0" } }, + "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/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -13945,14 +13999,6 @@ "multicast-dns": "cli.js" } }, - "node_modules/multiselect-react-dropdown": { - "version": "2.0.25", - "resolved": "https://registry.npmjs.org/multiselect-react-dropdown/-/multiselect-react-dropdown-2.0.25.tgz", - "integrity": "sha512-z8kUSyBNOuV7vn4Dk35snzXWtIfTdSEEXhgDdLMvOmR+xJFx35vc1voUlSuOvrk3khb+hXC219Qs9szOvNm25Q==", - "peerDependencies": { - "react": "^16.7.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -16299,25 +16345,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, - "node_modules/react-burger-menu": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/react-burger-menu/-/react-burger-menu-3.0.9.tgz", - "integrity": "sha512-Qy15hkCxwxNEKfqdAv43F+8ZSl+/c6KkqrBwGP0CesFYJ02onHtiUFUbuhSWCMtBH8/n0HhfekFlp/NyCdKYzQ==", - "dependencies": { - "browserify-optional": "^1.0.0", - "classnames": "^2.2.6", - "eve": "~0.5.1", - "prop-types": "^15.7.2", - "snapsvg-cjs": "0.0.6" - }, - "engines": { - "node": ">=4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0", - "react-dom": ">=0.14.0" - } - }, "node_modules/react-chartjs-2": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", @@ -17778,6 +17805,26 @@ "node": ">= 8" } }, + "node_modules/react-select": { + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.7.tgz", + "integrity": "sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-simple-code-editor": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/react-simple-code-editor/-/react-simple-code-editor-0.13.1.tgz", @@ -18037,6 +18084,21 @@ "node": ">= 0.8.0" } }, + "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/reactcss": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", @@ -18973,25 +19035,6 @@ "node": ">=8" } }, - "node_modules/snapsvg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/snapsvg/-/snapsvg-0.5.1.tgz", - "integrity": "sha512-CjwWYsL7+CCk1vCk9BBKGYS4WJVDfJAOMWU+Zhzf8wf6pAm/xT34wnpaMPAgcgCNkxuU6OkQPPd8wGuRCY9aNw==", - "dependencies": { - "eve": "~0.5.1" - } - }, - "node_modules/snapsvg-cjs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/snapsvg-cjs/-/snapsvg-cjs-0.0.6.tgz", - "integrity": "sha512-7NNvoGrc3BQvWz5rWK1DsD5/Vni4STswz5B3JrBADboQWcN8OBVGjYVJFPT5JkUXb2iVnEflZANhufEpEcTHXw==", - "dependencies": { - "snapsvg": "0.5.1" - }, - "peerDependencies": { - "eve": "~0.5.1" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -19373,6 +19416,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.34.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", @@ -19772,11 +19820,6 @@ "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -20434,6 +20477,19 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index fdb7386a..6287bdc0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,11 +19,11 @@ "react-leaflet-hotline": "^1.4.12", "react-router-dom": "^6.16.0", "react-scripts": "^5.0.1", + "react-select": "^5.7.7", "react-slider": "^2.0.6", "react-split": "^2.0.14", "typescript": "^4.9.5", - "web-vitals": "^3.4.0", - "chartjs-plugin-zoom": "^2.0.1" + "web-vitals": "^3.4.0" }, "scripts": { "start": "react-scripts start", @@ -53,6 +53,7 @@ }, "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@babel/traverse": ">=7.23.2", "@testing-library/jest-dom": "^6.1.3", "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.5.1", @@ -70,14 +71,13 @@ "eslint": "^8.49.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", + "nth-check": ">=2.0.1", + "postcss": ">=8.4.31", "prettier": "^3.0.3", "react-docgen-typescript": "^2.2.2", "react-styleguidist": "^13.1.1", "ts-loader": "^9.4.4", - "webpack": "^5.88.2", - "@babel/traverse": ">=7.23.2", - "nth-check": ">=2.0.1", - "postcss": ">=8.4.31" + "webpack": "^5.88.2" }, "jest": { "moduleNameMapper": { diff --git a/frontend/src/Components/Conditions/ConditionsMap.tsx b/frontend/src/Components/Conditions/ConditionsMap.tsx index 0f450700..cb6ff8c5 100644 --- a/frontend/src/Components/Conditions/ConditionsMap.tsx +++ b/frontend/src/Components/Conditions/ConditionsMap.tsx @@ -13,6 +13,7 @@ import { KPI, Mu, YearMonth, + MultiMode, } from '../../models/conditions'; import { getAllConditions } from '../../queries/conditions'; @@ -102,8 +103,8 @@ const getConditionColor = (properties: GeoJSON.GeoJsonProperties): string => { interface ConditionsMapProps { /** The children of the component **/ children: React.ReactNode; - /** The mode of the conditions to show **/ - mode: string; + /** The mode of the conditions to show (allows for multimodes)**/ + multiMode: MultiMode; /** The range of date to use to filter the conditions **/ rangeSelected: DateRange; } @@ -113,7 +114,7 @@ interface ConditionsMapProps { */ const ConditionsMap: FC = ({ children, - mode, + multiMode, rangeSelected, }) => { const geoJsonRef = useRef(); @@ -166,13 +167,14 @@ const ConditionsMap: FC = ({ geoJsonRef.current.addData(data); }; - // filter the data + // Filters the data + // multiMode functionality added by @author Hansen const featureCollection: FeatureCollection = { type: 'FeatureCollection', features: dataAll.features.filter( (f) => f.properties !== null && - (mode === 'ALL' || f.properties.type === mode) && + (multiMode.ALL! || multiMode.mode.includes(f.properties.type)) && (f.properties.valid_yearmonth === undefined || ((rangeSelected.start === undefined || lessOrEqualThan( @@ -187,7 +189,7 @@ const ConditionsMap: FC = ({ ), }; setConditions(featureCollection); - }, [dataAll, mode, rangeAll, rangeSelected]); + }, [dataAll, multiMode, rangeAll, rangeSelected]); return ( @@ -214,7 +216,7 @@ const ConditionsMap: FC = ({ feature.properties.type !== undefined ) { // When in mode 'ALL' show dashline using a color for each type - if (mode === 'ALL') { + if (multiMode.mode.includes(feature.properties.type)) { mapStyle.color = getTypeColor(feature.properties.type); mapStyle.opacity = 0.5; switch (feature.properties.type) { @@ -235,8 +237,9 @@ const ConditionsMap: FC = ({ mapStyle.dashArray = '22 22'; } } else if (feature.properties.value !== undefined) { - // otherwise use a specific color gradient for each type mapStyle.color = getConditionColor(feature.properties); + } else if (multiMode.count === 0) { + mapStyle.color = getTypeColor('default'); // @author Hansen } } diff --git a/frontend/src/Components/Map/Inputs/MonthFilter.tsx b/frontend/src/Components/Map/Inputs/MonthFilter.tsx index 31e48fc6..92dabb39 100644 --- a/frontend/src/Components/Map/Inputs/MonthFilter.tsx +++ b/frontend/src/Components/Map/Inputs/MonthFilter.tsx @@ -15,6 +15,8 @@ interface CustomInputProps { * * A class component is used to remove the following warning: * Function components cannot be given refs. Attempts to access this ref will fail. + * + * @author Hansen */ class CustomInput extends React.Component { constructor(props: CustomInputProps) { @@ -38,6 +40,8 @@ interface MonthFilterProps { /** * Component rendering Month Filter + * + * @author Hansen */ const MonthFilter: React.FC = ({ onEndChange, diff --git a/frontend/src/Components/Map/Inputs/MultiSelector.tsx b/frontend/src/Components/Map/Inputs/MultiSelector.tsx new file mode 100644 index 00000000..e768dd42 --- /dev/null +++ b/frontend/src/Components/Map/Inputs/MultiSelector.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import Select from 'react-select'; + +import '../../../css/multiselector.css'; +import { MultiSelectOptions } from '../../../models/conditions'; + +interface MultiSelectProps { + /** The function to call when an option is selected */ + handleSelectionChange: (value: any) => void; + /** The options to show in the dropdown menu */ + options: any; + /** The text to show in the selector */ + placeholder: string; + /** The children for the MultiSelector */ + children?: React.ReactNode; +} + +/** + * MultiSelector is a component that is a dropdown list + * that allows for multiple selection + * + * @author Hansen + */ + +const MultiSelector: React.FC = ({ + handleSelectionChange, + children, + options, + placeholder, +}) => { + return ( +
+ <> + + {children} + +
+ ); +}; + +export default MultiSelector; diff --git a/frontend/src/Components/Map/Inputs/Search.tsx b/frontend/src/Components/Map/Inputs/Search.tsx index d9dfdcb9..dc35237c 100644 --- a/frontend/src/Components/Map/Inputs/Search.tsx +++ b/frontend/src/Components/Map/Inputs/Search.tsx @@ -18,6 +18,8 @@ interface Props { /** * Component rendering Search bar + * + * @author Hansen */ const Search: React.FC = ({ onPlaceSelect }) => { @@ -25,50 +27,12 @@ const Search: React.FC = ({ onPlaceSelect }) => { console.log(value); } - // function preprocessHook(value: any) { - // return `${value}, Munich, Germany`; - // } - - // function postprocessHook(feature: any) { - // return feature.properties.street; - // } - - // function suggestionsFilter(suggestions: any) { - // const processedStreets: any[] = []; - - // const filtered = suggestions.filter((value: any) => { - // if ( - // !value.properties.street || - // processedStreets.indexOf(value.properties.street) >= 0 - // ) { - // return false; - // } else { - // processedStreets.push(value.properties.street); - // return true; - // } - // }); - - // return filtered; - // } - return ( diff --git a/frontend/src/css/multiselector.css b/frontend/src/css/multiselector.css new file mode 100644 index 00000000..ed208882 --- /dev/null +++ b/frontend/src/css/multiselector.css @@ -0,0 +1,31 @@ +.select__menu { + background-color: #dddddd9b !important; +} + +.react-select-container { + background-color: transparent; +} + +.react-select__control { + font-size: small; +} + +.select__placeholder { + font-size: 14px; +} + +.react-select__indicators { + color: black; + font-size: 12px; +} + +.select__menu-list { + background-color: #dddddd9b; + color: var(--background); + font-size: 12px; +} +.select__option { + background-color: black; + color: black; + font-size: 12px; +} diff --git a/frontend/src/models/conditions.ts b/frontend/src/models/conditions.ts index 712e1094..f53d05f9 100644 --- a/frontend/src/models/conditions.ts +++ b/frontend/src/models/conditions.ts @@ -15,6 +15,33 @@ export const conditionTypes = [ Enrg, ]; +// Options for condition indicator multiselect + +export const MultiSelectOptions = [ + { value: 'ALL', label: 'ALL' }, + { value: 'KPI', label: 'KPI' }, + { value: 'DI', label: 'DI' }, + { value: 'IRI', label: 'IRI' }, + { value: 'Mu', label: 'Mu' }, + { value: 'E_norm', label: 'E_norm' }, +]; + +// MultiMode manager + +export interface MultiMode { + count?: number; + mode?: any; + ALL?: boolean; +} + +// MultiMode manager default + +export const DefaultMode: MultiMode = { + count: 5, + mode: ['KPI', 'DI', 'IRI', 'Mu', 'E_norm'], + ALL: true, +}; + export interface YearMonth { year: number; month: number; diff --git a/frontend/src/pages/Main.tsx b/frontend/src/pages/Main.tsx index 70425291..c9243f6d 100644 --- a/frontend/src/pages/Main.tsx +++ b/frontend/src/pages/Main.tsx @@ -7,9 +7,16 @@ import ConditionsMap from '../Components/Conditions/ConditionsMap'; import Search from '../Components/Map/Inputs/Search'; import ForceMapUpdate from '../Components/Map/ForceMapUpdate'; import Roads from '../Components/Map/Roads'; -import { conditionTypes, DateRange, YearMonth } from '../models/conditions'; +import { + MultiSelectOptions, + DateRange, + YearMonth, + MultiMode, + DefaultMode, +} from '../models/conditions'; import MonthFilter from '../Components/Map/Inputs/MonthFilter'; import Selector from '../Components/Map/Inputs/Selector'; +import MultiSelector from '../Components/Map/Inputs/MultiSelector'; import '../css/navbar.css'; /** @@ -20,20 +27,66 @@ const Main: FC = () => { const [roads, setRoads] = useState(); // The position to move too (used by the Search component) const [moveToPosition, setMoveToPosition] = useState(); - // The indicator to display on the map - const [mode, setMode] = useState('ALL'); + // The indicator(s) to display on the map + const [multiMode, setMultiMode] = useState(DefaultMode); // The selected range of date (used to filter the data to show) const [rangeSelected, setRangeSelected] = useState({}); + /** + * Function multiModeSet for setting the mode + * to filter data on the map. + * + * @param selected, the object returned from the MultiSelector + * + * @author Hansen + */ + + function multiModeSet(selected: any) { + const selectedOptions: any = selected; + + const outputMode: MultiMode = { + count: selectedOptions.length + 0, + mode: selectedOptions + .map((e: any) => e.label) + .toString() + .split(','), + ALL: selectedOptions.some((e: any) => e.value === 'ALL'), + }; + + if (outputMode.count === 0) { + outputMode.mode = [' ']; + outputMode.ALL = false; + } else if (outputMode.ALL) { + outputMode.mode = ['KPI', 'DI', 'IRI', 'Mu', 'E_norm']; + outputMode.count = outputMode.mode.length; + } + setMultiMode(outputMode); + } + + /** + * + * @param date , returned from MonthFilter + * @returns date in YearMonth format + * + * @author Hansen + */ + function dateChange(date: any) { const YearMonth: YearMonth = { year: date.getFullYear(), - month: date.getMonth() + 1, // +1 why + month: date.getMonth() + 1, }; return YearMonth; } + /** + * + * @param d , the date in YearMonth format + * @param start , boolean specifying if the start point (true) or end point (false) of the range should be set. + * + */ + const rangeChange = (d: YearMonth, start: boolean) => { setRangeSelected((old) => { if (start) { @@ -69,14 +122,13 @@ const Main: FC = () => { />
- { - setMode(name); + { + multiModeSet(value); }} - defaultValue={'ALL'} - label={'Condition Type'} - /> + >
{

Start Date → End Date

- +