From 0216f8879440ce73d90a9e58cc5eac68240e9fdd Mon Sep 17 00:00:00 2001 From: Galen Guyer Date: Fri, 29 Oct 2021 12:19:15 -0400 Subject: add static data for 2020-2021 school year --- src/App.css | 15 ++++ src/App.js | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ src/App.test.js | 8 ++ src/Card.css | 10 +++ src/Card.js | 25 ++++++ src/GoatCounter.js | 26 ++++++ src/History.js | 82 +++++++++++++++++++ src/HistoryTable.js | 40 +++++++++ src/MainPage.js | 126 +++++++++++++++++++++++++++++ src/index.css | 15 ++++ src/index.js | 22 +++++ src/logo.svg | 7 ++ src/reportWebVitals.js | 13 +++ src/setupTests.js | 5 ++ 14 files changed, 609 insertions(+) create mode 100644 src/App.css create mode 100644 src/App.js create mode 100644 src/App.test.js create mode 100644 src/Card.css create mode 100644 src/Card.js create mode 100644 src/GoatCounter.js create mode 100644 src/History.js create mode 100644 src/HistoryTable.js create mode 100644 src/MainPage.js create mode 100644 src/index.css create mode 100644 src/index.js create mode 100644 src/logo.svg create mode 100644 src/reportWebVitals.js create mode 100644 src/setupTests.js (limited to 'src') diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..78106d4 --- /dev/null +++ b/src/App.css @@ -0,0 +1,15 @@ +.App { + text-align: center; + padding-bottom: 2rem; + padding-top: 1rem; + width: 90%; + margin-left: auto; + margin-right: auto; +} + +.Section { + display: flex; + justify-content: center; + margin-left: auto; + margin-right: auto; +} diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..fd5e6d0 --- /dev/null +++ b/src/App.js @@ -0,0 +1,215 @@ +import React from "react"; +import useSWR from "swr"; +import { DateTime } from "luxon"; +import { BrowserRouter, Route, Switch, Link } from "react-router-dom"; +import MainPage from "./MainPage"; +import History from "./History"; +import HistoryTable from "./HistoryTable"; +import "./App.css"; + +const url = "/data.json"; + +function App() { + let { data: rawData, error: error } = useSWR(url); + + const [timeDifference, setTimeDifference] = React.useState(1); + const [showAllTime, setShowAllTime] = React.useState(false); + + if (error) + return ( +
+

RIT Covid Dashboard

+

An error occurred

+
+ ); + if (!rawData) + return ( +
+

RIT Covid Dashboard

+

Loading latest data...

+
+ ); + + // rawData = rawData.slice(0, 177); + let data = rawData; + console.log(data.length); + const local = DateTime.local().zoneName; + const semesterStart = DateTime.fromISO("2021-01-01"); + // if (!showAllTime) { + // data = rawData.filter((d) => { + // let date = DateTime.fromSQL(d.last_updated, { zone: "UTC" }).setZone(local); + // return date > semesterStart; + // }); + // const last = rawData[rawData.length - data.length - 1]; + // data = data.map((d) => { + // return { + // alert_level: d.alert_level, + // beds_available: d.beds_available, + // isolation_off_campus: d.isolation_off_campus, + // isolation_on_campus: d.isolation_on_campus, + // last_updated: d.last_updated, + // new_staff: d.new_staff, + // new_students: d.new_students, + // quarantine_off_campus: d.quarantine_off_campus, + // quarantine_on_campus: d.quarantine_on_campus, + // tests_administered: d.tests_administered - last.tests_administered, + // total_staff: d.total_staff - last.total_staff, + // total_students: d.total_students - last.total_students, + // }; + // }); + // } + + const latest = data[data.length - 1]; + const prior = data[data.length - (1 + timeDifference)]; + return ( + +
+

+ RIT Covid Dashboard +

+ {/* +

+ Last Updated:{" "} + {lastUpdate.toLocaleString({ + weekday: "long", + month: "long", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + })} +

+

+ Prior Update:{" "} + {priorUpdate.toLocaleString({ + weekday: "long", + month: "long", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + })}{" "} + ({timeDifference == 1 ? "one day ago" : timeDifference == 5 ? "one week ago" : "two weeks ago"}) +

+ */} + {/* +   + */} +
+ + + + + + { + return { value: d.total_students, date: d.last_updated }; + })} + /> + + + { + return { value: d.total_staff, date: d.last_updated }; + })} + /> + + + { + return { value: d.new_students, date: d.last_updated }; + })} + /> + + + { + return { value: d.new_staff, date: d.last_updated }; + })} + /> + + + { + return { value: d.quarantine_on_campus, date: d.last_updated }; + })} + /> + + + { + return { value: d.quarantine_off_campus, date: d.last_updated }; + })} + /> + + + + { + return { value: d.isolation_on_campus, date: d.last_updated }; + })} + /> + + + { + return { value: d.isolation_off_campus, date: d.last_updated }; + })} + /> + + + { + return { value: d.tests_administered, date: d.last_updated }; + })} + /> + + + { + return { value: d.beds_available, date: d.last_updated }; + })} + /> + + +
+

+ By Galen Guyer. Source available on{" "} + + GitHub + {" "} + ( + + Report Issue + + ) +

+

+ + API Documentation + +

+
+
+ ); +} + +export default App; diff --git a/src/App.test.js b/src/App.test.js new file mode 100644 index 0000000..7c46384 --- /dev/null +++ b/src/App.test.js @@ -0,0 +1,8 @@ +import { render, screen } from "@testing-library/react"; +import App from "./App"; + +test("renders learn react link", () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/src/Card.css b/src/Card.css new file mode 100644 index 0000000..785b3e5 --- /dev/null +++ b/src/Card.css @@ -0,0 +1,10 @@ +.Card { + padding: 16px; + width: 40%; +} + +@media screen and (min-width: 768px) { + .Card { + width: 20%; + } +} diff --git a/src/Card.js b/src/Card.js new file mode 100644 index 0000000..a58f611 --- /dev/null +++ b/src/Card.js @@ -0,0 +1,25 @@ +import React from "react"; +import { Link } from "react-router-dom"; +import "./Card.css"; + +const Card = (props) => { + let diff = props.diff.toString(); + if (diff.charAt(0) != "-") { + diff = "+" + diff; + } + + return ( + +
+

+ + {props.latest}{" "} + +

+

{props.name}

+
+ + ); +}; + +export default Card; diff --git a/src/GoatCounter.js b/src/GoatCounter.js new file mode 100644 index 0000000..07a768a --- /dev/null +++ b/src/GoatCounter.js @@ -0,0 +1,26 @@ +import React from "react"; + +class GoatCounter extends React.Component { + componentDidMount() { + window.counter = "https://rcd.goatcounter.com/count"; + const script = window.document.createElement("script"); + script.async = 1; + script.src = "https://gc.zgo.at/count.js"; + script.id = "goatcounter"; + script.setAttribute("data-goatcounter", "https://rcd.goatcounter.com/count"); + (window.document.head || window.document.body).appendChild(script); + } + + componentWillUnmount() { + const script = window.document.getElementById("goatcounter"); + if (script) { + script.parentNode.removeChild(script); + } + } + + render() { + return null; + } +} + +export default GoatCounter; diff --git a/src/History.js b/src/History.js new file mode 100644 index 0000000..7425b61 --- /dev/null +++ b/src/History.js @@ -0,0 +1,82 @@ +import { React, PureComponent } from "react"; +import { DateTime } from "luxon"; +import { + BarChart, + Bar, + LineChart, + Line, + CartesianGrid, + XAxis, + YAxis, + Tooltip, + ResponsiveContainer, + Label, +} from "recharts"; +import GoatCounter from "./GoatCounter"; + +const History = (props) => { + const offset = DateTime.fromSQL(props.data[0].date, { zone: "UTC" }).setZone(DateTime.local().zoneName).toSeconds(); + const data = props.data.map((d) => { + return { + value: d.value, + date: DateTime.fromSQL(d.date, { zone: "UTC" }).setZone(DateTime.local().zoneName).toSeconds(), + }; + }); + + return ( + <> +

{props.name}

+ + + + } + height={90} + /> + + + + + + ); +}; + +class CustomizedAxisTick extends PureComponent { + render() { + const { x, y, payload } = this.props; + + return ( + + + {DateTime.fromSeconds(payload.value).toLocaleString()} + + + ); + } +} + +const CustomTooltip = ({ active, payload, label }) => { + if (active) { + return ( +
+

+ {DateTime.fromSeconds(label).toLocaleString({ weekday: "long", month: "long", day: "2-digit" })} +

+

{payload[0].value}

+
+ ); + } + return null; +}; + +export default History; diff --git a/src/HistoryTable.js b/src/HistoryTable.js new file mode 100644 index 0000000..fb27f0e --- /dev/null +++ b/src/HistoryTable.js @@ -0,0 +1,40 @@ +import { React } from "react"; +import { DateTime } from "luxon"; +import GoatCounter from "./GoatCounter"; + +const HistoryTable = (props) => { + const data = props.data; + console.log(data); + let table = ( + + + + + + + {data.map((element) => { + return ( + + + + + ); + })} + +
DatePositive Case Rate
+ {DateTime.fromSQL(element.date, { zone: "UTC" }) + .setZone(DateTime.local().zoneName) + .toLocaleString({ weekday: "long", month: "long", day: "2-digit" })} + {element.value}%
+ ); + + return ( + <> +

{props.name}

+ {table} + + + ); +}; + +export default HistoryTable; diff --git a/src/MainPage.js b/src/MainPage.js new file mode 100644 index 0000000..fcc2e0b --- /dev/null +++ b/src/MainPage.js @@ -0,0 +1,126 @@ +import React from "react"; +import Card from "./Card"; +import GoatCounter from "./GoatCounter"; + +const MainPage = (props) => { + const data = props.data; + const latest = data[data.length - 1]; + const prior = data[data.length - (1 + props.timeDifference)]; + + return ( + <> +

+ This site shows data from the 2020 Fall and 2021 Spring semesters. +

+
+
+

+ Total Positive Cases Since August 19 (First Day of Classes) +

+
+ + +
+
+
+
+

New Positive Cases From Past 14 Days

+
+ + +
+
+
+
+

Number of Students in Quarantine

+
+ Quarantine separates and restricts the movement of people who were exposed to a contagious disease + to see if they become sick. +
+
+ + +
+
+
+
+

Number of Students in Isolation

+
+ Isolation separates sick people with a contagious disease from people who are not sick. +
+
+ + +
+
+
+
+

Tests

+
+ +
+
+
+
+

Quarantine/Isolation Bed Availability On-campus

+
+ +
+
+ + + ); +}; + +export default MainPage; diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..868b6c6 --- /dev/null +++ b/src/index.css @@ -0,0 +1,15 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", + "Droid Sans", "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..4c1dc74 --- /dev/null +++ b/src/index.js @@ -0,0 +1,22 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { SWRConfig } from "swr"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; + +const fetcher = (...args) => fetch(...args).then((res) => res.json()); + +ReactDOM.render( + + + + + , + document.getElementById("root") +); + +// If you want to start measuring performance in your app, pass a function +// to log results (for example: reportWebVitals(console.log)) +// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals +reportWebVitals(); diff --git a/src/logo.svg b/src/logo.svg new file mode 100644 index 0000000..6b60c10 --- /dev/null +++ b/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/reportWebVitals.js b/src/reportWebVitals.js new file mode 100644 index 0000000..7dc6b90 --- /dev/null +++ b/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = (onPerfEntry) => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/src/setupTests.js b/src/setupTests.js new file mode 100644 index 0000000..1dd407a --- /dev/null +++ b/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import "@testing-library/jest-dom"; -- cgit v1.2.3