glitch-soc/mastodon

View on GitHub
app/javascript/flavours/glitch/features/ui/components/mute_modal.jsx

Summary

Maintainability
F
1 wk
Test Coverage
import PropTypes from 'prop-types';
import { useCallback, useState } from 'react';

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

import classNames from 'classnames';

import { useDispatch } from 'react-redux';


import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import CampaignIcon from '@/material-icons/400-24px/campaign.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react';
import { muteAccount } from 'flavours/glitch/actions/accounts';
import { closeModal } from 'flavours/glitch/actions/modal';
import { Button } from 'flavours/glitch/components/button';
import { CheckBox } from 'flavours/glitch/components/check_box';
import { Icon } from 'flavours/glitch/components/icon';
import { RadioButton } from 'flavours/glitch/components/radio_button';

const messages = defineMessages({
  minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
  hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
  days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
  indefinite: { id: 'mute_modal.indefinite', defaultMessage: 'Until I unmute them' },
  hideFromNotifications: { id: 'mute_modal.hide_from_notifications', defaultMessage: 'Hide from notifications' },
});

const RadioButtonLabel = ({ name, value, currentValue, onChange, label }) => (
  <RadioButton
    name={name}
    value={value}
    checked={value === currentValue}
    onChange={onChange}
    label={label}
  />
);

RadioButtonLabel.propTypes = {
  name: PropTypes.string,
  value: PropTypes.oneOf([PropTypes.string, PropTypes.number, PropTypes.bool]),
  currentValue: PropTypes.oneOf([PropTypes.string, PropTypes.number, PropTypes.bool]),
  checked: PropTypes.bool,
  onChange: PropTypes.func,
  label: PropTypes.node,
};

export const MuteModal = ({ accountId, acct }) => {
  const intl = useIntl();
  const dispatch = useDispatch();
  const [notifications, setNotifications] = useState(true);
  const [muteDuration, setMuteDuration] = useState('0');
  const [expanded, setExpanded] = useState(false);

  const handleClick = useCallback(() => {
    dispatch(closeModal({ modalType: undefined, ignoreFocus: false }));
    dispatch(muteAccount(accountId, notifications, muteDuration));
  }, [dispatch, accountId, notifications, muteDuration]);

  const handleCancel = useCallback(() => {
    dispatch(closeModal({ modalType: undefined, ignoreFocus: false }));
  }, [dispatch]);

  const handleToggleNotifications = useCallback(({ target }) => {
    setNotifications(target.checked);
  }, [setNotifications]);

  const handleChangeMuteDuration = useCallback(({ target }) => {
    setMuteDuration(target.value);
  }, [setMuteDuration]);

  const handleToggleSettings = useCallback(() => {
    setExpanded(!expanded);
  }, [expanded, setExpanded]);

  return (
    <div className='modal-root__modal safety-action-modal'>
      <div className='safety-action-modal__top'>
        <div className='safety-action-modal__header'>
          <div className='safety-action-modal__header__icon'>
            <Icon icon={VolumeOffIcon} />
          </div>

          <div>
            <h1><FormattedMessage id='mute_modal.title' defaultMessage='Mute user?' /></h1>
            <div>@{acct}</div>
          </div>
        </div>

        <div className='safety-action-modal__bullet-points'>
          <div>
            <div className='safety-action-modal__bullet-points__icon'><Icon icon={CampaignIcon} /></div>
            <div><FormattedMessage id='mute_modal.they_wont_know' defaultMessage="They won't know they've been muted." /></div>
          </div>

          <div>
            <div className='safety-action-modal__bullet-points__icon'><Icon icon={VisibilityOffIcon} /></div>
            <div><FormattedMessage id='mute_modal.you_wont_see_posts' defaultMessage="They can still see your posts, but you won't see theirs." /></div>
          </div>

          <div>
            <div className='safety-action-modal__bullet-points__icon'><Icon icon={AlternateEmailIcon} /></div>
            <div><FormattedMessage id='mute_modal.you_wont_see_mentions' defaultMessage="You won't see posts that mention them." /></div>
          </div>

          <div>
            <div className='safety-action-modal__bullet-points__icon'><Icon icon={ReplyIcon} /></div>
            <div><FormattedMessage id='mute_modal.they_can_mention_and_follow' defaultMessage="They can mention and follow you, but you won't see them." /></div>
          </div>
        </div>
      </div>

      <div className={classNames('safety-action-modal__bottom', { active: expanded })}>
        <div className='safety-action-modal__bottom__collapsible'>
          <div className='safety-action-modal__field-group'>
            <RadioButtonLabel name='duration' value='0' label={intl.formatMessage(messages.indefinite)} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
            <RadioButtonLabel name='duration' value='21600' label={intl.formatMessage(messages.hours, { number: 6 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
            <RadioButtonLabel name='duration' value='86400' label={intl.formatMessage(messages.hours, { number: 24 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
            <RadioButtonLabel name='duration' value='604800' label={intl.formatMessage(messages.days, { number: 7 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
            <RadioButtonLabel name='duration' value='2592000' label={intl.formatMessage(messages.days, { number: 30 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
          </div>

          <div className='safety-action-modal__field-group'>
            <CheckBox label={intl.formatMessage(messages.hideFromNotifications)} checked={notifications} onChange={handleToggleNotifications} />
          </div>
        </div>

        <div className='safety-action-modal__actions'>
          <button onClick={handleToggleSettings} className='link-button'>
            {expanded ? <FormattedMessage id='mute_modal.hide_options' defaultMessage='Hide options' /> : <FormattedMessage id='mute_modal.show_options' defaultMessage='Show options' />}
          </button>

          <div className='spacer' />

          <button onClick={handleCancel} className='link-button'>
            <FormattedMessage id='confirmation_modal.cancel' defaultMessage='Cancel' />
          </button>

          <Button onClick={handleClick} autoFocus>
            <FormattedMessage id='confirmations.mute.confirm' defaultMessage='Mute' />
          </Button>
        </div>
      </div>
    </div>
  );
};

MuteModal.propTypes = {
  accountId: PropTypes.string.isRequired,
  acct: PropTypes.string.isRequired,
};

export default MuteModal;