ReportReasonSelector.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import api from 'mastodon/api';
  4. import { injectIntl, defineMessages } from 'react-intl';
  5. import classNames from 'classnames';
  6. const messages = defineMessages({
  7. other: { id: 'report.categories.other', defaultMessage: 'Other' },
  8. spam: { id: 'report.categories.spam', defaultMessage: 'Spam' },
  9. violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
  10. });
  11. class Category extends React.PureComponent {
  12. static propTypes = {
  13. id: PropTypes.string.isRequired,
  14. text: PropTypes.string.isRequired,
  15. selected: PropTypes.bool,
  16. disabled: PropTypes.bool,
  17. onSelect: PropTypes.func,
  18. children: PropTypes.node,
  19. };
  20. handleClick = () => {
  21. const { id, disabled, onSelect } = this.props;
  22. if (!disabled) {
  23. onSelect(id);
  24. }
  25. };
  26. render () {
  27. const { id, text, disabled, selected, children } = this.props;
  28. return (
  29. <div tabIndex='0' role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
  30. {selected && <input type='hidden' name='report[category]' value={id} />}
  31. <div className='report-reason-selector__category__label'>
  32. <span className={classNames('poll__input', { active: selected, disabled })} />
  33. {text}
  34. </div>
  35. {(selected && children) && (
  36. <div className='report-reason-selector__category__rules'>
  37. {children}
  38. </div>
  39. )}
  40. </div>
  41. );
  42. }
  43. }
  44. class Rule extends React.PureComponent {
  45. static propTypes = {
  46. id: PropTypes.string.isRequired,
  47. text: PropTypes.string.isRequired,
  48. selected: PropTypes.bool,
  49. disabled: PropTypes.bool,
  50. onToggle: PropTypes.func,
  51. };
  52. handleClick = () => {
  53. const { id, disabled, onToggle } = this.props;
  54. if (!disabled) {
  55. onToggle(id);
  56. }
  57. };
  58. render () {
  59. const { id, text, disabled, selected } = this.props;
  60. return (
  61. <div tabIndex='0' role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
  62. <span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
  63. {selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
  64. {text}
  65. </div>
  66. );
  67. }
  68. }
  69. export default @injectIntl
  70. class ReportReasonSelector extends React.PureComponent {
  71. static propTypes = {
  72. id: PropTypes.string.isRequired,
  73. category: PropTypes.string.isRequired,
  74. rule_ids: PropTypes.arrayOf(PropTypes.string),
  75. disabled: PropTypes.bool,
  76. intl: PropTypes.object.isRequired,
  77. };
  78. state = {
  79. category: this.props.category,
  80. rule_ids: this.props.rule_ids || [],
  81. rules: [],
  82. };
  83. componentDidMount() {
  84. api().get('/api/v1/instance').then(res => {
  85. this.setState({
  86. rules: res.data.rules,
  87. });
  88. }).catch(err => {
  89. console.error(err);
  90. });
  91. }
  92. _save = () => {
  93. const { id, disabled } = this.props;
  94. const { category, rule_ids } = this.state;
  95. if (disabled) {
  96. return;
  97. }
  98. api().put(`/api/v1/admin/reports/${id}`, {
  99. category,
  100. rule_ids,
  101. }).catch(err => {
  102. console.error(err);
  103. });
  104. };
  105. handleSelect = id => {
  106. this.setState({ category: id }, () => this._save());
  107. };
  108. handleToggle = id => {
  109. const { rule_ids } = this.state;
  110. if (rule_ids.includes(id)) {
  111. this.setState({ rule_ids: rule_ids.filter(x => x !== id ) }, () => this._save());
  112. } else {
  113. this.setState({ rule_ids: [...rule_ids, id] }, () => this._save());
  114. }
  115. };
  116. render () {
  117. const { disabled, intl } = this.props;
  118. const { rules, category, rule_ids } = this.state;
  119. return (
  120. <div className='report-reason-selector'>
  121. <Category id='other' text={intl.formatMessage(messages.other)} selected={category === 'other'} onSelect={this.handleSelect} disabled={disabled} />
  122. <Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === 'spam'} onSelect={this.handleSelect} disabled={disabled} />
  123. <Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === 'violation'} onSelect={this.handleSelect} disabled={disabled}>
  124. {rules.map(rule => <Rule key={rule.id} id={rule.id} text={rule.text} selected={rule_ids.includes(rule.id)} onToggle={this.handleToggle} disabled={disabled} />)}
  125. </Category>
  126. </div>
  127. );
  128. }
  129. }