From b769e95898473d58c8e8a001c7ebcbd96c73bc4e Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Thu, 20 Jul 2017 01:19:45 +0700 Subject: [PATCH] Implement pagination --- .../beta/client/actions/notification.js | 1 + plugin-api/beta/client/services/index.js | 2 +- plugin-api/beta/client/utils/index.js | 8 ++- .../client/components/Comment.js | 2 +- .../client/components/LoadMore.js | 30 ++++++++++ .../client/components/Tab.js | 4 +- .../client/components/TabPane.js | 57 ++++++++++++++---- .../client/containers/TabPane.js | 59 ++++++++++++++++++- 8 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 plugin-api/beta/client/actions/notification.js create mode 100644 plugins/talk-plugin-featured-comments/client/components/LoadMore.js diff --git a/plugin-api/beta/client/actions/notification.js b/plugin-api/beta/client/actions/notification.js new file mode 100644 index 000000000..c1a75cb7a --- /dev/null +++ b/plugin-api/beta/client/actions/notification.js @@ -0,0 +1 @@ +export {addNotification} from 'coral-framework/actions/notification'; diff --git a/plugin-api/beta/client/services/index.js b/plugin-api/beta/client/services/index.js index ddaa346ab..ab0ab60b2 100644 --- a/plugin-api/beta/client/services/index.js +++ b/plugin-api/beta/client/services/index.js @@ -1,3 +1,3 @@ -export {t} from 'coral-framework/services/i18n'; +export {t, timeago} from 'coral-framework/services/i18n'; export {can} from 'coral-framework/services/perms'; export {isSlotEmpty} from 'coral-framework/helpers/plugins'; diff --git a/plugin-api/beta/client/utils/index.js b/plugin-api/beta/client/utils/index.js index aa63ccad2..5b9748699 100644 --- a/plugin-api/beta/client/utils/index.js +++ b/plugin-api/beta/client/utils/index.js @@ -1,2 +1,6 @@ -export {isTagged, insertCommentsSorted} from 'coral-framework/utils'; -export {getSlotFragmentSpreads} from 'coral-framework/utils'; +export { + isTagged, + insertCommentsSorted, + getSlotFragmentSpreads, + forEachError, +} from 'coral-framework/utils'; diff --git a/plugins/talk-plugin-featured-comments/client/components/Comment.js b/plugins/talk-plugin-featured-comments/client/components/Comment.js index cce9d000d..7ac2869b1 100644 --- a/plugins/talk-plugin-featured-comments/client/components/Comment.js +++ b/plugins/talk-plugin-featured-comments/client/components/Comment.js @@ -2,7 +2,7 @@ import React from 'react'; import cn from 'classnames'; import styles from './Comment.css'; import {name} from '../../package.json'; -import {timeago} from 'coral-framework/services/i18n'; +import {timeago} from 'plugin-api/beta/client/services'; import {Slot} from 'plugin-api/beta/client/components'; import {Icon} from 'plugin-api/beta/client/components/ui'; diff --git a/plugins/talk-plugin-featured-comments/client/components/LoadMore.js b/plugins/talk-plugin-featured-comments/client/components/LoadMore.js new file mode 100644 index 000000000..a168ed43a --- /dev/null +++ b/plugins/talk-plugin-featured-comments/client/components/LoadMore.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {Button} from 'coral-ui'; +import t from 'coral-framework/services/i18n'; +import cn from 'classnames'; + +class LoadMore extends React.Component { + render () { + const {loadingState, loadMore} = this.props; + const disabled = loadingState === 'loading'; + return ( +
+ +
+ ); + } +} + +LoadMore.propTypes = { + loadMore: PropTypes.func.isRequired, + loadingState: PropTypes.oneOf(['', 'loading', 'success', 'error']), +}; + +export default LoadMore; diff --git a/plugins/talk-plugin-featured-comments/client/components/Tab.js b/plugins/talk-plugin-featured-comments/client/components/Tab.js index 643d74574..1b535f982 100644 --- a/plugins/talk-plugin-featured-comments/client/components/Tab.js +++ b/plugins/talk-plugin-featured-comments/client/components/Tab.js @@ -1,9 +1,9 @@ import React from 'react'; import {TabCount} from 'plugin-api/beta/client/components/ui'; +import {t} from 'plugin-api/beta/client/services'; -// TODO: This is just example code, and needs to replaced by an actual implementation. export default ({active, asset: {featuredCommentsCount}}) => ( - Featured {featuredCommentsCount} + {t('featured')} {featuredCommentsCount} ); diff --git a/plugins/talk-plugin-featured-comments/client/components/TabPane.js b/plugins/talk-plugin-featured-comments/client/components/TabPane.js index 25d43aa7d..3cf8b2cfd 100644 --- a/plugins/talk-plugin-featured-comments/client/components/TabPane.js +++ b/plugins/talk-plugin-featured-comments/client/components/TabPane.js @@ -1,16 +1,47 @@ import React from 'react'; import Comment from '../containers/Comment'; +import LoadMore from './LoadMore'; +import {forEachError} from 'plugin-api/beta/client/utils'; -export default ({root, data, asset: {featuredComments, ...asset}, viewComment}) => ( -
- {featuredComments.nodes.map((comment) => - - )} -
-); +class TabPane extends React.Component { + state = { + loadingState: '', + }; + + loadMore = () => { + this.setState({loadingState: 'loading'}); + this.props.loadMore() + .then(() => { + this.setState({loadingState: 'success'}); + }) + .catch((error) => { + this.setState({loadingState: 'error'}); + forEachError(error, ({msg}) => {this.props.addNotification('error', msg);}); + }); + } + + render() { + const {root, data, asset: {featuredComments, ...asset}, viewComment} = this.props; + return ( +
+ {featuredComments.nodes.map((comment) => + + )} + {featuredComments.hasNextPage && + + } +
+ ); + } +} + +export default TabPane; diff --git a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js index 0dd83c92d..f7989099a 100644 --- a/plugins/talk-plugin-featured-comments/client/containers/TabPane.js +++ b/plugins/talk-plugin-featured-comments/client/containers/TabPane.js @@ -1,3 +1,4 @@ +import React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {compose, gql} from 'react-apollo'; @@ -5,12 +6,66 @@ import TabPane from '../components/TabPane'; import {withFragments} from 'plugin-api/beta/client/hocs'; import Comment from '../containers/Comment'; import {getDefinitionName} from 'coral-framework/utils'; - +import {addNotification} from 'plugin-api/beta/client/actions/notification'; import {viewComment} from 'coral-embed-stream/src/actions/stream'; +import {insertCommentsSorted} from 'plugin-api/beta/client/utils'; +import update from 'immutability-helper'; + +class TabPaneContainer extends React.Component { + + loadMore = () => { + return this.props.data.fetchMore({ + query: LOAD_MORE_QUERY, + variables: { + limit: 5, + cursor: this.props.root.asset.featuredComments.endCursor, + asset_id: this.props.root.asset.id, + sort: 'REVERSE_CHRONOLOGICAL', + excludeIgnored: this.props.data.variables.excludeIgnored, + }, + updateQuery: (previous, {fetchMoreResult:{comments}}) => { + const updated = update(previous, { + asset: { + featuredComments: { + nodes: { + $apply: (nodes) => insertCommentsSorted(nodes, comments.nodes, 'REVERSE_CHRONOLOGICAL'), + }, + hasNextPage: {$set: comments.hasNextPage}, + endCursor: {$set: comments.endCursor}, + }, + } + }); + return updated; + }, + }); + }; + + render() { + return ; + } +} + +const LOAD_MORE_QUERY = gql` + query CoralEmbedStream_LoadMoreComments($limit: Int = 5, $cursor: Date, $asset_id: ID, $sort: SORT_ORDER, $excludeIgnored: Boolean) { + comments(query: {limit: $limit, cursor: $cursor, tags: ["FEATURED"], asset_id: $asset_id, sort: $sort, excludeIgnored: $excludeIgnored}) { + nodes { + ...${getDefinitionName(Comment.fragments.comment)} + } + hasNextPage + startCursor + endCursor + } + } + ${Comment.fragments.comment} +`; const mapDispatchToProps = (dispatch) => bindActionCreators({ viewComment, + addNotification, }, dispatch); const enhance = compose( @@ -42,4 +97,4 @@ const enhance = compose( }), ); -export default enhance(TabPane); +export default enhance(TabPaneContainer);