aboutsummaryrefslogtreecommitdiff
path: root/src/pages
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2022-07-11 17:10:23 -0400
committerGalen Guyer <galen@galenguyer.com>2022-07-11 17:10:23 -0400
commit935ef7d2f76cca7bc1f9840dc357de85f93a1ec2 (patch)
treecb8ee298a747d6084107266e5d2882e60a6b5daa /src/pages
parent3694bf061ecfe0f6733a0cb9028d044dfc8cf9d2 (diff)
Update for new dashboard frontend
Diffstat (limited to 'src/pages')
-rw-r--r--src/pages/Graph.css33
-rw-r--r--src/pages/Graph.jsx118
-rw-r--r--src/pages/Index.css32
-rw-r--r--src/pages/Index.jsx76
4 files changed, 259 insertions, 0 deletions
diff --git a/src/pages/Graph.css b/src/pages/Graph.css
new file mode 100644
index 0000000..8cb98ee
--- /dev/null
+++ b/src/pages/Graph.css
@@ -0,0 +1,33 @@
+.Title {
+ font-size: 2em;
+ margin-top: 24px;
+}
+
+.ToTheMoon {
+ -webkit-animation-duration: 0.5s;
+ animation-duration: 0.5s;
+ -webkit-animation-delay: 1.5s;
+ animation-delay: 1.5s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-name: fadeIn;
+ animation-name: fadeIn;
+}
+
+@-webkit-keyframes fadeIn {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+@keyframes fadeIn {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
diff --git a/src/pages/Graph.jsx b/src/pages/Graph.jsx
new file mode 100644
index 0000000..bbfa43d
--- /dev/null
+++ b/src/pages/Graph.jsx
@@ -0,0 +1,118 @@
+import { DateTime } from "luxon";
+import {
+ LineChart,
+ Line,
+ CartesianGrid,
+ XAxis,
+ YAxis,
+ Tooltip,
+ ReferenceLine,
+ ReferenceDot,
+ Label,
+} from "recharts";
+import "./Graph.css";
+
+const Graph = (props) => {
+ const { name, response, dataKey } = props;
+ const { data, loading, error } = response;
+
+ if (loading) {
+ return <div></div>;
+ }
+
+ const eventStyle = { fill: "#767676" };
+
+ const parsed = data.map((d) => {
+ return {
+ date: DateTime.fromSQL(d["last_updated"], { zone: "UTC" }).setZone(DateTime.local().zoneName).toSeconds(),
+ value: d[dataKey],
+ };
+ });
+
+ const latest = parsed[parsed.length - 1];
+ const prior = parsed[parsed.length - 2];
+ const toTheMoon = latest.value > prior.value + 1;
+
+ return (
+ <div>
+ <div className="Title">{name}</div>
+ <LineChart
+ style={{ marginLeft: "auto", marginRight: "auto" }}
+ width={window.innerWidth > 600 ? 750 : window.innerWidth * 0.9}
+ height={500}
+ margin={{ top: 15, right: 30, left: 0, bottom: 5 }}
+ data={parsed}
+ >
+ <Line type="monotone" dataKey="value" stroke="#CD8508" dot={false} />
+ <ReferenceLine
+ x={1644594525}
+ label={{
+ value: "Visitor Policy adjusted",
+ angle: -90,
+ style: eventStyle,
+ position: "left",
+ }}
+ />
+ <ReferenceLine
+ x={1647550274}
+ label={{
+ value: "Mask Mandate dropped",
+ angle: -90,
+ style: eventStyle,
+ position: "left",
+ }}
+ />
+ {}
+ <CartesianGrid strokeDasharray="3 3" />
+ {toTheMoon ? (
+ <ReferenceDot
+ x={latest["date"]}
+ y={latest["value"]}
+ r={0}
+ label={<Label className="ToTheMoon">🚀</Label>}
+ />
+ ) : null}
+ <XAxis
+ dataKey="date"
+ type="number"
+ tickCount={14}
+ domain={["dataMin", "dataMax"]}
+ tick={<CustomizedAxisTick />}
+ height={90}
+ />
+ <YAxis dataKey="value" type="number"></YAxis>
+ <Tooltip content={CustomTooltip} />
+ </LineChart>
+ </div>
+ );
+};
+
+const CustomizedAxisTick = ({ x, y, payload }) => {
+ return (
+ <g transform={`translate(${x},${y})`}>
+ <text className="Graph-Label" x={0} y={0} dy={16} textAnchor="end" fill="#666" transform="rotate(-40)">
+ {DateTime.fromSeconds(payload.value).toLocaleString()}
+ </text>
+ </g>
+ );
+};
+
+const CustomTooltip = ({ active, payload, label }) => {
+ if (active) {
+ return (
+ <div className="custom-tooltip bg-white border-orange-300 border-2 rounded-lg p-2">
+ <p className="label">
+ {DateTime.fromSeconds(label).toLocaleString({
+ weekday: "long",
+ month: "long",
+ day: "2-digit",
+ })}
+ </p>
+ <p className="desc">{payload[0].value}</p>
+ </div>
+ );
+ }
+ return null;
+};
+
+export default Graph;
diff --git a/src/pages/Index.css b/src/pages/Index.css
new file mode 100644
index 0000000..3816796
--- /dev/null
+++ b/src/pages/Index.css
@@ -0,0 +1,32 @@
+.Message {
+ margin-top: 24px;
+ font-size: 1.4em;
+}
+
+@media screen and (max-width: 600px) {
+ .Message {
+ display: none;
+ }
+}
+
+.Section .Title {
+ text-align: center;
+ font-size: 1.6em;
+ flex-basis: 100%;
+ margin-top: 48px;
+}
+
+@media screen and (max-width: 600px) {
+ .Section .Title {
+ margin-top: 12px;
+ }
+}
+
+.Cards {
+ display: flex;
+ justify-content: center;
+}
+
+.Tip {
+ margin-top: 2px;
+} \ No newline at end of file
diff --git a/src/pages/Index.jsx b/src/pages/Index.jsx
new file mode 100644
index 0000000..78c32f0
--- /dev/null
+++ b/src/pages/Index.jsx
@@ -0,0 +1,76 @@
+import Card from "../components/Card";
+import "./Index.css";
+
+const Index = (props) => {
+ const response = props.response;
+ if (response.loading) {
+ return <div>Loading...</div>;
+ }
+
+ const data = response.data;
+
+ const latest = data[data.length - 1];
+
+ return (
+ <div>
+ <div>
+ <div className="Message">
+ This site shows data from the 2020 Fall and 2021 Spring semesters. For the latest data, visit{" "}
+ <a href="https://ritcoviddashboard.com/">ritcoviddashboard.com</a>
+ </div>
+ </div>
+ <div className="Section" id="total">
+ <div className="Title">Total Positive Cases Since August 19 (First Day of Classes)</div>
+ <div className="Cards">
+ <Card name="Students" link="/totalstudents" latest={latest["total_students"]} />
+ <Card name="Staff" link="/totalstaff" latest={latest["total_staff"]} />
+ </div>
+ </div>
+
+ <div className="Section" id="new">
+ <div className="Title">New Positive Cases From Past 14 Days</div>
+ <div className="Cards">
+ <Card name="Students" link="/newstudents" latest={latest["new_students"]} />
+ <Card name="Staff" link="/newstaff" latest={latest["new_staff"]} />
+ </div>
+ </div>
+
+ <div className="Section" id="quarantine">
+ <div className="Title">Number of Students in Quarantine</div>
+ <p className="Tip">
+ Quarantine separates and restricts the movement of people who were exposed to a contagious disease
+ to see if they become sick.
+ </p>
+ <div className="Cards">
+ <Card name="On Campus" link="/quarantineoncampus" latest={latest["quarantine_on_campus"]} />
+ <Card name="Off Campus" link="/quarantineoffcampus" latest={latest["quarantine_off_campus"]} />
+ </div>
+ </div>
+
+ <div className="Section" id="isolation">
+ <div className="Title">Number of Students in Isolation</div>
+ <p className="Tip">Isolation separates sick people with a contagious disease from people who are not sick.</p>
+ <div className="Cards">
+ <Card name="On Campus" link="/isolationoncampus" latest={latest["isolation_on_campus"]} />
+ <Card name="Off Campus" link="/isolationoffcampus" latest={latest["isolation_off_campus"]} />
+ </div>
+ </div>
+
+ <div className="Section" id="tests">
+ <div className="Title">Tests</div>
+ <div className="Cards">
+ <Card name="Tests Administered" link="/tests" latest={latest["tests_administered"]} />
+ </div>
+ </div>
+
+ <div className="Section" id="beds">
+ <div className="Title">Quarantine/Isolation Bed Availability On-campus</div>
+ <div className="Cards">
+ <Card name="Beds Available" link="/beds" latest={latest["beds_available"]} suffix="%" />
+ </div>
+ </div>
+ </div>
+ );
+};
+
+export default Index;