Added dynamic grouping to time-based line chart

This commit is contained in:
Alejandro Celaya 2020-05-30 09:57:21 +02:00
parent 61867366e7
commit 68b0577526

View file

@ -1,6 +1,14 @@
import React, { useState, useMemo } from 'react'; import React, { useState, useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Card, CardHeader, CardBody } from 'reactstrap'; import {
Card,
CardHeader,
CardBody,
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from 'reactstrap';
import { Line } from 'react-chartjs-2'; import { Line } from 'react-chartjs-2';
import { reverse } from 'ramda'; import { reverse } from 'ramda';
import moment from 'moment'; import moment from 'moment';
@ -13,15 +21,39 @@ const propTypes = {
highlightedVisits: PropTypes.arrayOf(VisitType), highlightedVisits: PropTypes.arrayOf(VisitType),
}; };
const STEP_TO_DATE_FORMAT_MAP = { const steps = [
hourly: 'YYYY-MM-DD HH:00', {
daily: 'YYYY-MM-DD', value: 'monthly',
weekly: '', menuText: 'Month',
monthly: 'YYYY-MM', },
{
value: 'weekly',
menuText: 'Week',
},
{
value: 'daily',
menuText: 'Day',
},
{
value: 'hourly',
menuText: 'Hour',
},
];
const STEP_TO_DATE_FORMAT = {
hourly: (date) => moment(date).format('YYYY-MM-DD HH:00'),
daily: (date) => moment(date).format('YYYY-MM-DD'),
weekly(date) {
const firstWeekDay = moment(date).isoWeekday(1).format('YYYY-MM-DD');
const lastWeekDay = moment(date).isoWeekday(7).format('YYYY-MM-DD');
return `${firstWeekDay} - ${lastWeekDay}`;
},
monthly: (date) => moment(date).format('YYYY-MM'),
}; };
const groupVisitsByStep = (step, visits) => visits.reduce((acc, visit) => { const groupVisitsByStep = (step, visits) => visits.reduce((acc, visit) => {
const key = moment(visit.date).format(STEP_TO_DATE_FORMAT_MAP[step]); const key = STEP_TO_DATE_FORMAT[step](visit.date);
acc[key] = acc[key] ? acc[key] + 1 : 1; acc[key] = acc[key] ? acc[key] + 1 : 1;
@ -38,7 +70,7 @@ const generateDataset = (stats, label, color) => ({
}); });
const LineChartCard = ({ title, visits, highlightedVisits }) => { const LineChartCard = ({ title, visits, highlightedVisits }) => {
const [ step ] = useState('monthly'); // hourly, daily, weekly, monthly const [ step, setStep ] = useState(steps[0].value);
const groupedVisits = useMemo(() => groupVisitsByStep(step, reverse(visits)), [ visits, step ]); const groupedVisits = useMemo(() => groupVisitsByStep(step, reverse(visits)), [ visits, step ]);
const labels = useMemo(() => Object.keys(groupedVisits), [ groupedVisits ]); const labels = useMemo(() => Object.keys(groupedVisits), [ groupedVisits ]);
const groupedHighlighted = useMemo( const groupedHighlighted = useMemo(
@ -66,7 +98,23 @@ const LineChartCard = ({ title, visits, highlightedVisits }) => {
return ( return (
<Card> <Card>
<CardHeader>{title}</CardHeader> <CardHeader>
{title}
<div className="float-right">
<UncontrolledDropdown>
<DropdownToggle caret color="link" className="btn-sm p-0">
Group by
</DropdownToggle>
<DropdownMenu right>
{steps.map(({ menuText, value }) => (
<DropdownItem key={value} active={step === value} onClick={() => setStep(value)}>
{menuText}
</DropdownItem>
))}
</DropdownMenu>
</UncontrolledDropdown>
</div>
</CardHeader>
<CardBody> <CardBody>
<Line data={data} options={options} height={80} /> <Line data={data} options={options} height={80} />
</CardBody> </CardBody>