mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
126 lines
4.0 KiB
TypeScript
126 lines
4.0 KiB
TypeScript
import { useState } from 'react';
|
|
import classNames from 'classnames';
|
|
import { useMessages, useSticky } from 'components/hooks';
|
|
import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
|
|
import MetricCard from 'components/metrics/MetricCard';
|
|
import MetricsBar from 'components/metrics/MetricsBar';
|
|
import { formatShortTime } from 'lib/format';
|
|
import WebsiteFilterButton from './WebsiteFilterButton';
|
|
import useWebsiteStats from 'components/hooks/queries/useWebsiteStats';
|
|
import styles from './WebsiteMetricsBar.module.css';
|
|
import { Dropdown, Item } from 'react-basics';
|
|
|
|
export function WebsiteMetricsBar({
|
|
websiteId,
|
|
sticky,
|
|
showChange = false,
|
|
compareMode = false,
|
|
}: {
|
|
websiteId: string;
|
|
sticky?: boolean;
|
|
showChange?: boolean;
|
|
compareMode?: boolean;
|
|
}) {
|
|
const { formatMessage, labels } = useMessages();
|
|
const [compare, setCompare] = useState('prev');
|
|
const { ref, isSticky } = useSticky({ enabled: sticky });
|
|
const { data, isLoading, isFetched, error } = useWebsiteStats(websiteId, compare);
|
|
|
|
const { pageviews, visitors, visits, bounces, totaltime } = data || {};
|
|
|
|
const metrics = data
|
|
? [
|
|
{
|
|
...pageviews,
|
|
label: formatMessage(labels.views),
|
|
change: pageviews.value - pageviews.prev,
|
|
},
|
|
{
|
|
...visits,
|
|
label: formatMessage(labels.visits),
|
|
change: visits.value - visits.prev,
|
|
},
|
|
{
|
|
...visitors,
|
|
label: formatMessage(labels.visitors),
|
|
change: visitors.value - visitors.prev,
|
|
},
|
|
{
|
|
label: formatMessage(labels.bounceRate),
|
|
value: (Math.min(visitors.value, bounces.value) / visitors.value) * 100,
|
|
prev: (Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100,
|
|
change:
|
|
(Math.min(visitors.value, bounces.value) / visitors.value) * 100 -
|
|
(Math.min(visitors.prev, bounces.prev) / visitors.prev) * 100,
|
|
format: n => Number(n).toFixed(0) + '%',
|
|
reverseColors: true,
|
|
},
|
|
{
|
|
label: formatMessage(labels.visitDuration),
|
|
value: totaltime.value / visits.value,
|
|
prev: totaltime.prev / visits.prev,
|
|
change: totaltime.value / visits.value - totaltime.prev / visits.prev,
|
|
format: n => `${+n < 0 ? '-' : ''}${formatShortTime(Math.abs(~~n), ['m', 's'], ' ')}`,
|
|
},
|
|
]
|
|
: [];
|
|
|
|
const items = [
|
|
{ label: formatMessage(labels.previousPeriod), value: 'prev' },
|
|
{ label: formatMessage(labels.yearOverYear), value: 'yoy' },
|
|
];
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={classNames(styles.container, {
|
|
[styles.sticky]: sticky,
|
|
[styles.isSticky]: isSticky,
|
|
})}
|
|
>
|
|
<div>
|
|
<MetricsBar isLoading={isLoading} isFetched={isFetched} error={error}>
|
|
{metrics.map(({ label, value, prev, change, format, reverseColors }) => {
|
|
return (
|
|
<MetricCard
|
|
key={label}
|
|
value={value}
|
|
previousValue={prev}
|
|
label={label}
|
|
change={change}
|
|
format={format}
|
|
reverseColors={reverseColors}
|
|
showChange={compareMode || showChange}
|
|
showPrevious={compareMode}
|
|
/>
|
|
);
|
|
})}
|
|
</MetricsBar>
|
|
</div>
|
|
<div className={styles.actions}>
|
|
<WebsiteFilterButton websiteId={websiteId} />
|
|
<WebsiteDateFilter websiteId={websiteId} />
|
|
{compareMode && (
|
|
<div className={styles.vs}>
|
|
<b>VS</b>
|
|
<Dropdown
|
|
className={styles.dropdown}
|
|
items={items}
|
|
value={compare}
|
|
renderValue={value => items.find(i => i.value === value)?.label}
|
|
alignment="end"
|
|
onChange={(e: any) => setCompare(e)}
|
|
>
|
|
{items.map(({ label, value }) => (
|
|
<Item key={value}>{label}</Item>
|
|
))}
|
|
</Dropdown>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default WebsiteMetricsBar;
|