frontend/app/DeliverablesDash/DeliverablesDashFront.tsx (228 lines of code) (raw):

import React, { useEffect, useState } from "react"; import { Helmet } from "react-helmet"; import { FormControl, FormControlLabel, Grid, IconButton, InputLabel, MenuItem, Select, TextField, Tooltip, Typography, } from "@material-ui/core"; import DateFnsUtils from "@date-io/date-fns"; import DeliverablesDashList from "./DeliverablesDashList"; import { DatePicker, MuiPickersUtilsProvider } from "@material-ui/pickers"; import { Assessment, AssessmentOutlined, AssessmentRounded, Search, } from "@material-ui/icons"; import UploadsGraph from "./UploadsGraph"; import { add, formatISO, parseISO, set } from "date-fns"; import { useHistory, useLocation } from "react-router-dom"; import { break_down_searchstring } from "../utils/searchstring"; type DelivTypes = "fullmasters" | "all"; const DeliverablesDashFront: React.FC = () => { const [startDateEntered, setStartDateEntered] = useState<Date>(() => { let d = new Date(); d.setDate(1); d.setHours(0); d.setMinutes(0); d.setSeconds(0); d.setMilliseconds(0); return d; }); const [titleSearchValue, setTitleSearchValue] = useState(""); const [finishDateEntered, setFinishDateEntered] = useState<Date>( set(new Date(), { hours: 23, minutes: 59, seconds: 59, milliseconds: 999 }) ); const [selectedDelivTypes, setSelectedDelivTypes] = useState<DelivTypes>( "fullmasters" ); const [showingChart, setShowingChart] = useState(true); const history = useHistory(); const location = useLocation(); console.log("searchstring: ", location.search); useEffect(() => { if (location.search !== "") { const args = break_down_searchstring(location.search); const maybeStartTime = args.get("from"); if (maybeStartTime) { try { const parsedStartTime = parseISO(maybeStartTime); setStartDateEntered(parsedStartTime); } catch (err) { console.warn(`${maybeStartTime} is not a valid time: `, err); } } const maybeFinishTime = args.get("until"); if (maybeFinishTime) { try { const parsedFinishTime = parseISO(maybeFinishTime); setFinishDateEntered(parsedFinishTime); } catch (err) { console.warn(`${maybeFinishTime} is not a valid time: `, err); } } } }, [location.search]); const dateFilterUpdated = ( newStartTime: Date | undefined, newFinishTime: Date | undefined ) => { const zeroTimePart = { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }; const lateTimePart = { hours: 23, minutes: 59, seconds: 59, milliseconds: 999, }; const params = [ [ "from", newStartTime ? formatISO(set(newStartTime, zeroTimePart)) : undefined, ], [ "until", newFinishTime ? formatISO(set(newFinishTime, lateTimePart)) : undefined, ], ].filter((entry) => !!entry[1]); if (params.length > 0) { const paramString = params .map((kv) => kv[0] && kv[1] ? `${encodeURIComponent(kv[0])}=${encodeURIComponent(kv[1])}` : "" ) .join("&"); history.push("?" + paramString); } else { history.push("/dash"); } }; return ( <MuiPickersUtilsProvider utils={DateFnsUtils}> <Helmet> <title>Deliverables Dashboard</title> </Helmet> <Typography variant="h2">Deliverables Dashboard</Typography> <Grid container direction="column" spacing={2}> <Grid item> <Grid container justify="space-between" style={{ marginBottom: "1em" }} > <Grid item> <Grid container spacing={3}> <Grid item> <Search style={{ verticalAlign: "bottom" }} /> <TextField label="Search for title" value={titleSearchValue} onChange={(evt) => setTitleSearchValue(evt.target.value)} /> </Grid> <Grid item> <FormControl> <InputLabel id="deliv-type-label"> Deliverable Type </InputLabel> <Select labelId="deliv-type-label" onChange={(evt) => setSelectedDelivTypes(evt.target.value as DelivTypes) } value={selectedDelivTypes} > <MenuItem value="fullmasters">Full masters only</MenuItem> <MenuItem value="all">All deliverables</MenuItem> </Select> </FormControl> </Grid> <Grid item> <Tooltip title={`${ showingChart ? "Hide" : "Show" } upload summary graph`} > <IconButton onClick={() => setShowingChart((prev) => !prev)} > {showingChart ? ( <AssessmentOutlined /> ) : ( <AssessmentRounded /> )} </IconButton> </Tooltip> </Grid> </Grid> </Grid> <Grid item> <Grid container justify="flex-end" spacing={3}> <Grid item> <DatePicker label="Search from" value={startDateEntered} onChange={(newValue) => dateFilterUpdated( newValue ?? undefined, finishDateEntered ) } /> </Grid> <Grid item> <DatePicker label="Search until" value={finishDateEntered} onChange={(newValue) => dateFilterUpdated(startDateEntered, newValue ?? undefined) } /> </Grid> </Grid> </Grid> </Grid> </Grid> {showingChart ? ( <Grid item style={{ height: "45%", maxHeight: "800px", minHeight: "200px" }} > <UploadsGraph startDate={startDateEntered} endDate={finishDateEntered} columnClicked={(columnIndex) => { const targetDate = add(startDateEntered, { days: columnIndex }); const targetEndDate = set(targetDate, { hours: 23, minutes: 59, seconds: 59, milliseconds: 999, }); history.push( "?from=" + formatISO(targetDate) + "&until=" + formatISO(targetEndDate) ); }} /> </Grid> ) : undefined} <Grid item style={{ flexGrow: 1 }}> <DeliverablesDashList startDate={startDateEntered} endDate={finishDateEntered} types={selectedDelivTypes} titleSearchValue={titleSearchValue} /> </Grid> </Grid> </MuiPickersUtilsProvider> ); }; export default DeliverablesDashFront;