frontend/app/DeliverablesDash/UploadsGraph.tsx (109 lines of code) (raw):
import React, { useEffect, useState } from "react";
import { Bar } from "react-chartjs-2";
import { format, formatISO, parseISO } from "date-fns";
import axios from "axios";
import {
SystemNotifcationKind,
SystemNotification,
} from "@guardian/pluto-headers";
interface UploadsGraphProps {
startDate: Date;
endDate: Date;
formatString?: string; //date-fns format string for the time
colourOffset?: number;
saturation?: string; //should be percentage 0->100%
value?: string; //should be percentage 0->100%
columnClicked?: (columnIndex: number) => void;
}
const UploadsGraph: React.FC<UploadsGraphProps> = (props) => {
const [labels, setLabels] = useState<string[]>([]);
const [datasets, setDatasets] = useState<ChartDataset[]>([]);
const defaultFormatString = "EEEEE do MMM";
/**
* loads in data from the server
*/
useEffect(() => {
const loadData = async () => {
try {
const response = await axios.get<UploadSummaryResponse>(
`/api/dash/summary?startDate=${formatISO(
props.startDate
)}&endDate=${formatISO(props.endDate)}`
);
const newLabels = response.data.dates.map((dateString) => {
try {
const parsedDate = parseISO(dateString);
return format(
parsedDate,
props.formatString ?? defaultFormatString
);
} catch (err) {
console.error("Could not reformat ", dateString, ": ", err);
return "(err)";
}
});
setLabels(newLabels);
const colourInterval =
response.data.platforms.length > 0
? 360 / (response.data.platforms.length + 1)
: 0;
const datasets: ChartDataset[] = response.data.platforms
.filter((p) => !!p)
.map((platform, idx) => ({
label: platform.name,
data: platform.data,
backgroundColor: `hsl(${
(props.colourOffset ?? 0) + colourInterval * idx
}, ${props.saturation ?? "90%"}, ${props.value ?? "65%"})`,
borderColor: `has(${
(props.colourOffset ?? 0) + colourInterval * idx
}, ${props.saturation ?? "90%"}, ${props.value ?? "10%"}`,
borderWidth: 1,
}));
setDatasets(datasets);
} catch (err) {
console.error("Could not load data: ", err);
SystemNotification.open(
SystemNotifcationKind.Error,
"Could not load in graph data, see browser console for details"
);
}
};
loadData();
}, [props.startDate, props.endDate, props.saturation, props.value]);
const graphWasClicked = (
evt: MouseEvent,
elements: Array<{ _index?: number }>
) => {
//elements gives us an array of Dataset instances, for each of the data sets in the "bucket" defined by the date
//the property `_index` tells us which column it is, i.e. how many days since the start date of the graph.
//the first index is 0, i.e. date = startDate + _index
try {
if (elements.length > 0) {
const maybeColumnIndex = elements[0]["_index"];
if (maybeColumnIndex && props.columnClicked) {
props.columnClicked(maybeColumnIndex);
} else {
console.error("No _index defined under ", elements[0]);
}
} else {
console.log(
"Graph was clicked outside of the datasets, can't tell which day"
);
}
} catch (err) {
console.error(err);
}
};
return (
<Bar
data={{
labels: labels,
datasets: datasets,
}}
options={{
maintainAspectRatio: false,
responsive: true,
onClick: graphWasClicked,
}}
/>
);
};
export default UploadsGraph;