diff options
author | Galen Guyer <galen@galenguyer.com> | 2022-07-11 17:10:23 -0400 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2022-07-11 17:10:23 -0400 |
commit | 935ef7d2f76cca7bc1f9840dc357de85f93a1ec2 (patch) | |
tree | cb8ee298a747d6084107266e5d2882e60a6b5daa /src/pages | |
parent | 3694bf061ecfe0f6733a0cb9028d044dfc8cf9d2 (diff) |
Update for new dashboard frontend
Diffstat (limited to 'src/pages')
-rw-r--r-- | src/pages/Graph.css | 33 | ||||
-rw-r--r-- | src/pages/Graph.jsx | 118 | ||||
-rw-r--r-- | src/pages/Index.css | 32 | ||||
-rw-r--r-- | src/pages/Index.jsx | 76 |
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; |