Merge branch 'master' into update-my-comments

This commit is contained in:
Wyatt Johnson
2017-08-09 09:58:44 +10:00
committed by GitHub
11 changed files with 112 additions and 35 deletions
@@ -0,0 +1,21 @@
.loadMoreContainer {
display: flex;
justify-content: center;
width: 100%;
}
.loadMore {
width: 100%;
text-align: center;
color: #FFF;
max-width: 660px;
margin-bottom: 30px;
background-color: #2376D8;
cursor: pointer;
}
.loadMore:hover {
background-color: #4399FF;
}
@@ -1,9 +1,10 @@
import React, {PropTypes} from 'react'; import React, {PropTypes} from 'react';
import {Button} from 'coral-ui'; import {Button} from 'coral-ui';
import styles from './styles.css'; import styles from './LoadMore.css';
import cn from 'classnames';
const LoadMore = ({loadMore, showLoadMore}) => const LoadMore = ({loadMore, showLoadMore, className, ...rest}) =>
<div className={styles.loadMoreContainer}> <div {...rest} className={cn(className, styles.loadMoreContainer)}>
{ {
showLoadMore && <Button showLoadMore && <Button
className={styles.loadMore} className={styles.loadMore}
@@ -79,3 +79,12 @@
margin-left: -10px; margin-left: -10px;
} }
} }
.loadMore > button {
background-color: #696969;
&:hover {
background-color: #404040;
color: white;
}
}
@@ -6,6 +6,7 @@ import {Slot} from 'coral-framework/components';
import ButtonCopyToClipboard from './ButtonCopyToClipboard'; import ButtonCopyToClipboard from './ButtonCopyToClipboard';
import {actionsMap} from '../utils/moderationQueueActionsMap'; import {actionsMap} from '../utils/moderationQueueActionsMap';
import ClickOutside from 'coral-framework/components/ClickOutside'; import ClickOutside from 'coral-framework/components/ClickOutside';
import LoadMore from '../components/LoadMore';
export default class UserDetail extends React.Component { export default class UserDetail extends React.Component {
@@ -59,7 +60,7 @@ export default class UserDetail extends React.Component {
user, user,
totalComments, totalComments,
rejectedComments, rejectedComments,
comments: {nodes} comments: {nodes, hasNextPage}
}, },
activeTab, activeTab,
selectedCommentIds, selectedCommentIds,
@@ -70,6 +71,7 @@ export default class UserDetail extends React.Component {
bulkReject, bulkReject,
hideUserDetail, hideUserDetail,
viewUserDetail, viewUserDetail,
loadMore,
} = this.props; } = this.props;
const localProfile = user.profiles.find((p) => p.provider === 'local'); const localProfile = user.profiles.find((p) => p.provider === 'local');
@@ -167,6 +169,11 @@ export default class UserDetail extends React.Component {
}) })
} }
</div> </div>
<LoadMore
className={styles.loadMore}
loadMore={loadMore}
showLoadMore={hasNextPage}
/>
</Drawer> </Drawer>
</ClickOutside> </ClickOutside>
); );
@@ -8,6 +8,10 @@
min-height: 0; min-height: 0;
} }
.root:last-child {
border: 0;
}
.rootSelected { .rootSelected {
background-color: #ecf4ff; background-color: #ecf4ff;
} }
@@ -14,6 +14,7 @@ import {
} from 'coral-admin/src/actions/userDetail'; } from 'coral-admin/src/actions/userDetail';
import {withSetCommentStatus} from 'coral-framework/graphql/mutations'; import {withSetCommentStatus} from 'coral-framework/graphql/mutations';
import UserDetailComment from './UserDetailComment'; import UserDetailComment from './UserDetailComment';
import update from 'immutability-helper';
const commentConnectionFragment = gql` const commentConnectionFragment = gql`
fragment CoralAdmin_Moderation_CommentConnection on CommentConnection { fragment CoralAdmin_Moderation_CommentConnection on CommentConnection {
@@ -32,6 +33,7 @@ const slots = [
]; ];
class UserDetailContainer extends React.Component { class UserDetailContainer extends React.Component {
isLoadingMore = false;
// status can be 'ACCEPTED' or 'REJECTED' // status can be 'ACCEPTED' or 'REJECTED'
bulkSetCommentStatus = (status) => { bulkSetCommentStatus = (status) => {
@@ -40,7 +42,6 @@ class UserDetailContainer extends React.Component {
}); });
Promise.all(changes).then(() => { Promise.all(changes).then(() => {
this.props.data.refetch(); // some comments may have moved out of this tab
this.props.clearUserDetailSelections(); // un-select everything this.props.clearUserDetailSelections(); // un-select everything
}); });
} }
@@ -61,12 +62,53 @@ class UserDetailContainer extends React.Component {
return this.props.setCommentStatus({commentId, status: 'REJECTED'}); return this.props.setCommentStatus({commentId, status: 'REJECTED'});
} }
loadMore = () => {
if (this.isLoadingMore) {
return;
}
this.isLoadingMore = true;
const variables = {
limit: 10,
cursor: this.props.root.comments.endCursor,
author_id: this.props.data.variables.author_id,
statuses: this.props.data.variables.statuses,
};
this.props.data.fetchMore({
query: LOAD_MORE_QUERY,
variables,
updateQuery: (prev, {fetchMoreResult:{comments}}) => {
return update(prev, {
comments: {
nodes: {$push: comments.nodes},
hasNextPage: {$set: comments.hasNextPage},
startCursor: {$set: comments.startCursor},
endCursor: {$set: comments.endCursor},
},
});
}
})
.then(() => {
this.isLoadingMore = false;
})
.catch((err) => {
this.isLoadingMore = false;
throw err;
});
};
componentWillReceiveProps(next) {
if (this.props.userId === null && next.userId) {
next.data.refetch();
}
}
render () { render () {
if (!this.props.userId) { if (!this.props.userId) {
return null; return null;
} }
const loading = !('user' in this.props.root) || this.props.root.user.id !== this.props.userId; const loading = [1, 2, 4].indexOf(this.props.data.networkStatus) >= 0;
return <UserDetail return <UserDetail
bulkReject={this.bulkReject} bulkReject={this.bulkReject}
@@ -76,10 +118,20 @@ class UserDetailContainer extends React.Component {
acceptComment={this.acceptComment} acceptComment={this.acceptComment}
rejectComment={this.rejectComment} rejectComment={this.rejectComment}
loading={loading} loading={loading}
loadMore={this.loadMore}
{...this.props} />; {...this.props} />;
} }
} }
const LOAD_MORE_QUERY = gql`
query CoralAdmin_Moderation_LoadMore($limit: Int = 10, $cursor: Date, $author_id: ID!, $statuses: [COMMENT_STATUS!]) {
comments(query: {limit: $limit, cursor: $cursor, author_id: $author_id, statuses: $statuses}) {
...CoralAdmin_Moderation_CommentConnection
}
}
${commentConnectionFragment}
`;
export const withUserDetailQuery = withQuery(gql` export const withUserDetailQuery = withQuery(gql`
query CoralAdmin_UserDetail($author_id: ID!, $statuses: [COMMENT_STATUS!]) { query CoralAdmin_UserDetail($author_id: ID!, $statuses: [COMMENT_STATUS!]) {
user(id: $author_id) { user(id: $author_id) {
@@ -4,7 +4,7 @@ import Comment from '../containers/Comment';
import styles from './styles.css'; import styles from './styles.css';
import EmptyCard from '../../../components/EmptyCard'; import EmptyCard from '../../../components/EmptyCard';
import {actionsMap} from '../../../utils/moderationQueueActionsMap'; import {actionsMap} from '../../../utils/moderationQueueActionsMap';
import LoadMore from './LoadMore'; import LoadMore from '../../../components/LoadMore';
import t from 'coral-framework/services/i18n'; import t from 'coral-framework/services/i18n';
import {CSSTransitionGroup} from 'react-transition-group'; import {CSSTransitionGroup} from 'react-transition-group';
@@ -397,26 +397,6 @@ span {
} }
} }
.loadMoreContainer {
display: flex;
justify-content: center;
width: 100%;
};
.loadMore {
width: 100%;
text-align: center;
color: #FFF;
max-width: 660px;
margin-bottom: 30px;
background-color: #2376D8;
cursor: pointer;
}
.loadMore:hover {
background-color: #4399FF;
}
.tabIcon { .tabIcon {
position: relative; position: relative;
top: 3px; top: 3px;
@@ -499,4 +479,4 @@ span {
right: 0px; right: 0px;
top: 0px; top: 0px;
text-align: right; text-align: right;
} }
@@ -400,7 +400,7 @@ export default class Comment extends React.Component {
<div className={commentClassName}> <div className={commentClassName}>
<Slot <Slot
className={styles.commentAvatar} className={`${styles.commentAvatar} talk-stream-comment-avatar`}
fill="commentAvatar" fill="commentAvatar"
{...slotProps} {...slotProps}
inline inline
+1 -1
View File
@@ -3,7 +3,7 @@
min-width: 550px; min-width: 550px;
position: fixed; position: fixed;
top: 0; top: 0;
right: -17px; right: 0px;
bottom: 0; bottom: 0;
background-color: white; background-color: white;
transition: transform 500ms ease-in-out; transition: transform 500ms ease-in-out;
+8 -5
View File
@@ -2,18 +2,21 @@ const errors = require('../../errors');
const {Error: {ValidationError}} = require('mongoose'); const {Error: {ValidationError}} = require('mongoose');
/** /**
* Wraps up a promise to return an object with the resolution of the promise * Wraps up a promise or value to return an object with the resolution of the promise
* keyed at `key` or an error caught at `errors`. * keyed at `key` or an error caught at `errors`.
*/ */
const wrapResponse = (key) => (promise) => { const wrapResponse = (key) => async (promise) => {
return promise.then((value) => { try {
let value = await promise;
let res = {}; let res = {};
if (key) { if (key) {
res[key] = value; res[key] = value;
} }
return res; return res;
}).catch((err) => { } catch (err) {
if (err instanceof errors.APIError) { if (err instanceof errors.APIError) {
return { return {
errors: [err] errors: [err]
@@ -25,7 +28,7 @@ const wrapResponse = (key) => (promise) => {
} }
throw err; throw err;
}); }
}; };
module.exports = wrapResponse; module.exports = wrapResponse;