[Glitch] Replace shortNumberFormat with <ShortNumber>
Port cb2adaaf9d to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		@@ -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 && (
 | 
			
		||||
      <ShortNumber
 | 
			
		||||
        value={tag.history.reduce((total, day) => total + day.uses * 1, 0)}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div className='autosuggest-hashtag'>
 | 
			
		||||
        <div className='autosuggest-hashtag__name'>#<strong>{tag.name}</strong></div>
 | 
			
		||||
        {tag.history !== undefined && <div className='autosuggest-hashtag__uses'><FormattedMessage id='autosuggest_hashtag.per_week' defaultMessage='{count} per week' values={{ count: weeklyUses }} /></div>}
 | 
			
		||||
        <div className='autosuggest-hashtag__name'>
 | 
			
		||||
          #<strong>{tag.name}</strong>
 | 
			
		||||
        </div>
 | 
			
		||||
        {tag.history !== undefined && (
 | 
			
		||||
          <div className='autosuggest-hashtag__uses'>
 | 
			
		||||
            <FormattedMessage
 | 
			
		||||
              id='autosuggest_hashtag.per_week'
 | 
			
		||||
              defaultMessage='{count} per week'
 | 
			
		||||
              values={{ count: weeklyUses }}
 | 
			
		||||
            />
 | 
			
		||||
          </div>
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								app/javascript/flavours/glitch/components/common_counter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								app/javascript/flavours/glitch/components/common_counter.js
									
									
									
									
									
										Normal file
									
								
							@@ -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) => <strong>{displayNumber}</strong>
 | 
			
		||||
    : (displayNumber) => displayNumber;
 | 
			
		||||
 | 
			
		||||
  switch (counterType) {
 | 
			
		||||
  case 'statuses': {
 | 
			
		||||
    return (displayNumber, pluralReady) => (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='account.statuses_counter'
 | 
			
		||||
        defaultMessage='{count, plural, one {{counter} Toot} other {{counter} Toots}}'
 | 
			
		||||
        values={{
 | 
			
		||||
          count: pluralReady,
 | 
			
		||||
          counter: renderCounter(displayNumber),
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  case 'following': {
 | 
			
		||||
    return (displayNumber, pluralReady) => (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='account.following_counter'
 | 
			
		||||
        defaultMessage='{count, plural, other {{counter} Following}}'
 | 
			
		||||
        values={{
 | 
			
		||||
          count: pluralReady,
 | 
			
		||||
          counter: renderCounter(displayNumber),
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  case 'followers': {
 | 
			
		||||
    return (displayNumber, pluralReady) => (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='account.followers_counter'
 | 
			
		||||
        defaultMessage='{count, plural, one {{counter} Follower} other {{counter} Followers}}'
 | 
			
		||||
        values={{
 | 
			
		||||
          count: pluralReady,
 | 
			
		||||
          counter: renderCounter(displayNumber),
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  default: throw Error(`Incorrect counter name: ${counterType}. Ensure it accepted by commonCounter function`);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -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) => (
 | 
			
		||||
  <FormattedMessage
 | 
			
		||||
    id='trends.counter_by_accounts'
 | 
			
		||||
    defaultMessage='{count, plural, one {{counter} person} other {{counter} people}} talking'
 | 
			
		||||
    values={{
 | 
			
		||||
      count: pluralReady,
 | 
			
		||||
      counter: <strong>{displayNumber}</strong>,
 | 
			
		||||
    }}
 | 
			
		||||
  />
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const Hashtag = ({ hashtag }) => (
 | 
			
		||||
  <div className='trends__item'>
 | 
			
		||||
    <div className='trends__item__name'>
 | 
			
		||||
      <Permalink href={hashtag.get('url')} to={`/timelines/tag/${hashtag.get('name')}`}>
 | 
			
		||||
      <Permalink
 | 
			
		||||
        href={hashtag.get('url')}
 | 
			
		||||
        to={`/timelines/tag/${hashtag.get('name')}`}
 | 
			
		||||
      >
 | 
			
		||||
        #<span>{hashtag.get('name')}</span>
 | 
			
		||||
      </Permalink>
 | 
			
		||||
 | 
			
		||||
      <FormattedMessage id='trends.count_by_accounts' defaultMessage='{count} {rawCount, plural, one {person} other {people}} talking' values={{ rawCount: hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1, count: <strong>{shortNumberFormat(hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1)}</strong> }} />
 | 
			
		||||
      <ShortNumber
 | 
			
		||||
        value={
 | 
			
		||||
          hashtag.getIn(['history', 0, 'accounts']) * 1 +
 | 
			
		||||
          hashtag.getIn(['history', 1, 'accounts']) * 1
 | 
			
		||||
        }
 | 
			
		||||
        renderer={accountsCountRenderer}
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div className='trends__item__current'>
 | 
			
		||||
      {shortNumberFormat(hashtag.getIn(['history', 0, 'uses']) * 1 + hashtag.getIn(['history', 1, 'uses']) * 1)}
 | 
			
		||||
      <ShortNumber
 | 
			
		||||
        value={
 | 
			
		||||
          hashtag.getIn(['history', 0, 'uses']) * 1 +
 | 
			
		||||
          hashtag.getIn(['history', 1, 'uses']) * 1
 | 
			
		||||
        }
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div className='trends__item__sparkline'>
 | 
			
		||||
      <Sparklines width={50} height={28} data={hashtag.get('history').reverse().map(day => day.get('uses')).toArray()}>
 | 
			
		||||
      <Sparklines
 | 
			
		||||
        width={50}
 | 
			
		||||
        height={28}
 | 
			
		||||
        data={hashtag
 | 
			
		||||
          .get('history')
 | 
			
		||||
          .reverse()
 | 
			
		||||
          .map((day) => day.get('uses'))
 | 
			
		||||
          .toArray()}
 | 
			
		||||
      >
 | 
			
		||||
        <SparklinesCurve style={{ fill: 'none' }} />
 | 
			
		||||
      </Sparklines>
 | 
			
		||||
    </div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										117
									
								
								app/javascript/flavours/glitch/components/short_number.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								app/javascript/flavours/glitch/components/short_number.js
									
									
									
									
									
										Normal file
									
								
							@@ -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 = <ShortNumberCounter value={shortNumber} />;
 | 
			
		||||
 | 
			
		||||
  // 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 = (
 | 
			
		||||
    <FormattedNumber
 | 
			
		||||
      value={rawNumber}
 | 
			
		||||
      maximumFractionDigits={maxFractionDigits}
 | 
			
		||||
    />
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  let values = { count, rawNumber };
 | 
			
		||||
 | 
			
		||||
  switch (unit) {
 | 
			
		||||
  case DECIMAL_UNITS.THOUSAND: {
 | 
			
		||||
    return (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='units.short.thousand'
 | 
			
		||||
        defaultMessage='{count}K'
 | 
			
		||||
        values={values}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  case DECIMAL_UNITS.MILLION: {
 | 
			
		||||
    return (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='units.short.million'
 | 
			
		||||
        defaultMessage='{count}M'
 | 
			
		||||
        values={values}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  case DECIMAL_UNITS.BILLION: {
 | 
			
		||||
    return (
 | 
			
		||||
      <FormattedMessage
 | 
			
		||||
        id='units.short.billion'
 | 
			
		||||
        defaultMessage='{count}B'
 | 
			
		||||
        values={values}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  // Not sure if we should go farther - @Sasha-Sorokin
 | 
			
		||||
  default: return count;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShortNumberCounter.propTypes = {
 | 
			
		||||
  value: PropTypes.arrayOf(PropTypes.number),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default React.memo(ShortNumber);
 | 
			
		||||
		Reference in New Issue
	
	Block a user