Update tooltip date formats.

This commit is contained in:
Mike Cao 2023-03-16 15:56:05 -07:00
parent afec08b355
commit c62e2e9cc7
5 changed files with 60 additions and 42 deletions

View File

@ -1,4 +1,4 @@
import { useState, useRef, useEffect, useMemo } from 'react'; import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import { StatusLight } from 'react-basics'; import { StatusLight } from 'react-basics';
import classNames from 'classnames'; import classNames from 'classnames';
import Chart from 'chart.js/auto'; import Chart from 'chart.js/auto';
@ -15,14 +15,14 @@ export default function BarChart({
datasets, datasets,
unit, unit,
animationDuration = DEFAULT_ANIMATION_DURATION, animationDuration = DEFAULT_ANIMATION_DURATION,
className,
stacked = false, stacked = false,
loading = false, loading = false,
onCreate = () => {}, onCreate = () => {},
onUpdate = () => {}, onUpdate = () => {},
className,
}) { }) {
const canvas = useRef(); const canvas = useRef();
const chart = useRef(); const chart = useRef(null);
const [tooltip, setTooltip] = useState(null); const [tooltip, setTooltip] = useState(null);
const { locale } = useLocale(); const { locale } = useLocale();
const [theme] = useTheme(); const [theme] = useTheme();
@ -39,34 +39,45 @@ export default function BarChart({
return +label > 1000 ? formatLongNumber(label) : label; return +label > 1000 ? formatLongNumber(label) : label;
}; };
const renderTooltip = model => { const renderTooltip = useCallback(
const { opacity, labelColors, dataPoints } = model.tooltip; model => {
const { opacity, labelColors, dataPoints } = model.tooltip;
if (!dataPoints?.length || !opacity) { if (!dataPoints?.length || !opacity) {
setTooltip(null); setTooltip(null);
return; return;
} }
const format = unit === 'hour' ? 'EEE p — PPP' : 'PPPP'; const formats = {
millisecond: 'T',
second: 'pp',
minute: 'p',
hour: 'h aaa',
day: 'PPPP',
week: 'PPPP',
month: 'LLLL yyyy',
quarter: 'qqq',
year: 'yyyy',
};
setTooltip( setTooltip(
<> <div className={styles.tooltip}>
<div>{dateFormat(new Date(dataPoints[0].raw.x), format, locale)}</div> <div>{dateFormat(new Date(dataPoints[0].raw.x), formats[unit], locale)}</div>
<div> <div>
<StatusLight color={labelColors?.[0]?.backgroundColor}> <StatusLight color={labelColors?.[0]?.backgroundColor}>
<b> <div className={styles.value}>
{formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label} {formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label}
</b> </div>
</StatusLight> </StatusLight>
</div> </div>
</>, </div>,
); );
}; },
[unit],
);
const createChart = () => { const getOptions = useCallback(() => {
Chart.defaults.font.family = 'Inter'; return {
const options = {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
animation: { animation: {
@ -124,6 +135,12 @@ export default function BarChart({
}, },
}, },
}; };
}, [animationDuration, renderTooltip, stacked, colors]);
const createChart = () => {
Chart.defaults.font.family = 'Inter';
const options = getOptions();
onCreate(options); onCreate(options);
@ -137,15 +154,9 @@ export default function BarChart({
}; };
const updateChart = () => { const updateChart = () => {
const { animation, scales } = chart.current.options; setTooltip(null);
animation.duration = animationDuration; chart.current.options = getOptions();
scales.x.ticks.color = colors.text;
scales.x.time.unit = unit;
scales.x.border.color = colors.line;
scales.y.ticks.color = colors.text;
scales.y.grid.color = colors.line;
scales.y.border.color = colors.line;
onUpdate(chart.current); onUpdate(chart.current);
@ -157,7 +168,6 @@ export default function BarChart({
if (!chart.current) { if (!chart.current) {
createChart(); createChart();
} else { } else {
setTooltip(null);
updateChart(); updateChart();
} }
} }

View File

@ -4,6 +4,16 @@
overflow: hidden; overflow: hidden;
} }
.tooltip {
display: flex;
flex-direction: column;
gap: 10px;
}
.tooltip .value {
text-transform: lowercase;
}
@media only screen and (max-width: 992px) { @media only screen and (max-width: 992px) {
.chart { .chart {
/*height: 200px;*/ /*height: 200px;*/

View File

@ -33,12 +33,12 @@ export default function EventsChart({ websiteId, className, token }) {
if (!data) return []; if (!data) return [];
if (isLoading) return data; if (isLoading) return data;
const map = data.reduce((obj, { x, t, y }) => { const map = data.reduce((obj, { x, y }) => {
if (!obj[x]) { if (!obj[x]) {
obj[x] = []; obj[x] = [];
} }
obj[x].push({ t, y }); obj[x].push({ x, y });
return obj; return obj;
}, {}); }, {});

View File

@ -58,14 +58,12 @@ export default function PageviewsChart({
{ {
label: formatMessage(labels.uniqueVisitors), label: formatMessage(labels.uniqueVisitors),
data: data.sessions, data: data.sessions,
lineTension: 0,
borderWidth: 1, borderWidth: 1,
...colors.visitors, ...colors.visitors,
}, },
{ {
label: formatMessage(labels.pageViews), label: formatMessage(labels.pageViews),
data: data.pageviews, data: data.pageviews,
lineTension: 0,
borderWidth: 1, borderWidth: 1,
...colors.views, ...colors.views,
}, },

View File

@ -5,7 +5,7 @@ import { FixedSizeList } from 'react-window';
import firstBy from 'thenby'; import firstBy from 'thenby';
import FilterButtons from 'components/common/FilterButtons'; import FilterButtons from 'components/common/FilterButtons';
import NoData from 'components/common/NoData'; import NoData from 'components/common/NoData';
import { getDeviceMessage, labels, messages } from 'components/messages'; import { labels, messages } from 'components/messages';
import useLocale from 'hooks/useLocale'; import useLocale from 'hooks/useLocale';
import useCountryNames from 'hooks/useCountryNames'; import useCountryNames from 'hooks/useCountryNames';
import { BROWSERS } from 'lib/constants'; import { BROWSERS } from 'lib/constants';
@ -102,7 +102,7 @@ export default function RealtimeLog({ data, websiteDomain }) {
country: <b>{countryNames[country] || formatMessage(labels.unknown)}</b>, country: <b>{countryNames[country] || formatMessage(labels.unknown)}</b>,
browser: <b>{BROWSERS[browser]}</b>, browser: <b>{BROWSERS[browser]}</b>,
os: <b>{os}</b>, os: <b>{os}</b>,
device: <b>{formatMessage(getDeviceMessage(device))}</b>, device: <b>{formatMessage(labels[device] || labels.unknown)}</b>,
}} }}
/> />
); );