From bfbaec8ed2193f9f64e254e6d94517ab09fb6762 Mon Sep 17 00:00:00 2001 From: Dipit Vasdev Date: Wed, 4 Dec 2024 20:52:19 -0800 Subject: [PATCH 1/2] 1651 filtering sorting dro admin (#1990) * Working on it * Adding filtering and sorting to Admin Notes and DRO(testing to be done) * Merged fix to 1651 with develop --------- Co-authored-by: John Darragh --- client/package-lock.json | 340 +++++++----------- .../ProjectTableColumnHeader.jsx | 32 +- .../Projects/ColumnHeaderPopups/TextPopup.jsx | 59 ++- .../src/components/Projects/FilterDrawer.jsx | 42 ++- .../components/Projects/ProjectTableRow.jsx | 18 +- .../src/components/Projects/ProjectsPage.jsx | 169 +++++---- 6 files changed, 340 insertions(+), 320 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 61a1e44f..34577383 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -83,6 +83,7 @@ }, "node_modules/@ampproject/remapping": { "version": "2.2.1", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", @@ -178,6 +179,7 @@ }, "node_modules/@babel/compat-data": { "version": "7.23.2", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -185,6 +187,7 @@ }, "node_modules/@babel/core": { "version": "7.23.2", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -213,6 +216,7 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -253,6 +257,7 @@ }, "node_modules/@babel/generator": { "version": "7.23.0", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.23.0", @@ -287,6 +292,7 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.22.15", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.22.9", @@ -301,6 +307,7 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -409,6 +416,7 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.22.5", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -439,6 +447,7 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.23.0", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -504,6 +513,7 @@ }, "node_modules/@babel/helper-simple-access": { "version": "7.22.5", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" @@ -548,6 +558,7 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.22.15", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -568,6 +579,7 @@ }, "node_modules/@babel/helpers": { "version": "7.23.2", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", @@ -2132,6 +2144,7 @@ }, "node_modules/@babel/traverse": { "version": "7.23.2", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.22.13", @@ -2913,6 +2926,7 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -2925,6 +2939,7 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2932,6 +2947,7 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2948,10 +2964,12 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.20", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -5109,53 +5127,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" - } - }, - "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "peer": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-macros/node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "peer": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/babel-plugin-named-asset-import": { "version": "0.3.8", "dev": true, @@ -5507,6 +5478,7 @@ }, "node_modules/browserslist": { "version": "4.22.1", + "dev": true, "funding": [ { "type": "opencollective", @@ -5648,6 +5620,7 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001561", + "dev": true, "funding": [ { "type": "opencollective", @@ -6067,6 +6040,7 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -7161,6 +7135,7 @@ }, "node_modules/electron-to-chromium": { "version": "1.4.578", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -7381,6 +7356,7 @@ }, "node_modules/escalade": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8779,6 +8755,7 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8922,6 +8899,7 @@ }, "node_modules/globals": { "version": "11.12.0", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -11092,6 +11070,7 @@ }, "node_modules/jsesc": { "version": "2.5.2", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -11130,6 +11109,7 @@ }, "node_modules/json5": { "version": "2.2.3", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -11867,6 +11847,7 @@ }, "node_modules/lru-cache": { "version": "5.1.1", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -12252,6 +12233,7 @@ }, "node_modules/node-releases": { "version": "2.0.13", + "dev": true, "license": "MIT" }, "node_modules/normalize-path": { @@ -12701,6 +12683,7 @@ }, "node_modules/picocolors": { "version": "1.0.0", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -18368,20 +18351,6 @@ "is-typedarray": "^1.0.0" } }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/unbox-primitive": { "version": "1.0.2", "dev": true, @@ -18515,6 +18484,7 @@ }, "node_modules/update-browserslist-db": { "version": "1.0.13", + "dev": true, "funding": [ { "type": "opencollective", @@ -19465,6 +19435,7 @@ }, "node_modules/yallist": { "version": "3.1.1", + "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -19523,6 +19494,7 @@ }, "@ampproject/remapping": { "version": "2.2.1", + "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -19582,10 +19554,12 @@ } }, "@babel/compat-data": { - "version": "7.23.2" + "version": "7.23.2", + "dev": true }, "@babel/core": { "version": "7.23.2", + "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", @@ -19605,7 +19579,8 @@ }, "dependencies": { "semver": { - "version": "6.3.1" + "version": "6.3.1", + "dev": true } } }, @@ -19630,6 +19605,7 @@ }, "@babel/generator": { "version": "7.23.0", + "dev": true, "requires": { "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", @@ -19652,6 +19628,7 @@ }, "@babel/helper-compilation-targets": { "version": "7.22.15", + "dev": true, "requires": { "@babel/compat-data": "^7.22.9", "@babel/helper-validator-option": "^7.22.15", @@ -19661,7 +19638,8 @@ }, "dependencies": { "semver": { - "version": "6.3.1" + "version": "6.3.1", + "dev": true } } }, @@ -19733,6 +19711,7 @@ }, "@babel/helper-hoist-variables": { "version": "7.22.5", + "dev": true, "requires": { "@babel/types": "^7.22.5" } @@ -19751,6 +19730,7 @@ }, "@babel/helper-module-transforms": { "version": "7.23.0", + "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -19787,6 +19767,7 @@ }, "@babel/helper-simple-access": { "version": "7.22.5", + "dev": true, "requires": { "@babel/types": "^7.22.5" } @@ -19810,7 +19791,8 @@ "version": "7.22.20" }, "@babel/helper-validator-option": { - "version": "7.22.15" + "version": "7.22.15", + "dev": true }, "@babel/helper-wrap-function": { "version": "7.22.20", @@ -19823,6 +19805,7 @@ }, "@babel/helpers": { "version": "7.23.2", + "dev": true, "requires": { "@babel/template": "^7.22.15", "@babel/traverse": "^7.23.2", @@ -20671,8 +20654,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "requires": {} + "dev": true }, "semver": { "version": "6.3.1", @@ -20732,6 +20714,7 @@ }, "@babel/traverse": { "version": "7.23.2", + "dev": true, "requires": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -20861,13 +20844,11 @@ }, "@csstools/postcss-unset-value": { "version": "1.0.2", - "dev": true, - "requires": {} + "dev": true }, "@csstools/selector-specificity": { "version": "2.2.0", - "dev": true, - "requires": {} + "dev": true }, "@emotion/babel-plugin": { "version": "11.11.0", @@ -20978,8 +20959,7 @@ "version": "0.8.1" }, "@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "requires": {} + "version": "1.0.1" }, "@emotion/utils": { "version": "1.2.1" @@ -21200,6 +21180,7 @@ }, "@jridgewell/gen-mapping": { "version": "0.3.3", + "dev": true, "requires": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -21207,10 +21188,12 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "@jridgewell/set-array": { - "version": "1.1.2" + "version": "1.1.2", + "dev": true }, "@jridgewell/source-map": { "version": "0.3.5", @@ -21221,10 +21204,12 @@ } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.15" + "version": "1.4.15", + "dev": true }, "@jridgewell/trace-mapping": { "version": "0.3.20", + "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -21718,8 +21703,7 @@ }, "@testing-library/user-event": { "version": "14.5.1", - "dev": true, - "requires": {} + "dev": true }, "@tootallnate/once": { "version": "1.1.2", @@ -22328,12 +22312,10 @@ "version": "1.9.5", "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-jsx": { - "version": "5.3.2", - "requires": {} + "version": "5.3.2" }, "acorn-walk": { "version": "7.2.0", @@ -22655,8 +22637,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -22696,50 +22677,9 @@ "@types/babel__traverse": "^7.0.6" } }, - "babel-plugin-macros": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", - "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", - "dev": true, - "peer": true, - "requires": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "peer": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "peer": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, "babel-plugin-named-asset-import": { "version": "0.3.8", - "dev": true, - "requires": {} + "dev": true }, "babel-plugin-polyfill-corejs2": { "version": "0.4.6", @@ -22997,6 +22937,7 @@ }, "browserslist": { "version": "4.22.1", + "dev": true, "requires": { "caniuse-lite": "^1.0.30001541", "electron-to-chromium": "^1.4.535", @@ -23074,7 +23015,8 @@ } }, "caniuse-lite": { - "version": "1.0.30001561" + "version": "1.0.30001561", + "dev": true }, "case-sensitive-paths-webpack-plugin": { "version": "2.4.0", @@ -23342,7 +23284,8 @@ "dev": true }, "convert-source-map": { - "version": "2.0.0" + "version": "2.0.0", + "dev": true }, "cookie": { "version": "0.7.1", @@ -23428,8 +23371,7 @@ }, "css-declaration-sorter": { "version": "6.4.1", - "dev": true, - "requires": {} + "dev": true }, "css-has-pseudo": { "version": "3.0.4", @@ -23497,8 +23439,7 @@ }, "css-prefers-color-scheme": { "version": "6.0.3", - "dev": true, - "requires": {} + "dev": true }, "css-select": { "version": "4.3.0", @@ -23598,8 +23539,7 @@ }, "cssnano-utils": { "version": "3.1.0", - "dev": true, - "requires": {} + "dev": true }, "csso": { "version": "4.2.0", @@ -24042,7 +23982,8 @@ } }, "electron-to-chromium": { - "version": "1.4.578" + "version": "1.4.578", + "dev": true }, "emoji-regex": { "version": "10.3.0" @@ -24213,7 +24154,8 @@ } }, "escalade": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "escape-html": { "version": "1.0.3" @@ -24351,8 +24293,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-config-react-app": { "version": "7.0.1", @@ -24547,8 +24488,7 @@ }, "eslint-plugin-react-hooks": { "version": "4.6.0", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-testing-library": { "version": "5.11.1", @@ -24986,8 +24926,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "chalk": { "version": "4.1.2", @@ -25116,7 +25055,8 @@ "version": "1.2.3" }, "gensync": { - "version": "1.0.0-beta.2" + "version": "1.0.0-beta.2", + "dev": true }, "get-caller-file": { "version": "2.0.5", @@ -25206,7 +25146,8 @@ } }, "globals": { - "version": "11.12.0" + "version": "11.12.0", + "dev": true }, "globalthis": { "version": "1.0.3", @@ -25497,8 +25438,7 @@ }, "icss-utils": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "idb": { "version": "7.1.1", @@ -26463,8 +26403,7 @@ }, "jest-pnp-resolver": { "version": "1.2.3", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "27.5.1", @@ -26689,7 +26628,8 @@ } }, "jsesc": { - "version": "2.5.2" + "version": "2.5.2", + "dev": true }, "json-buffer": { "version": "3.0.1" @@ -26715,7 +26655,8 @@ "dev": true }, "json5": { - "version": "2.2.3" + "version": "2.2.3", + "dev": true }, "jsonfile": { "version": "6.1.0", @@ -27215,6 +27156,7 @@ }, "lru-cache": { "version": "5.1.1", + "dev": true, "requires": { "yallist": "^3.0.2" } @@ -27450,7 +27392,8 @@ "dev": true }, "node-releases": { - "version": "2.0.13" + "version": "2.0.13", + "dev": true }, "normalize-path": { "version": "3.0.0", @@ -27727,7 +27670,8 @@ "dev": true }, "picocolors": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "picomatch": { "version": "2.3.1", @@ -27845,8 +27789,7 @@ }, "postcss-browser-comments": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-calc": { "version": "8.2.4", @@ -27932,23 +27875,19 @@ }, "postcss-discard-comments": { "version": "5.1.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-duplicates": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-empty": { "version": "5.1.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-discard-overridden": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-double-position-gradients": { "version": "3.1.2", @@ -27967,8 +27906,7 @@ }, "postcss-flexbugs-fixes": { "version": "5.0.2", - "dev": true, - "requires": {} + "dev": true }, "postcss-focus-visible": { "version": "6.0.4", @@ -27986,13 +27924,11 @@ }, "postcss-font-variant": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-gap-properties": { "version": "3.0.5", - "dev": true, - "requires": {} + "dev": true }, "postcss-image-set-function": { "version": "4.0.7", @@ -28023,8 +27959,7 @@ }, "postcss-initial": { "version": "4.0.1", - "dev": true, - "requires": {} + "dev": true }, "postcss-js": { "version": "4.0.1", @@ -28066,13 +28001,11 @@ }, "postcss-logical": { "version": "5.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-media-minmax": { "version": "5.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-merge-longhand": { "version": "5.1.7", @@ -28126,8 +28059,7 @@ }, "postcss-modules-extract-imports": { "version": "3.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.3", @@ -28178,8 +28110,7 @@ }, "postcss-normalize-charset": { "version": "5.1.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-normalize-display-values": { "version": "5.1.0", @@ -28241,8 +28172,7 @@ }, "postcss-opacity-percentage": { "version": "1.1.3", - "dev": true, - "requires": {} + "dev": true }, "postcss-ordered-values": { "version": "5.1.3", @@ -28261,8 +28191,7 @@ }, "postcss-page-break": { "version": "3.0.4", - "dev": true, - "requires": {} + "dev": true }, "postcss-place": { "version": "7.0.5", @@ -28350,8 +28279,7 @@ }, "postcss-replace-overflow-wrap": { "version": "4.0.0", - "dev": true, - "requires": {} + "dev": true }, "postcss-selector-not": { "version": "6.0.1", @@ -28774,8 +28702,7 @@ "react-icons": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", - "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", - "requires": {} + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==" }, "react-input-mask": { "version": "2.0.4", @@ -28830,8 +28757,7 @@ "react-onclickoutside": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz", - "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==", - "requires": {} + "integrity": "sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==" }, "react-popper": { "version": "2.3.0", @@ -29906,12 +29832,10 @@ "react-tiny-popover": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/react-tiny-popover/-/react-tiny-popover-8.1.2.tgz", - "integrity": "sha512-zzG9hGBCNeSesZLLItNOiQvIU+/tLdLQ9y8cfSAtLQnOH7eoKVJflQzEng8w7rTblE+cV0/R6dFjjiZS1A4qTA==", - "requires": {} + "integrity": "sha512-zzG9hGBCNeSesZLLItNOiQvIU+/tLdLQ9y8cfSAtLQnOH7eoKVJflQzEng8w7rTblE+cV0/R6dFjjiZS1A4qTA==" }, "react-to-print": { - "version": "2.14.15", - "requires": {} + "version": "2.14.15" }, "react-tooltip": { "version": "5.22.0", @@ -29932,8 +29856,7 @@ } }, "reactjs-popup": { - "version": "2.0.6", - "requires": {} + "version": "2.0.6" }, "read-cache": { "version": "1.0.0", @@ -30320,8 +30243,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -30903,8 +30825,7 @@ }, "style-loader": { "version": "3.3.3", - "dev": true, - "requires": {} + "dev": true }, "stylehacks": { "version": "5.1.1", @@ -31445,13 +31366,6 @@ "is-typedarray": "^1.0.0" } }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "peer": true - }, "unbox-primitive": { "version": "1.0.2", "dev": true, @@ -31542,6 +31456,7 @@ }, "update-browserslist-db": { "version": "1.0.13", + "dev": true, "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -31564,12 +31479,10 @@ } }, "use-isomorphic-layout-effect": { - "version": "1.1.2", - "requires": {} + "version": "1.1.2" }, "use-memo-one": { - "version": "1.1.3", - "requires": {} + "version": "1.1.3" }, "util-deprecate": { "version": "1.0.2" @@ -31778,8 +31691,7 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -32197,8 +32109,7 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "dev": true, - "requires": {} + "dev": true }, "xml-name-validator": { "version": "3.0.0", @@ -32219,7 +32130,8 @@ "dev": true }, "yallist": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "yaml": { "version": "1.10.2" diff --git a/client/src/components/Projects/ColumnHeaderPopups/ProjectTableColumnHeader.jsx b/client/src/components/Projects/ColumnHeaderPopups/ProjectTableColumnHeader.jsx index 4586146e..10a5cad1 100644 --- a/client/src/components/Projects/ColumnHeaderPopups/ProjectTableColumnHeader.jsx +++ b/client/src/components/Projects/ColumnHeaderPopups/ProjectTableColumnHeader.jsx @@ -76,7 +76,8 @@ const ProjectTableColumnHeader = ({ orderBy, setSort, setCheckedProjectIds, - setSelectAllChecked + setSelectAllChecked, + droOptions }) => { const theme = useTheme(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -84,10 +85,23 @@ const ProjectTableColumnHeader = ({ // Filter is considered Applied if it is not set // to the default criteria values. const isFilterApplied = () => { - let propertyName = header.id; + let propertyName = header.accessor || header.id; if (header.popupType === "text") { - propertyName += "List"; - return criteria[propertyName].length > 0; + const listPropertyName = propertyName + "List"; + const listValue = criteria[listPropertyName]; + + if (propertyName === "droName") { + return Array.isArray(listValue) && listValue.length > 0; + } + + const headerValue = criteria[header.id]; + + const isListFilterApplied = + Array.isArray(listValue) && listValue.length > 0; + const isTextFilterApplied = + typeof headerValue === "string" && headerValue.length > 0; + + return isListFilterApplied || isTextFilterApplied; } if (header.popupType === "datetime") { return ( @@ -101,6 +115,12 @@ const ProjectTableColumnHeader = ({ if (header.id === "dateSnapshotted") { return criteria.type !== "all" || criteria.status !== "active"; } + if (header.id === "dro") { + return criteria.droList?.length > 0; // Use optional chaining + } + if (header.id === "adminNotes") { + return (criteria.adminNotes || "").length > 0; // Set default empty string + } return false; }; @@ -151,6 +171,7 @@ const ProjectTableColumnHeader = ({ setSelectAllChecked={setSelectAllChecked} projects={projects} filter={filter} + droOptions={droOptions} /> ) : header.popupType === "visibility" ? ( { + const property = header.accessor || header.id; + const getDisplayValue = value => { + if (property === "droName" && value === "") { + return "No DRO Assigned"; + } + return value; + }; + + const getInternalValue = displayValue => { + if (property === "droName" && displayValue === "No DRO Assigned") { + return ""; + } + return displayValue; + }; const classes = useStyles(); const [newOrder, setNewOrder] = useState( header.id !== orderBy ? null : order ); const [selectedListItems, setSelectedListItems] = useState( - criteria[header.id + "List"].map(s => ({ value: s, label: s })) + (criteria[header.id + "List"] || []).map(s => ({ + value: getDisplayValue(s), + label: getDisplayValue(s) + })) ); const [searchString, setSearchString] = useState(""); @@ -77,13 +95,26 @@ const TextPopup = ({ // are currently selected EXCEPT the criteria we are currently editing. const listCriteria = { ...criteria, [header.id + "List"]: [] }; const filteredProjects = projects.filter(p => filter(p, listCriteria)); - const property = header.id == "author" ? "fullname" : header.id; - const selectOptions = [...new Set(filteredProjects.map(p => p[property]))] - .filter(value => value !== null) - .sort( - (a, b) => (initiallyChecked(b) ? 1 : 0) - (initiallyChecked(a) ? 1 : 0) - ); + // const property = header.id == "author" ? "fullname" : header.id; + + let selectOptions; + if (property === "droName") { + selectOptions = droOptions.map(dro => dro.name); + selectOptions.push("No DRO Assigned"); + } else if (property === "fullname") { + selectOptions = [...new Set(filteredProjects.map(p => p[property]))] + .filter(value => value !== null) + .sort( + (a, b) => (initiallyChecked(b) ? 1 : 0) - (initiallyChecked(a) ? 1 : 0) + ); + } else { + selectOptions = [...new Set(filteredProjects.map(p => p[property]))] + .filter(value => value !== null && value !== "") + .sort( + (a, b) => (initiallyChecked(b) ? 1 : 0) - (initiallyChecked(a) ? 1 : 0) + ); + } const filteredOptions = selectOptions .filter(o => !!o) .filter(opt => opt.toLowerCase().includes(searchString.toLowerCase())); @@ -110,16 +141,21 @@ const TextPopup = ({ const isChecked = optionValue => { const checked = selectedListItems.find( - option => option.value == optionValue + option => option.value === optionValue ); return !!checked; }; const applyChanges = () => { + let selectedValues = selectedListItems.map(sli => + getInternalValue(sli.value) + ); + setCriteria({ ...criteria, - [header.id + "List"]: selectedListItems.map(sli => sli.value) + [header.id + "List"]: selectedValues }); + if (newOrder) { setSort(header.id, newOrder); } @@ -239,7 +275,8 @@ TextPopup.propTypes = { orderBy: PropTypes.string, setSort: PropTypes.func, setCheckedProjectIds: PropTypes.func, - setSelectAllChecked: PropTypes.func + setSelectAllChecked: PropTypes.func, + droOptions: PropTypes.array.isRequired }; export default TextPopup; diff --git a/client/src/components/Projects/FilterDrawer.jsx b/client/src/components/Projects/FilterDrawer.jsx index f3a61c40..0e9126a9 100644 --- a/client/src/components/Projects/FilterDrawer.jsx +++ b/client/src/components/Projects/FilterDrawer.jsx @@ -50,7 +50,8 @@ const FilterPopup = ({ setCriteria, setCollapsed, setCheckedProjectIds, - setSelectAllChecked + setSelectAllChecked, + droOptions }) => { const userContext = useContext(UserContext); const account = userContext.account; @@ -71,7 +72,9 @@ const FilterPopup = ({ nameList: [], authorList: [], addressList: [], - alternativeList: [] + alternativeList: [], + dro: "", + adminNotes: "" }); }; @@ -208,6 +211,33 @@ const FilterPopup = ({ setEndDate={date => handleChangeDate("endDateModified", date)} /> +

+ Development Review Offices (DRO) +

+ ({ + value: dro.name, + label: dro.name + }))} + onChange={e => setCriteria({ ...criteria, dro: e.target.value })} + name="dro" + className={classes.dropdown} + /> + + {account?.isAdmin && ( + <> +

Admin Notes

+ + + )} +
@@ -222,7 +252,13 @@ FilterPopup.propTypes = { collapsed: PropTypes.bool, setCollapsed: PropTypes.func, setCheckedProjectIds: PropTypes.func, - setSelectAllChecked: PropTypes.func + setSelectAllChecked: PropTypes.func, + droOptions: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.any.isRequired, + name: PropTypes.string.isRequired + }) + ).isRequired }; export default FilterPopup; diff --git a/client/src/components/Projects/ProjectTableRow.jsx b/client/src/components/Projects/ProjectTableRow.jsx index b16aaccd..ea673e90 100644 --- a/client/src/components/Projects/ProjectTableRow.jsx +++ b/client/src/components/Projects/ProjectTableRow.jsx @@ -223,7 +223,7 @@ const ProjectTableRow = ({ {dateSubmittedDisplay()} {/* DRO Column */} - {isAdmin && droOptions.data ? ( + {isAdmin && droOptions.length > 0 ? (
({ + ...droOptions.map(dro => ({ value: dro.id, label: dro.name })) @@ -372,14 +372,12 @@ ProjectTableRow.propTypes = { handleCheckboxChange: PropTypes.func.isRequired, checkedProjectIds: PropTypes.arrayOf(PropTypes.number).isRequired, isAdmin: PropTypes.bool.isRequired, - droOptions: PropTypes.shape({ - data: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.number.isRequired, - name: PropTypes.string.isRequired - }) - ).isRequired - }).isRequired, + droOptions: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + name: PropTypes.string.isRequired + }) + ).isRequired, onDroChange: PropTypes.func.isRequired, // New propType onAdminNoteUpdate: PropTypes.func.isRequired // New propType }; diff --git a/client/src/components/Projects/ProjectsPage.jsx b/client/src/components/Projects/ProjectsPage.jsx index 751096b5..30c04be1 100644 --- a/client/src/components/Projects/ProjectsPage.jsx +++ b/client/src/components/Projects/ProjectsPage.jsx @@ -47,7 +47,7 @@ const DEFAULT_FILTER_CRITERIA = { alternativeList: [], authorList: [], droList: [], - adminNotes: "", + adminNotesList: [], startDateModifiedAdmin: null, endDateModifiedAdmin: null }; @@ -214,72 +214,37 @@ const ProjectsPage = ({ contentContainerRef }) => { const projectsPerPage = perPage; const isAdmin = userContext.account?.isAdmin || false; - useEffect(() => { - // Check if the user is an admin - const isAdmin = userContext.account?.isAdmin || false; - - if (isAdmin) { - // Fetch available DROs + const enhancedProjects = projects + ? projects.map(project => { + const droName = + droOptions.find(dro => dro.id === project.droId)?.name || ""; + return { + ...project, + droName: droName, + adminNotes: project.adminNotes || "" + }; + }) + : []; - const fetchDroOptions = async () => { + useEffect(() => { + const fetchDroOptions = async () => { + try { const result = await droService.get(); - setDroOptions(result); - }; - fetchDroOptions().catch(console.error); - } - }, [userContext.account]); + setDroOptions(result.data); // Adjust based on your API response structure + } catch (error) { + console.error("Error fetching DRO options:", error); + } + }; + fetchDroOptions(); + }, []); useEffect(() => { - const isAdmin = userContext.account?.isAdmin || false; - - if (!isAdmin) { - // Extract unique droIds from projects - const uniqueDroIds = [ - ...new Set( - projects - .filter(project => project.droId) - .map(project => project.droId) - ) - ]; - - // Function to fetch DRO names for given droIds - const fetchDroNames = async () => { - try { - // Initialize a temporary map - const tempDroNameMap = {}; - - // Fetch each DRO by ID - await Promise.all( - uniqueDroIds.map(async droId => { - try { - const response = await droService.getById(droId); - tempDroNameMap[droId] = response.data.name || "N/A"; - } catch (error) { - console.error(`Error fetching DRO with ID ${droId}:`, error); - tempDroNameMap[droId] = "N/A"; - } - }) - ); - - // Update the droNameMap state - setDroNameMap(tempDroNameMap); - } catch (error) { - console.error("Error fetching DRO names:", error); - } - }; - - // Only fetch if there are droIds to fetch - if (uniqueDroIds.length > 0) { - fetchDroNames(); - } else { - // Reset the map if no droIds are present - setDroNameMap({}); - } - } else { - // If admin, reset the map since admin already has droOptions - setDroNameMap({}); - } - }, [projects, userContext.account?.isAdmin]); + const droMap = {}; + droOptions.forEach(dro => { + droMap[dro.id] = dro.name; + }); + setDroNameMap(droMap); + }, [droOptions]); const perPageOptions = [ { value: projects.length.toString(), label: "All" }, @@ -577,17 +542,31 @@ const ProjectsPage = ({ contentContainerRef }) => { ) { projectA = a[orderBy] ? a[orderBy] : "2000-01-01"; projectB = b[orderBy] ? b[orderBy] : "2000-01-01"; + } else if (orderBy === "dro") { + projectA = a.droName ? a.droName.toLowerCase() : null; + projectB = b.droName ? b.droName.toLowerCase() : null; + } else if (orderBy === "adminNotes") { + projectA = a.adminNotes ? a.adminNotes.toLowerCase() : null; + projectB = b.adminNotes ? b.adminNotes.toLowerCase() : null; } else { - projectA = a[orderBy].toLowerCase(); - projectB = b[orderBy].toLowerCase(); + projectA = a[orderBy] ? a[orderBy].toLowerCase() : ""; + projectB = b[orderBy] ? b[orderBy].toLowerCase() : ""; } - if (projectA < projectB) { + if (projectA === null && projectB === null) { + return 0; + } else if (projectA === null) { + return 1; // null values are greater + } else if (projectB === null) { return -1; - } else if (projectA > projectB) { - return 1; } else { - return 0; + if (projectA < projectB) { + return -1; + } else if (projectA > projectB) { + return 1; + } else { + return 0; + } } }; @@ -636,7 +615,6 @@ const ProjectsPage = ({ contentContainerRef }) => { const handleFilterTextChange = text => { setFilterText(text); }; - const getDateOnly = date => { const dateOnly = new Date(date).toDateString(); return new Date(dateOnly); @@ -739,15 +717,47 @@ const ProjectsPage = ({ contentContainerRef }) => { return false; } - if (criteria.dro && !p.dro.includes(criteria.dro)) return false; + if (criteria.droList.length > 0) { + const droNames = criteria.droList.map(n => n.toLowerCase()); + const projectDroName = (p.droName || "").toLowerCase(); + + if (!droNames.includes(projectDroName)) { + return false; + } + } if ( - criteria.adminNotes && - !p.adminNotes.toLowerCase().includes(criteria.adminNotes.toLowerCase()) + criteria.adminNotesList.length > 0 && + !criteria.adminNotesList + .map(n => n.toLowerCase()) + .includes( + p.adminNotes ? p.adminNotes.toLowerCase() : "eowurqoieuroiwutposi" + ) ) { return false; } + // if (userContext.account?.isAdmin) { + // const projectAdminNotes = (p.adminNotes || "").toLowerCase().trim(); + // const criteriaAdminNotes = criteria.adminNotes.toLowerCase().trim(); + + // if ( + // criteriaAdminNotes && + // !projectAdminNotes.includes(criteriaAdminNotes) + // ) { + // return false; + // } + + // if ( + // criteria.adminNotesList.length > 0 && + // !criteria.adminNotesList + // .map(n => n.toLowerCase()) + // .includes((p.adminNotes || "").toLowerCase()) + // ) { + // return false; + // } + // } + if ( criteria.startDateModifiedAdmin && getDateOnly(p.dateModifiedAdmin) < @@ -834,7 +844,8 @@ const ProjectsPage = ({ contentContainerRef }) => { { id: "dro", label: "DRO", - popupType: null // temporarily disable filtering by DRO, as it crashes + popupType: "text", + accessor: "droName" }, ...(userContext.account?.isAdmin @@ -842,7 +853,8 @@ const ProjectsPage = ({ contentContainerRef }) => { { id: "adminNotes", label: "Admin Notes", - popupType: null // No filter needed for this column + popupType: "text", + accessor: "adminNotes" }, { id: "dateModifiedAdmin", @@ -859,7 +871,7 @@ const ProjectsPage = ({ contentContainerRef }) => { const indexOfLastPost = currentPage * projectsPerPage; const indexOfFirstPost = indexOfLastPost - projectsPerPage; - let sortedProjects = projects.filter(p => filter(p, filterCriteria)); + let sortedProjects = enhancedProjects.filter(p => filter(p, filterCriteria)); for (let i = 0; i < sortCriteria.length; i++) { sortedProjects.sort( getComparator(sortCriteria[i].direction, sortCriteria[i].field) @@ -965,6 +977,7 @@ const ProjectsPage = ({ contentContainerRef }) => { } setCheckedProjectIds={setCheckedProjectIds} setSelectAllChecked={setSelectAllChecked} + droOptions={droOptions} /> @@ -973,7 +986,7 @@ const ProjectsPage = ({ contentContainerRef }) => { - {projects.length ? ( + {enhancedProjects.length ? ( currentProjects.map(project => ( { Items per page
{/*
{JSON.stringify(sortCriteria, null, 2)}
*/} + {/*
{JSON.stringify(filterCriteria, null, 2)}
*/} {(selectedProject || checkedProjectsStatusData) && ( <> { + `` ); From 001bdb01d048f4b8df8019092061a5fb4e0faa7a Mon Sep 17 00:00:00 2001 From: Nelson Pang Date: Fri, 6 Dec 2024 16:51:38 -0800 Subject: [PATCH 2/2] created an modal that gives options to confirming leaving the page or cancel after making an edit to the FAQ in admin mode --- .../src/components/Faq/FaqConfirmDialog.jsx | 82 +++++++++++++++++++ client/src/components/Faq/FaqView.jsx | 44 +++++++++- .../ProjectWizard/TdmCalculationWizard.jsx | 2 - 3 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 client/src/components/Faq/FaqConfirmDialog.jsx diff --git a/client/src/components/Faq/FaqConfirmDialog.jsx b/client/src/components/Faq/FaqConfirmDialog.jsx new file mode 100644 index 00000000..820d85ce --- /dev/null +++ b/client/src/components/Faq/FaqConfirmDialog.jsx @@ -0,0 +1,82 @@ +import React from "react"; +import PropTypes from "prop-types"; +import ModalDialog from "../UI/AriaModal/ModalDialog"; +import Button from "../Button/Button"; +import { createUseStyles } from "react-jss"; +import { MdWarning } from "react-icons/md"; + +const useStyles = createUseStyles({ + title: { + textAlign: "center" + }, + warningWrapper: { + color: "#B64E38", + display: "flex", + alignItems: "center", + justifyContent: "center" + }, + warningMessage: { + verticalAlign: "middle", + display: "flex", + alignItems: "center", + justifyContent: "center", + marginBottom: "1em" + }, + modalActions: { + display: "flex", + justifyContent: "center" + }, + proceedButton: { + color: "white", + fontWeight: "bold" + } +}); + +const FaqConfirmDialog = ({ blocker }) => { + const classes = useStyles(); + return ( + +
+ +
+

+ Unsaved changes will be lost +

+

+ +   Leaving this page will permanently delete any unsaved changes + to the FAQ. + +

+
+ + +
+
+ ); +}; + +FaqConfirmDialog.propTypes = { + blocker: PropTypes.object.isRequired +}; + +export default FaqConfirmDialog; diff --git a/client/src/components/Faq/FaqView.jsx b/client/src/components/Faq/FaqView.jsx index 053f8373..022a1978 100644 --- a/client/src/components/Faq/FaqView.jsx +++ b/client/src/components/Faq/FaqView.jsx @@ -10,6 +10,8 @@ import AddNewCategoryButton from "../Button/AddNewCategory"; import { createUseStyles } from "react-jss"; import DeleteFaqModal from "./DeleteFaqModal"; import SaveConfirmationModal from "./SaveConfirmationModal"; +import FaqConfirmDialog from "./FaqConfirmDialog"; +import { matchPath, unstable_useBlocker as useBlocker } from "react-router-dom"; const useStyles = createUseStyles(theme => ({ headerContainer: { @@ -35,6 +37,7 @@ const FaqView = () => { const [highestFaqId, setHighestFaqId] = useState(0); const [highestCategoryId, setHighestCategoryId] = useState(0); const [expanded, setExpanded] = useState(false); + const [formHasSaved, setFormHasSaved] = useState(false); const [admin, setAdmin] = useState(false); const [categoryToDelete, setCategoryToDelete] = useState(null); const [faqToDelete, setFaqToDelete] = useState(null); @@ -47,6 +50,36 @@ const FaqView = () => { fetchFaqData(); }, []); + const calculationPath = "/faqs"; + + const shouldBlock = React.useCallback( + ({ currentLocation, nextLocation }) => { + const isSamePage = (currentLocation, nextLocation) => { + const currentMatch = matchPath( + { + path: calculationPath, + exact: true + }, + currentLocation.pathname + ); + const nextMatch = matchPath( + { + path: calculationPath, + exact: true + }, + nextLocation.pathname + ); + + return currentMatch && nextMatch; + }; + + return formHasSaved && !isSamePage(currentLocation, nextLocation); + }, + [formHasSaved] + ); + + const blocker = useBlocker(shouldBlock); + const handleDragEnd = result => { const { type, destination, source } = result; @@ -161,12 +194,14 @@ const FaqView = () => { }; setHighestCategoryId(updatedHighestCategoryId); setFaqCategoryList(prevState => [...prevState, newCategory]); + setFormHasSaved(true); }; const onDeleteCategory = categoryId => { setFaqCategoryList(prevState => prevState.filter(category => category.id !== categoryId) ); + setFormHasSaved(true); }; const handleAddFAQ = (category, question, answer) => { @@ -198,6 +233,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const handleEditFAQ = (categoryId, faqId, question, answer) => { @@ -224,6 +260,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const handleEditCategory = (category, name) => { @@ -240,6 +277,7 @@ const FaqView = () => { return cat; }) ); + setFormHasSaved(true); }; const onDeleteFAQ = (categoryId, faqId) => { @@ -256,6 +294,7 @@ const FaqView = () => { return category; }) ); + setFormHasSaved(true); }; const expandFaq = faq => { @@ -312,7 +351,7 @@ const FaqView = () => { // Submit data and set admin to false submitFaqData(); setAdmin(false); - + setFormHasSaved(false); // Close the save confirmation modal closeSaveConfirmationModal(); }; @@ -320,12 +359,14 @@ const FaqView = () => { const handleDeleteCategory = categoryId => { setCategoryToDelete(categoryId); setIsDeleteConfirmationModalOpen(true); + setFormHasSaved(true); }; const handleDeleteFAQ = (categoryId, faqId) => { setCategoryToDelete(categoryId); setFaqToDelete(faqId); setIsDeleteConfirmationModalOpen(true); + setFormHasSaved(true); }; const closeModal = () => { @@ -405,6 +446,7 @@ const FaqView = () => { onClose={closeSaveConfirmationModal} onYes={handleSaveConfirmationYes} /> + {blocker ? : null} ); }; diff --git a/client/src/components/ProjectWizard/TdmCalculationWizard.jsx b/client/src/components/ProjectWizard/TdmCalculationWizard.jsx index 8922b0a2..6175f248 100644 --- a/client/src/components/ProjectWizard/TdmCalculationWizard.jsx +++ b/client/src/components/ProjectWizard/TdmCalculationWizard.jsx @@ -96,7 +96,6 @@ const TdmCalculationWizard = props => { }, nextLocation.pathname ); - return ( currentMatch && nextMatch && @@ -104,7 +103,6 @@ const TdmCalculationWizard = props => { !projectId) ); }; - return formIsDirty && !isSameProject(currentLocation, nextLocation); }, [formIsDirty, projectId]