]> cat aescling's git repositories - mastodon.git/blob - app/javascript/mastodon/components/short_number.js
Merge branch 'main' into glitch-soc/merge-upstream
[mastodon.git] / app / javascript / mastodon / components / short_number.js
1 import React from 'react';
2 import PropTypes from 'prop-types';
3 import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';
4 import { FormattedMessage, FormattedNumber } from 'react-intl';
5 // @ts-check
6
7 /**
8 * @callback ShortNumberRenderer
9 * @param {JSX.Element} displayNumber Number to display
10 * @param {number} pluralReady Number used for pluralization
11 * @returns {JSX.Element} Final render of number
12 */
13
14 /**
15 * @typedef {object} ShortNumberProps
16 * @property {number} value Number to display in short variant
17 * @property {ShortNumberRenderer} [renderer]
18 * Custom renderer for numbers, provided as a prop. If another renderer
19 * passed as a child of this component, this prop won't be used.
20 * @property {ShortNumberRenderer} [children]
21 * Custom renderer for numbers, provided as a child. If another renderer
22 * passed as a prop of this component, this one will be used instead.
23 */
24
25 /**
26 * Component that renders short big number to a shorter version
27 *
28 * @param {ShortNumberProps} param0 Props for the component
29 * @returns {JSX.Element} Rendered number
30 */
31 function ShortNumber({ value, renderer, children }) {
32 const shortNumber = toShortNumber(value);
33 const [, division] = shortNumber;
34
35 // eslint-disable-next-line eqeqeq
36 if (children != null && renderer != null) {
37 console.warn('Both renderer prop and renderer as a child provided. This is a mistake and you really should fix that. Only renderer passed as a child will be used.');
38 }
39
40 // eslint-disable-next-line eqeqeq
41 const customRenderer = children != null ? children : renderer;
42
43 const displayNumber = <ShortNumberCounter value={shortNumber} />;
44
45 // eslint-disable-next-line eqeqeq
46 return customRenderer != null
47 ? customRenderer(displayNumber, pluralReady(value, division))
48 : displayNumber;
49 }
50
51 ShortNumber.propTypes = {
52 value: PropTypes.number.isRequired,
53 renderer: PropTypes.func,
54 children: PropTypes.func,
55 };
56
57 /**
58 * @typedef {object} ShortNumberCounterProps
59 * @property {import('../utils/number').ShortNumber} value Short number
60 */
61
62 /**
63 * Renders short number into corresponding localizable react fragment
64 *
65 * @param {ShortNumberCounterProps} param0 Props for the component
66 * @returns {JSX.Element} FormattedMessage ready to be embedded in code
67 */
68 function ShortNumberCounter({ value }) {
69 const [rawNumber, unit, maxFractionDigits = 0] = value;
70
71 const count = (
72 <FormattedNumber
73 value={rawNumber}
74 maximumFractionDigits={maxFractionDigits}
75 />
76 );
77
78 let values = { count, rawNumber };
79
80 switch (unit) {
81 case DECIMAL_UNITS.THOUSAND: {
82 return (
83 <FormattedMessage
84 id='units.short.thousand'
85 defaultMessage='{count}K'
86 values={values}
87 />
88 );
89 }
90 case DECIMAL_UNITS.MILLION: {
91 return (
92 <FormattedMessage
93 id='units.short.million'
94 defaultMessage='{count}M'
95 values={values}
96 />
97 );
98 }
99 case DECIMAL_UNITS.BILLION: {
100 return (
101 <FormattedMessage
102 id='units.short.billion'
103 defaultMessage='{count}B'
104 values={values}
105 />
106 );
107 }
108 // Not sure if we should go farther - @Sasha-Sorokin
109 default: return count;
110 }
111 }
112
113 ShortNumberCounter.propTypes = {
114 value: PropTypes.arrayOf(PropTypes.number),
115 };
116
117 export default React.memo(ShortNumber);
This page took 0.075294 seconds and 4 git commands to generate.