From b8de18c0fa762acb8e4733d81c2f9183af4661f8 Mon Sep 17 00:00:00 2001 From: Irina Vivdenko Date: Mon, 5 Nov 2018 17:43:54 +0300 Subject: [PATCH 1/4] Add a frame for pagination --- src/ac/index.js | 28 ++++++++++++ src/components/app.js | 2 + src/components/comment-list/comments.js | 59 +++++++++++++++++++++++++ src/components/routes/comments-page.js | 28 ++++++++++++ src/constants/index.js | 2 + src/reducer/comments.js | 26 ++++++++++- src/selectors/index.js | 10 ++++- 7 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/components/comment-list/comments.js create mode 100644 src/components/routes/comments-page.js diff --git a/src/ac/index.js b/src/ac/index.js index b1d12b8..8405f89 100644 --- a/src/ac/index.js +++ b/src/ac/index.js @@ -7,6 +7,7 @@ import { LOAD_ALL_ARTICLES, LOAD_ARTICLE, LOAD_ARTICLE_COMMENTS, + LOAD_ALL_COMMENTS, SUCCESS, FAIL, START @@ -87,3 +88,30 @@ export function loadArticleComments(articleId) { callAPI: `/api/comment?article=${articleId}` } } + +export function loadComments({ limit = 5, currentPage = 0 }) { + const offset = currentPage * 5 + return (dispatch) => { + dispatch({ + type: LOAD_ALL_COMMENTS + START, + payload: { offset } + }) + + fetch(`/api/comment?limit=${limit}&offset=${offset}`) + .then((res) => res.json()) + .then((response) => + dispatch({ + type: LOAD_ALL_COMMENTS + SUCCESS, + payload: { offset }, + response: response.records + }) + ) + .catch((error) => + dispatch({ + type: LOAD_ALL_COMMENTS + FAIL, + payload: { offset }, + error + }) + ) + } +} diff --git a/src/components/app.js b/src/components/app.js index df3a463..bd78d50 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -4,6 +4,7 @@ import ArticlesPage from './routes/articles-page' import UserForm from './user-form' import Filters from './filters' import Counter from './counter' +import CommentsPage from './routes/comments-page' class App extends Component { render() { @@ -36,6 +37,7 @@ class App extends Component { render={() =>

New Article Page

} /> +

Not Found Page

} /> diff --git a/src/components/comment-list/comments.js b/src/components/comment-list/comments.js new file mode 100644 index 0000000..455d6bb --- /dev/null +++ b/src/components/comment-list/comments.js @@ -0,0 +1,59 @@ +import React, { Component, Fragment } from 'react' +import { connect } from 'react-redux' +import { NavLink } from 'react-router-dom' + +import { commentsListSelector } from '../../selectors' + +import { loadComments } from '../../ac' + +class PaginationComments extends Component { + constructor(props) { + super(props) + const { page } = this.props + this.state = { + currentPage: parseInt(page) + } + } + + componentDidMount(oldProps) { + const { loadComments } = this.props + const { currentPage } = this.state + loadComments({ currentPage }) + } + + render() { + const { comments = [] } = this.props + const { currentPage } = this.state + + return ( +
+
    + {comments.map((el) => ( +
  • {`${el.id}: ${el.text}`}
  • + ))} +
+ + Previous + + + Next + +
+ ) + } +} + +export default connect( + (state) => { + return { + comments: commentsListSelector(state) + } + }, + { loadComments } +)(PaginationComments) diff --git a/src/components/routes/comments-page.js b/src/components/routes/comments-page.js new file mode 100644 index 0000000..6f2cc44 --- /dev/null +++ b/src/components/routes/comments-page.js @@ -0,0 +1,28 @@ +import React, { Component, Fragment } from 'react' +import { Route } from 'react-router-dom' +import PaginationComments from '../comment-list/comments' + +class CommentsPage extends Component { + static propTypes = {} + + render() { + console.log('---', 'comments-page match: ', this.props.match) + // const title = this.props.match.isExact &&

Select an Article

+ return ( + + + + ) + } + + getComments = ({ match }) => { + console.log('---', 'comments match: ', match) + + if (!match) return

Please Select A Page

+ + const { page } = match.params + return + } +} + +export default CommentsPage diff --git a/src/constants/index.js b/src/constants/index.js index 419b7a9..d7f9169 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -10,6 +10,8 @@ export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' export const ADD_COMMENT = 'ADD_COMMENT' export const LOAD_ARTICLE_COMMENTS = 'LOAD_ARTICLE_COMMENTS' +export const LOAD_ALL_COMMENTS = 'LOAD_ALL_COMMENTS' + export const START = '_START' export const SUCCESS = '_SUCCESS' export const FAIL = '_FAIL' diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 92f9afd..d6a2a83 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,4 +1,10 @@ -import { ADD_COMMENT, LOAD_ARTICLE_COMMENTS, SUCCESS } from '../constants' +import { + ADD_COMMENT, + LOAD_ARTICLE_COMMENTS, + LOAD_ALL_COMMENTS, + START, + SUCCESS +} from '../constants' import { Record, OrderedMap } from 'immutable' import { arrToMap } from './utils' @@ -8,8 +14,12 @@ const CommentRecord = Record({ user: null }) +// Реализованная пагинация ломает работу комментариев в связке со статьей const ReducerRecord = Record({ - entities: new OrderedMap({}) + entities: new OrderedMap({}), + loading: false, + loaded: false, + error: null }) export default (state = new ReducerRecord(), action) => { @@ -28,6 +38,18 @@ export default (state = new ReducerRecord(), action) => { case LOAD_ARTICLE_COMMENTS + SUCCESS: return state.mergeIn(['entities'], arrToMap(response, CommentRecord)) + case LOAD_ALL_COMMENTS + START: + return state.set('loading', true).set('loaded', false) + + case LOAD_ALL_COMMENTS + SUCCESS: + return ( + state + // Не сохраняем в store предыдущий набор статей + .set(['entities'], arrToMap(response, CommentRecord)) + .set('loading', false) + .set('loaded', true) + ) + default: return state } diff --git a/src/selectors/index.js b/src/selectors/index.js index 10ae8e3..3f3fff5 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -9,9 +9,15 @@ export const articleListSelector = createSelector( articlesMapSelector, (articlesMap) => articlesMap.valueSeq().toArray() ) -export const commentsSelector = (state) => state.comments + +export const commentsMapSelector = (state) => state.comments.entities export const idSelector = (_, props) => props.id +export const commentsListSelector = createSelector( + commentsMapSelector, + (commentsMap) => commentsMap.valueSeq().toArray() +) + export const filtratedArticlesSelector = createSelector( selectionSelector, dateRangeSelector, @@ -32,7 +38,7 @@ export const filtratedArticlesSelector = createSelector( ) export const createCommentSelector = () => - createSelector(commentsSelector, idSelector, (comments, id) => { + createSelector(commentsListSelector, idSelector, (comments, id) => { return comments.getIn(['entities', id]) }) From e2d6447e2a53646454f80e27440763acc31fe9b6 Mon Sep 17 00:00:00 2001 From: Irina Vivdenko Date: Mon, 5 Nov 2018 17:56:27 +0300 Subject: [PATCH 2/4] Add logic for a count for pages --- src/ac/index.js | 9 ++++----- src/components/comment-list/comments.js | 10 ++++++++-- src/reducer/comments.js | 2 ++ src/selectors/index.js | 2 ++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ac/index.js b/src/ac/index.js index 8405f89..0ab7e48 100644 --- a/src/ac/index.js +++ b/src/ac/index.js @@ -93,17 +93,16 @@ export function loadComments({ limit = 5, currentPage = 0 }) { const offset = currentPage * 5 return (dispatch) => { dispatch({ - type: LOAD_ALL_COMMENTS + START, - payload: { offset } + type: LOAD_ALL_COMMENTS + START }) fetch(`/api/comment?limit=${limit}&offset=${offset}`) .then((res) => res.json()) - .then((response) => + .then(({ total, records }) => dispatch({ type: LOAD_ALL_COMMENTS + SUCCESS, - payload: { offset }, - response: response.records + payload: { pagesCount: total }, + response: records }) ) .catch((error) => diff --git a/src/components/comment-list/comments.js b/src/components/comment-list/comments.js index 455d6bb..9917f7b 100644 --- a/src/components/comment-list/comments.js +++ b/src/components/comment-list/comments.js @@ -2,7 +2,10 @@ import React, { Component, Fragment } from 'react' import { connect } from 'react-redux' import { NavLink } from 'react-router-dom' -import { commentsListSelector } from '../../selectors' +import { + commentsListSelector, + commentsPagesCountSelector +} from '../../selectors' import { loadComments } from '../../ac' @@ -22,9 +25,11 @@ class PaginationComments extends Component { } render() { - const { comments = [] } = this.props + const { comments = [], pagesCount } = this.props const { currentPage } = this.state + console.log(pagesCount, 'pagesCount') + console.log(comments, 'comments') return (
    @@ -52,6 +57,7 @@ class PaginationComments extends Component { export default connect( (state) => { return { + pagesCount: commentsPagesCountSelector(state), comments: commentsListSelector(state) } }, diff --git a/src/reducer/comments.js b/src/reducer/comments.js index d6a2a83..84d09b9 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -17,6 +17,7 @@ const CommentRecord = Record({ // Реализованная пагинация ломает работу комментариев в связке со статьей const ReducerRecord = Record({ entities: new OrderedMap({}), + pagesCount: null, loading: false, loaded: false, error: null @@ -46,6 +47,7 @@ export default (state = new ReducerRecord(), action) => { state // Не сохраняем в store предыдущий набор статей .set(['entities'], arrToMap(response, CommentRecord)) + .set('pagesCount', payload.pagesCount) .set('loading', false) .set('loaded', true) ) diff --git a/src/selectors/index.js b/src/selectors/index.js index 3f3fff5..62cda89 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -18,6 +18,8 @@ export const commentsListSelector = createSelector( (commentsMap) => commentsMap.valueSeq().toArray() ) +export const commentsPagesCountSelector = (state) => state.comments.pagesCount + export const filtratedArticlesSelector = createSelector( selectionSelector, dateRangeSelector, From 3a4f06ac1c032fb0c380605f3fef5073e11ca1da Mon Sep 17 00:00:00 2001 From: Irina Vivdenko Date: Mon, 5 Nov 2018 18:14:33 +0300 Subject: [PATCH 3/4] Fix logic for pagesCount. Add the message about loading --- src/ac/index.js | 3 +-- src/components/comment-list/comments.js | 28 ++++++++++++++++--------- src/selectors/index.js | 2 ++ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/ac/index.js b/src/ac/index.js index 0ab7e48..3b02572 100644 --- a/src/ac/index.js +++ b/src/ac/index.js @@ -101,14 +101,13 @@ export function loadComments({ limit = 5, currentPage = 0 }) { .then(({ total, records }) => dispatch({ type: LOAD_ALL_COMMENTS + SUCCESS, - payload: { pagesCount: total }, + payload: { pagesCount: parseInt(total / limit) }, response: records }) ) .catch((error) => dispatch({ type: LOAD_ALL_COMMENTS + FAIL, - payload: { offset }, error }) ) diff --git a/src/components/comment-list/comments.js b/src/components/comment-list/comments.js index 9917f7b..0e6a066 100644 --- a/src/components/comment-list/comments.js +++ b/src/components/comment-list/comments.js @@ -4,6 +4,7 @@ import { NavLink } from 'react-router-dom' import { commentsListSelector, + commentsLoadingSelector, commentsPagesCountSelector } from '../../selectors' @@ -25,26 +26,32 @@ class PaginationComments extends Component { } render() { - const { comments = [], pagesCount } = this.props + const { comments = [], loading, pagesCount } = this.props const { currentPage } = this.state - console.log(pagesCount, 'pagesCount') - console.log(comments, 'comments') + if (currentPage > pagesCount) { + return
    {'No comments'}
    + } + return (
      - {comments.map((el) => ( -
    • {`${el.id}: ${el.text}`}
    • - ))} + {!loading + ? comments.map((el) => ( +
    • {`${el.id}: ${el.text}`}
    • + )) + : `Loading...`}
    1 ? currentPage - 1 : 1}`} activeStyle={{ color: 'red' }} > Previous Next @@ -57,8 +64,9 @@ class PaginationComments extends Component { export default connect( (state) => { return { - pagesCount: commentsPagesCountSelector(state), - comments: commentsListSelector(state) + comments: commentsListSelector(state), + loading: commentsLoadingSelector(state), + pagesCount: commentsPagesCountSelector(state) } }, { loadComments } diff --git a/src/selectors/index.js b/src/selectors/index.js index 62cda89..3c08fd5 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -20,6 +20,8 @@ export const commentsListSelector = createSelector( export const commentsPagesCountSelector = (state) => state.comments.pagesCount +export const commentsLoadingSelector = (state) => state.comments.loading + export const filtratedArticlesSelector = createSelector( selectionSelector, dateRangeSelector, From 19e1e4827ca87cdd69b246919153d55cbbf3477c Mon Sep 17 00:00:00 2001 From: Irina Vivdenko Date: Mon, 5 Nov 2018 18:16:21 +0300 Subject: [PATCH 4/4] Add the comment --- src/components/comment-list/comments.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/comment-list/comments.js b/src/components/comment-list/comments.js index 0e6a066..5eb73b3 100644 --- a/src/components/comment-list/comments.js +++ b/src/components/comment-list/comments.js @@ -29,6 +29,7 @@ class PaginationComments extends Component { const { comments = [], loading, pagesCount } = this.props const { currentPage } = this.state + // Эту проверку лучше делать на уровне CommentsPage? if (currentPage > pagesCount) { return
    {'No comments'}
    }