import PropTypes from 'prop-types'; import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import { OrderedSet } from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { connect } from 'react-redux'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import { submitReport } from 'mastodon/actions/reports'; import { fetchServer } from 'mastodon/actions/server'; import { expandAccountTimeline } from 'mastodon/actions/timelines'; import { IconButton } from 'mastodon/components/icon_button'; import Category from 'mastodon/features/report/category'; import Comment from 'mastodon/features/report/comment'; import Rules from 'mastodon/features/report/rules'; import Statuses from 'mastodon/features/report/statuses'; import Thanks from 'mastodon/features/report/thanks'; import { makeGetAccount } from 'mastodon/selectors'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, }); const makeMapStateToProps = () => { const getAccount = makeGetAccount(); const mapStateToProps = (state, { accountId }) => ({ account: getAccount(state, accountId), }); return mapStateToProps; }; class ReportModal extends ImmutablePureComponent { static propTypes = { accountId: PropTypes.string.isRequired, statusId: PropTypes.string, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, account: ImmutablePropTypes.record.isRequired, }; state = { step: 'category', selectedStatusIds: OrderedSet(this.props.statusId ? [this.props.statusId] : []), selectedDomains: OrderedSet(), comment: '', category: null, selectedRuleIds: OrderedSet(), isSubmitting: false, isSubmitted: false, }; handleSubmit = () => { const { dispatch, accountId } = this.props; const { selectedStatusIds, selectedDomains, comment, category, selectedRuleIds } = this.state; this.setState({ isSubmitting: true }); dispatch(submitReport({ account_id: accountId, status_ids: selectedStatusIds.toArray(), forward_to_domains: selectedDomains.toArray(), comment, forward: selectedDomains.size > 0, category, rule_ids: selectedRuleIds.toArray(), }, this.handleSuccess, this.handleFail)); }; handleSuccess = () => { this.setState({ isSubmitting: false, isSubmitted: true, step: 'thanks' }); }; handleFail = () => { this.setState({ isSubmitting: false }); }; handleStatusToggle = (statusId, checked) => { const { selectedStatusIds } = this.state; if (checked) { this.setState({ selectedStatusIds: selectedStatusIds.add(statusId) }); } else { this.setState({ selectedStatusIds: selectedStatusIds.remove(statusId) }); } }; handleDomainToggle = (domain, checked) => { if (checked) { this.setState((state) => ({ selectedDomains: state.selectedDomains.add(domain) })); } else { this.setState((state) => ({ selectedDomains: state.selectedDomains.remove(domain) })); } }; handleRuleToggle = (ruleId, checked) => { if (checked) { this.setState((state) => ({ selectedRuleIds: state.selectedRuleIds.add(ruleId) })); } else { this.setState((state) => ({ selectedRuleIds: state.selectedRuleIds.remove(ruleId) })); } }; handleChangeCategory = category => { this.setState({ category }); }; handleChangeComment = comment => { this.setState({ comment }); }; handleNextStep = step => { this.setState({ step }); }; componentDidMount () { const { dispatch, accountId } = this.props; dispatch(expandAccountTimeline(accountId, { withReplies: true })); dispatch(fetchServer()); } render () { const { accountId, account, intl, onClose, } = this.props; if (!account) { return null; } const { step, selectedStatusIds, selectedRuleIds, selectedDomains, comment, category, isSubmitting, isSubmitted, } = this.state; const domain = account.get('acct').split('@')[1]; const isRemote = !!domain; let stepComponent; switch(step) { case 'category': stepComponent = ( <Category onNextStep={this.handleNextStep} startedFrom={this.props.statusId ? 'status' : 'account'} category={category} onChangeCategory={this.handleChangeCategory} /> ); break; case 'rules': stepComponent = ( <Rules onNextStep={this.handleNextStep} selectedRuleIds={selectedRuleIds} onToggle={this.handleRuleToggle} /> ); break; case 'statuses': stepComponent = ( <Statuses onNextStep={this.handleNextStep} accountId={accountId} selectedStatusIds={selectedStatusIds} onToggle={this.handleStatusToggle} /> ); break; case 'comment': stepComponent = ( <Comment onSubmit={this.handleSubmit} isSubmitting={isSubmitting} isRemote={isRemote} comment={comment} domain={domain} onChangeComment={this.handleChangeComment} statusIds={selectedStatusIds} selectedDomains={selectedDomains} onToggleDomain={this.handleDomainToggle} /> ); break; case 'thanks': stepComponent = ( <Thanks submitted={isSubmitted} account={account} onClose={onClose} /> ); } return ( <div className='modal-root__modal report-dialog-modal'> <div className='report-modal__target'> <IconButton className='report-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={20} /> <FormattedMessage id='report.target' defaultMessage='Report {target}' values={{ target: <strong>{account.get('acct')}</strong> }} /> </div> <div className='report-dialog-modal__container'> {stepComponent} </div> </div> ); } } export default connect(makeMapStateToProps)(injectIntl(ReportModal));