Merge branch 'round-follower-counts' into 'develop'

Improve formatting of short numbers

See merge request soapbox-pub/soapbox-fe!1749
environments/review-develop-3zknud/deployments/835
Justin 2 years ago
commit 5ad4303c3e

@ -17,10 +17,9 @@ import { initReport } from 'soapbox/actions/reports';
import { setSearchAccount } from 'soapbox/actions/search'; import { setSearchAccount } from 'soapbox/actions/search';
import { getSettings } from 'soapbox/actions/settings'; import { getSettings } from 'soapbox/actions/settings';
import snackbar from 'soapbox/actions/snackbar'; import snackbar from 'soapbox/actions/snackbar';
import Avatar from 'soapbox/components/avatar';
import Badge from 'soapbox/components/badge'; import Badge from 'soapbox/components/badge';
import StillImage from 'soapbox/components/still_image'; import StillImage from 'soapbox/components/still_image';
import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, MenuDivider } from 'soapbox/components/ui'; import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, MenuDivider, Avatar } from 'soapbox/components/ui';
import SvgIcon from 'soapbox/components/ui/icon/svg-icon'; import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
import MovedNote from 'soapbox/features/account_timeline/components/moved_note'; import MovedNote from 'soapbox/features/account_timeline/components/moved_note';
import ActionButton from 'soapbox/features/ui/components/action-button'; import ActionButton from 'soapbox/features/ui/components/action-button';
@ -757,7 +756,8 @@ const Header: React.FC<IHeader> = ({ account }) => {
<div className='flex'> <div className='flex'>
<a href={account.avatar} onClick={handleAvatarClick} target='_blank'> <a href={account.avatar} onClick={handleAvatarClick} target='_blank'>
<Avatar <Avatar
account={account} src={account.avatar}
size={96}
className='h-24 w-24 rounded-full ring-4 ring-white dark:ring-primary-900' className='h-24 w-24 rounded-full ring-4 ring-white dark:ring-primary-900'
/> />
</a> </a>

@ -27,11 +27,77 @@ describe('shortNumberFormat', () => {
test('formats numbers under 1,000,000', () => { test('formats numbers under 1,000,000', () => {
render(<div data-testid='num'>{shortNumberFormat(5555)}</div>, undefined, null); render(<div data-testid='num'>{shortNumberFormat(5555)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('5.6K'); expect(screen.getByTestId('num')).toHaveTextContent('5.55k');
}); });
test('formats numbers over 1,000,000', () => { test('formats numbers over 1,000,000', () => {
render(<div data-testid='num'>{shortNumberFormat(5555555)}</div>, undefined, null); render(<div data-testid='num'>{shortNumberFormat(5555555)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('5.6M'); expect(screen.getByTestId('num')).toHaveTextContent('5.55M');
});
test('formats a multitude of numbers', () => {
let result = render(<div data-testid='num'>{shortNumberFormat(0)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('0');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1)}</div>);
expect(screen.getByTestId('num')).toHaveTextContent('1');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(999)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('999');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1000)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1001)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1005)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1006)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1010)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1.01k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1530)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1.53k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(10530)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('10.5k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(999500)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('999k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(999999)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('999k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(999499)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('999k');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1000000)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1M');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(3905558)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('3.9M');
result.unmount();
result = render(<div data-testid='num'>{shortNumberFormat(1031511)}</div>, undefined, null);
expect(screen.getByTestId('num')).toHaveTextContent('1.03M');
result.unmount();
}); });
}); });

@ -4,17 +4,41 @@ import { FormattedNumber } from 'react-intl';
/** Check if a value is REALLY a number. */ /** Check if a value is REALLY a number. */
export const isNumber = (value: unknown): value is number => typeof value === 'number' && !isNaN(value); export const isNumber = (value: unknown): value is number => typeof value === 'number' && !isNaN(value);
const roundDown = (num: number) => {
if (num >= 100 && num < 1000) {
num = Math.floor(num);
}
const n = Number(num.toFixed(2));
return (n > num) ? n - (1 / (Math.pow(10, 2))) : n;
};
/** Display a number nicely for the UI, eg 1000 becomes 1K. */ /** Display a number nicely for the UI, eg 1000 becomes 1K. */
export const shortNumberFormat = (number: any): React.ReactNode => { export const shortNumberFormat = (number: any): React.ReactNode => {
if (!isNumber(number)) return '•'; if (!isNumber(number)) return '•';
if (number < 1000) { let value = number;
return <FormattedNumber value={number} />; let factor: string = '';
} else if (number < 1000000) { if (number >= 1000 && number < 1000000) {
return <span><FormattedNumber value={number / 1000} maximumFractionDigits={1} />K</span>; factor = 'k';
} else { value = roundDown(value / 1000);
return <span><FormattedNumber value={number / 1000000} maximumFractionDigits={1} />M</span>; } else if (number >= 1000000) {
factor = 'M';
value = roundDown(value / 1000000);
} }
return (
<span>
<FormattedNumber
value={value}
maximumFractionDigits={0}
minimumFractionDigits={0}
maximumSignificantDigits={3}
style='decimal'
/>
{factor}
</span>
);
}; };
/** Check if an entity ID is an integer (eg not a FlakeId). */ /** Check if an entity ID is an integer (eg not a FlakeId). */

Loading…
Cancel
Save