From a3ac322ded4277f954b45697ea765b0d90d37e9d Mon Sep 17 00:00:00 2001 From: Sasha Sorokin Date: Mon, 6 Jul 2020 19:27:32 +0700 Subject: [Glitch] Replace shortNumberFormat with Port cb2adaaf9d6c3147de9060132b69933df734d5dc to glitch-soc Signed-off-by: Thibaut Girka --- .../glitch/components/autosuggest_hashtag.js | 24 ++++- .../flavours/glitch/components/common_counter.js | 62 +++++++++++ .../flavours/glitch/components/hashtag.js | 49 ++++++++- .../flavours/glitch/components/short_number.js | 117 +++++++++++++++++++++ 4 files changed, 242 insertions(+), 10 deletions(-) create mode 100644 app/javascript/flavours/glitch/components/common_counter.js create mode 100644 app/javascript/flavours/glitch/components/short_number.js (limited to 'app/javascript/flavours/glitch/components') diff --git a/app/javascript/flavours/glitch/components/autosuggest_hashtag.js b/app/javascript/flavours/glitch/components/autosuggest_hashtag.js index 648987dfd..d787ed07a 100644 --- a/app/javascript/flavours/glitch/components/autosuggest_hashtag.js +++ b/app/javascript/flavours/glitch/components/autosuggest_hashtag.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { shortNumberFormat } from 'flavours/glitch/util/numbers'; +import ShortNumber from 'flavours/glitch/components/short_number'; import { FormattedMessage } from 'react-intl'; export default class AutosuggestHashtag extends React.PureComponent { @@ -13,14 +13,28 @@ export default class AutosuggestHashtag extends React.PureComponent { }).isRequired, }; - render () { + render() { const { tag } = this.props; - const weeklyUses = tag.history && shortNumberFormat(tag.history.reduce((total, day) => total + (day.uses * 1), 0)); + const weeklyUses = tag.history && ( + total + day.uses * 1, 0)} + /> + ); return (
-
#{tag.name}
- {tag.history !== undefined &&
} +
+ #{tag.name} +
+ {tag.history !== undefined && ( +
+ +
+ )}
); } diff --git a/app/javascript/flavours/glitch/components/common_counter.js b/app/javascript/flavours/glitch/components/common_counter.js new file mode 100644 index 000000000..4fdf3babf --- /dev/null +++ b/app/javascript/flavours/glitch/components/common_counter.js @@ -0,0 +1,62 @@ +// @ts-check +import React from 'react'; +import { FormattedMessage } from 'react-intl'; + +/** + * Returns custom renderer for one of the common counter types + * + * @param {"statuses" | "following" | "followers"} counterType + * Type of the counter + * @param {boolean} isBold Whether display number must be displayed in bold + * @returns {(displayNumber: JSX.Element, pluralReady: number) => JSX.Element} + * Renderer function + * @throws If counterType is not covered by this function + */ +export function counterRenderer(counterType, isBold = true) { + /** + * @type {(displayNumber: JSX.Element) => JSX.Element} + */ + const renderCounter = isBold + ? (displayNumber) => {displayNumber} + : (displayNumber) => displayNumber; + + switch (counterType) { + case 'statuses': { + return (displayNumber, pluralReady) => ( + + ); + } + case 'following': { + return (displayNumber, pluralReady) => ( + + ); + } + case 'followers': { + return (displayNumber, pluralReady) => ( + + ); + } + default: throw Error(`Incorrect counter name: ${counterType}. Ensure it accepted by commonCounter function`); + } +} diff --git a/app/javascript/flavours/glitch/components/hashtag.js b/app/javascript/flavours/glitch/components/hashtag.js index d42bee0e9..639d87a1e 100644 --- a/app/javascript/flavours/glitch/components/hashtag.js +++ b/app/javascript/flavours/glitch/components/hashtag.js @@ -1,26 +1,65 @@ +// @ts-check import React from 'react'; import { Sparklines, SparklinesCurve } from 'react-sparklines'; import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import Permalink from './permalink'; -import { shortNumberFormat } from 'flavours/glitch/util/numbers'; +import ShortNumber from 'flavours/glitch/components/short_number'; + +/** + * Used to render counter of how much people are talking about hashtag + * + * @type {(displayNumber: JSX.Element, pluralReady: number) => JSX.Element} + */ +const accountsCountRenderer = (displayNumber, pluralReady) => ( + {displayNumber}, + }} + /> +); const Hashtag = ({ hashtag }) => (
- + #{hashtag.get('name')} - {shortNumberFormat(hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1)} }} /> +
- {shortNumberFormat(hashtag.getIn(['history', 0, 'uses']) * 1 + hashtag.getIn(['history', 1, 'uses']) * 1)} +
- day.get('uses')).toArray()}> + day.get('uses')) + .toArray()} + >
diff --git a/app/javascript/flavours/glitch/components/short_number.js b/app/javascript/flavours/glitch/components/short_number.js new file mode 100644 index 000000000..e4ba09634 --- /dev/null +++ b/app/javascript/flavours/glitch/components/short_number.js @@ -0,0 +1,117 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../util/numbers'; +import { FormattedMessage, FormattedNumber } from 'react-intl'; +// @ts-check + +/** + * @callback ShortNumberRenderer + * @param {JSX.Element} displayNumber Number to display + * @param {number} pluralReady Number used for pluralization + * @returns {JSX.Element} Final render of number + */ + +/** + * @typedef {object} ShortNumberProps + * @property {number} value Number to display in short variant + * @property {ShortNumberRenderer} [renderer] + * Custom renderer for numbers, provided as a prop. If another renderer + * passed as a child of this component, this prop won't be used. + * @property {ShortNumberRenderer} [children] + * Custom renderer for numbers, provided as a child. If another renderer + * passed as a prop of this component, this one will be used instead. + */ + +/** + * Component that renders short big number to a shorter version + * + * @param {ShortNumberProps} param0 Props for the component + * @returns {JSX.Element} Rendered number + */ +function ShortNumber({ value, renderer, children }) { + const shortNumber = toShortNumber(value); + const [, division] = shortNumber; + + // eslint-disable-next-line eqeqeq + if (children != null && renderer != null) { + 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.'); + } + + // eslint-disable-next-line eqeqeq + const customRenderer = children != null ? children : renderer; + + const displayNumber = ; + + // eslint-disable-next-line eqeqeq + return customRenderer != null + ? customRenderer(displayNumber, pluralReady(value, division)) + : displayNumber; +} + +ShortNumber.propTypes = { + value: PropTypes.number.isRequired, + renderer: PropTypes.func, + children: PropTypes.func, +}; + +/** + * @typedef {object} ShortNumberCounterProps + * @property {import('../util/number').ShortNumber} value Short number + */ + +/** + * Renders short number into corresponding localizable react fragment + * + * @param {ShortNumberCounterProps} param0 Props for the component + * @returns {JSX.Element} FormattedMessage ready to be embedded in code + */ +function ShortNumberCounter({ value }) { + const [rawNumber, unit, maxFractionDigits = 0] = value; + + const count = ( + + ); + + let values = { count, rawNumber }; + + switch (unit) { + case DECIMAL_UNITS.THOUSAND: { + return ( + + ); + } + case DECIMAL_UNITS.MILLION: { + return ( + + ); + } + case DECIMAL_UNITS.BILLION: { + return ( + + ); + } + // Not sure if we should go farther - @Sasha-Sorokin + default: return count; + } +} + +ShortNumberCounter.propTypes = { + value: PropTypes.arrayOf(PropTypes.number), +}; + +export default React.memo(ShortNumber); -- cgit