mirror of
https://github.com/umami-software/umami.git
synced 2026-02-19 12:05:41 +01:00
Replace formatLongNumber with intl.formatNumber
This commit is contained in:
parent
5636bd9617
commit
16f86c7715
12 changed files with 44 additions and 48 deletions
|
|
@ -39,7 +39,7 @@ export function FunnelChart({ className }: FunnelChartProps) {
|
||||||
{formatMessage(labels.visitors)}
|
{formatMessage(labels.visitors)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.percent}>
|
<div className={styles.percent}>
|
||||||
{intl.formatNumber(+remaining, { style: 'percent', maximumFractionDigits: 1 })}
|
{intl.formatNumber(remaining, { style: 'percent', maximumFractionDigits: 1 })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.track}>
|
<div className={styles.track}>
|
||||||
|
|
@ -49,7 +49,7 @@ export function FunnelChart({ className }: FunnelChartProps) {
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
<b>{intl.formatNumber(dropped, formatLongNumberOptions(dropped))}</b>{' '}
|
<b>{intl.formatNumber(dropped, formatLongNumberOptions(dropped))}</b>{' '}
|
||||||
{formatMessage(labels.visitorsDroppedOff)} (
|
{formatMessage(labels.visitorsDroppedOff)} (
|
||||||
{intl.formatNumber(+dropoff, { style: 'percent', maximumFractionDigits: 1 })})
|
{intl.formatNumber(dropoff, { style: 'percent', maximumFractionDigits: 1 })})
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ import { useContext } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
import styles from './GoalsChart.module.css';
|
import styles from './GoalsChart.module.css';
|
||||||
|
|
||||||
export function GoalsChart({ className }: { className?: string; isLoading?: boolean }) {
|
export function GoalsChart({ className }: { className?: string; isLoading?: boolean }) {
|
||||||
const { report } = useContext(ReportContext);
|
const { report } = useContext(ReportContext);
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const { data } = report || {};
|
const { data } = report || {};
|
||||||
|
|
||||||
|
|
@ -58,10 +60,15 @@ export function GoalsChart({ className }: { className?: string; isLoading?: bool
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.metric}>
|
<div className={styles.metric}>
|
||||||
<div className={styles.value}>
|
<div className={styles.value}>
|
||||||
{formatLongNumber(result)}
|
{intl.formatNumber(result, formatLongNumberOptions(result))}
|
||||||
<span className={styles.total}> / {formatLongNumber(goal)}</span>
|
<span className={styles.total}>
|
||||||
|
{' '}
|
||||||
|
/ {intl.formatNumber(goal, formatLongNumberOptions(goal))}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.percent}>
|
||||||
|
{intl.formatNumber(result / goal, { style: 'percent', maximumFractionDigits: 1 })}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.percent}>{((result / goal) * 100).toFixed(2)}%</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useLocale, 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 { renderDateLabels } from 'lib/charts';
|
import { renderDateLabels } from 'lib/charts';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
import { useContext, useMemo } from 'react';
|
import { useContext, useMemo } from 'react';
|
||||||
import { ReportContext } from '../[reportId]/Report';
|
import { ReportContext } from '../[reportId]/Report';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
@ -57,22 +57,22 @@ export function RevenueChart({ isLoading, ...props }: PageviewsChartProps) {
|
||||||
{
|
{
|
||||||
value: sum,
|
value: sum,
|
||||||
label: formatMessage(labels.total),
|
label: formatMessage(labels.total),
|
||||||
formatValue: formatLongNumber,
|
formatValue: (n: number) => intl.formatNumber(n, formatLongNumberOptions(n)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: avg,
|
value: avg,
|
||||||
label: formatMessage(labels.average),
|
label: formatMessage(labels.average),
|
||||||
formatValue: formatLongNumber,
|
formatValue: (n: number) => intl.formatNumber(n, formatLongNumberOptions(n)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: count,
|
value: count,
|
||||||
label: formatMessage(labels.transactions),
|
label: formatMessage(labels.transactions),
|
||||||
formatValue: formatLongNumber,
|
formatValue: (n: number) => intl.formatNumber(n, formatLongNumberOptions(n)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: uniqueCount,
|
value: uniqueCount,
|
||||||
label: formatMessage(labels.uniqueCustomers),
|
label: formatMessage(labels.uniqueCustomers),
|
||||||
formatValue: formatLongNumber,
|
formatValue: (n: number) => intl.formatNumber(n, formatLongNumberOptions(n)),
|
||||||
},
|
},
|
||||||
] as any;
|
] as any;
|
||||||
}, [data, locale]);
|
}, [data, locale]);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import BarChartTooltip from 'components/charts/BarChartTooltip';
|
import BarChartTooltip from 'components/charts/BarChartTooltip';
|
||||||
import Chart, { ChartProps } from 'components/charts/Chart';
|
import Chart, { ChartProps } from 'components/charts/Chart';
|
||||||
import { useTheme } from 'components/hooks';
|
import { useTheme } from 'components/hooks';
|
||||||
import { renderNumberLabels } from 'lib/charts';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
export interface BarChartProps extends ChartProps {
|
export interface BarChartProps extends ChartProps {
|
||||||
|
|
@ -18,6 +19,7 @@ export interface BarChartProps extends ChartProps {
|
||||||
export function BarChart(props: BarChartProps) {
|
export function BarChart(props: BarChartProps) {
|
||||||
const [tooltip, setTooltip] = useState(null);
|
const [tooltip, setTooltip] = useState(null);
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
const intl = useIntl();
|
||||||
const {
|
const {
|
||||||
renderXLabel,
|
renderXLabel,
|
||||||
renderYLabel,
|
renderYLabel,
|
||||||
|
|
@ -66,7 +68,8 @@ export function BarChart(props: BarChartProps) {
|
||||||
},
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
color: colors.chart.text,
|
color: colors.chart.text,
|
||||||
callback: renderYLabel || renderNumberLabels,
|
callback: (n: number) =>
|
||||||
|
renderYLabel || intl.formatNumber(n, formatLongNumberOptions(n)),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Flexbox, StatusLight } from 'react-basics';
|
import { Flexbox, StatusLight } from 'react-basics';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
const formats = {
|
const formats = {
|
||||||
|
|
@ -31,7 +31,8 @@ export default function BarChartTooltip({ tooltip, unit }) {
|
||||||
<div>{intl.formatDate(dataPoints[0].raw.d || dataPoints[0].raw.x, formats[unit])}</div>
|
<div>{intl.formatDate(dataPoints[0].raw.d || dataPoints[0].raw.x, formats[unit])}</div>
|
||||||
<div>
|
<div>
|
||||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||||
{formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label}
|
{intl.formatNumber(dataPoints[0].raw.y, formatLongNumberOptions(dataPoints[0].raw.y))}{' '}
|
||||||
|
{dataPoints[0].dataset.label}
|
||||||
</StatusLight>
|
</StatusLight>
|
||||||
</div>
|
</div>
|
||||||
</Flexbox>
|
</Flexbox>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { Chart, ChartProps } from 'components/charts/Chart';
|
import { Chart, ChartProps } from 'components/charts/Chart';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { StatusLight } from 'react-basics';
|
import { StatusLight } from 'react-basics';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export interface BubbleChartProps extends ChartProps {
|
export interface BubbleChartProps extends ChartProps {
|
||||||
type?: 'bubble';
|
type?: 'bubble';
|
||||||
|
|
@ -10,6 +11,7 @@ export interface BubbleChartProps extends ChartProps {
|
||||||
export default function BubbleChart(props: BubbleChartProps) {
|
export default function BubbleChart(props: BubbleChartProps) {
|
||||||
const [tooltip, setTooltip] = useState(null);
|
const [tooltip, setTooltip] = useState(null);
|
||||||
const { type = 'bubble' } = props;
|
const { type = 'bubble' } = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleTooltip = ({ tooltip }) => {
|
const handleTooltip = ({ tooltip }) => {
|
||||||
const { labelColors, dataPoints } = tooltip;
|
const { labelColors, dataPoints } = tooltip;
|
||||||
|
|
@ -17,7 +19,8 @@ export default function BubbleChart(props: BubbleChartProps) {
|
||||||
setTooltip(
|
setTooltip(
|
||||||
tooltip.opacity ? (
|
tooltip.opacity ? (
|
||||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||||
{formatLongNumber(dataPoints?.[0]?.raw)} {dataPoints?.[0]?.label}
|
{intl.formatNumber(dataPoints?.[0]?.raw, formatLongNumberOptions(dataPoints?.[0]?.raw))}{' '}
|
||||||
|
{dataPoints?.[0]?.label}
|
||||||
</StatusLight>
|
</StatusLight>
|
||||||
) : null,
|
) : null,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { Chart, ChartProps } from 'components/charts/Chart';
|
import { Chart, ChartProps } from 'components/charts/Chart';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { StatusLight } from 'react-basics';
|
import { StatusLight } from 'react-basics';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
export interface PieChartProps extends ChartProps {
|
export interface PieChartProps extends ChartProps {
|
||||||
type?: 'doughnut' | 'pie';
|
type?: 'doughnut' | 'pie';
|
||||||
|
|
@ -10,6 +11,7 @@ export interface PieChartProps extends ChartProps {
|
||||||
export default function PieChart(props: PieChartProps) {
|
export default function PieChart(props: PieChartProps) {
|
||||||
const [tooltip, setTooltip] = useState(null);
|
const [tooltip, setTooltip] = useState(null);
|
||||||
const { type = 'pie' } = props;
|
const { type = 'pie' } = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleTooltip = ({ tooltip }) => {
|
const handleTooltip = ({ tooltip }) => {
|
||||||
const { labelColors, dataPoints } = tooltip;
|
const { labelColors, dataPoints } = tooltip;
|
||||||
|
|
@ -17,7 +19,8 @@ export default function PieChart(props: PieChartProps) {
|
||||||
setTooltip(
|
setTooltip(
|
||||||
tooltip.opacity ? (
|
tooltip.opacity ? (
|
||||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||||
{formatLongNumber(dataPoints?.[0]?.raw)} {dataPoints?.[0]?.label}
|
{intl.formatNumber(dataPoints?.[0]?.raw, formatLongNumberOptions(dataPoints?.[0]?.raw))}{' '}
|
||||||
|
{dataPoints?.[0]?.label}
|
||||||
</StatusLight>
|
</StatusLight>
|
||||||
) : null,
|
) : null,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ const AnimatedRow = ({ label, value = 0, percent, change, animate, showPercentag
|
||||||
<div className={styles.percent}>
|
<div className={styles.percent}>
|
||||||
<animated.div className={styles.bar} style={{ width: props.width.to(n => `${n}%`) }} />
|
<animated.div className={styles.bar} style={{ width: props.width.to(n => `${n}%`) }} />
|
||||||
<animated.span>
|
<animated.span>
|
||||||
{props.width.to(n => intl.formatNumber(+n / 100, { style: 'percent' }))}
|
{props.width.to(n => intl.formatNumber(n / 100, { style: 'percent' }))}
|
||||||
</animated.span>
|
</animated.span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { Loading, cloneChildren } from 'react-basics';
|
import { Loading, cloneChildren } from 'react-basics';
|
||||||
import ErrorMessage from 'components/common/ErrorMessage';
|
import ErrorMessage from 'components/common/ErrorMessage';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
import styles from './MetricsBar.module.css';
|
import styles from './MetricsBar.module.css';
|
||||||
|
|
||||||
export interface MetricsBarProps {
|
export interface MetricsBarProps {
|
||||||
|
|
@ -12,7 +13,8 @@ export interface MetricsBarProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MetricsBar({ children, isLoading, isFetched, error }: MetricsBarProps) {
|
export function MetricsBar({ children, isLoading, isFetched, error }: MetricsBarProps) {
|
||||||
const formatFunc = n => (n >= 0 ? formatLongNumber(n) : `-${formatLongNumber(Math.abs(n))}`);
|
const intl = useIntl();
|
||||||
|
const formatFunc = (n: number) => intl.formatNumber(n, formatLongNumberOptions(n));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.bar}>
|
<div className={styles.bar}>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { useDateRange, useTheme, useWebsiteMetrics } from 'components/hooks';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import { useLocale } from 'components/hooks';
|
import { useLocale } from 'components/hooks';
|
||||||
import { useMessages } from 'components/hooks';
|
import { useMessages } from 'components/hooks';
|
||||||
import { formatLongNumber } from 'lib/format';
|
import { formatLongNumberOptions } from 'lib/format';
|
||||||
import { percentFilter } from 'lib/filters';
|
import { percentFilter } from 'lib/filters';
|
||||||
import styles from './WorldMap.module.css';
|
import styles from './WorldMap.module.css';
|
||||||
|
|
||||||
|
|
@ -62,8 +62,9 @@ export function WorldMap({
|
||||||
if (code === 'AQ') return;
|
if (code === 'AQ') return;
|
||||||
const country = metrics?.find(({ x }) => x === code);
|
const country = metrics?.find(({ x }) => x === code);
|
||||||
setTooltipPopup(
|
setTooltipPopup(
|
||||||
`${intl.formatDisplayName(code, { type: 'region' })}: ${formatLongNumber(
|
`${intl.formatDisplayName(code, { type: 'region' })}: ${intl.formatNumber(
|
||||||
country?.y || 0,
|
country?.y || 0,
|
||||||
|
formatLongNumberOptions(country?.y || 0),
|
||||||
)} ${visitorsLabel}` as any,
|
)} ${visitorsLabel}` as any,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
import { formatLongNumber } from 'lib/format';
|
|
||||||
import { type IntlShape } from 'react-intl';
|
import { type IntlShape } from 'react-intl';
|
||||||
|
|
||||||
export function renderNumberLabels(label: string) {
|
|
||||||
return +label > 1000 ? formatLongNumber(+label) : label;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderDateLabels(intl: IntlShape, unit: string) {
|
export function renderDateLabels(intl: IntlShape, unit: string) {
|
||||||
return (label: string, index: number, values: any[]) => {
|
return (label: string, index: number, values: any[]) => {
|
||||||
const d = new Date(values[index].value);
|
const d = new Date(values[index].value);
|
||||||
|
|
|
||||||
|
|
@ -46,25 +46,6 @@ export function formatNumber(n: string | number) {
|
||||||
return Number(n).toFixed(0);
|
return Number(n).toFixed(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatLongNumber(value: number) {
|
|
||||||
const n = Number(value);
|
|
||||||
|
|
||||||
if (n >= 1000000) {
|
|
||||||
return `${(n / 1000000).toFixed(1)}m`;
|
|
||||||
}
|
|
||||||
if (n >= 100000) {
|
|
||||||
return `${(n / 1000).toFixed(0)}k`;
|
|
||||||
}
|
|
||||||
if (n >= 10000) {
|
|
||||||
return `${(n / 1000).toFixed(1)}k`;
|
|
||||||
}
|
|
||||||
if (n >= 1000) {
|
|
||||||
return `${(n / 1000).toFixed(2)}k`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatNumber(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function formatLongNumberOptions(value: number): FormatNumberOptions {
|
export function formatLongNumberOptions(value: number): FormatNumberOptions {
|
||||||
return value < 100
|
return value < 100
|
||||||
? {
|
? {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue