Merge pull request #952 from coralproject/instream-ban

In-Stream Ban
This commit is contained in:
Kim Gardner
2017-09-18 18:26:59 +01:00
committed by GitHub
13 changed files with 253 additions and 5 deletions
+1
View File
@@ -7,6 +7,7 @@ export {default as connect} from 'coral-framework/hocs/connect';
export {default as withEmit} from 'coral-framework/hocs/withEmit';
export {
withIgnoreUser,
withSetUserStatus,
withStopIgnoringUser,
withSetCommentStatus,
} from 'coral-framework/graphql/mutations';
@@ -1,4 +1,4 @@
import {OPEN_MENU, CLOSE_MENU} from './constants';
import {OPEN_MENU, CLOSE_MENU, OPEN_BAN_DIALOG, CLOSE_BAN_DIALOG} from './constants';
export const openMenu = (id) => ({
type: OPEN_MENU,
@@ -8,3 +8,14 @@ export const openMenu = (id) => ({
export const closeMenu = () => ({
type: CLOSE_MENU,
});
export const openBanDialog = ({commentId, authorId, commentStatus}) => ({
type: OPEN_BAN_DIALOG,
commentId,
authorId,
commentStatus
});
export const closeBanDialog = () => ({
type: CLOSE_BAN_DIALOG,
});
@@ -0,0 +1,14 @@
import React from 'react';
import styles from './styles.css';
import {t} from 'plugin-api/beta/client/services';
import {Icon} from 'plugin-api/beta/client/components/ui';
import cn from 'classnames';
export default ({onBanUser}) => (
<button
className={cn(styles.button, 'talk-plugin-moderation-actions-reject')}
onClick={onBanUser} >
<Icon name="block" className={styles.icon} />
{t('talk-plugin-moderation-actions.ban_user')}
</button>
);
@@ -0,0 +1,38 @@
.dialog {
border: none;
box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
}
.buttons {
text-align: right;
margin: 20px;
text-align: center;
}
.cancel, .confirm {
width: 48%;
}
.cancel {
margin-right: 10px;
}
.copy {
font-style: italic;
}
.close {
font-size: 20px;
line-height: 14px;
top: 10px;
right: 10px;
position: absolute;
display: block;
font-weight: bold;
color: #363636;
cursor: pointer;
}
.close:hover {
color: #6b6b6b;
}
@@ -0,0 +1,23 @@
import React from 'react';
import styles from './BanUserDialog.css';
import {t} from 'plugin-api/beta/client/services';
import {Dialog, Button} from 'plugin-api/beta/client/components/ui';
export default ({showBanDialog, closeBanDialog, banUser}) => (
<Dialog open={showBanDialog} className={styles.dialog}>
<span className={styles.close} onClick={closeBanDialog}>×</span>
<h2>{t('talk-plugin-moderation-actions.ban_user_dialog_headline')}</h2>
<h3>{t('talk-plugin-moderation-actions.ban_user_dialog_sub')}</h3>
<p className={styles.copy}>
{t('talk-plugin-moderation-actions.ban_user_dialog_copy')}
</p>
<div className={styles.buttons}>
<Button cStyle="cancel" onClick={closeBanDialog} className={styles.cancel} raised>
{t('talk-plugin-moderation-actions.ban_user_dialog_cancel')}
</Button>
<Button cStyle="black" onClick={banUser} className={styles.confirm} raised>
{t('talk-plugin-moderation-actions.ban_user_dialog_yes')}
</Button>
</div>
</Dialog>
);
@@ -6,11 +6,12 @@ import {Icon} from 'plugin-api/beta/client/components/ui';
import ClickOutside from 'coral-framework/components/ClickOutside';
import RejectCommentAction from '../containers/RejectCommentAction';
import ApproveCommentAction from '../containers/ApproveCommentAction';
import BanUserAction from '../containers/BanUserAction';
import {Slot} from 'plugin-api/beta/client/components';
export default class ModerationActions extends React.Component {
render() {
const {comment, asset, data, menuVisible, toogleMenu, hideMenu} = this.props;
const {comment, root, asset, data, menuVisible, toogleMenu, hideMenu} = this.props;
return(
<ClickOutside onClickOutside={hideMenu}>
@@ -29,6 +30,7 @@ export default class ModerationActions extends React.Component {
/>
<ApproveCommentAction comment={comment} hideMenu={hideMenu} />
<RejectCommentAction comment={comment} hideMenu={hideMenu} />
<BanUserAction comment={comment} root={root} hideMenu={hideMenu} />
</Menu>
)}
</div>
@@ -2,3 +2,5 @@ const prefix = 'TALK_MODERATION_ACTIONS';
export const OPEN_MENU = `${prefix}_OPEN_MENU`;
export const CLOSE_MENU = `${prefix}_CLOSE_MENU`;
export const OPEN_BAN_DIALOG = `${prefix}_OPEN_BAN_DIALOG`;
export const CLOSE_BAN_DIALOG = `${prefix}_CLOSE_BAN_DIALOG`;
@@ -0,0 +1,36 @@
import React from 'react';
import {compose} from 'react-apollo';
import {openBanDialog} from '../actions';
import {bindActionCreators} from 'redux';
import BanUserAction from '../components/BanUserAction';
import {connect} from 'plugin-api/beta/client/hocs';
class BanUserActionContainer extends React.Component {
onBanUser = () => {
this.props.openBanDialog({
commentId: this.props.comment.id,
commentStatus: this.props.comment.status,
authorId: this.props.comment.user.id
});
}
render() {
const {root: {me}, comment} = this.props;
return (me.id !== comment.user.id) ?
<BanUserAction
onBanUser={this.onBanUser}
comment={this.props.comment}
/> : null;
}
}
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
openBanDialog
}, dispatch);
const enhance = compose(
connect(null, mapDispatchToProps)
);
export default enhance(BanUserActionContainer);
@@ -0,0 +1,76 @@
import React from 'react';
import {compose} from 'react-apollo';
import {bindActionCreators} from 'redux';
import {closeBanDialog, closeMenu} from '../actions';
import {notify} from 'plugin-api/beta/client/actions/notification';
import {connect, withSetCommentStatus, withSetUserStatus} from 'plugin-api/beta/client/hocs';
import {getErrorMessages} from 'plugin-api/beta/client/utils';
import BanUserDialog from '../components/BanUserDialog';
class BanUserDialogContainer extends React.Component {
banUser = async () => {
const {
notify,
authorId,
commentId,
commentStatus,
closeMenu,
closeBanDialog,
setCommentStatus,
setUserStatus
} = this.props;
try {
await setUserStatus({
userId: authorId,
status: 'BANNED'
});
closeMenu();
closeBanDialog();
if (commentStatus !== 'REJECTED') {
await setCommentStatus({
commentId: commentId,
status: 'REJECTED'
});
}
}
catch(err) {
notify('error', getErrorMessages(err));
}
}
render() {
return (
<BanUserDialog
banUser={this.banUser}
showBanDialog={this.props.showBanDialog}
closeBanDialog={this.props.closeBanDialog}
/>
);
}
}
const mapStateToProps = ({talkPluginModerationActions: state}) => ({
showBanDialog: state.showBanDialog,
commentId: state.commentId,
authorId: state.authorId
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators({
notify,
closeBanDialog,
closeMenu
}, dispatch);
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
withSetCommentStatus,
withSetUserStatus
);
export default enhance(BanUserDialogContainer);
@@ -47,9 +47,9 @@ class ModerationActionsContainer extends React.Component {
root={this.props.root}
asset={this.props.asset}
comment={this.props.comment}
menuVisible={this.props.showMenuForComment === this.props.comment.id}
toogleMenu={this.toogleMenu}
hideMenu={this.hideMenu}
menuVisible={this.props.showMenuForComment === this.props.comment.id}
/>;
}
}
@@ -68,6 +68,13 @@ const mapDispatchToProps = (dispatch) =>
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
withFragments({
root: gql`
fragment TalkModerationActions_root on RootQuery {
me {
id
}
}`
,
asset: gql`
fragment TalkModerationActions_asset on Asset {
id
@@ -77,6 +84,9 @@ const enhance = compose(
fragment TalkModerationActions_comment on Comment {
id
status
user {
id
}
tags {
tag {
name
@@ -1,9 +1,11 @@
import ModerationActions from './containers/ModerationActions';
import BanUserDialog from './containers/BanUserDialog';
import translations from './translations.yml';
import reducer from './reducer';
export default {
slots: {
embed: [BanUserDialog],
commentInfoBar: [ModerationActions],
},
reducer,
@@ -1,7 +1,11 @@
import {OPEN_MENU, CLOSE_MENU} from './constants';
import {OPEN_MENU, CLOSE_MENU, OPEN_BAN_DIALOG, CLOSE_BAN_DIALOG} from './constants';
const initialState = {
showMenuForComment: null,
showBanDialog: false,
authorId: null,
commentId: null,
commentStatus: null
};
export default function reducer(state = initialState, action) {
@@ -16,6 +20,22 @@ export default function reducer(state = initialState, action) {
...state,
showMenuForComment: null
};
case OPEN_BAN_DIALOG:
return {
...state,
showBanDialog: true,
authorId: action.authorId,
commentId: action.commentId,
commentStatus: action.commentStatus
};
case CLOSE_BAN_DIALOG:
return {
...state,
showBanDialog: false,
authorId: null,
commentId: null,
commentStatus: null
};
default :
return state;
}
@@ -4,9 +4,22 @@ en:
approve_comment: "Approve"
approved_comment: "Approved"
moderation_actions: "Moderation Actions"
ban_user: "Ban User"
ban_user_dialog_sub: "Are you sure you would like to ban this user?"
ban_user_dialog_copy: "Note: Banning this user will also place this comment in the Rejected queue."
ban_user_dialog_cancel: "Cancel"
ban_user_dialog_yes: "Yes. Ban user"
ban_user_dialog_headline: "Ban User?"
es:
talk-plugin-moderation-actions:
reject_comment: "Rechazar"
approve_comment: "Aprobar"
approved_comment: "Aprobado"
moderation_actions: "Acciones de Moderación"
moderation_actions: "Acciones de Moderación"
ban_user: "Banear usuario"
ban_user_dialog_sub: "Está seguro de querer banear a este usuario?"
ban_user_dialog_copy: "Nota: Baneando a este usuario pondrá el comentario en la cola de comentarios Rechazados."
ban_user_dialog_cancel: "Cancelar"
ban_user_dialog_yes: "Si. Banear usuario"
ban_user_dialog_headline: "Banear Usuario?"