From c3b4b377795e10bdcdf40ff0980bfe4f120e103e Mon Sep 17 00:00:00 2001 From: Ryan Bagwell Date: Sat, 7 Aug 2021 09:39:21 -0400 Subject: [PATCH 1/2] add vaccinations to the ui --- gatsby-browser.js | 1 + gatsby-node.js | 72 ++++++++++++++++++++---- gatsby-ssr.js | 1 + src/components/App/index.js | 22 +++++++- src/components/VaccinationTable/index.js | 66 ++++++++++++++++++++++ src/stores/global.js | 10 +++- src/templates/index.js | 6 +- 7 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 src/components/VaccinationTable/index.js diff --git a/gatsby-browser.js b/gatsby-browser.js index 5b7f52c..91ec0da 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -6,6 +6,7 @@ export const wrapPageElement = ({ element, props }) => { {element} diff --git a/gatsby-node.js b/gatsby-node.js index f3db385..14dc0fa 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -17,6 +17,14 @@ const formatCaseCountNumber = n => { return n.replace(/[,]/gi, "") } +const trimAndParseInt = str => { + try { + return parseInt(str.trim().replace(",", "")) + } catch (err) { + return 0 + } +} + const parseReportDate = memoize(dateStr => { return parse(dateStr, "M/d/yy", new Date()) }) @@ -297,6 +305,46 @@ exports.createPages = async ({ graphql, actions }) => { }) }) + const vaccinations = results.data.vaccinations.nodes.reduce( + (final, current) => { + const { + town, + ageGroup, + population, + fullyVaccinated, + partiallyVaccinated, + } = current + + if (town === "Town") return final + + let color = "black" + try { + color = allNormalized[town].color + } catch (err) {} + + final[town] = final[town] || { + townName: town, + color: color, + totalEligible: 0, + totalFullyVaccinated: 0, + totalPartiallyVaccinated: 0, + } + + if (ageGroup !== "Total") { + final[town].totalEligible = + final[town].totalEligible + trimAndParseInt(population) + final[town].totalFullyVaccinated = + final[town].totalFullyVaccinated + trimAndParseInt(fullyVaccinated) + final[town].totalPartiallyVaccinated = + final[town].totalPartiallyVaccinated + + trimAndParseInt(partiallyVaccinated) + } + + return final + }, + {} + ) + const productTemplate = path.resolve(`src/templates/index.js`) createPage({ @@ -304,19 +352,21 @@ exports.createPages = async ({ graphql, actions }) => { component: productTemplate, context: { townCounts: allNormalized, + vaccinations, }, }) - //if (process.env.NODE_ENV === "production") { - Object.keys(populations).map(townName => { - createPage({ - path: `/${slugify(townName, { lower: true })}/`, - component: productTemplate, - context: { - townCounts: allNormalized, - townName: townName, - }, + if (process.env.NODE_ENV === "production") { + Object.keys(populations).map(townName => { + createPage({ + path: `/${slugify(townName, { lower: true })}/`, + component: productTemplate, + context: { + townCounts: allNormalized, + townName: townName, + vaccinations, + }, + }) }) - }) - //} + } } diff --git a/gatsby-ssr.js b/gatsby-ssr.js index 73ab133..e8158b0 100644 --- a/gatsby-ssr.js +++ b/gatsby-ssr.js @@ -6,6 +6,7 @@ export const wrapPageElement = ({ element, props }) => { {element} diff --git a/src/components/App/index.js b/src/components/App/index.js index f3783e0..047e4fe 100644 --- a/src/components/App/index.js +++ b/src/components/App/index.js @@ -1,14 +1,20 @@ import React from "react" import SearchBox from "../SearchBox" import { observer } from "mobx-react" +import { useStore } from "../../stores/global" import Header from "../Header" import Grid from "@material-ui/core/Grid" import FAQ from "../FAQ" import loadable from "@loadable/component" +import VaccinationTable from "../VaccinationTable" +import Box from "@material-ui/core/Box" +import Typography from "@material-ui/core/Typography" const Chart = loadable(() => import("../Chart")) -export default observer(() => { +export default observer(props => { + const { selectedTowns } = useStore() + return ( <> @@ -23,6 +29,20 @@ export default observer(() => { {typeof window !== "undefined" && } + {selectedTowns.length !== 0 && ( + + + + Vaccinations + + + + + )} { + const { selectedTowns, vaccinations } = useStore() + + const selectedTownsStr = JSON.stringify(selectedTowns) + + const towns = useMemo(() => { + const selectedTownNames = selectedTowns.map(st => st.town) + return Object.values(vaccinations).filter(({ townName }) => { + return selectedTownNames.indexOf(townName) > -1 + }) + }, [selectedTownsStr, vaccinations, selectedTowns]) + + return ( + + + + + + Town + Fully Vaccinated + Fully & Partially Vaccinated + + + + {towns.map( + ({ + townName, + color, + totalEligible, + totalFullyVaccinated, + totalPartiallyVaccinated, + }) => ( + + + {townName} + + + {Math.round((totalFullyVaccinated / totalEligible) * 100)}% + + + {Math.round( + ((totalFullyVaccinated + totalPartiallyVaccinated) / + totalEligible) * + 100 + )} + % + + + ) + )} + +
Percentage of eligible residents who are vaccinated
+
+ ) +}) diff --git a/src/stores/global.js b/src/stores/global.js index 2c900a0..d361e30 100644 --- a/src/stores/global.js +++ b/src/stores/global.js @@ -67,6 +67,8 @@ class GlobalStore { dataTypes = DATA_TYPES + vaccinations = {} + setTownCounts = (counts = []) => { this.townCounts = counts.reduce((final, current) => { final[current.town] = current @@ -137,9 +139,15 @@ const initializedGlobalStore = new GlobalStore() const storeContext = React.createContext(initializedGlobalStore) -export const GlobalStoreProvider = ({ initialTown, townCounts, children }) => { +export const GlobalStoreProvider = ({ + initialTown, + townCounts, + vaccinations, + children, +}) => { initializedGlobalStore.availableTowns = Object.values(townCounts) initializedGlobalStore.townCounts = townCounts + initializedGlobalStore.vaccinations = vaccinations if (initialTown) { initializedGlobalStore.selectedTowns = [ diff --git a/src/templates/index.js b/src/templates/index.js index a069130..8296a8c 100644 --- a/src/templates/index.js +++ b/src/templates/index.js @@ -5,9 +5,9 @@ import App from "../components/App" const getPageDescription = town => { if (town) { - return `Track and compare COVID-19 cases in ${town} and towns throughout Massachusetts.` + return `Track and compare COVID-19 cases and vaccinations in ${town} and towns throughout Massachusetts.` } else { - return `Track and compare COVID-19 cases towns throughout Massachusetts.` + return `Track and compare COVID-19 cases and vaccinations towns throughout Massachusetts.` } } @@ -17,7 +17,7 @@ const IndexPage = props => { From 8ed306bda4f9f65d22ace815f5b7f0abc77b5b9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Aug 2021 18:32:17 +0000 Subject: [PATCH 2/2] Bump path-parse from 1.0.6 to 1.0.7 Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/jbgutierrez/path-parse/releases) - [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7) --- updated-dependencies: - dependency-name: path-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 11642be..8345860 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10851,9 +10851,9 @@ path-key@^3.0.0, path-key@^3.1.0: integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-starts-with@^1.0.0: version "1.0.0"