mirror of
https://github.com/wassname/talk.git
synced 2026-07-07 17:19:49 +08:00
Support load more in user history
This commit is contained in:
@@ -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
-1
@@ -1,6 +1,6 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import {Button} from 'coral-ui';
|
||||
import styles from './styles.css';
|
||||
import styles from './LoadMore.css';
|
||||
|
||||
const LoadMore = ({loadMore, showLoadMore}) =>
|
||||
<div className={styles.loadMoreContainer}>
|
||||
@@ -6,6 +6,7 @@ import {Slot} from 'coral-framework/components';
|
||||
import ButtonCopyToClipboard from './ButtonCopyToClipboard';
|
||||
import {actionsMap} from '../utils/moderationQueueActionsMap';
|
||||
import ClickOutside from 'coral-framework/components/ClickOutside';
|
||||
import LoadMore from '../components/LoadMore';
|
||||
|
||||
export default class UserDetail extends React.Component {
|
||||
|
||||
@@ -59,7 +60,7 @@ export default class UserDetail extends React.Component {
|
||||
user,
|
||||
totalComments,
|
||||
rejectedComments,
|
||||
comments: {nodes}
|
||||
comments: {nodes, hasNextPage}
|
||||
},
|
||||
activeTab,
|
||||
selectedCommentIds,
|
||||
@@ -70,6 +71,7 @@ export default class UserDetail extends React.Component {
|
||||
bulkReject,
|
||||
hideUserDetail,
|
||||
viewUserDetail,
|
||||
loadMore,
|
||||
} = this.props;
|
||||
|
||||
const localProfile = user.profiles.find((p) => p.provider === 'local');
|
||||
@@ -167,6 +169,10 @@ export default class UserDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<LoadMore
|
||||
loadMore={loadMore}
|
||||
showLoadMore={hasNextPage}
|
||||
/>
|
||||
</Drawer>
|
||||
</ClickOutside>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.root:last-child {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.rootSelected {
|
||||
background-color: #ecf4ff;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from 'coral-admin/src/actions/userDetail';
|
||||
import {withSetCommentStatus} from 'coral-framework/graphql/mutations';
|
||||
import UserDetailComment from './UserDetailComment';
|
||||
import update from 'immutability-helper';
|
||||
|
||||
const commentConnectionFragment = gql`
|
||||
fragment CoralAdmin_Moderation_CommentConnection on CommentConnection {
|
||||
@@ -32,6 +33,7 @@ const slots = [
|
||||
];
|
||||
|
||||
class UserDetailContainer extends React.Component {
|
||||
isLoadingMore = false;
|
||||
|
||||
// status can be 'ACCEPTED' or 'REJECTED'
|
||||
bulkSetCommentStatus = (status) => {
|
||||
@@ -40,7 +42,6 @@ class UserDetailContainer extends React.Component {
|
||||
});
|
||||
|
||||
Promise.all(changes).then(() => {
|
||||
this.props.data.refetch(); // some comments may have moved out of this tab
|
||||
this.props.clearUserDetailSelections(); // un-select everything
|
||||
});
|
||||
}
|
||||
@@ -61,12 +62,53 @@ class UserDetailContainer extends React.Component {
|
||||
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 () {
|
||||
if (!this.props.userId) {
|
||||
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
|
||||
bulkReject={this.bulkReject}
|
||||
@@ -76,10 +118,20 @@ class UserDetailContainer extends React.Component {
|
||||
acceptComment={this.acceptComment}
|
||||
rejectComment={this.rejectComment}
|
||||
loading={loading}
|
||||
loadMore={this.loadMore}
|
||||
{...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`
|
||||
query CoralAdmin_UserDetail($author_id: ID!, $statuses: [COMMENT_STATUS!]) {
|
||||
user(id: $author_id) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import Comment from '../containers/Comment';
|
||||
import styles from './styles.css';
|
||||
import EmptyCard from '../../../components/EmptyCard';
|
||||
import {actionsMap} from '../../../utils/moderationQueueActionsMap';
|
||||
import LoadMore from './LoadMore';
|
||||
import LoadMore from '../../../components/LoadMore';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
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 {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
@@ -499,4 +479,4 @@ span {
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,19 @@ const errors = require('../../errors');
|
||||
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`.
|
||||
*/
|
||||
|
||||
const wrapResponse = (key) => (promise) => {
|
||||
return promise.then((value) => {
|
||||
const wrapResponse = (key) => (promiseOrValue) => {
|
||||
return Promise.resolve(promiseOrValue).then((value) => {
|
||||
let res = {};
|
||||
if (key) {
|
||||
res[key] = value;
|
||||
}
|
||||
return res;
|
||||
}).catch((err) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err instanceof errors.APIError) {
|
||||
return {
|
||||
errors: [err]
|
||||
|
||||
Reference in New Issue
Block a user