diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e018f09..d5b81698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - SNAP page and connected to SNAP API Point [#59](https://github.com/policy-design-lab/pdl-frontend/issues/59) - Local development work environment to connect dev api server [#93](https://github.com/policy-design-lab/pdl-frontend/issues/93/) +- CSP page [#74](https://github.com/policy-design-lab/pdl-frontend/issues/74) ### Changed - eslint rules back to original [#94](https://github.com/policy-design-lab/pdl-frontend/issues/94) diff --git a/package-lock.json b/package-lock.json index 4d1219fc..5a2caa25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,7 @@ "style-loader": "^2.0.0", "svg-inline-loader": "^0.8.2", "ts-jest": "^26.5.6", - "typedoc": "^0.20.36", + "typedoc": "^0.24.6", "typescript": "^4.8.4", "url-loader": "^4.1.1", "webpack": "^5.37.0", @@ -6546,6 +6546,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7040,15 +7046,6 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -10585,6 +10582,23 @@ "node": ">=4" } }, + "node_modules/eslint-plugin-flowtype": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz", + "integrity": "sha512-vcz32f+7TP+kvTUyMXZmCnNujBQZDNmcqPImw8b9PZ+16w1Qdm6ryRuYZYVaG9xRqqmAPr2Cs9FAX5gN+x/bjw==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.1.0" + } + }, "node_modules/eslint-plugin-import": { "version": "2.22.1", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", @@ -12426,27 +12440,6 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -13171,15 +13164,6 @@ "node": ">=12" } }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -14648,6 +14632,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -15350,15 +15340,15 @@ } }, "node_modules/marked": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", - "integrity": "sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, "bin": { - "marked": "bin/marked" + "marked": "bin/marked.js" }, "engines": { - "node": ">= 8.16.2" + "node": ">= 12" } }, "node_modules/mdn-data": { @@ -16317,30 +16307,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/onigasm": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", - "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", - "dev": true, - "dependencies": { - "lru-cache": "^5.1.1" - } - }, - "node_modules/onigasm/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/onigasm/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -18174,18 +18140,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/reduce-css-calc": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", @@ -19297,23 +19251,6 @@ "node": ">=0.10.0" } }, - "node_modules/shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -19322,13 +19259,15 @@ "optional": true }, "node_modules/shiki": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.3.tgz", - "integrity": "sha512-NEjg1mVbAUrzRv2eIcUt3TG7X9svX7l3n3F5/3OdFq+/BxUdmBOeKGiH4icZJBLHy354Shnj6sfBTemea2e7XA==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz", + "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==", "dev": true, "dependencies": { - "onigasm": "^2.2.5", - "vscode-textmate": "^5.2.0" + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" } }, "node_modules/side-channel": { @@ -19962,6 +19901,13 @@ "node": ">=10" } }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true, + "peer": true + }, "node_modules/string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -21230,82 +21176,48 @@ } }, "node_modules/typedoc": { - "version": "0.20.36", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.36.tgz", - "integrity": "sha512-qFU+DWMV/hifQ9ZAlTjdFO9wbUIHuUBpNXzv68ZyURAP9pInjZiO4+jCPeAzHVcaBCHER9WL/+YzzTt6ZlN/Nw==", + "version": "0.24.6", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz", + "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==", "dev": true, "dependencies": { - "colors": "^1.4.0", - "fs-extra": "^9.1.0", - "handlebars": "^4.7.7", - "lodash": "^4.17.21", "lunr": "^2.3.9", - "marked": "^2.0.3", - "minimatch": "^3.0.0", - "progress": "^2.0.3", - "shelljs": "^0.8.4", - "shiki": "^0.9.3", - "typedoc-default-themes": "^0.12.10" + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 10.8.0" + "node": ">= 14.14" }, "peerDependencies": { - "typescript": "3.9.x || 4.0.x || 4.1.x || 4.2.x" - } - }, - "node_modules/typedoc-default-themes": { - "version": "0.12.10", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", - "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", - "dev": true, - "engines": { - "node": ">= 8" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x" } }, - "node_modules/typedoc/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" + "balanced-match": "^1.0.0" } }, - "node_modules/typedoc/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dev": true, "dependencies": { - "universalify": "^2.0.0" + "brace-expansion": "^2.0.1" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/typedoc/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/typedoc/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, "engines": { - "node": ">= 10.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/typescript": { @@ -21321,19 +21233,6 @@ "node": ">=4.2.0" } }, - "node_modules/uglify-js": { - "version": "3.13.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.6.tgz", - "integrity": "sha512-rRprLwl8RVaS+Qvx3Wh5hPfPBn9++G6xkGlUupya0s5aDmNjI7z3lnRLB3u7sN4OmbB0pWgzhM9BEJyiWAwtAA==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -21794,10 +21693,16 @@ "node": ">= 0.10" } }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, "node_modules/vscode-textmate": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.4.0.tgz", - "integrity": "sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, "node_modules/w3c-hr-time": { @@ -22819,12 +22724,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -28559,6 +28458,12 @@ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, + "ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -28950,12 +28855,6 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -31847,6 +31746,17 @@ } } }, + "eslint-plugin-flowtype": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz", + "integrity": "sha512-vcz32f+7TP+kvTUyMXZmCnNujBQZDNmcqPImw8b9PZ+16w1Qdm6ryRuYZYVaG9xRqqmAPr2Cs9FAX5gN+x/bjw==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.15", + "string-natural-compare": "^3.0.1" + } + }, "eslint-plugin-import": { "version": "2.22.1", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", @@ -33142,19 +33052,6 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -33726,12 +33623,6 @@ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -34853,6 +34744,12 @@ "minimist": "^1.2.5" } }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -35392,9 +35289,9 @@ } }, "marked": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", - "integrity": "sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true }, "mdn-data": { @@ -36147,32 +36044,6 @@ "mimic-fn": "^2.1.0" } }, - "onigasm": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/onigasm/-/onigasm-2.2.5.tgz", - "integrity": "sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==", - "dev": true, - "requires": { - "lru-cache": "^5.1.1" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, "opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -37556,15 +37427,6 @@ "decimal.js-light": "^2.4.1" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, "reduce-css-calc": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz", @@ -38481,17 +38343,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shelljs": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", - "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -38500,13 +38351,15 @@ "optional": true }, "shiki": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.3.tgz", - "integrity": "sha512-NEjg1mVbAUrzRv2eIcUt3TG7X9svX7l3n3F5/3OdFq+/BxUdmBOeKGiH4icZJBLHy354Shnj6sfBTemea2e7XA==", + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.2.tgz", + "integrity": "sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==", "dev": true, "requires": { - "onigasm": "^2.2.5", - "vscode-textmate": "^5.2.0" + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" } }, "side-channel": { @@ -39034,6 +38887,13 @@ "strip-ansi": "^6.0.0" } }, + "string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", + "dev": true, + "peer": true + }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -39997,79 +39857,43 @@ } }, "typedoc": { - "version": "0.20.36", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.20.36.tgz", - "integrity": "sha512-qFU+DWMV/hifQ9ZAlTjdFO9wbUIHuUBpNXzv68ZyURAP9pInjZiO4+jCPeAzHVcaBCHER9WL/+YzzTt6ZlN/Nw==", + "version": "0.24.6", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz", + "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==", "dev": true, "requires": { - "colors": "^1.4.0", - "fs-extra": "^9.1.0", - "handlebars": "^4.7.7", - "lodash": "^4.17.21", "lunr": "^2.3.9", - "marked": "^2.0.3", - "minimatch": "^3.0.0", - "progress": "^2.0.3", - "shelljs": "^0.8.4", - "shiki": "^0.9.3", - "typedoc-default-themes": "^0.12.10" + "marked": "^4.3.0", + "minimatch": "^9.0.0", + "shiki": "^0.14.1" }, "dependencies": { - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "balanced-match": "^1.0.0" } }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "minimatch": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", + "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dev": true, "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" + "brace-expansion": "^2.0.1" } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true } } }, - "typedoc-default-themes": { - "version": "0.12.10", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.12.10.tgz", - "integrity": "sha512-fIS001cAYHkyQPidWXmHuhs8usjP5XVJjWB8oZGqkTowZaz3v7g3KDZeeqE82FBrmkAnIBOY3jgy7lnPnqATbA==", - "dev": true - }, "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "dev": true }, - "uglify-js": { - "version": "3.13.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.6.tgz", - "integrity": "sha512-rRprLwl8RVaS+Qvx3Wh5hPfPBn9++G6xkGlUupya0s5aDmNjI7z3lnRLB3u7sN4OmbB0pWgzhM9BEJyiWAwtAA==", - "dev": true, - "optional": true - }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -40437,10 +40261,16 @@ "replace-ext": "^1.0.0" } }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, "vscode-textmate": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.4.0.tgz", - "integrity": "sha512-c0Q4zYZkcLizeYJ3hNyaVUM2AA8KDhNCA3JvXY8CeZSJuBdAy3bAvSbv46RClC4P3dSO9BdwhnKEx2zOo6vP/w==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, "w3c-hr-time": { @@ -41215,12 +41045,6 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", diff --git a/package.json b/package.json index cbea41ad..7d0a3294 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "style-loader": "^2.0.0", "svg-inline-loader": "^0.8.2", "ts-jest": "^26.5.6", - "typedoc": "^0.20.36", + "typedoc": "^0.24.6", "typescript": "^4.8.4", "url-loader": "^4.1.1", "webpack": "^5.37.0", diff --git a/src/components/LandingDisplay.tsx b/src/components/LandingDisplay.tsx index 9efe0ca3..8f754110 100644 --- a/src/components/LandingDisplay.tsx +++ b/src/components/LandingDisplay.tsx @@ -110,26 +110,25 @@ export default function LandingDisplay({ programTitle }: { programTitle: string boldText = "What is Farm Bill?"; bodyText = "The Supplemental Nutrition Assistance Program [SNAP] provides financial assistance to low-income families to help cover the cost of food. Benefits can only be used to purchase food products and are provided in electronic format similar to a credit card and known as the Electronic Benefit Transfer (EBT) card. The map shows the total SNAP costs of the nutrition title by state from 2018-2022."; - route = "/snap"; + route = "/"; buttonText = "Explore Maps of SNAP"; button = ( - - - + ); break; case "All Programs": diff --git a/src/components/LandingPageMap.tsx b/src/components/LandingPageMap.tsx index f9d82556..daa22a1b 100644 --- a/src/components/LandingPageMap.tsx +++ b/src/components/LandingPageMap.tsx @@ -111,7 +111,7 @@ const MapChart = ({ setTooltipContent, title }) => { color5 = "#045A8D"; legendTitle = ( - Total Supplemental Nutrition Assistance Programs Benefits from 2018 - 2022 + Total Supplemental Nutrition Assistance Program (SNAP) Costs from 2018 - 2022 ); break; @@ -228,6 +228,13 @@ const MapChart = ({ setTooltipContent, title }) => { ); + const fillColour = () => { + if (total) { + if (total !== 0) return colorScale(total); + return "#D2D2D2"; + } + return "#D2D2D2"; + }; return ( { onMouseLeave={() => { setTooltipContent(""); }} - fill={colorScale(total)} + fill={fillColour()} stroke="#FFF" style={{ default: { stroke: "#FFFFFF", strokeWidth: 0.75, outline: "none" }, diff --git a/src/components/ProgramDrawer.tsx b/src/components/ProgramDrawer.tsx index bd746993..90fd8eaf 100644 --- a/src/components/ProgramDrawer.tsx +++ b/src/components/ProgramDrawer.tsx @@ -8,7 +8,7 @@ import ListItem from "@mui/material/ListItem"; import ListItemButton from "@mui/material/ListItemButton"; import ListItemText from "@mui/material/ListItemText"; import PropTypes from "prop-types"; -import { useLocation } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; const drawerWidth = 240; @@ -23,7 +23,7 @@ ProgramDrawer.propTypes = { }; let currentChecked = 0; -function EQIPCheckboxList({ setEQIPChecked, setShowPopUp }) { +function EQIPCheckboxList({ setEQIPChecked, setShowPopUp, zeroCategory }) { const [checked, setChecked] = React.useState(currentChecked); const handleToggle = (value: number) => () => { @@ -53,6 +53,27 @@ function EQIPCheckboxList({ setEQIPChecked, setShowPopUp }) { {EQIPList.map((category, value) => { const labelId = `checkbox-list-label-${value}`; + if (zeroCategory && zeroCategory.includes(category)) { + return ( + + + + + + + ); + } if ( category !== "Land management" && category !== "Other planning" && @@ -154,22 +175,209 @@ function EQIPCheckboxList({ setEQIPChecked, setShowPopUp }) { ); } -export default function ProgramDrawer({ setEQIPChecked }): JSX.Element { +function CSPCheckboxList({ setCSPChecked, setShowPopUp, zeroCategory }) { + const [checked, setChecked] = React.useState(currentChecked); + + const handleToggle = (value: number) => () => { + setChecked(value); + setCSPChecked(value); + currentChecked = value; + setShowPopUp(false); + }; + + // Match PR89 suggestions + const CSPList = [ + "Total CSP Benefits", + "2018 Practices", + "Structural", + "Vegetative", + "Land management", + "Forest management", + "Soil remediation", + "Existing activity payments", + "Bundles", + "Soil testing", + "Other improvement", + + "2014 Eligible Land", + "Cropland", + "Grassland", + "Rangeland", + "Pastureland", + "Non-industrial private forestland", + "Other: supplemental, adjustment & other" + ]; + + return ( + + {CSPList.map((category, value) => { + const labelId = `checkbox-list-label-${value}`; + if (zeroCategory && zeroCategory.includes(category)) { + return ( + + + + + + + ); + } + if ( + category !== "2018 Practices" && + category !== "2014 Eligible Land" && + category !== "Total CSP Benefits" + ) { + return ( + + + + + + + ); + } + if (category === "Total CSP Benefits") { + return ( + + + + + + + ); + } + if (category === "2018 Practices" || category === "2014 Eligible Land") { + return ( + + + + + + + + + ); + } + return ( + + + + + + + + + ); + })} + + ); +} + +export default function ProgramDrawer({ setEQIPChecked, setCSPChecked, zeroCategories }): JSX.Element { const location = useLocation(); + const navigate = useNavigate(); + const [zeroCategory, setZeroCategory] = React.useState(zeroCategories); const [eqipOpen, setEqipOpen] = React.useState(false); const eqipRef = React.useRef(null); const handleEqipClick = () => { - setEqipOpen((prevEqipOpen) => !prevEqipOpen); + if (location.pathname !== "/eqip") { + navigate("/eqip"); + window.location.reload(false); + } else { + setEqipOpen((prevEqipOpen) => !prevEqipOpen); + } }; const prevEqipOpen = React.useRef(eqipOpen); React.useEffect(() => { - if (prevEqipOpen.current === true && eqipOpen === false) { + if (prevEqipOpen.current && !eqipOpen) { eqipRef.current.focus(); } prevEqipOpen.current = eqipOpen; }, [eqipOpen]); + const [cspOpen, setCspOpen] = React.useState(false); + const cspRef = React.useRef(null); + const handleCspClick = () => { + if (location.pathname !== "/csp") { + navigate("/csp"); + window.location.reload(false); + } else { + setCspOpen((prevCspOpen) => !prevCspOpen); + } + }; + const prevCspOpen = React.useRef(cspOpen); + React.useEffect(() => { + if (prevCspOpen.current && !cspOpen) { + cspRef.current.focus(); + } + + prevCspOpen.current = cspOpen; + }, [cspOpen]); + return ( - {eqipOpen ? ( + {location.pathname === "/eqip" ? ( EQIP: Environmental Quality Incentives Program @@ -225,15 +433,74 @@ export default function ProgramDrawer({ setEQIPChecked }): JSX.Element { - + - + + + + + + + + {location.pathname === "/csp" ? ( + + CSP: Conservation Stewardship Program + + ) : ( + CSP: Conservation Stewardship Program + )} + + + + STATUTE + + + + + + + + + - - CSP: Conservation Stewardship Program - CRP: Conservation Reserve Program diff --git a/src/components/SemiDonutChart.tsx b/src/components/SemiDonutChart.tsx index f5828177..d41e4d3c 100644 --- a/src/components/SemiDonutChart.tsx +++ b/src/components/SemiDonutChart.tsx @@ -6,7 +6,6 @@ const RADIAN = Math.PI / 180; // eslint-disable-next-line export default function SemiDonutChart({ data, label1, label2 }: any): JSX.Element { - const data01 = data; // eslint-disable-next-line const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, percent }: any) => { const radius = innerRadius + (outerRadius - innerRadius) * 0.5; @@ -56,7 +55,7 @@ export default function SemiDonutChart({ data, label1, label2 }: any): JSX.Eleme { + const { setTooltipContent, maxValue, allStates, statePerformance } = props; + const colorScale = scaleQuantize() + .domain([0, maxValue]) + .range(["#F0F9E8", "#BAE4BC", "#7BCCC4", "#43A2CA", "#0868AC"]); + + return ( +
+ {allStates.length > 0 && statePerformance.Wisconsin !== undefined ? ( + + + {({ geographies }) => ( + <> + {geographies.map((geo) => { + if (!Object.keys(statePerformance).includes(geo.properties.name)) { + return null; + } + const record = statePerformance[geo.properties.name][0]; + const totalPaymentInDollars = record.totalPaymentInDollars; + const totalPaymentInPercentageNationwide = + record.totalPaymentInPercentageNationwide; + const hoverContent = ( + + + {geo.properties.name} + + + {Number(totalPaymentInDollars) < 1000000 + ? `$${Number( + Number(totalPaymentInDollars) / 1000.0 + ).toLocaleString(undefined, { + maximumFractionDigits: 2 + })}K` + : `$${Number( + Number(totalPaymentInDollars) / 1000000.0 + ).toLocaleString(undefined, { + maximumFractionDigits: 2 + })}M`} + + + + {totalPaymentInPercentageNationwide + ? `${totalPaymentInPercentageNationwide} %` + : "0%"} + + + + + ); + const fillColour = () => { + if (totalPaymentInDollars) { + if (totalPaymentInDollars !== 0) return colorScale(totalPaymentInDollars); + return "#D2D2D2"; + } + return "#D2D2D2"; + }; + return ( + { + setTooltipContent(hoverContent); + }} + onMouseLeave={() => { + setTooltipContent(""); + }} + fill={fillColour()} + stroke="#FFF" + style={{ + default: { stroke: "#FFFFFF", strokeWidth: 0.75, outline: "none" }, + hover: { + stroke: "#232323", + strokeWidth: 2, + outline: "none" + }, + pressed: { + fill: "#345feb", + outline: "none" + } + }} + /> + ); + })} + {geographies.map((geo) => { + const centroid = geoCentroid(geo); + const cur = allStates.find((s) => s.val === geo.id); + return ( + + {cur && + centroid[0] > -160 && + centroid[0] < -67 && + (Object.keys(offsets).indexOf(cur.id) === -1 ? ( + + + {cur.id} + + + ) : ( + + + {cur.id} + + + ))} + + ); + })} + + )} + + + ) : ( + +

Loading Map Data...

+
+ )} +
+ ); +}; + +MapChart.propTypes = { + setTooltipContent: PropTypes.func, + maxValue: PropTypes.number +}; + +const CSPTotalMap = ({ statePerformance, allStates }: { statePerformance: any; allStates: any }): JSX.Element => { + const quantizeArray: number[] = []; + Object.values(statePerformance).map((value) => { + if (Array.isArray(value)) { + quantizeArray.push(value[0].totalPaymentInDollars); + } + return null; + }); + const maxValue = Math.max(...quantizeArray); + const label1 = (maxValue / 5) * 0; + const label2 = (maxValue / 5) * 1; + const label3 = (maxValue / 5) * 2; + const label4 = (maxValue / 5) * 3; + const label5 = (maxValue / 5) * 4; + const [content, setContent] = useState(""); + + return ( +
+
+ + + + + + +
+ + {content} + +
+
+
+ ); +}; + +export default CSPTotalMap; diff --git a/src/components/csp/CSPTotalTable.tsx b/src/components/csp/CSPTotalTable.tsx new file mode 100644 index 00000000..9325f37e --- /dev/null +++ b/src/components/csp/CSPTotalTable.tsx @@ -0,0 +1,208 @@ +import React from "react"; +import styled from "styled-components"; +import { useTable, useSortBy } from "react-table"; +import Box from "@mui/material/Box"; +import "../../styles/table.css"; +import { config } from "../../app.config"; +import { getJsonDataFromUrl } from "../../utils/apiutil"; + +const Styles = styled.div` + padding: 1rem; + + table { + border-spacing: 0; + border: 1px solid #e4ebe7; + border-left: none; + border-right: none; + + tr { + :last-child { + td { + border-bottom: 0; + } + } + } + + th { + background-color: #f1f1f1; + padding: 1rem; + } + + td { + margin: 0; + padding: 1rem; + padding-left: 5rem; + padding-right: 5rem; + border-bottom: 1px solid #e4ebe7; + border-right: none; + + :last-child { + border-right: 0; + } + } + } +`; + +// eslint-disable-next-line +function Table({ columns, data }: { columns: any; data: any }) { + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable( + { + columns, + data + }, + useSortBy + ); + + const firstPageRows = rows.slice(0, 50); + + return ( + <> + + + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + // Add the sorting props to control sorting. + + ))} + + ))} + + + { + // eslint-disable-next-line + firstPageRows.map((row, i) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => { + return ( + + ); + })} + + ); + }) + } + +
+ + {column.render("Header")} +
+ {(() => { + if (!column.isSorted) return {"\u{2B83}"}; + if (column.isSortedDesc) return {"\u{25BC}"}; + return {"\u{25B2}"}; + })()} +
+
+
+ {cell.render("Cell")} +
+
+
+ Showing the first {rows.length} results of {rows.length} rows +
+ + ); +} + +function App(): JSX.Element { + const [statePerformance, setStatePerformance] = React.useState([]); + const [allStates, setAllStates] = React.useState([]); + + // TBD: due to the time limited, leave this + React.useEffect(() => { + const allprograms_url = `${config.apiUrl}/programs/conservation/csp/state-distribution`; + getJsonDataFromUrl(allprograms_url).then((response) => { + setStatePerformance(response); + }); + const allstates_url = `${config.apiUrl}/states`; + getJsonDataFromUrl(allstates_url).then((response) => { + setAllStates(response); + }); + }, []); + + function compareWithDollarSign(rowA, rowB, id, desc) { + const a = Number.parseFloat(rowA.values[id].substring(1).replaceAll(",", "")); + const b = Number.parseFloat(rowB.values[id].substring(1).replaceAll(",", "")); + if (a > b) return 1; + if (a < b) return -1; + return 0; + } + + function compareWithPercentSign(rowA, rowB, id, desc) { + const a = Number.parseFloat(rowA.values[id].replaceAll("%", "")); + const b = Number.parseFloat(rowB.values[id].replaceAll("%", "")); + if (a > b) return 1; + if (a < b) return -1; + return 0; + } + + const cspTableData: any[] = []; + + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of Object.entries(statePerformance)) { + const newRecord = () => { + return { + state: key, + cspBenefit: `$${value[0].totalPaymentInDollars + .toLocaleString(undefined, { minimumFractionDigits: 2 }) + .toString()}`, + percentage: `${value[0].totalPaymentInPercentageNationwide.toString()}%` + }; + }; + cspTableData.push(newRecord()); + } + + const columns = React.useMemo( + () => [ + { + Header: STATES, + accessor: "state", + paddingLeft: "5rem", + paddingRight: "32rem" + }, + { + Header: ( + + CSP BENEFITS + + ), + accessor: "cspBenefit", + sortType: compareWithDollarSign, + Cell: function styleCells(row) { + return
{row.value}
; + } + }, + { + Header: PCT. NATIONWIDE, + accessor: "percentage", + sortType: compareWithPercentSign, + Cell: function styleCells(row) { + return
{row.value}
; + } + } + ], + [] + ); + + return ( + + + + + + ); +} + +export default App; diff --git a/src/components/csp/CategoryMap.tsx b/src/components/csp/CategoryMap.tsx new file mode 100644 index 00000000..49c49114 --- /dev/null +++ b/src/components/csp/CategoryMap.tsx @@ -0,0 +1,323 @@ +import React, { useEffect, useState } from "react"; +import { geoCentroid } from "d3-geo"; +import { ComposableMap, Geographies, Geography, Marker, Annotation } from "react-simple-maps"; +import ReactTooltip from "react-tooltip"; +import { scaleQuantile, scaleQuantize } from "d3-scale"; +import Divider from "@mui/material/Divider"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import PropTypes from "prop-types"; +import "../../styles/map.css"; +import HorizontalStackedBar from "../HorizontalStackedBar"; + +const geoUrl = "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json"; + +const offsets = { + VT: [50, -8], + NH: [34, 2], + MA: [30, -1], + RI: [28, 2], + CT: [35, 10], + NJ: [34, 1], + DE: [33, 0], + MD: [47, 10], + DC: [49, 21] +}; + +const MapChart = (props) => { + const { setTooltipContent, category, maxValue, allStates, statePerformance } = props; + const colorScale = scaleQuantize() + .domain([0, maxValue]) + .range(["#F0F9E8", "#BAE4BC", "#7BCCC4", "#43A2CA", "#0868AC"]); + let categoryRecord; + return ( +
+ + + {({ geographies }) => ( + <> + {geographies.map((geo) => { + if (!Object.keys(statePerformance).includes(geo.properties.name)) { + return null; + } + const statuteRecord = statePerformance[geo.properties.name][0].statutes; + const ACur = statuteRecord.find((s) => s.statuteName === "2018 Practices"); + const AArray = ACur.practiceCategories; + const BCur = statuteRecord.find((s) => s.statuteName === "2014 Eligible Land"); + const BArray = BCur.practiceCategories; + const TotalArray = AArray.concat(BArray); + if (category === "2018 Practices") { + categoryRecord = statuteRecord[0]; + } else if (category === "2014 Eligible Land") { + categoryRecord = statuteRecord[1]; + } else { + categoryRecord = TotalArray.find((s) => s.practiceCategoryName === category); + } + const categoryPayment = + category === "2018 Practices" || category === "2014 Eligible Land" + ? categoryRecord.statutePaymentInDollars + : categoryRecord.paymentInDollars; + const nationwidePercentage = + category === "2018 Practices" || category === "2014 Eligible Land" + ? categoryRecord.statutePaymentInPercentageNationwide + : categoryRecord.paymentInPercentageNationwide; + const withinStatePercentage = + category === "2018 Practices" || category === "2014 Eligible Land" + ? categoryRecord.statutePaymentInPercentageWithinState + : categoryRecord.paymentInPercentageWithinState; + const hoverContent = ( + + + {geo.properties.name} + + + {Number(categoryPayment) < 1000000 + ? `$${Number(Number(categoryPayment) / 1000.0).toLocaleString( + undefined, + { + maximumFractionDigits: 2 + } + )}K` + : `$${Number( + Number(categoryPayment) / 1000000.0 + ).toLocaleString(undefined, { + maximumFractionDigits: 2 + })}M`} + + + + {nationwidePercentage ? `${nationwidePercentage} %` : "0%"} + + + + + ); + const fillColour = () => { + if (categoryPayment) { + if (categoryPayment !== 0) return colorScale(categoryPayment); + return "#D2D2D2"; + } + return "#D2D2D2"; + }; + return ( + { + setTooltipContent(hoverContent); + }} + onMouseLeave={() => { + setTooltipContent(""); + }} + fill={fillColour()} + stroke="#FFFFFF" + style={{ + default: { stroke: "#FFFFFF", strokeWidth: 0.75, outline: "none" }, + hover: { + stroke: "#232323", + strokeWidth: 2, + outline: "none" + }, + pressed: { + fill: "#345feb", + outline: "none" + } + }} + /> + ); + })} + {geographies.map((geo) => { + const centroid = geoCentroid(geo); + const cur = allStates.find((s) => s.val === geo.id); + return ( + + {cur && + centroid[0] > -160 && + centroid[0] < -67 && + (Object.keys(offsets).indexOf(cur.id) === -1 ? ( + + + {cur.id} + + + ) : ( + + + {cur.id} + + + ))} + + ); + })} + + )} + + +
+ ); +}; + +MapChart.propTypes = { + setTooltipContent: PropTypes.func, + category: PropTypes.string, + maxValue: PropTypes.number +}; + +const CategoryMap = ({ + category, + statePerformance, + allStates +}: { + category: string; + statePerformance: any; + allStates: any; +}): JSX.Element => { + const [content, setContent] = useState(""); + const title = `${category} Benefits`; + const quantizeArray: number[] = []; + let categoryRecord = {}; + Object.values(statePerformance).map((value) => { + if (Array.isArray(value)) { + const statuteRecord = value[0].statutes; + const ACur = statuteRecord.find((s) => s.statuteName === "2018 Practices"); + const AArray = ACur.practiceCategories; + const BCur = statuteRecord.find((s) => s.statuteName === "2014 Eligible Land"); + const BArray = BCur.practiceCategories; + const TotalArray = AArray.concat(BArray); + if (category === "2018 Practices") { + categoryRecord = statuteRecord[0]; + } else if (category === "2014 Eligible Land") { + categoryRecord = statuteRecord[1]; + } else { + categoryRecord = TotalArray.find((s) => s.practiceCategoryName === category); + } + if (categoryRecord !== undefined) { + if (category === "2018 Practices" || category === "2014 Eligible Land") + quantizeArray.push(categoryRecord.statutePaymentInDollars); + else quantizeArray.push(categoryRecord.paymentInDollars); + } + } + return null; + }); + const maxValue = Math.max(...quantizeArray); + const label1 = (maxValue / 5) * 0; + const label2 = (maxValue / 5) * 1; + const label3 = (maxValue / 5) * 2; + const label4 = (maxValue / 5) * 3; + const label5 = (maxValue / 5) * 4; + return ( +
+ {maxValue !== 0 ? ( + + = 1000000 + ? `$${Number(label2 / 1000000).toLocaleString(undefined, { + maximumFractionDigits: 0 + })}M` + : `$${Number(label2 / 1000.0).toLocaleString(undefined, { + maximumFractionDigits: 1 + })}K` + } + label3={ + label3 >= 1000000 + ? `$${Number(label3 / 1000000).toLocaleString(undefined, { + maximumFractionDigits: 0 + })}M` + : `$${Number(label3 / 1000.0).toLocaleString(undefined, { + maximumFractionDigits: 1 + })}K` + } + label4={ + label4 >= 1000000 + ? `$${Number(label4 / 1000000).toLocaleString(undefined, { + maximumFractionDigits: 0 + })}M` + : `$${Number(label4 / 1000.0).toLocaleString(undefined, { + maximumFractionDigits: 1 + })}K` + } + label5={ + label5 >= 1000000 + ? `$${Number(label5 / 1000000).toLocaleString(undefined, { + maximumFractionDigits: 0 + })}M` + : `$${Number(label5 / 1000.0).toLocaleString(undefined, { + maximumFractionDigits: 1 + })}K` + } + label6={ + maxValue >= 1000000 + ? `$${Number(maxValue / 1000000).toLocaleString(undefined, { + maximumFractionDigits: 0 + })}M` + : `$${Number(maxValue / 1000.0).toLocaleString(undefined, { + maximumFractionDigits: 1 + })}K` + } + /> + + ) : ( + + + + {title} + + + + + {title} data is unavailable for all states. + + + + )} + +
+ + {content} + +
+
+ ); +}; + +export default CategoryMap; diff --git a/src/components/csp/CategoryTable.tsx b/src/components/csp/CategoryTable.tsx new file mode 100644 index 00000000..b8ef58c9 --- /dev/null +++ b/src/components/csp/CategoryTable.tsx @@ -0,0 +1,299 @@ +import React from "react"; +import styled from "styled-components"; +import { useTable, useSortBy } from "react-table"; +import Box from "@mui/material/Box"; +import "../../styles/table.css"; + +const Styles = styled.div` + padding: 1rem; + + table { + border-spacing: 0; + border: 1px solid #e4ebe7; + border-left: none; + border-right: none; + + tr { + :last-child { + td { + border-bottom: 0; + } + } + } + + th { + background-color: #f1f1f1; + padding-top: 1rem; + padding-bottom: 1rem; + } + + td { + margin: 0; + padding: 0rem; + padding-left: 3rem; + padding-right: 3rem; + border-bottom: 1px solid #e4ebe7; + border-right: none; + + :last-child { + border-right: 2rem; + } + } + } +`; + +// eslint-disable-next-line +function Table({ columns, data, statePerformance }: { columns: any; data: any; statePerformance: any }) { + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable( + { + columns, + data + }, + useSortBy + ); + + const firstPageRows = rows.slice(0, 50); + + return ( + <> +
+ + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + // Add the sorting props to control sorting. + + ))} + + ))} + + + { + // eslint-disable-next-line + firstPageRows.map((row, i) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => { + return ( + + ); + })} + + ); + }) + } + +
+ + {column.render("Header")} +
+ {(() => { + if (!column.isSorted) return {"\u{2B83}"}; + if (column.isSortedDesc) return {"\u{25BC}"}; + return {"\u{25B2}"}; + })()} +
+
+
+ {cell.render("Cell")} +
+
+
+ Showing the first {rows.length} results of {rows.length} rows +
+ + ); +} + +function App({ category, statePerformance }: { category: string; statePerformance: any }): JSX.Element { + const cspTableData: any[] = []; + let categoryRecord = []; + // eslint-disable-next-line no-restricted-syntax + for (const [key, value] of Object.entries(statePerformance)) { + if (Array.isArray(value)) { + const statuteRecord = value[0].statutes; + const ACur = statuteRecord.find((s) => s.statuteName === "2018 Practices"); + const AArray = ACur.practiceCategories; + const BCur = statuteRecord.find((s) => s.statuteName === "2014 Eligible Land"); + const BArray = BCur.practiceCategories; + const TotalArray = AArray.concat(BArray); + if (category === "2018 Practices") { + categoryRecord = statuteRecord[0]; + } else if (category === "2014 Eligible Land") { + categoryRecord = statuteRecord[1]; + } else { + categoryRecord = TotalArray.find((s) => s.practiceCategoryName === category); + } + if (categoryRecord !== undefined) { + const paymentInDollars = + category === "2018 Practices" || category === "2014 Eligible Land" + ? categoryRecord.statutePaymentInDollars + : categoryRecord.paymentInDollars; + const paymentInPercentageWithinState = + category === "2018 Practices" || category === "2014 Eligible Land" + ? categoryRecord.statutePaymentInPercentageWithinState + : categoryRecord.paymentInPercentageWithinState; + const newRecord = () => { + return { + state: key, + categoryBenefit: `$${Number(paymentInDollars).toLocaleString(undefined, { + minimumFractionDigits: 2 + })}`, + categoryPercentage: `${paymentInPercentageWithinState.toString()}%`, + cspBenefit: `$${value[0].totalPaymentInDollars.toLocaleString(undefined, { + minimumFractionDigits: 2 + })}`, + percentage: `${value[0].totalPaymentInPercentageNationwide.toString()}%` + }; + }; + cspTableData.push(newRecord()); + } + } + } + + function compareWithDollarSign(rowA, rowB, id, desc) { + const a = Number.parseFloat(rowA.values[id].substring(1).replaceAll(",", "")); + const b = Number.parseFloat(rowB.values[id].substring(1).replaceAll(",", "")); + if (a > b) return 1; + if (a < b) return -1; + return 0; + } + + function compareWithPercentSign(rowA, rowB, id, desc) { + const a = Number.parseFloat(rowA.values[id].replaceAll("%", "")); + const b = Number.parseFloat(rowB.values[id].replaceAll("%", "")); + if (a > b) return 1; + if (a < b) return -1; + return 0; + } + + const columns = React.useMemo( + () => [ + { + Header: ( + + STATES + + ), + accessor: "state", + Cell: function styleCells(props: { + value: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; + }) { + return ( +
+ + {props.value} + +
+ ); + } + }, + { + Header: ( + + {`${category} Benefit`.toUpperCase()} + + ), + accessor: "categoryBenefit", + sortType: compareWithDollarSign, + Cell: function styleCells(props: { + value: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; + }) { + return ( +
+ + {props.value} + +
+ ); + } + }, + { + Header: ( + + {`${category} Percentage Within State`.toUpperCase()} + + ), + accessor: "categoryPercentage", + sortType: compareWithPercentSign, + Cell: function styleCells(props: { + value: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; + }) { + return ( +
+ + {props.value} + +
+ ); + } + }, + { + Header: ( + + CSP BENEFITS + + ), + accessor: "cspBenefit", + sortType: compareWithDollarSign, + Cell: function styleCells(row) { + return
{row.value}
; + } + }, + { + Header: PCT. NATIONWIDE, + accessor: "percentage", + sortType: compareWithPercentSign, + Cell: function styleCells(row) { + return
{row.value}
; + } + } + ], + [] + ); + + return ( + + + + + + ); +} + +export default App; diff --git a/src/components/eqip/CategoryMap.tsx b/src/components/eqip/CategoryMap.tsx index 31f42f03..4b7bda73 100644 --- a/src/components/eqip/CategoryMap.tsx +++ b/src/components/eqip/CategoryMap.tsx @@ -101,7 +101,7 @@ const MapChart = ({ setTooltipContent, category, maxValue }) => { onMouseLeave={() => { setTooltipContent(""); }} - fill={colorScale(categoryPayment)} + fill={colorScale(categoryPayment || { value: 0 }) || "#D2D2D2"} stroke="#FFF" style={{ default: { stroke: "#FFFFFF", strokeWidth: 0.75, outline: "none" }, diff --git a/src/components/eqip/EqipTotalMap.tsx b/src/components/eqip/EQIPTotalMap.tsx similarity index 98% rename from src/components/eqip/EqipTotalMap.tsx rename to src/components/eqip/EQIPTotalMap.tsx index 0e56f1d3..513929cc 100644 --- a/src/components/eqip/EqipTotalMap.tsx +++ b/src/components/eqip/EQIPTotalMap.tsx @@ -95,7 +95,7 @@ const MapChart = ({ setTooltipContent, maxValue }) => { onMouseLeave={() => { setTooltipContent(""); }} - fill={colorScale(totalPaymentInDollars)} + fill={colorScale(totalPaymentInDollars || { value: 0 }) || "#D2D2D2"} stroke="#FFF" style={{ default: { stroke: "#FFFFFF", strokeWidth: 0.75, outline: "none" }, @@ -153,7 +153,7 @@ MapChart.propTypes = { maxValue: PropTypes.number }; -const EqipTotalMap = (): JSX.Element => { +const EQIPTotalMap = (): JSX.Element => { const quantizeArray: number[] = []; Object.values(statePerformance).map((value) => quantizeArray.push(value[0].totalPaymentInDollars)); const maxValue = Math.max(...quantizeArray); @@ -203,4 +203,4 @@ const EqipTotalMap = (): JSX.Element => { ); }; -export default EqipTotalMap; +export default EQIPTotalMap; diff --git a/src/main.tsx b/src/main.tsx index f1c96b71..17a4176a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from "react"; import { Routes, Route, useLocation } from "react-router-dom"; import LandingPage from "./pages/LandingPage"; import EQIPPage from "./pages/EQIPPage"; +import CSPPage from "./pages/CSPPage"; import SNAPPage from "./pages/SNAPPage"; const ScrollToTop = (props: any) => { @@ -18,7 +19,8 @@ export default function Main(): JSX.Element { } /> } /> - } /> + } /> + {/* } /> */} ); diff --git a/src/pages/CSPPage.tsx b/src/pages/CSPPage.tsx new file mode 100644 index 00000000..333468f8 --- /dev/null +++ b/src/pages/CSPPage.tsx @@ -0,0 +1,448 @@ +import Box from "@mui/material/Box"; +import * as React from "react"; +import { createTheme, ThemeProvider, Typography } from "@mui/material"; +import NavBar from "../components/NavBar"; +import Drawer from "../components/ProgramDrawer"; +import SemiDonutChart from "../components/SemiDonutChart"; +import DataTable from "../components/csp/CSPTotalTable"; +import CSPTotalMap from "../components/csp/CSPTotalMap"; +import CategoryTable from "../components/csp/CategoryTable"; +import CategoryMap from "../components/csp/CategoryMap"; +import { config } from "../app.config"; +import { getJsonDataFromUrl } from "../utils/apiutil"; + +export default function CSPPage(): JSX.Element { + const [checked, setChecked] = React.useState(0); + const [statePerformance, setStatePerformance] = React.useState({}); + const [allStates, setAllStates] = React.useState([]); + const [totalChartData, setTotalChartData] = React.useState([{}]); + const [old2014ChartData, setOld2014ChartData] = React.useState([{}]); + const [new2018ChartData, setNew2018ChartData] = React.useState([{}]); + const [firstTotal, setFirstTotal] = React.useState(0); + const [secondTotal, setSecondTotal] = React.useState(0); + const [zeroCategories, setZeroCategories] = React.useState([]); + + const defaultTheme = createTheme(); + let landManagementTotal = 0; + let otherImprovementTotal = 0; + let vegetativeTotal = 0; + let forestManagementTotal = 0; + let soilRemediationTotal = 0; + let existingAPTotal = 0; + let structuralTotal = 0; + let croplandTotal = 0; + let rangelandTotal = 0; + let bundlesTotal = 0; + let soilTestingTotal = 0; + let NIPFTotal = 0; + let pasturelandTotal = 0; + let SAOTotal = 0; + let grasslandTotal = 0; + let new2018Total = 0; + let old2014Total = 0; + const zeroCategory = []; + + React.useEffect(() => { + const allprograms_url = `${config.apiUrl}/programs/conservation/csp/state-distribution`; + getJsonDataFromUrl(allprograms_url).then((response) => { + setStatePerformance(response); + }); + + const allstates_url = `${config.apiUrl}/states`; + getJsonDataFromUrl(allstates_url).then((response) => { + setAllStates(response); + }); + + const chartData_url = `${config.apiUrl}/programs/conservation/csp/practice-categories`; + getJsonDataFromUrl(chartData_url).then((response) => { + processData(response); + }); + }, []); + + const processData = (chartData) => { + if (chartData.statutes === undefined) return; + + // eslint-disable-next-line + const cur1 = chartData.statutes.find((s) => s.statuteName === "2018 Practices"); + const cur2 = chartData.statutes.find((s) => s.statuteName === "2014 Eligible Land"); + new2018Total = cur1.totalPaymentInDollars; + old2014Total = cur2.totalPaymentInDollars; + setFirstTotal(new2018Total); + setSecondTotal(old2014Total); + const ACur = cur1.practiceCategories; + const BCur = cur2.practiceCategories; + + const landManagementCur = ACur.find((s) => s.practiceCategoryName === "Land management"); + const otherImprovementCur = ACur.find((s) => s.practiceCategoryName === "Other improvement"); + const existingAPCur = ACur.find((s) => s.practiceCategoryName === "Existing activity payments"); + const vegetativeCur = ACur.find((s) => s.practiceCategoryName === "Vegetative"); + const forestManagementCur = ACur.find((s) => s.practiceCategoryName === "Forest management"); + const soilRemediationCur = ACur.find((s) => s.practiceCategoryName === "Soil remediation"); + const structuralCur = ACur.find((s) => s.practiceCategoryName === "Structural"); + const bundlesCur = ACur.find((s) => s.practiceCategoryName === "Bundles"); + const soilTestingCur = ACur.find((s) => s.practiceCategoryName === "Soil testing"); + + const croplandCur = BCur.find((s) => s.practiceCategoryName === "Cropland"); + const rangelandCur = BCur.find((s) => s.practiceCategoryName === "Rangeland"); + const pasturelandCur = BCur.find((s) => s.practiceCategoryName === "Pastureland"); + const SAOCur = BCur.find((s) => s.practiceCategoryName === "Other: supplemental, adjustment & other"); + const NIPFCur = BCur.find((s) => s.practiceCategoryName === "Non-industrial private forestland"); + const grasslandCur = BCur.find((s) => s.practiceCategoryName === "Grassland"); + + landManagementTotal += Number(landManagementCur.totalPaymentInDollars); + if (landManagementTotal === 0) zeroCategory.push("Land management"); + otherImprovementTotal += Number(otherImprovementCur.totalPaymentInDollars); + if (otherImprovementTotal === 0) zeroCategory.push("Other improvement"); + existingAPTotal += Number(existingAPCur.totalPaymentInDollars); + if (existingAPTotal === 0) zeroCategory.push("Existing activity payments"); + vegetativeTotal += Number(vegetativeCur.totalPaymentInDollars); + if (vegetativeTotal === 0) zeroCategory.push("Vegetative"); + forestManagementTotal += Number(forestManagementCur.totalPaymentInDollars); + if (forestManagementTotal === 0) zeroCategory.push("Forest management"); + soilRemediationTotal += Number(soilRemediationCur.totalPaymentInDollars); + if (soilRemediationTotal === 0) zeroCategory.push("Soil remediation"); + structuralTotal += Number(structuralCur.totalPaymentInDollars); + if (structuralTotal === 0) zeroCategory.push("Structural"); + bundlesTotal += Number(bundlesCur.totalPaymentInDollars); + if (bundlesTotal === 0) zeroCategory.push("Bundles"); + soilTestingTotal = Number(soilTestingCur.totalPaymentInDollars); + if (soilTestingTotal === 0) zeroCategory.push("Soil testing"); + + croplandTotal += Number(croplandCur.totalPaymentInDollars); + if (croplandTotal === 0) zeroCategory.push("Cropland"); + rangelandTotal += Number(rangelandCur.totalPaymentInDollars); + if (rangelandTotal === 0) zeroCategory.push("Rangeland"); + pasturelandTotal += Number(pasturelandCur.totalPaymentInDollars); + if (pasturelandTotal === 0) zeroCategory.push("Pastureland"); + SAOTotal += Number(SAOCur.totalPaymentInDollars); + if (SAOTotal === 0) zeroCategory.push("Other: supplemental, adjustment & other"); + NIPFTotal += Number(NIPFCur.totalPaymentInDollars); + if (NIPFTotal === 0) zeroCategory.push("Non-industrial private forestland"); + if (grasslandCur !== undefined) grasslandTotal += Number(grasslandCur.totalPaymentInDollars); + if (grasslandTotal === 0) zeroCategory.push("Grassland"); + + setNew2018ChartData([ + { name: "Land management", value: landManagementTotal, color: "#2F7164" }, + { name: "Other Improvement", value: otherImprovementTotal, color: "#4D847A" }, + { name: "Existing activity payments", value: existingAPTotal, color: "#869397" }, + { name: "Vegetative", value: vegetativeTotal, color: "#749F97" }, + { name: "Forest management", value: forestManagementTotal, color: "#9CBAB4" }, + { name: "Soil remediation", value: soilRemediationTotal, color: "#B9CDC9" }, + { name: "Structural", value: structuralTotal, color: "#CDDBD8" }, + { name: "Bundles", value: bundlesTotal, color: "#C3C5C4" }, + { name: "Soil Testing", value: soilTestingTotal, color: "#CAD4C5" } + ]); + + setOld2014ChartData([ + { name: "Cropland", value: croplandTotal, color: "#2F7164" }, + { name: "Rangeland", value: rangelandTotal, color: "#4D847A" }, + { name: "Pastureland", value: pasturelandTotal, color: "#749F97" }, + { name: "Other: supplemental, adjustment & other", value: SAOTotal, color: "#869397" }, + { name: "Non-industrial private forestland", value: NIPFTotal, color: "#9CBAB4" }, + { name: "Grassland", value: grasslandTotal, color: "#B9CDC9" } + ]); + + setTotalChartData([ + { name: "2018 Practices", value: new2018Total, color: "#2F7164" }, + { name: "2014 Eligible Land", value: old2014Total, color: "#9CBAB4" } + ]); + + setZeroCategories(zeroCategory); + }; + return ( + + {allStates.length > 0 && statePerformance.Wisconsin !== undefined ? ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSP: State Performance by Category + + + + CSP provides five-year annual contract payments to farmers in return for increasing, + improving or advancing conservation across the entire farm operation. + + + + {firstTotal >= 0 || secondTotal >= 0 ? ( +
+ + + + = 1 && checked <= 10 ? "block" : "none" }}> + + + = 11 ? "block" : "none" }}> + + +
+ ) : null} + + + + Performance by State + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ ) : ( +

Loading data...

+ )} +
+ ); +} diff --git a/src/pages/EQIPPage.tsx b/src/pages/EQIPPage.tsx index 2a2956c4..a829e6c7 100644 --- a/src/pages/EQIPPage.tsx +++ b/src/pages/EQIPPage.tsx @@ -5,7 +5,7 @@ import NavBar from "../components/NavBar"; import Drawer from "../components/ProgramDrawer"; import SemiDonutChart from "../components/SemiDonutChart"; import DataTable from "../components/eqip/EQIPTotalTable"; -import EqipTotalMap from "../components/eqip/EqipTotalMap"; +import EqipTotalMap from "../components/eqip/EQIPTotalMap"; import chartData from "../data/EQIP/EQIP_STATUTE_PERFORMANCE_DATA.json"; import CategoryTable from "../components/eqip/CategoryTable"; import CategoryMap from "../components/eqip/CategoryMap"; @@ -99,7 +99,7 @@ export default function EQIPPage(): JSX.Element { - + diff --git a/src/pages/SNAPPage.tsx b/src/pages/SNAPPage.tsx index 6e93d34a..b7a2066f 100644 --- a/src/pages/SNAPPage.tsx +++ b/src/pages/SNAPPage.tsx @@ -24,6 +24,7 @@ import NavSearchBar from "../components/shared/NavSearchBar"; import { hexToRGB } from "../components/shared/StyleFunctions"; import "../styles/snap.css"; import { config } from "../app.config"; +import { getJsonDataFromUrl } from "../utils/apiutil"; export default function SNAPPage(): JSX.Element { const paddingLR = 40; @@ -39,10 +40,9 @@ export default function SNAPPage(): JSX.Element { const [data, setData] = React.useState(null); React.useEffect(() => { - fetch(`${config.apiUrl}/programs/snap/state-distribution`) - .then((response) => response.json()) - .then((d) => setData(d)) - .catch((error) => console.error(error)); + getJsonDataFromUrl(`${config.apiUrl}/programs/snap/state-distribution`).then((response) => { + setData(response); + }); }, []); const defaultTheme = createTheme({ spacing: 8 diff --git a/src/utils/apiutil.js b/src/utils/apiutil.tsx similarity index 100% rename from src/utils/apiutil.js rename to src/utils/apiutil.tsx