glitch-soc/mastodon

View on GitHub
app/javascript/flavours/glitch/components/admin/ReportReasonSelector.jsx

Summary

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

import { injectIntl, defineMessages } from 'react-intl';

import classNames from 'classnames';

import api from 'flavours/glitch/api';

const messages = defineMessages({
  legal: { id: 'report.categories.legal', defaultMessage: 'Legal' },
  other: { id: 'report.categories.other', defaultMessage: 'Other' },
  spam: { id: 'report.categories.spam', defaultMessage: 'Spam' },
  violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
});

class Category extends PureComponent {

  static propTypes = {
    id: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    selected: PropTypes.bool,
    disabled: PropTypes.bool,
    onSelect: PropTypes.func,
    children: PropTypes.node,
  };

  handleClick = () => {
    const { id, disabled, onSelect } = this.props;

    if (!disabled) {
      onSelect(id);
    }
  };

  render () {
    const { id, text, disabled, selected, children } = this.props;

    return (
      <div tabIndex={0} role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
        {selected && <input type='hidden' name='report[category]' value={id} />}

        <div className='report-reason-selector__category__label'>
          <span className={classNames('poll__input', { active: selected, disabled })} />
          {text}
        </div>

        {(selected && children) && (
          <div className='report-reason-selector__category__rules'>
            {children}
          </div>
        )}
      </div>
    );
  }

}

class Rule extends PureComponent {

  static propTypes = {
    id: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    selected: PropTypes.bool,
    disabled: PropTypes.bool,
    onToggle: PropTypes.func,
  };

  handleClick = () => {
    const { id, disabled, onToggle } = this.props;

    if (!disabled) {
      onToggle(id);
    }
  };

  render () {
    const { id, text, disabled, selected } = this.props;

    return (
      <div tabIndex={0} role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
        <span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
        {selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
        {text}
      </div>
    );
  }

}

class ReportReasonSelector extends PureComponent {

  static propTypes = {
    id: PropTypes.string.isRequired,
    category: PropTypes.string.isRequired,
    rule_ids: PropTypes.arrayOf(PropTypes.string),
    disabled: PropTypes.bool,
    intl: PropTypes.object.isRequired,
  };

  state = {
    category: this.props.category,
    rule_ids: this.props.rule_ids || [],
    rules: [],
  };

  componentDidMount() {
    api(false).get('/api/v1/instance').then(res => {
      this.setState({
        rules: res.data.rules,
      });
    }).catch(err => {
      console.error(err);
    });
  }

  _save = () => {
    const { id, disabled } = this.props;
    const { category, rule_ids } = this.state;

    if (disabled) {
      return;
    }

    api(false).put(`/api/v1/admin/reports/${id}`, {
      category,
      rule_ids: category === 'violation' ? rule_ids : [],
    }).catch(err => {
      console.error(err);
    });
  };

  handleSelect = id => {
    this.setState({ category: id }, () => this._save());
  };

  handleToggle = id => {
    const { rule_ids } = this.state;

    if (rule_ids.includes(id)) {
      this.setState({ rule_ids: rule_ids.filter(x => x !== id ) }, () => this._save());
    } else {
      this.setState({ rule_ids: [...rule_ids, id] }, () => this._save());
    }
  };

  render () {
    const { disabled, intl } = this.props;
    const { rules, category, rule_ids } = this.state;

    return (
      <div className='report-reason-selector'>
        <Category id='other' text={intl.formatMessage(messages.other)} selected={category === 'other'} onSelect={this.handleSelect} disabled={disabled} />
        <Category id='legal' text={intl.formatMessage(messages.legal)} selected={category === 'legal'} onSelect={this.handleSelect} disabled={disabled} />
        <Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === 'spam'} onSelect={this.handleSelect} disabled={disabled} />
        <Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === 'violation'} onSelect={this.handleSelect} disabled={disabled || rules.length === 0}>
          {rules.map(rule => <Rule key={rule.id} id={rule.id} text={rule.text} selected={rule_ids.includes(rule.id)} onToggle={this.handleToggle} disabled={disabled} />)}
        </Category>
      </div>
    );
  }

}

export default injectIntl(ReportReasonSelector);