From adcdb53864f370ec9abea30a8f1b6ecc9b4b3835 Mon Sep 17 00:00:00 2001 From: Alex McGuigan Date: Tue, 13 Apr 2021 20:25:32 -0400 Subject: [PATCH] Sandbox Graphs and Componentization (#75) * Add funnel chart dependency The funnel chart dependency tree is out of sync with other nivo dependencies, throwing an error when trying to install it. However, it seems like the upstream version numbers just weren't bumped, and the package works fine in my tests. I force installed it and was able to get a dummy funnel chart in the app. re #69 * Reorganzing the functions * common data pull * adding react router, adding new sandbox page * added treepmap to sandbox page * Created helper classes for turnaround times and fee ranges * timeline graph component * treemap component * filter using turnaround times * remove comments * fixed graph sizing * funnel and pie graphs * fucking sankey y'alllllllklklllllllllllll * adding node_modules to git ignore * adding fee bubble graph * Fee bubble is working * currency tooltip * fixing up some labels and tooltips * tweak my bubblessss Co-authored-by: Chris DeLuca --- .gitignore | 2 + browser/package-lock.json | 314 ++++++++++++++++++ browser/package.json | 4 + browser/src/App.js | 275 ++------------- .../{FoiaList.js => FoiaList/index.js} | 74 +---- browser/src/components/FoiaStatus.js | 31 -- browser/src/components/Footer/index.js | 16 + .../Graphs/FoiaFeeBubbleGraph/index.js | 74 +++++ .../components/Graphs/FoiaFeeGraph/index.js | 70 ++++ .../Graphs/FoiaStatusFunnelGraph/index.js | 89 +++++ .../Graphs/FoiaStatusPieGraph/index.js | 57 ++++ .../Graphs/FoiaStatusSankeyGraph/index.js | 104 ++++++ .../Graphs/FoiaStatusTreeGraph/index.js | 36 ++ .../temp-treemap-data.json | 0 .../Graphs/FoiaTimelineGraph/index.js | 67 ++++ browser/src/components/Header/index.js | 58 ++++ browser/src/pages/Home.js | 49 +++ browser/src/pages/Sandbox.js | 31 ++ browser/src/utils/FeeRange.js | 44 +++ browser/src/utils/FoiaStatus.js | 61 ++++ browser/src/utils/TurnaroundTime.js | 70 ++++ browser/src/utils/getMuckrockData.js | 15 + 22 files changed, 1200 insertions(+), 341 deletions(-) rename browser/src/components/{FoiaList.js => FoiaList/index.js} (66%) delete mode 100644 browser/src/components/FoiaStatus.js create mode 100644 browser/src/components/Footer/index.js create mode 100644 browser/src/components/Graphs/FoiaFeeBubbleGraph/index.js create mode 100644 browser/src/components/Graphs/FoiaFeeGraph/index.js create mode 100644 browser/src/components/Graphs/FoiaStatusFunnelGraph/index.js create mode 100644 browser/src/components/Graphs/FoiaStatusPieGraph/index.js create mode 100644 browser/src/components/Graphs/FoiaStatusSankeyGraph/index.js create mode 100644 browser/src/components/Graphs/FoiaStatusTreeGraph/index.js rename browser/src/{ => components/Graphs/FoiaStatusTreeGraph}/temp-treemap-data.json (100%) create mode 100644 browser/src/components/Graphs/FoiaTimelineGraph/index.js create mode 100644 browser/src/components/Header/index.js create mode 100644 browser/src/pages/Home.js create mode 100644 browser/src/pages/Sandbox.js create mode 100644 browser/src/utils/FeeRange.js create mode 100644 browser/src/utils/FoiaStatus.js create mode 100644 browser/src/utils/TurnaroundTime.js create mode 100644 browser/src/utils/getMuckrockData.js diff --git a/.gitignore b/.gitignore index 47fee6c..51a0705 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ server/src/datastore/data .env +.DS_Store +node_modules diff --git a/browser/package-lock.json b/browser/package-lock.json index 6d1f942..6ac63af 100644 --- a/browser/package-lock.json +++ b/browser/package-lock.json @@ -8,8 +8,11 @@ "version": "0.1.0", "dependencies": { "@nivo/bar": "^0.67.0", + "@nivo/circle-packing": "^0.67.0", "@nivo/core": "^0.67.0", "@nivo/funnel": "^0.67.0", + "@nivo/pie": "^0.67.0", + "@nivo/sankey": "^0.67.0", "@nivo/treemap": "^0.67.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", @@ -22,6 +25,7 @@ "react-async": "^10.0.1", "react-dom": "^16.13.1", "react-hamburger-menu": "^1.2.1", + "react-router-dom": "^5.2.0", "react-scripts": "3.4.3" }, "devDependencies": { @@ -1810,6 +1814,24 @@ "react": ">= 16.8.4 < 18.0.0" } }, + "node_modules/@nivo/circle-packing": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/circle-packing/-/circle-packing-0.67.0.tgz", + "integrity": "sha512-/ci7082YaabBL9axOjAW6SsxjynGEoYyvFopsh5eKlkGyAB4bWLLyiCm7R0Z5ZmFRiPInxZ+z5aAMZXmfr/wbg==", + "dependencies": { + "@nivo/colors": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-hierarchy": "^1.1.8", + "lodash": "^4.17.11", + "react-motion": "^0.5.2", + "recompose": "^0.30.0" + }, + "peerDependencies": { + "@nivo/core": "0.67.0", + "prop-types": ">= 15.5.10 < 16.0.0", + "react": ">= 16.8.4 < 18.0.0" + } + }, "node_modules/@nivo/colors": { "version": "0.67.0", "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.67.0.tgz", @@ -1883,6 +1905,41 @@ "react": ">= 16.8.4 < 18.0.0" } }, + "node_modules/@nivo/pie": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/pie/-/pie-0.67.0.tgz", + "integrity": "sha512-TYxwvX5xCPQ+vUOFAPjhvwWw++/HXdRzCm08RHCAWtH5iNPwMoALPh2cSawqcVFwxNPnh0xv/nLTKkZIq2N2dw==", + "dependencies": { + "@nivo/colors": "0.67.0", + "@nivo/legends": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-shape": "^1.3.5", + "lodash": "^4.17.11" + }, + "peerDependencies": { + "@nivo/core": "0.67.0", + "react": ">= 16.8.4 < 18.0.0" + } + }, + "node_modules/@nivo/sankey": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/sankey/-/sankey-0.67.0.tgz", + "integrity": "sha512-LpWI72eLbFj7OyLsL/ZROSsMMOYSo42B37S9QXABX97qByjxBAvTRfVbKCSya3fEo90KmpgHc7lLRZuBWrwCQw==", + "dependencies": { + "@nivo/colors": "0.67.0", + "@nivo/legends": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-sankey": "^0.12.1", + "d3-shape": "^1.3.5", + "lodash": "^4.17.11", + "react-spring": "9.0.0-rc.3" + }, + "peerDependencies": { + "@nivo/core": "0.67.0", + "prop-types": ">= 15.5.10 < 16.0.0", + "react": ">= 16.8.4 < 18.0.0" + } + }, "node_modules/@nivo/scales": { "version": "0.67.0", "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.67.0.tgz", @@ -5694,6 +5751,15 @@ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, "node_modules/d3-scale": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz", @@ -8180,6 +8246,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -10698,6 +10777,19 @@ "node": ">=4" } }, + "node_modules/mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/mini-css-extract-plugin": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", @@ -13791,6 +13883,64 @@ "react": "^0.14.9 || ^15.3.0 || ^16.0.0" } }, + "node_modules/react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router/node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/react-router/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/react-router/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/react-scripts": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.3.tgz", @@ -14328,6 +14478,11 @@ "node": ">=4" } }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -16300,6 +16455,16 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "node_modules/tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -16821,6 +16986,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -19394,6 +19564,19 @@ "recompose": "^0.30.0" } }, + "@nivo/circle-packing": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/circle-packing/-/circle-packing-0.67.0.tgz", + "integrity": "sha512-/ci7082YaabBL9axOjAW6SsxjynGEoYyvFopsh5eKlkGyAB4bWLLyiCm7R0Z5ZmFRiPInxZ+z5aAMZXmfr/wbg==", + "requires": { + "@nivo/colors": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-hierarchy": "^1.1.8", + "lodash": "^4.17.11", + "react-motion": "^0.5.2", + "recompose": "^0.30.0" + } + }, "@nivo/colors": { "version": "0.67.0", "resolved": "https://registry.npmjs.org/@nivo/colors/-/colors-0.67.0.tgz", @@ -19444,6 +19627,32 @@ "recompose": "^0.30.0" } }, + "@nivo/pie": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/pie/-/pie-0.67.0.tgz", + "integrity": "sha512-TYxwvX5xCPQ+vUOFAPjhvwWw++/HXdRzCm08RHCAWtH5iNPwMoALPh2cSawqcVFwxNPnh0xv/nLTKkZIq2N2dw==", + "requires": { + "@nivo/colors": "0.67.0", + "@nivo/legends": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-shape": "^1.3.5", + "lodash": "^4.17.11" + } + }, + "@nivo/sankey": { + "version": "0.67.0", + "resolved": "https://registry.npmjs.org/@nivo/sankey/-/sankey-0.67.0.tgz", + "integrity": "sha512-LpWI72eLbFj7OyLsL/ZROSsMMOYSo42B37S9QXABX97qByjxBAvTRfVbKCSya3fEo90KmpgHc7lLRZuBWrwCQw==", + "requires": { + "@nivo/colors": "0.67.0", + "@nivo/legends": "0.67.0", + "@nivo/tooltip": "0.67.0", + "d3-sankey": "^0.12.1", + "d3-shape": "^1.3.5", + "lodash": "^4.17.11", + "react-spring": "9.0.0-rc.3" + } + }, "@nivo/scales": { "version": "0.67.0", "resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.67.0.tgz", @@ -22503,6 +22712,15 @@ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" }, + "d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "requires": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, "d3-scale": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz", @@ -24497,6 +24715,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -26480,6 +26711,15 @@ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, "mini-css-extract-plugin": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", @@ -28991,6 +29231,60 @@ "raf": "^3.1.0" } }, + "react-router": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", + "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", + "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "react-scripts": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.4.3.tgz", @@ -29412,6 +29706,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -30985,6 +31284,16 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -31400,6 +31709,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/browser/package.json b/browser/package.json index 63f1a0e..fef5db4 100644 --- a/browser/package.json +++ b/browser/package.json @@ -5,8 +5,11 @@ "proxy": "http://server:3001", "dependencies": { "@nivo/bar": "^0.67.0", + "@nivo/circle-packing": "^0.67.0", "@nivo/core": "^0.67.0", "@nivo/funnel": "^0.67.0", + "@nivo/pie": "^0.67.0", + "@nivo/sankey": "^0.67.0", "@nivo/treemap": "^0.67.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", @@ -19,6 +22,7 @@ "react-async": "^10.0.1", "react-dom": "^16.13.1", "react-hamburger-menu": "^1.2.1", + "react-router-dom": "^5.2.0", "react-scripts": "3.4.3" }, "scripts": { diff --git a/browser/src/App.js b/browser/src/App.js index 957841b..0849d14 100644 --- a/browser/src/App.js +++ b/browser/src/App.js @@ -1,265 +1,44 @@ -import React, { useState } from "react"; +import React from "react"; import { useAsync } from "react-async"; -import FoiaList from "./components/FoiaList"; -import { ResponsiveBar } from "@nivo/bar"; -import { ResponsiveTreeMap } from "@nivo/treemap"; -import { DateTime } from "luxon"; -import HamburgerMenu from "react-hamburger-menu"; -import Drawer from "./components/Toolbar/Drawer/Drawer"; +import { + BrowserRouter as Router, + Switch, + Route +} from "react-router-dom"; +import Header from "./components/Header"; +import Footer from "./components/Footer"; +import Home from "./pages/Home"; +import Sandbox from "./pages/Sandbox"; +import getMuckrockData from "./utils/getMuckrockData"; import "normalize.css"; import "./astoria-tech-design.css"; import "./styles.css"; -async function getMuckrockData() { - // When in production, the API is at the same domain as the frontend - let latest; - if (process.env.REACT_APP_DEPLOYMENT_MODE === "production") { - latest = "/v1/latest"; - } else { - latest = "http://localhost:3001/v1/latest"; - } - - return await fetch(latest) - .then((response) => (response.ok ? response : Promise.reject(response))) - .then((response) => response.json()); -} function App() { const { data, error, isLoading } = useAsync({ promiseFn: getMuckrockData }); - const [menuOpen, setMenuOpen] = useState(false); if (isLoading) return

Loading…

; if (error) return
{JSON.stringify(error, null, 2)}
; if (!data) return

No data

; - const uniquePrices = new Set(); - const turnaroundTimes = new Map(); - turnaroundTimes.set("1–10", 0); - turnaroundTimes.set("11–30", 0); - turnaroundTimes.set("31–50", 0); - turnaroundTimes.set("51–100", 0); - turnaroundTimes.set("101–150", 0); - turnaroundTimes.set("151+", 0); - - data.foiaList.forEach((item) => { - if (item.foiaReq.datetime_done) { - const start = DateTime.fromISO(item.foiaReq.datetime_submitted); - const end = DateTime.fromISO(item.foiaReq.datetime_done); - const diff = Math.floor(end.diff(start, "days").toObject().days); - if (diff > 150) { - const prev = turnaroundTimes.get("151+"); - turnaroundTimes.set("151+", prev + 1); - } else if (diff > 100) { - const prev = turnaroundTimes.get("101–150"); - turnaroundTimes.set("101–150", prev + 1); - } else if (diff > 50) { - const prev = turnaroundTimes.get("51–100"); - turnaroundTimes.set("51–100", prev + 1); - } else if (diff > 30) { - const prev = turnaroundTimes.get("31–50"); - turnaroundTimes.set("31–50", prev + 1); - } else if (diff > 10) { - const prev = turnaroundTimes.get("11–30"); - turnaroundTimes.set("11–30", prev + 1); - } else { - const prev = turnaroundTimes.get("1–10"); - turnaroundTimes.set("1–10", prev + 1); - } - } - const price = parseFloat(item.foiaReq.price); - if (price <= 0) return false; - uniquePrices.add(price); - }); - - const prices = Array.from(uniquePrices) - .sort((first, second) => second - first) - .map((item) => { - return { - value: item, - id: item, - }; - }); - - const times = Array.from(turnaroundTimes).map((item) => { - return { - value: item[1], - id: item[0], - }; - }); - - // Temporary treemap data. - // Delete this call and associated file when statusGraphData is done. - // See file for data structure the graph expects. - const tmpdata = require("./temp-treemap-data.json"); - - const statuses = new Map(); - data.foiaList.forEach((item) => { - if (statuses.has(item.foiaReq.status)) { - statuses.set(item.foiaReq.status, statuses.get(item.foiaReq.status) + 1); - } else { - statuses.set(item.foiaReq.status, 1); - } - }); - - const statusGraphData = function statusGraphData() { - // Sweet math here. Return result when done. - return tmpdata; - }; - return ( <> -
-
- - setMenuOpen((prev) => { - return !prev; - }) - } - width={30} - height={15} - strokeWidth={2} - rotate={0} - color="black" - borderRadius={0} - animationDuration={0.1} - /> -
-
- - - - - - - - - - -

Track 50-a

-
- - setMenuOpen(false)} /> -
-
-

- Visualizing the process of requesting Freedom of Information Law - Requests from New York State Police Departments -

-

Explore the data

-

- In response to the Freedom of Information Law Requests, New York State - police departments have claimed to have no records (“no documents”) of - officer misconduct from the past 50 years. -

-

- The done status may not mean that the request was successful, Muckrock - is restarting some requests from the beginning after having previous - requests rejected. The appealing process means that the initial - request was rejected and that they are rewriting their argument and a - copy of the letter must go to the Committe on Open Government. A - lawsuit status indicates that the process has escalated to the - courtroom. -

-

Timeline of the Request Process

-
- -
-

- Agencies have five days to confirm a FOIL request, but are not held to - any timeline for how long it takes them to complete the request. -

-

Fees Charged by agency

-
- new Intl.NumberFormat('en-US',{style: 'currency', currency: 'USD'}).format(config.value)} - labelFormat={(num) => { - const numString = Math.round(num) + ''; - if (numString.length < 4) return `$${numString}`; - return `$${numString.slice(0, 3)}k`; - }} - axisLeft={null} - data={prices} - /> -
-

- Most agencies have not charged fees for their requests and it is not - clear how the fees are calculated when there is a required payment. -

-

About These Requests

-

- In June of 2020, New York’s Governor, Andrew Cuomo signed a bill - repealing section 50-a of the state’s Civil Rights law that had been - used to prevent police officer misconduct allegations and - investiagtions from being subject to freedom of information law - requests. Muckrock began sending FOIL requests to every police - department in New York state shortly after, and their site contains - the documents obtained and provides the data surrounding these - requests. -

-

- The team at Astoria Digital is using the data from these request to - create visualizations to show their process in real time. -

- - - -
- + +
+ + + + + + + + +