Understanding reducers

This commit is contained in:
gaba
2016-11-30 11:12:09 -08:00
parent 8af9e14971
commit ba47250933
8 changed files with 70 additions and 46 deletions
+26 -14
View File
@@ -5,14 +5,15 @@ import styles from './CommentList.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations.json';
import Linkify from 'react-linkify';
import {FabButton} from 'coral-ui';
import {Icon} from 'react-mdl';
import {FabButton, Button} from 'coral-ui';
const linkify = new Linkify();
// Render a single comment for the list
export default props => {
const links = linkify.getMatches(props.comment.get('body'));
const banned = props.comment.get('banned');
return (
<li tabIndex={props.index} className={`${styles.listItem} ${props.isActive && !props.hideActive ? styles.activeItem : ''}`}>
@@ -27,15 +28,13 @@ export default props => {
{links ?
<span className={styles.hasLinks}><Icon name='error_outline'/> Contains Link</span> : null}
<div className={styles.actions}>
{props.actions.map((action, i) => canShowAction(action, props.comment) ? (
<FabButton icon={props.actionsMap[action].icon} className={styles.actionButton}
cStyle={action}
key={i}
onClick={() => props.onClickAction(props.actionsMap[action].status, props.comment.get('id'))}
/>
) : null)}
{props.actions.map((action, i) => getActionButton(action, i, props))}
</div>
</div>
<div>
{banned ?
<span className={styles.banned}><Icon name='error_outline'/> Banned User</span> : null}
</div>
</div>
<div className={styles.itemBody}>
<span className={styles.body}>
@@ -48,15 +47,28 @@ export default props => {
);
};
// Check if an action can be performed over a comment
const canShowAction = (action, comment) => {
const status = comment.get('status');
const flagged = comment.get('flagged');
// Get the button of the action performed over a comment if any
const getActionButton = (action, i, props) => {
const status = props.comment.get('status');
const flagged = props.comment.get('flagged');
if (action === 'flag' && (status || flagged === true)) {
return false;
return null;
}
return true;
if (action === 'ban') {
return (
<Button
cStyle='darkGrey'
onClick={() => props.onClickAction(props.actionsMap[action].status, props.comment.get('id'))}>{lang.t('comment.ban_user')}</Button>
);
}
return (
<FabButton icon={props.actionsMap[action].icon} className={styles.actionButton}
cStyle={action}
key={i}
onClick={() => props.onClickAction(props.actionsMap[action].status, props.comment.get('id'))}
/>
);
};
const linkStyles = {
@@ -122,7 +122,6 @@
}
.hasLinks {
color: #f00;
text-align: right;
@@ -133,3 +132,14 @@
margin-right: 5px;
}
}
.banned {
color: #f00;
text-align: left;
display: flex;
align-items: center;
i {
margin-right: 5px;
}
}
@@ -9,7 +9,8 @@ import Comment from 'components/Comment';
const actions = {
'reject': {status: 'rejected', icon: 'close', key: 'r'},
'approve': {status: 'accepted', icon: 'done', key: 't'},
'flag': {status: 'flagged', icon: 'flag', filter: 'Untouched'}
'flag': {status: 'flagged', icon: 'flag', filter: 'Untouched'},
'ban': {status: 'ban'}
};
// Renders a comment list and allow performing actions
@@ -6,6 +6,7 @@ import ModerationKeysModal from 'components/ModerationKeysModal';
import CommentList from 'components/CommentList';
import {updateStatus} from 'actions/comments';
import {updateUserStatus} from 'actions/users';
import styles from './ModerationQueue.css';
import I18n from 'coral-framework/modules/i18n/i18n';
@@ -51,8 +52,15 @@ class ModerationQueue extends React.Component {
}
// Dispatch the update status action
onCommentAction (status, id) {
this.props.dispatch(updateStatus(status, id));
onCommentAction (action, id) {
// if we are banning a user by the action then dispatch updateUserStatus
// action = 'banned' in the case of banning
if (action === 'banned') {
this.props.dispatch(updateUserStatus(action, id));
}
// If not banning then change the status to approved or flagged as action = status
this.props.dispatch(updateStatus(action, id));
}
onTabClick (activeTab) {
@@ -61,7 +69,7 @@ class ModerationQueue extends React.Component {
// Render the tabbed lists moderation queues
render () {
const {comments} = this.props;
const {comments, commenters} = this.props;
const {activeTab, singleView, modalOpen} = this.state;
return (
@@ -86,8 +94,9 @@ class ModerationQueue extends React.Component {
.get('status'))
}
comments={comments.get('byId')}
commenters={commenters}
onClickAction={(action, id) => this.onCommentAction(action, id)}
actions={['reject', 'approve']}
actions={['reject', 'approve', 'ban']}
loading={comments.loading} />
</div>
<div className={`mdl-tabs__panel ${styles.listContainer}`} id='rejected'>
@@ -104,6 +113,7 @@ class ModerationQueue extends React.Component {
.get('status') === 'rejected')
}
comments={comments.get('byId')}
commenters={commenters}
onClickAction={(action, id) => this.onCommentAction(action, id)}
actions={['approve']}
loading={comments.loading} />
@@ -117,6 +127,7 @@ class ModerationQueue extends React.Component {
return !data.get('status') && data.get('flagged') === true;
})}
comments={comments.get('byId')}
commenters={commenters}
onClickAction={(action, id) => this.onCommentAction(action, id)}
actions={['reject', 'approve']}
loading={comments.loading} />
-23
View File
@@ -1,23 +0,0 @@
import {Map, List} from 'immutable';
const initialState = Map({
byId: Map(),
ids: List(),
loading: false
});
// Handle the users actions
export default (state = initialState, action) => {
switch (action.type) {
case 'SET_COMMENTER_STATUS': return updateUserStatus(state, action);
default: return state;
}
};
// Update a user status
const updateUserStatus = (state, action) => {
const byId = state.get('byId');
const data = byId.get(action.id).set('status', action.status.toLowerCase());
return state.set('byId', byId.set(action.id, data));
};
@@ -24,6 +24,9 @@ export default store => next => action => {
case 'COMMENT_CREATE':
createComment(store, action.name, action.body);
break;
case 'BAN_USER':
banUser(store, action.comment);
break;
}
next(action);
@@ -68,3 +71,11 @@ const createComment = (store, name, comment) => {
.then(res => store.dispatch({type: 'COMMENT_CREATE_SUCCESS', comment: res}))
.catch(error => store.dispatch({type: 'COMMENT_CREATE_FAILED', error}));
};
// Ban a user
const banUser = (store, comment) => {
fetch(`${base}/user/${comment.get('author_id')}/status`, getInit('POST', {status: comment.get('status')}))
.then(handleResp)
.then(res => store.dispatch({type: 'USER_BAN_SUCESSS', res}))
.catch(error => store.dispatch({type: 'USER_BAN_FAILED', error}));
};
+4 -2
View File
@@ -32,7 +32,8 @@
},
"comment": {
"flagged": "flagged",
"anon": "Anonymous"
"anon": "Anonymous",
"ban_user": "Ban User"
},
"embedlink": {
"copy": "Copy to Clipboard"
@@ -76,7 +77,8 @@
},
"comment": {
"flagged": "marcado",
"anon": "Anónimo"
"anon": "Anónimo",
"ban_user": "Suspender Usuario"
},
"configure": {
"enable-pre-moderation": "Habilitar pre-moderación",
+1 -1
View File
@@ -62,7 +62,7 @@ router.post('/:user_id/role', authorization.needed('admin'), (req, res, next) =>
router.post('/:user_id/status', (req, res, next) => {
User
.setStatus(req.params.user_id, req.body.status)
.setStatus(req.params.user_id, req.body.status, res.body.comment_id)
.then(status => {
res.send(status);
})