mirror of
https://github.com/umami-software/umami.git
synced 2026-02-19 20:15:41 +01:00
formatLongNumberOptions
This commit is contained in:
parent
7676a69190
commit
b60bd074f4
5 changed files with 36 additions and 56 deletions
|
|
@ -3,13 +3,13 @@ import { useDateRange, useMessages, useSticky } from 'components/hooks';
|
||||||
import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
|
import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
|
||||||
import MetricCard from 'components/metrics/MetricCard';
|
import MetricCard from 'components/metrics/MetricCard';
|
||||||
import MetricsBar from 'components/metrics/MetricsBar';
|
import MetricsBar from 'components/metrics/MetricsBar';
|
||||||
import { formatShortTime } from 'lib/format';
|
import { formatLongNumberOptions, formatShortTime } from 'lib/format';
|
||||||
import WebsiteFilterButton from './WebsiteFilterButton';
|
import WebsiteFilterButton from './WebsiteFilterButton';
|
||||||
import useWebsiteStats from 'components/hooks/queries/useWebsiteStats';
|
import useWebsiteStats from 'components/hooks/queries/useWebsiteStats';
|
||||||
import styles from './WebsiteMetricsBar.module.css';
|
import styles from './WebsiteMetricsBar.module.css';
|
||||||
import { Dropdown, Item } from 'react-basics';
|
import { Dropdown, Item } from 'react-basics';
|
||||||
import useStore, { setWebsiteDateCompare } from 'store/websites';
|
import useStore, { setWebsiteDateCompare } from 'store/websites';
|
||||||
import { type FormatNumberOptions, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export function WebsiteMetricsBar({
|
export function WebsiteMetricsBar({
|
||||||
websiteId,
|
websiteId,
|
||||||
|
|
@ -36,8 +36,6 @@ export function WebsiteMetricsBar({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const { pageviews, visitors, visits, bounces, totaltime } = data || {};
|
const { pageviews, visitors, visits, bounces, totaltime } = data || {};
|
||||||
const optionsNumber: FormatNumberOptions = { notation: 'compact', maximumSignificantDigits: 3 };
|
|
||||||
const optionsSmallNumber: FormatNumberOptions = { notation: 'compact' };
|
|
||||||
|
|
||||||
const metrics = data
|
const metrics = data
|
||||||
? [
|
? [
|
||||||
|
|
@ -45,22 +43,19 @@ export function WebsiteMetricsBar({
|
||||||
...pageviews,
|
...pageviews,
|
||||||
label: formatMessage(labels.views),
|
label: formatMessage(labels.views),
|
||||||
change: pageviews.value - pageviews.prev,
|
change: pageviews.value - pageviews.prev,
|
||||||
formatValue: (n: number) =>
|
formatValue: (n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n)),
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...visits,
|
...visits,
|
||||||
label: formatMessage(labels.visits),
|
label: formatMessage(labels.visits),
|
||||||
change: visits.value - visits.prev,
|
change: visits.value - visits.prev,
|
||||||
formatValue: (n: number) =>
|
formatValue: (n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n)),
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...visitors,
|
...visitors,
|
||||||
label: formatMessage(labels.visitors),
|
label: formatMessage(labels.visitors),
|
||||||
change: visitors.value - visitors.prev,
|
change: visitors.value - visitors.prev,
|
||||||
formatValue: (n: number) =>
|
formatValue: (n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n)),
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: formatMessage(labels.bounceRate),
|
label: formatMessage(labels.bounceRate),
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@ import MetricCard from 'components/metrics/MetricCard';
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { RealtimeData } from 'lib/types';
|
import { RealtimeData } from 'lib/types';
|
||||||
import styles from './RealtimeHeader.module.css';
|
import styles from './RealtimeHeader.module.css';
|
||||||
import { type FormatNumberOptions, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
|
||||||
export function RealtimeHeader({ data }: { data: RealtimeData }) {
|
export function RealtimeHeader({ data }: { data: RealtimeData }) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { totals }: any = data || {};
|
const { totals }: any = data || {};
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const optionsNumber: FormatNumberOptions = { notation: 'compact', maximumSignificantDigits: 3 };
|
|
||||||
const optionsSmallNumber: FormatNumberOptions = { notation: 'compact' };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.metrics}>
|
<div className={styles.metrics}>
|
||||||
|
|
@ -19,33 +17,25 @@ export function RealtimeHeader({ data }: { data: RealtimeData }) {
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
label={formatMessage(labels.views)}
|
label={formatMessage(labels.views)}
|
||||||
value={totals.views}
|
value={totals.views}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
label={formatMessage(labels.visitors)}
|
label={formatMessage(labels.visitors)}
|
||||||
value={totals.visitors}
|
value={totals.visitors}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
label={formatMessage(labels.events)}
|
label={formatMessage(labels.events)}
|
||||||
value={totals.events}
|
value={totals.events}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
className={styles.card}
|
className={styles.card}
|
||||||
label={formatMessage(labels.countries)}
|
label={formatMessage(labels.countries)}
|
||||||
value={totals.countries}
|
value={totals.countries}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,47 +3,37 @@ import useWebsiteSessionStats from 'components/hooks/queries/useWebsiteSessionSt
|
||||||
import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
|
import WebsiteDateFilter from 'components/input/WebsiteDateFilter';
|
||||||
import MetricCard from 'components/metrics/MetricCard';
|
import MetricCard from 'components/metrics/MetricCard';
|
||||||
import MetricsBar from 'components/metrics/MetricsBar';
|
import MetricsBar from 'components/metrics/MetricsBar';
|
||||||
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
import { Flexbox } from 'react-basics';
|
import { Flexbox } from 'react-basics';
|
||||||
import { type FormatNumberOptions, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export function SessionsMetricsBar({ websiteId }: { websiteId: string }) {
|
export function SessionsMetricsBar({ websiteId }: { websiteId: string }) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const { data, isLoading, isFetched, error } = useWebsiteSessionStats(websiteId);
|
const { data, isLoading, isFetched, error } = useWebsiteSessionStats(websiteId);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const optionsNumber: FormatNumberOptions = { notation: 'compact', maximumSignificantDigits: 3 };
|
|
||||||
const optionsSmallNumber: FormatNumberOptions = { notation: 'compact' };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}>
|
<Flexbox direction="row" justifyContent="space-between" style={{ minHeight: 120 }}>
|
||||||
<MetricsBar isLoading={isLoading} isFetched={isFetched} error={error}>
|
<MetricsBar isLoading={isLoading} isFetched={isFetched} error={error}>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
value={data?.visitors?.value}
|
value={data?.visitors?.value}
|
||||||
label={formatMessage(labels.visitors)}
|
label={formatMessage(labels.visitors)}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
value={data?.visits?.value}
|
value={data?.visits?.value}
|
||||||
label={formatMessage(labels.visits)}
|
label={formatMessage(labels.visits)}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
value={data?.pageviews?.value}
|
value={data?.pageviews?.value}
|
||||||
label={formatMessage(labels.views)}
|
label={formatMessage(labels.views)}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
value={data?.countries?.value}
|
value={data?.countries?.value}
|
||||||
label={formatMessage(labels.countries)}
|
label={formatMessage(labels.countries)}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</MetricsBar>
|
</MetricsBar>
|
||||||
<WebsiteDateFilter websiteId={websiteId} />
|
<WebsiteDateFilter websiteId={websiteId} />
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,29 @@
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import MetricCard from 'components/metrics/MetricCard';
|
import MetricCard from 'components/metrics/MetricCard';
|
||||||
import MetricsBar from 'components/metrics/MetricsBar';
|
import MetricsBar from 'components/metrics/MetricsBar';
|
||||||
import { formatShortTime } from 'lib/format';
|
import { formatLongNumberOptions, formatShortTime } from 'lib/format';
|
||||||
import { type FormatNumberOptions, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export function SessionStats({ data }) {
|
export function SessionStats({ data }) {
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const optionsNumber: FormatNumberOptions = { notation: 'compact', maximumSignificantDigits: 3 };
|
|
||||||
const optionsSmallNumber: FormatNumberOptions = { notation: 'compact' };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MetricsBar isFetched={true}>
|
<MetricsBar isFetched={true}>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label={formatMessage(labels.visits)}
|
label={formatMessage(labels.visits)}
|
||||||
value={data?.visits}
|
value={data?.visits}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label={formatMessage(labels.views)}
|
label={formatMessage(labels.views)}
|
||||||
value={data?.views}
|
value={data?.views}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label={formatMessage(labels.events)}
|
label={formatMessage(labels.events)}
|
||||||
value={data?.events}
|
value={data?.events}
|
||||||
formatValue={(n: number) =>
|
formatValue={(n: number) => intl.formatNumber(+n, formatLongNumberOptions(+n))}
|
||||||
intl.formatNumber(+n, +n < 100 ? optionsSmallNumber : optionsNumber)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<MetricCard
|
<MetricCard
|
||||||
label={formatMessage(labels.visitDuration)}
|
label={formatMessage(labels.visitDuration)}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type { FormatNumberOptions } from 'react-intl';
|
||||||
|
|
||||||
export function parseTime(val: number) {
|
export function parseTime(val: number) {
|
||||||
const days = ~~(val / 86400);
|
const days = ~~(val / 86400);
|
||||||
const hours = ~~(val / 3600) - days * 24;
|
const hours = ~~(val / 3600) - days * 24;
|
||||||
|
|
@ -63,6 +65,18 @@ export function formatLongNumber(value: number) {
|
||||||
return formatNumber(n);
|
return formatNumber(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatLongNumberOptions(value: number): FormatNumberOptions {
|
||||||
|
return value < 100
|
||||||
|
? {
|
||||||
|
notation: 'compact',
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
notation: 'compact',
|
||||||
|
maximumSignificantDigits: 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function stringToColor(str: string) {
|
export function stringToColor(str: string) {
|
||||||
if (!str) {
|
if (!str) {
|
||||||
return '#ffffff';
|
return '#ffffff';
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue