import React, {Component} from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {compose} from 'react-apollo'; import * as notification from 'coral-admin/src/services/notification'; import key from 'keymaster'; import isEqual from 'lodash/isEqual'; import styles from './components/styles.css'; import translations from 'coral-admin/src/translations'; import I18n from 'coral-framework/modules/i18n/i18n'; import {modQueueQuery, getQueueCounts} from '../../graphql/queries'; import {banUser, setCommentStatus, suspendUser} from '../../graphql/mutations'; import {fetchSettings} from 'actions/settings'; import {updateAssets} from 'actions/assets'; import { toggleModal, singleView, showBanUserDialog, hideBanUserDialog, showSuspendUserDialog, hideSuspendUserDialog, hideShortcutsNote, viewUserDetail, hideUserDetail } from 'actions/moderation'; import {Spinner} from 'coral-ui'; import BanUserDialog from './components/BanUserDialog'; import SuspendUserDialog from './components/SuspendUserDialog'; import ModerationQueue from './ModerationQueue'; import ModerationMenu from './components/ModerationMenu'; import ModerationHeader from './components/ModerationHeader'; import NotFoundAsset from './components/NotFoundAsset'; import ModerationKeysModal from '../../components/ModerationKeysModal'; import UserDetail from './UserDetail'; const lang = new I18n(translations); class ModerationContainer extends Component { state = { selectedIndex: 0, sort: 'REVERSE_CHRONOLOGICAL' } componentWillMount() { const {toggleModal, singleView} = this.props; this.props.fetchSettings(); key('s', () => singleView()); key('shift+/', () => toggleModal(true)); key('esc', () => toggleModal(false)); key('j', this.select(true)); key('k', this.select(false)); key('r', this.moderate(false)); key('t', this.moderate(true)); } moderate = (accept) => () => { const {acceptComment, rejectComment} = this.props; const {selectedIndex} = this.state; const comments = this.getComments(); const comment = comments[selectedIndex]; const commentId = {commentId: comment.id}; if (accept) { comment.status !== 'ACCEPTED' && acceptComment(commentId); } else { comment.status !== 'REJECTED' && rejectComment(commentId); } } getComments = () => { const {data, route} = this.props; const activeTab = route.path === ':id' ? 'premod' : route.path; return data[activeTab]; } select = (next) => () => { if (next) { this.setState((prevState) => ({ ...prevState, selectedIndex: prevState.selectedIndex < this.getComments().length - 1 ? prevState.selectedIndex + 1 : prevState.selectedIndex })); } else { this.setState((prevState) => ({ ...prevState, selectedIndex: prevState.selectedIndex > 0 ? prevState.selectedIndex - 1 : prevState.selectedIndex })); } } selectSort = (sort) => { this.setState({sort}); this.props.modQueueResort(sort); } suspendUser = async (args) => { this.props.hideSuspendUserDialog(); try { const result = await this.props.suspendUser(args); if (result.data.suspendUser.errors) { throw result.data.suspendUser.errors; } notification.success( lang.t('suspenduser.notify_suspend_until', this.props.moderation.suspendUserDialog.username, lang.timeago(args.until)), ); const {commentStatus, commentId} = this.props.moderation.suspendUserDialog; if (commentStatus !== 'REJECTED') { return this.props.rejectComment({commentId}) .then((result) => { if (result.data.setCommentStatus.errors) { throw result.data.setCommentStatus.errors; } }); } } catch(err) { notification.handleMutationErrors(err); } }; componentWillUnmount() { key.unbind('s'); key.unbind('shift+/'); key.unbind('esc'); key.unbind('j'); key.unbind('k'); key.unbind('r'); key.unbind('t'); } componentDidUpdate(_, prevState) { // If paging through using keybaord shortcuts, scroll the page to keep the selected // comment in view. if (prevState.selectedIndex !== this.state.selectedIndex) { // the 'smooth' flag only works in FF as of March 2017 document.querySelector(`.${styles.selected}`).scrollIntoView({behavior: 'smooth'}); } } componentWillReceiveProps(nextProps) { const {updateAssets} = this.props; if(!isEqual(nextProps.data.assets, this.props.data.assets)) { updateAssets(nextProps.data.assets); } } render () { const {data, moderation, settings, assets, onClose, viewUserDetail, hideUserDetail, ...props} = this.props; const providedAssetId = this.props.params.id; const activeTab = this.props.route.path === ':id' ? 'premod' : this.props.route.path; let asset; if (!('premodCount' in data)) { return