mirror of
https://github.com/wassname/talk.git
synced 2026-07-10 02:41:53 +08:00
Move userDetail out of Moderation route
This commit is contained in:
@@ -15,33 +15,11 @@ export const hideShortcutsNote = () => {
|
||||
return {type: actions.HIDE_SHORTCUTS_NOTE};
|
||||
};
|
||||
|
||||
export const viewUserDetail = (userId) => ({type: actions.VIEW_USER_DETAIL, userId});
|
||||
export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL});
|
||||
|
||||
export const setSortOrder = (order) => ({
|
||||
type: actions.SET_SORT_ORDER,
|
||||
order
|
||||
});
|
||||
|
||||
export const changeUserDetailStatuses = (tab) => {
|
||||
let statuses;
|
||||
if (tab === 'all') {
|
||||
statuses = ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'];
|
||||
} else if (tab === 'rejected') {
|
||||
statuses = ['REJECTED'];
|
||||
}
|
||||
return {type: actions.CHANGE_USER_DETAIL_STATUSES, tab, statuses};
|
||||
};
|
||||
|
||||
export const clearUserDetailSelections = () => ({type: actions.CLEAR_USER_DETAIL_SELECTIONS});
|
||||
|
||||
export const toggleSelectCommentInUserDetail = (id, active) => {
|
||||
return {
|
||||
type: active ? actions.SELECT_USER_DETAIL_COMMENT : actions.UNSELECT_USER_DETAIL_COMMENT,
|
||||
id
|
||||
};
|
||||
};
|
||||
|
||||
export const toggleStorySearch = (active) => ({
|
||||
type: active ? actions.SHOW_STORY_SEARCH : actions.HIDE_STORY_SEARCH
|
||||
});
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import * as actions from 'constants/moderation';
|
||||
|
||||
export const viewUserDetail = (userId) => ({type: actions.VIEW_USER_DETAIL, userId});
|
||||
export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL});
|
||||
|
||||
export const changeUserDetailStatuses = (tab) => {
|
||||
let statuses;
|
||||
if (tab === 'all') {
|
||||
statuses = ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'];
|
||||
} else if (tab === 'rejected') {
|
||||
statuses = ['REJECTED'];
|
||||
}
|
||||
return {type: actions.CHANGE_USER_DETAIL_STATUSES, tab, statuses};
|
||||
};
|
||||
|
||||
export const clearUserDetailSelections = () => ({type: actions.CLEAR_USER_DETAIL_SELECTIONS});
|
||||
|
||||
export const toggleSelectCommentInUserDetail = (id, active) => {
|
||||
return {
|
||||
type: active ? actions.SELECT_USER_DETAIL_COMMENT : actions.UNSELECT_USER_DETAIL_COMMENT,
|
||||
id
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import styles from './ModerationList.css';
|
||||
import {Button} from 'coral-ui';
|
||||
import {menuActionsMap} from '../routes/Moderation/helpers/moderationQueueActionsMap';
|
||||
import {menuActionsMap} from '../utils/moderationQueueActionsMap';
|
||||
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
.bodyLeave {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
opacity: 1.0;
|
||||
transition: background 400ms, opacity 800ms 1600ms;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bodyLeaveActive {
|
||||
opacity: 0;
|
||||
background-color: rgba(255,255,0, 0.2);
|
||||
}
|
||||
|
||||
.bodyEnter {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bodyEnterActive {
|
||||
opacity: 1.0;
|
||||
transition: opacity 800ms 2400ms;
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import {murmur3} from 'murmurhash-js';
|
||||
import {CSSTransitionGroup} from 'react-transition-group';
|
||||
import styles from './styles.css';
|
||||
import styles from './CommentAnimatedEdit.css';
|
||||
|
||||
export default ({children, body}) => {
|
||||
return (
|
||||
+21
-3
@@ -1,10 +1,10 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import Comment from './UserDetailComment';
|
||||
import styles from './UserDetail.css';
|
||||
import {Button, Drawer} from 'coral-ui';
|
||||
import {Button, Drawer, Spinner} from 'coral-ui';
|
||||
import {Slot} from 'coral-framework/components';
|
||||
import ButtonCopyToClipboard from './ButtonCopyToClipboard';
|
||||
import {actionsMap} from '../helpers/moderationQueueActionsMap';
|
||||
import {actionsMap} from '../utils/moderationQueueActionsMap';
|
||||
import ClickOutside from 'coral-framework/components/ClickOutside';
|
||||
|
||||
export default class UserDetail extends React.Component {
|
||||
@@ -43,7 +43,17 @@ export default class UserDetail extends React.Component {
|
||||
this.props.changeStatus('rejected');
|
||||
}
|
||||
|
||||
render () {
|
||||
renderLoading() {
|
||||
return (
|
||||
<ClickOutside onClickOutside={this.props.hideUserDetail}>
|
||||
<Drawer onClose={this.props.hideUserDetail}>
|
||||
<Spinner />
|
||||
</Drawer>
|
||||
</ClickOutside>
|
||||
);
|
||||
}
|
||||
|
||||
renderLoaded() {
|
||||
const {
|
||||
root: {
|
||||
user,
|
||||
@@ -61,6 +71,7 @@ export default class UserDetail extends React.Component {
|
||||
hideUserDetail,
|
||||
viewUserDetail,
|
||||
} = this.props;
|
||||
|
||||
const localProfile = user.profiles.find((p) => p.provider === 'local');
|
||||
|
||||
let profile;
|
||||
@@ -160,4 +171,11 @@ export default class UserDetail extends React.Component {
|
||||
</ClickOutside>
|
||||
);
|
||||
}
|
||||
|
||||
render () {
|
||||
if (this.props.loading) {
|
||||
return this.renderLoading();
|
||||
}
|
||||
return this.renderLoaded();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export const VIEW_USER_DETAIL = 'VIEW_USER_DETAIL';
|
||||
export const HIDE_USER_DETAIL = 'HIDE_USER_DETAIL';
|
||||
export const CHANGE_USER_DETAIL_STATUSES = 'CHANGE_USER_DETAIL_STATUSES';
|
||||
export const SELECT_USER_DETAIL_COMMENT = 'SELECT_USER_DETAIL_COMMENT';
|
||||
export const UNSELECT_USER_DETAIL_COMMENT = 'UNSELECT_USER_DETAIL_COMMENT';
|
||||
export const CLEAR_USER_DETAIL_SELECTIONS = 'CLEAR_USER_DETAIL_SELECTIONS';
|
||||
|
||||
@@ -10,6 +10,7 @@ import SuspendUserDialog from './SuspendUserDialog';
|
||||
import {toggleModal as toggleShortcutModal} from '../actions/moderation';
|
||||
import {checkLogin, handleLogin, requestPasswordReset} from '../actions/auth';
|
||||
import {can} from 'coral-framework/services/perms';
|
||||
import UserDetail from 'coral-admin/src/containers/UserDetail';
|
||||
|
||||
class LayoutContainer extends Component {
|
||||
componentWillMount() {
|
||||
@@ -57,6 +58,7 @@ class LayoutContainer extends Component {
|
||||
>
|
||||
<BanUserDialog />
|
||||
<SuspendUserDialog />
|
||||
<UserDetail />
|
||||
{this.props.children}
|
||||
</Layout>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import React from 'react';
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
@@ -6,23 +6,25 @@ import UserDetail from '../components/UserDetail';
|
||||
import withQuery from 'coral-framework/hocs/withQuery';
|
||||
import {getDefinitionName, getSlotFragmentSpreads} from 'coral-framework/utils';
|
||||
import {
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
changeUserDetailStatuses,
|
||||
clearUserDetailSelections,
|
||||
toggleSelectCommentInUserDetail
|
||||
} from 'coral-admin/src/actions/moderation';
|
||||
toggleSelectCommentInUserDetail,
|
||||
} from 'coral-admin/src/actions/userDetail';
|
||||
import {withSetCommentStatus} from 'coral-framework/graphql/mutations';
|
||||
import Comment from './Comment';
|
||||
import UserDetailComment from './UserDetailComment';
|
||||
|
||||
const commentConnectionFragment = gql`
|
||||
fragment CoralAdmin_Moderation_CommentConnection on CommentConnection {
|
||||
nodes {
|
||||
...${getDefinitionName(Comment.fragments.comment)}
|
||||
...${getDefinitionName(UserDetailComment.fragments.comment)}
|
||||
}
|
||||
hasNextPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
${Comment.fragments.comment}
|
||||
${UserDetailComment.fragments.comment}
|
||||
`;
|
||||
|
||||
const slots = [
|
||||
@@ -30,14 +32,10 @@ const slots = [
|
||||
];
|
||||
|
||||
class UserDetailContainer extends React.Component {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
hideUserDetail: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
// status can be 'ACCEPTED' or 'REJECTED'
|
||||
bulkSetCommentStatus = (status) => {
|
||||
const changes = this.props.moderation.userDetailSelectedIds.map((commentId) => {
|
||||
const changes = this.props.selectedIds.map((commentId) => {
|
||||
return this.props.setCommentStatus({commentId, status});
|
||||
});
|
||||
|
||||
@@ -55,16 +53,29 @@ class UserDetailContainer extends React.Component {
|
||||
this.bulkSetCommentStatus('ACCEPTED');
|
||||
}
|
||||
|
||||
acceptComment = ({commentId}) => {
|
||||
return this.props.setCommentStatus({commentId, status: 'ACCEPTED'});
|
||||
}
|
||||
|
||||
rejectComment = ({commentId}) => {
|
||||
return this.props.setCommentStatus({commentId, status: 'REJECTED'});
|
||||
}
|
||||
|
||||
render () {
|
||||
if (!('user' in this.props.root)) {
|
||||
if (!this.props.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const loading = !('user' in this.props.root) || this.props.root.user.id !== this.props.id;
|
||||
|
||||
return <UserDetail
|
||||
bulkReject={this.bulkReject}
|
||||
bulkAccept={this.bulkAccept}
|
||||
changeStatus={this.props.changeUserDetailStatuses}
|
||||
toggleSelect={this.props.toggleSelectCommentInUserDetail}
|
||||
acceptComment={this.acceptComment}
|
||||
rejectComment={this.rejectComment}
|
||||
loading={loading}
|
||||
{...this.props} />;
|
||||
}
|
||||
}
|
||||
@@ -93,22 +104,30 @@ export const withUserDetailQuery = withQuery(gql`
|
||||
}
|
||||
${commentConnectionFragment}
|
||||
`, {
|
||||
options: ({id, moderation: {userDetailStatuses: statuses}}) => {
|
||||
options: ({id, statuses}) => {
|
||||
return {
|
||||
variables: {author_id: id, statuses}
|
||||
};
|
||||
}
|
||||
},
|
||||
skip: (ownProps) => !ownProps.id,
|
||||
});
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
moderation: state.moderation.toJS()
|
||||
id: state.userDetail.userDetailId,
|
||||
selectedIds: state.userDetail.userDetailSelectedIds,
|
||||
statuses: state.userDetail.userDetailStatuses,
|
||||
activeTab: state.userDetail.userDetailActiveTab,
|
||||
bannedWords: state.settings.toJS().wordlist.banned,
|
||||
suspectWords: state.settings.toJS().wordlist.suspect,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
...bindActionCreators({
|
||||
changeUserDetailStatuses,
|
||||
clearUserDetailSelections,
|
||||
toggleSelectCommentInUserDetail
|
||||
toggleSelectCommentInUserDetail,
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
}, dispatch)
|
||||
});
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ import install from './install';
|
||||
import config from './config';
|
||||
import banUserDialog from './banUserDialog';
|
||||
import suspendUserDialog from './suspendUserDialog';
|
||||
import userDetail from './userDetail';
|
||||
|
||||
export default {
|
||||
auth,
|
||||
banUserDialog,
|
||||
suspendUserDialog,
|
||||
userDetail,
|
||||
assets,
|
||||
settings,
|
||||
community,
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import {fromJS, Set} from 'immutable';
|
||||
import {fromJS} from 'immutable';
|
||||
import * as actions from '../constants/moderation';
|
||||
|
||||
const initialState = fromJS({
|
||||
singleView: false,
|
||||
modalOpen: false,
|
||||
userDetailId: null,
|
||||
userDetailActiveTab: 'all',
|
||||
userDetailStatuses: ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'],
|
||||
userDetailSelectedIds: new Set(),
|
||||
storySearchVisible: false,
|
||||
storySearchString: '',
|
||||
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show',
|
||||
@@ -18,9 +14,6 @@ export default function moderation (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case actions.MODERATION_CLEAR_STATE:
|
||||
return initialState;
|
||||
case actions.SET_ACTIVE_TAB:
|
||||
return state
|
||||
.set('activeTab', action.activeTab);
|
||||
case actions.TOGGLE_MODAL:
|
||||
return state
|
||||
.set('modalOpen', action.open);
|
||||
@@ -30,22 +23,6 @@ export default function moderation (state = initialState, action) {
|
||||
case actions.HIDE_SHORTCUTS_NOTE:
|
||||
return state
|
||||
.set('shortcutsNoteVisible', 'hide');
|
||||
case actions.VIEW_USER_DETAIL:
|
||||
return state.set('userDetailId', action.userId);
|
||||
case actions.HIDE_USER_DETAIL:
|
||||
return state
|
||||
.set('userDetailId', null)
|
||||
.update('userDetailSelectedIds', (set) => set.clear());
|
||||
case actions.CLEAR_USER_DETAIL_SELECTIONS:
|
||||
return state.update('userDetailSelectedIds', (set) => set.clear());
|
||||
case actions.CHANGE_USER_DETAIL_STATUSES:
|
||||
return state
|
||||
.set('userDetailActiveTab', action.tab)
|
||||
.set('userDetailStatuses', action.statuses);
|
||||
case actions.SELECT_USER_DETAIL_COMMENT:
|
||||
return state.update('userDetailSelectedIds', (set) => set.add(action.id));
|
||||
case actions.UNSELECT_USER_DETAIL_COMMENT:
|
||||
return state.update('userDetailSelectedIds', (set) => set.delete(action.id));
|
||||
case actions.SHOW_STORY_SEARCH:
|
||||
return state.set('storySearchVisible', true);
|
||||
case actions.HIDE_STORY_SEARCH:
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import * as actions from '../constants/userDetail';
|
||||
|
||||
const initialState = {
|
||||
userDetailId: null,
|
||||
userDetailActiveTab: 'all',
|
||||
userDetailStatuses: ['NONE', 'ACCEPTED', 'REJECTED', 'PREMOD'],
|
||||
userDetailSelectedIds: [],
|
||||
};
|
||||
|
||||
export default function banUserDialog(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case actions.VIEW_USER_DETAIL:
|
||||
return {
|
||||
...state,
|
||||
userDetailId: action.userId,
|
||||
};
|
||||
case actions.HIDE_USER_DETAIL:
|
||||
return {
|
||||
...state,
|
||||
userDetailId: null,
|
||||
userDetailSelectedIds: [],
|
||||
};
|
||||
case actions.CLEAR_USER_DETAIL_SELECTIONS:
|
||||
return {
|
||||
...state,
|
||||
userDetailSelectedIds: [],
|
||||
};
|
||||
case actions.CHANGE_USER_DETAIL_STATUSES:
|
||||
return {
|
||||
...state,
|
||||
userDetailActiveTab: action.tab,
|
||||
userDetailStatuses: action.statuses,
|
||||
};
|
||||
case actions.SELECT_USER_DETAIL_COMMENT:
|
||||
return {
|
||||
...state,
|
||||
userDetailSelectedIds: [...state.userDetailSelectedIds, action.id],
|
||||
};
|
||||
case actions.UNSELECT_USER_DETAIL_COMMENT:
|
||||
return {
|
||||
...state,
|
||||
userDetailSelectedIds: state.userDetailSelectedIds.filter((id) => id !== action.id),
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import styles from './Community.css';
|
||||
import {Button} from 'coral-ui';
|
||||
import {menuActionsMap} from '../../Moderation/helpers/moderationQueueActionsMap';
|
||||
import {menuActionsMap} from '../../../utils/moderationQueueActionsMap';
|
||||
|
||||
import t from 'coral-framework/services/i18n';
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ import React, {PropTypes} from 'react';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import {Icon} from 'coral-ui';
|
||||
import FlagBox from './FlagBox';
|
||||
import FlagBox from 'coral-admin/src/components/FlagBox';
|
||||
import styles from './styles.css';
|
||||
import CommentType from './CommentType';
|
||||
import CommentAnimatedEdit from './CommentAnimatedEdit';
|
||||
import CommentType from 'coral-admin/src/components/CommentType';
|
||||
import CommentAnimatedEdit from 'coral-admin/src/components/CommentAnimatedEdit';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
import {getActionSummary} from 'coral-framework/utils';
|
||||
import ActionButton from 'coral-admin/src/components/ActionButton';
|
||||
|
||||
@@ -6,7 +6,6 @@ import ModerationQueue from './ModerationQueue';
|
||||
import ModerationMenu from './ModerationMenu';
|
||||
import ModerationHeader from './ModerationHeader';
|
||||
import ModerationKeysModal from '../../../components/ModerationKeysModal';
|
||||
import UserDetail from '../containers/UserDetail';
|
||||
import StorySearch from '../containers/StorySearch';
|
||||
|
||||
export default class Moderation extends Component {
|
||||
@@ -173,12 +172,6 @@ export default class Moderation extends Component {
|
||||
open={moderation.modalOpen}
|
||||
onClose={this.onClose}/>
|
||||
|
||||
{moderation.userDetailId && (
|
||||
<UserDetail
|
||||
id={moderation.userDetailId}
|
||||
/>
|
||||
)}
|
||||
|
||||
<StorySearch
|
||||
assetId={assetId}
|
||||
moderation={this.props.moderation}
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, {PropTypes} from 'react';
|
||||
import Comment from '../containers/Comment';
|
||||
import styles from './styles.css';
|
||||
import EmptyCard from '../../../components/EmptyCard';
|
||||
import {actionsMap} from '../helpers/moderationQueueActionsMap';
|
||||
import {actionsMap} from '../../../utils/moderationQueueActionsMap';
|
||||
import LoadMore from './LoadMore';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import {CSSTransitionGroup} from 'react-transition-group';
|
||||
|
||||
@@ -480,31 +480,6 @@ span {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.bodyLeave {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background-color: white;
|
||||
opacity: 1.0;
|
||||
transition: background 400ms, opacity 800ms 1600ms;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bodyLeaveActive {
|
||||
opacity: 0;
|
||||
background-color: rgba(255,255,0, 0.2);
|
||||
}
|
||||
|
||||
.bodyEnter {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.bodyEnterActive {
|
||||
opacity: 1.0;
|
||||
transition: opacity 800ms 2400ms;
|
||||
}
|
||||
|
||||
.editedMarker {
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
|
||||
@@ -15,13 +15,12 @@ import {handleCommentChange} from '../../../graphql/utils';
|
||||
import {fetchSettings} from 'actions/settings';
|
||||
import {showBanUserDialog} from 'actions/banUserDialog';
|
||||
import {showSuspendUserDialog} from 'actions/suspendUserDialog';
|
||||
import {viewUserDetail} from '../../../actions/userDetail';
|
||||
import {
|
||||
toggleModal,
|
||||
singleView,
|
||||
hideShortcutsNote,
|
||||
toggleStorySearch,
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
setSortOrder,
|
||||
storySearchChange,
|
||||
clearState
|
||||
@@ -426,7 +425,6 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
toggleStorySearch,
|
||||
showSuspendUserDialog,
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
setSortOrder,
|
||||
storySearchChange,
|
||||
clearState
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import {compose, gql} from 'react-apollo';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import UserDetail from '../components/UserDetail';
|
||||
import withQuery from 'coral-framework/hocs/withQuery';
|
||||
import {getDefinitionName, getSlotFragmentSpreads} from 'coral-framework/utils';
|
||||
import {viewUserDetail, hideUserDetail} from 'actions/moderation';
|
||||
import {
|
||||
changeUserDetailStatuses,
|
||||
clearUserDetailSelections,
|
||||
toggleSelectCommentInUserDetail,
|
||||
} from 'coral-admin/src/actions/moderation';
|
||||
import {withSetCommentStatus} from 'coral-framework/graphql/mutations';
|
||||
import UserDetailComment from './UserDetailComment';
|
||||
|
||||
const commentConnectionFragment = gql`
|
||||
fragment CoralAdmin_Moderation_CommentConnection on CommentConnection {
|
||||
nodes {
|
||||
...${getDefinitionName(UserDetailComment.fragments.comment)}
|
||||
}
|
||||
hasNextPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
${UserDetailComment.fragments.comment}
|
||||
`;
|
||||
|
||||
const slots = [
|
||||
'userProfile',
|
||||
];
|
||||
|
||||
class UserDetailContainer extends React.Component {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
// status can be 'ACCEPTED' or 'REJECTED'
|
||||
bulkSetCommentStatus = (status) => {
|
||||
const changes = this.props.selectedIds.map((commentId) => {
|
||||
return this.props.setCommentStatus({commentId, status});
|
||||
});
|
||||
|
||||
Promise.all(changes).then(() => {
|
||||
this.props.data.refetch(); // some comments may have moved out of this tab
|
||||
this.props.clearUserDetailSelections(); // un-select everything
|
||||
});
|
||||
}
|
||||
|
||||
bulkReject = () => {
|
||||
this.bulkSetCommentStatus('REJECTED');
|
||||
}
|
||||
|
||||
bulkAccept = () => {
|
||||
this.bulkSetCommentStatus('ACCEPTED');
|
||||
}
|
||||
|
||||
acceptComment = ({commentId}) => {
|
||||
return this.props.setCommentStatus({commentId, status: 'ACCEPTED'});
|
||||
}
|
||||
|
||||
rejectComment = ({commentId}) => {
|
||||
return this.props.setCommentStatus({commentId, status: 'REJECTED'});
|
||||
}
|
||||
|
||||
render () {
|
||||
if (!('user' in this.props.root)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <UserDetail
|
||||
bulkReject={this.bulkReject}
|
||||
bulkAccept={this.bulkAccept}
|
||||
changeStatus={this.props.changeUserDetailStatuses}
|
||||
toggleSelect={this.props.toggleSelectCommentInUserDetail}
|
||||
acceptComment={this.acceptComment}
|
||||
rejectComment={this.rejectComment}
|
||||
{...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export const withUserDetailQuery = withQuery(gql`
|
||||
query CoralAdmin_UserDetail($author_id: ID!, $statuses: [COMMENT_STATUS!]) {
|
||||
user(id: $author_id) {
|
||||
id
|
||||
username
|
||||
created_at
|
||||
profiles {
|
||||
id
|
||||
provider
|
||||
}
|
||||
${getSlotFragmentSpreads(slots, 'user')}
|
||||
}
|
||||
totalComments: commentCount(query: {author_id: $author_id})
|
||||
rejectedComments: commentCount(query: {author_id: $author_id, statuses: [REJECTED]})
|
||||
comments: comments(query: {
|
||||
author_id: $author_id,
|
||||
statuses: $statuses
|
||||
}) {
|
||||
...CoralAdmin_Moderation_CommentConnection
|
||||
}
|
||||
${getSlotFragmentSpreads(slots, 'root')}
|
||||
}
|
||||
${commentConnectionFragment}
|
||||
`, {
|
||||
options: ({id, statuses}) => {
|
||||
return {
|
||||
variables: {author_id: id, statuses}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
selectedIds: state.moderation.toJS().userDetailSelectedIds,
|
||||
statuses: state.moderation.toJS().userDetailStatuses,
|
||||
activeTab: state.moderation.toJS().userDetailActiveTab,
|
||||
bannedWords: state.settings.toJS().wordlist.banned,
|
||||
suspectWords: state.settings.toJS().wordlist.suspect,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
...bindActionCreators({
|
||||
changeUserDetailStatuses,
|
||||
clearUserDetailSelections,
|
||||
toggleSelectCommentInUserDetail,
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
}, dispatch)
|
||||
});
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withUserDetailQuery,
|
||||
withSetCommentStatus,
|
||||
)(UserDetailContainer);
|
||||
Reference in New Issue
Block a user