formatLongNumberOptions

This commit is contained in:
Minseo Lee 2024-08-29 23:15:14 +09:00
parent 7676a69190
commit b60bd074f4
5 changed files with 36 additions and 56 deletions

View file

@ -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),

View file

@ -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>

View file

@ -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} />

View file

@ -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)}

View file

@ -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';