mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Added dynamic grouping to time-based line chart
This commit is contained in:
parent
61867366e7
commit
68b0577526
1 changed files with 57 additions and 9 deletions
|
@ -1,6 +1,14 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
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 { reverse } from 'ramda';
|
||||
import moment from 'moment';
|
||||
|
@ -13,15 +21,39 @@ const propTypes = {
|
|||
highlightedVisits: PropTypes.arrayOf(VisitType),
|
||||
};
|
||||
|
||||
const STEP_TO_DATE_FORMAT_MAP = {
|
||||
hourly: 'YYYY-MM-DD HH:00',
|
||||
daily: 'YYYY-MM-DD',
|
||||
weekly: '',
|
||||
monthly: 'YYYY-MM',
|
||||
const steps = [
|
||||
{
|
||||
value: 'monthly',
|
||||
menuText: 'Month',
|
||||
},
|
||||
{
|
||||
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 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;
|
||||
|
||||
|
@ -38,7 +70,7 @@ const generateDataset = (stats, label, color) => ({
|
|||
});
|
||||
|
||||
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 labels = useMemo(() => Object.keys(groupedVisits), [ groupedVisits ]);
|
||||
const groupedHighlighted = useMemo(
|
||||
|
@ -66,7 +98,23 @@ const LineChartCard = ({ title, visits, highlightedVisits }) => {
|
|||
|
||||
return (
|
||||
<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>
|
||||
<Line data={data} options={options} height={80} />
|
||||
</CardBody>
|
||||
|
|
Loading…
Reference in a new issue