Merge branch 'master' of github.com:coralproject/talk into load-more-replies

This commit is contained in:
David Jay
2017-02-15 17:51:30 -05:00
17 changed files with 53 additions and 216 deletions
-2
View File
@@ -4,7 +4,6 @@ import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-ro
import Streams from 'containers/Streams/Streams';
import Configure from 'containers/Configure/Configure';
import LayoutContainer from 'containers/LayoutContainer';
import CommentStream from 'containers/CommentStream/CommentStream';
import InstallContainer from 'containers/Install/InstallContainer';
import CommunityContainer from 'containers/Community/CommunityContainer';
@@ -16,7 +15,6 @@ const routes = (
<Route exact path="/admin/install" component={InstallContainer}/>
<Route path='/admin' component={LayoutContainer}>
<IndexRoute component={ModerationContainer} />
<Route path='embed' component={CommentStream} />
<Route path='community' component={CommunityContainer} />
<Route path='configure' component={Configure} />
<Route path='streams' component={Streams} />
-103
View File
@@ -1,103 +0,0 @@
import coralApi from '../../../coral-framework/helpers/response';
import * as commentTypes from '../constants/comments';
import * as actionTypes from '../constants/actions';
function addUsersCommentsActions (dispatch, {comments, users, actions}) {
dispatch({type: commentTypes.USERS_MODERATION_QUEUE_FETCH_SUCCESS, users});
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS, comments});
dispatch({type: actionTypes.ACTIONS_MODERATION_QUEUE_FETCH_SUCCESS, actions});
}
// Get comments to fill each of the three lists on the mod queue
export const fetchModerationQueueComments = () => {
return dispatch => {
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST});
return Promise.all([
coralApi('/queue/comments/premod'),
coralApi('/queue/users/flagged'),
coralApi('/queue/comments/rejected'),
coralApi('/queue/comments/flagged')
])
.then(([premodComments, pendingUsers, rejected, flagged]) => {
/* Combine seperate calls into a single object */
flagged.comments.forEach(comment => comment.flagged = true);
return {
comments: [...premodComments.comments, ...rejected.comments, ...flagged.comments],
users: [...premodComments.users, ...pendingUsers.users, ...rejected.users, ...flagged.users],
actions: [...premodComments.actions, ...pendingUsers.actions, ...rejected.actions, ...flagged.actions]
};
})
.then(addUsersCommentsActions.bind(this, dispatch));
};
};
export const fetchPremodQueue = () => {
return dispatch => {
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST});
return coralApi('/queue/comments/premod')
.then(addUsersCommentsActions.bind(this, dispatch));
};
};
export const fetchPendingUsersQueue = () => {
return dispatch => {
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST});
return coralApi('/queue/users/flagged')
.then(addUsersCommentsActions.bind(this, dispatch));
};
};
export const fetchRejectedQueue = () => {
return dispatch => {
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST});
return coralApi('/queue/comments/rejected')
.then(addUsersCommentsActions.bind(this, dispatch));
};
};
export const fetchFlaggedQueue = () => {
return dispatch => {
dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST});
return coralApi('/queue/comments/flagged')
.then(results => {
results.comments.forEach(comment => comment.flagged = true);
return results;
})
.then(addUsersCommentsActions.bind(this, dispatch));
};
};
// Create a new comment
export const createComment = (name, body) => {
return (dispatch) => {
const formData = {body, name};
return coralApi('/comments', {method: 'POST', body: formData})
.then(res => dispatch({type: commentTypes.COMMENT_CREATE_SUCCESS, comment: res}))
.catch(error => dispatch({type: commentTypes.COMMENT_CREATE_FAILED, error}));
};
};
/**
* Action disptacher related to comments
*/
// Update a comment. Now to update a comment we need to send back the whole object
export const updateStatus = (status, comment) => {
return dispatch => {
dispatch({type: commentTypes.COMMENT_STATUS_UPDATE_REQUEST, id: comment.id, status});
return coralApi(`/comments/${comment.id}/status`, {method: 'PUT', body: {status}})
.then(res => dispatch({type: commentTypes.COMMENT_STATUS_UPDATE_SUCCESS, res}))
.catch(error => dispatch({type: commentTypes.COMMENT_STATUS_UPDATE_FAILURE, error}));
};
};
export const flagComment = id => (dispatch, getState) => {
dispatch({type: commentTypes.COMMENT_FLAG, id});
dispatch({type: 'COMMENT_UPDATE', comment: getState().comments.get('byId').get(id)});
};
@@ -1,13 +0,0 @@
@custom-media --big-viewport (min-width: 780px);
.container {
max-width: 860px;
margin: 0 auto;
}
@media (--big-viewport) {
.tab {
flex: none;
}
}
@@ -1,66 +0,0 @@
import React from 'react';
import styles from './CommentStream.css';
import {Snackbar} from 'react-mdl';
import {connect} from 'react-redux';
import {createComment, flagComment} from 'actions/comments';
import ModerationList from 'components/ModerationList';
import CommentBox from 'components/CommentBox';
/**
* Renders a comment stream using a ModerationList component
* and adds a box for adding a new comment
*/
class CommentStream extends React.Component {
constructor (props) {
super(props);
this.state = {snackbar: false, snackbarMsg: ''};
this.onSubmit = this.onSubmit.bind(this);
this.onClickAction = this.onClickAction.bind(this);
}
// Fetch the comments before mounting
componentWillMount () {
this.props.dispatch({type: 'COMMENT_STREAM_FETCH'});
}
// Submit the new comment
onSubmit (comment) {
this.props.dispatch(createComment(comment.name, comment.body));
}
// The only action for now is flagging
onClickAction (action, id) {
if (action === 'flag') {
this.props.dispatch(flagComment(id));
clearTimeout(this._snackTimeout);
this.setState({snackbar: true, snackbarMsg: 'Thank you for reporting this comment. Our moderation team has been notified and will review it shortly.'});
this._snackTimeout = setTimeout(() => this.setState({snackbar: false}), 30000);
}
}
// Render the comment box along with the ModerationList
render ({comments, users}, {snackbar, snackbarMsg}) {
return (
<div className={styles.container}>
<CommentBox onSubmit={this.onSubmit} />
<ModerationList isActive hideActive
singleView={false}
commentIds={comments.ids}
comments={comments.byId}
users={users.byId}
onClickAction={this.onClickAction}
actions={['flag']}
loading={comments.loading} />
<Snackbar active={snackbar}>{snackbarMsg}</Snackbar>
</div>
);
}
}
const mapStateToProps = state => ({
comments: state.comments.toJS(),
users: state.users.toJS()
});
export default connect(mapStateToProps)(CommentStream);
@@ -9,12 +9,13 @@ const ModerationQueue = ({activeTab = 'premod', ...props}) => {
<ul>
{
props.data[activeTab].map((comment, i) => {
const status = comment.action_summaries ? 'FLAGGED' : comment.status;
return <Comment
key={i}
index={i}
comment={comment}
suspectWords={props.suspectWords}
actions={actionsMap[comment.status]}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
@@ -318,6 +318,7 @@ span {
}
.flagBox {
max-width: 480px;
border-top: 1px solid rgba(66, 66, 66, 0.12);
h3 {
font-size: 14px;
@@ -1,6 +1,6 @@
export const actionsMap = {
PREMOD: ['REJECT', 'APPROVE', 'BAN'],
FLAGGED: ['REJECT', 'APPROVE'],
FLAGGED: ['REJECT', 'APPROVE', 'BAN'],
REJECTED: ['APPROVE']
};
@@ -9,7 +9,8 @@ query ModQueue ($asset_id: ID!) {
}
flagged: comments(query: {
action_type: FLAG,
asset_id: $asset_id
asset_id: $asset_id,
statuses: [NONE, PREMOD]
}) {
...commentView
action_summaries {
+1 -1
View File
@@ -161,7 +161,7 @@ class Embed extends Component {
notification={{text: null}}
/>
<LoadMore
id={asset.id}
assetId={asset.id}
comments={asset.comments}
moreComments={asset.commentCount > asset.comments.length}
loadMore={this.props.loadMore}/>
+21 -12
View File
@@ -1,11 +1,11 @@
import React from 'react';
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations.json';
import {ADDTL_COMMENTS_ON_LOAD_MORE} from 'coral-framework/constants/comments';
import {Button} from 'coral-ui';
const lang = new I18n(translations);
const loadMoreComments = (id, comments, loadMore, parentId) => {
const loadMoreComments = (assetId, comments, loadMore, parentId) => {
if (!comments.length) {
return;
@@ -18,20 +18,29 @@ const loadMoreComments = (id, comments, loadMore, parentId) => {
loadMore({
limit: ADDTL_COMMENTS_ON_LOAD_MORE,
cursor,
asset_id: id,
assetId,
parent_id: parentId,
sort: parentId ? 'CHRONOLOGICAL' : 'REVERSE_CHRONOLOGICAL'
});
};
const LoadMore = ({id, comments, loadMore, moreComments, parentId}) => moreComments ?
<Button
className='coral-load-more'
onClick={() => loadMoreComments(id, comments, loadMore, parentId)}>
{
lang.t('loadMore')
}
</Button>
: null;
const LoadMore = ({assetId, comments, loadMore, moreComments, parentId}) => (
moreComments
? <Button
className='coral-load-more'
onClick={() => loadMoreComments(assetId, comments, loadMore, parentId)}>
{
lang.t('loadMore')
}
</Button>
: null
);
LoadMore.propTypes = {
assetId: PropTypes.string.isRequired,
comments: PropTypes.array.isRequired,
moreComments: PropTypes.bool.isRequired,
loadMore: PropTypes.func.isRequired
};
export default LoadMore;