glitch-soc/mastodon

View on GitHub
app/javascript/mastodon/features/explore/components/card.jsx

Summary

Maintainability
F
4 days
Test Coverage
import PropTypes from 'prop-types';
import { useCallback } from 'react';

import { FormattedMessage, useIntl, defineMessages } from 'react-intl';

import { Link } from 'react-router-dom';

import { useDispatch, useSelector } from 'react-redux';

import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { followAccount, unfollowAccount } from 'mastodon/actions/accounts';
import { dismissSuggestion } from 'mastodon/actions/suggestions';
import { Avatar } from 'mastodon/components/avatar';
import { Button } from 'mastodon/components/button';
import { DisplayName } from 'mastodon/components/display_name';
import { IconButton } from 'mastodon/components/icon_button';
import { domain } from 'mastodon/initial_state';

const messages = defineMessages({
  follow: { id: 'account.follow', defaultMessage: 'Follow' },
  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
  dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" },
});

export const Card = ({ id, source }) => {
  const intl = useIntl();
  const account = useSelector(state => state.getIn(['accounts', id]));
  const relationship = useSelector(state => state.getIn(['relationships', id]));
  const dispatch = useDispatch();
  const following = relationship?.get('following') ?? relationship?.get('requested');

  const handleFollow = useCallback(() => {
    if (following) {
      dispatch(unfollowAccount(id));
    } else {
      dispatch(followAccount(id));
    }
  }, [id, following, dispatch]);

  const handleDismiss = useCallback(() => {
    dispatch(dismissSuggestion(id));
  }, [id, dispatch]);

  let label;

  switch (source) {
  case 'friends_of_friends':
    label = <FormattedMessage id='follow_suggestions.friends_of_friends_longer' defaultMessage='Popular among people you follow' />;
    break;
  case 'similar_to_recently_followed':
    label = <FormattedMessage id='follow_suggestions.similar_to_recently_followed_longer' defaultMessage='Similar to profiles you recently followed' />;
    break;
  case 'featured':
    label = <FormattedMessage id='follow_suggestions.featured_longer' defaultMessage='Hand-picked by the {domain} team' values={{ domain }} />;
    break;
  case 'most_followed':
    label = <FormattedMessage id='follow_suggestions.popular_suggestion_longer' defaultMessage='Popular on {domain}' values={{ domain }} />;
    break;
  case 'most_interactions':
    label = <FormattedMessage id='follow_suggestions.popular_suggestion_longer' defaultMessage='Popular on {domain}' values={{ domain }} />;
    break;
  }

  return (
    <div className='explore__suggestions__card'>
      <div className='explore__suggestions__card__source'>
        {label}
      </div>

      <div className='explore__suggestions__card__body'>
        <Link to={`/@${account.get('acct')}`}><Avatar account={account} size={48} /></Link>

        <div className='explore__suggestions__card__body__main'>
          <div className='explore__suggestions__card__body__main__name-button'>
            <Link className='explore__suggestions__card__body__main__name-button__name' to={`/@${account.get('acct')}`}><DisplayName account={account} /></Link>
            <IconButton iconComponent={CloseIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
            <Button text={intl.formatMessage(following ? messages.unfollow : messages.follow)} secondary={following} onClick={handleFollow} />
          </div>
        </div>
      </div>
    </div>
  );
};

Card.propTypes = {
  id: PropTypes.string.isRequired,
  source: PropTypes.oneOf(['friends_of_friends', 'similar_to_recently_followed', 'featured', 'most_followed', 'most_interactions']),
};