diff --git a/src/AC/index.js b/src/AC/index.js index d3d7bdb..50f910b 100644 --- a/src/AC/index.js +++ b/src/AC/index.js @@ -1,6 +1,6 @@ import { INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, - LOAD_ARTICLE_COMMENTS, START, SUCCESS, FAIL + LOAD_ARTICLE_COMMENTS, START, SUCCESS, FAIL, LOAD_ALL_COMMENTS } from '../constants' export function increment() { @@ -82,4 +82,29 @@ export function loadArticleComments(articleId) { payload: { articleId }, callAPI: `/api/comment?article=${articleId}` } -} \ No newline at end of file +} + +export function loadAllcomments(offset, page) { + return (dispatch, getState) => { + const pageLoaded = getState().comments.loadedPages.has(page) + if (!pageLoaded) { + dispatch({ + type: LOAD_ALL_COMMENTS + START, + }) + + setTimeout(() => { + fetch(`/api/comment?limit=5&offset=${offset}`) + .then(res => res.json()) + .then(response => dispatch({ + type: LOAD_ALL_COMMENTS + SUCCESS, + payload: { page }, + response + })) + .catch(error => dispatch({ + type: LOAD_ALL_COMMENTS + FAIL, + payload: { page, error } + })) + }, 1000) + } + } +} diff --git a/src/App.js b/src/App.js index e7c257c..e86b2c7 100644 --- a/src/App.js +++ b/src/App.js @@ -5,6 +5,7 @@ import ArticlesPage from './components/routes/articles' import UserForm from './components/user-form' import Filters from './components/filters' import Counter from './components/counter' +import AllComments from './components/AllComments' import 'react-select/dist/react-select.css' class App extends Component { @@ -19,8 +20,10 @@ class App extends Component {
  • counter
  • filters
  • articles
  • +
  • comments
  • +

    New Article Form

    } /> @@ -32,4 +35,4 @@ class App extends Component { } } -export default App \ No newline at end of file +export default App diff --git a/src/components/AllComments/CommentsPage.js b/src/components/AllComments/CommentsPage.js new file mode 100644 index 0000000..93e1f45 --- /dev/null +++ b/src/components/AllComments/CommentsPage.js @@ -0,0 +1,58 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import Comment from '../comment' +import { commentsByPage, commentsLoading } from '../../selectors' +import { loadAllcomments } from '../../AC' +import Loader from '../loader' + +class CommentsPage extends React.Component { + + componentWillReceiveProps(nextProps) { + if (nextProps.page !== this.props.page) { + const { comments } = this.props + this.props.loadAllcomments((nextProps.page - 1)*5, nextProps.page) + } + } + + render() { + const { comments, loading } = this.props + return( +
    + {loading ? : +
      + { + comments.map(id => +
    • + +
    • ) + } +
    + } +
    + ) + } +} + +CommentsPage.propTypes = { + comments: PropTypes.array, + loading: PropTypes.bool, + loadAllcomments: PropTypes.fun +} + +CommentsPage.defaultProps = { + comments: [], +} + +const mapStateToProps = (state, ownProps) => { + return { + comments: commentsByPage(state, ownProps), + loading: commentsLoading(state) + } +} + +const mapDispatchToProps = { + loadAllcomments +} + +export default connect(mapStateToProps, mapDispatchToProps)(CommentsPage) diff --git a/src/components/AllComments/index.js b/src/components/AllComments/index.js new file mode 100644 index 0000000..2d50da0 --- /dev/null +++ b/src/components/AllComments/index.js @@ -0,0 +1,58 @@ +import React from 'react' +import { NavLink, Route } from 'react-router-dom' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import Comment from '../comment' +import CommentsPage from './CommentsPage' +import { loadAllcomments } from '../../AC' +import { allCommentsSelector, totalComments } from '../../selectors' + +class AllComments extends React.Component { + + componentDidMount() { + this.props.loadAllcomments(0, "1") + } + + renderButtons = total => { + const count = new Array(Math.ceil(total / 5)).fill(null) + return count.map((_, index) => ( + + + + )) + } + + render() { + const { total, match } = this.props + return( +
    + + {this.renderButtons(total)} +
    + ) + } + + getCommentsPage = ({ match }) => { + if (!match) { + return + } + return + } +} + +AllComments.propTypes = { + match: PropTypes.object, + total: PropTypes.number +} + +const mapStateToProps = (state, ownProps) => { + return { + total: totalComments(state), + } +} + +const mapDispatchToProps = { + loadAllcomments +} + +export default connect(mapStateToProps, mapDispatchToProps)(AllComments) diff --git a/src/constants/index.js b/src/constants/index.js index c71387f..64d40c2 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -9,7 +9,8 @@ export const CHANGE_SELECTION = 'CHANGE_SELECTION' export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' export const ADD_COMMENT = 'ADD_COMMENT' +export const LOAD_ALL_COMMENTS = 'LOAD_ALL_COMMENTS' export const START = '_START' export const SUCCESS = '_SUCCESS' -export const FAIL = '_FAIL' \ No newline at end of file +export const FAIL = '_FAIL' diff --git a/src/middlewares/api.js b/src/middlewares/api.js index 2386a76..0581553 100644 --- a/src/middlewares/api.js +++ b/src/middlewares/api.js @@ -8,7 +8,7 @@ export default store => next => action => { type: type + START, ...rest }) - + //REMOVE THIS! setTimeout(() => { fetch(callAPI) @@ -16,4 +16,4 @@ export default store => next => action => { .then(response => next({ ...rest, type: type + SUCCESS, response })) .catch(error => next({ ...rest, type: type + FAIL, error })) }, 1000) -} \ No newline at end of file +} diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 6586253..8a32b6e 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,4 +1,4 @@ -import { ADD_COMMENT, LOAD_ARTICLE_COMMENTS, SUCCESS } from '../constants' +import { ADD_COMMENT, LOAD_ARTICLE_COMMENTS, SUCCESS, LOAD_ALL_COMMENTS, START } from '../constants' import {Record, OrderedMap} from 'immutable' import {arrToMap} from './utils' @@ -9,7 +9,10 @@ const CommentRecord = Record({ }) const ReducerState = Record({ - entities: new OrderedMap({}) + entities: new OrderedMap({}), + loadedPages: new OrderedMap({}), + total: null, + loading: false, }) export default (state = new ReducerState(), action) => { @@ -25,7 +28,17 @@ export default (state = new ReducerState(), action) => { case LOAD_ARTICLE_COMMENTS + SUCCESS: return state.mergeIn(['entities'], arrToMap(response, CommentRecord)) + case LOAD_ALL_COMMENTS + START: + return state.updateIn(['loading'], value => true) + + case LOAD_ALL_COMMENTS + SUCCESS: + const ids = response.records.map(comment => comment.id) + return state.mergeIn(['entities'], arrToMap(response.records, CommentRecord)) + .mergeIn(['loadedPages'], new OrderedMap({[payload.page]: ids})) + .updateIn(['total'], value => response.total === value ? value : response.total ) + .updateIn(['loading'], value => false) + default: return state } -} \ No newline at end of file +} diff --git a/src/reducer/utils.js b/src/reducer/utils.js index e8c7c63..042c8ba 100644 --- a/src/reducer/utils.js +++ b/src/reducer/utils.js @@ -5,4 +5,4 @@ export function arrToMap(arr, DataRecord) { acc.set(item.id, DataRecord ? new DataRecord(item) : item) , new OrderedMap({}) ) -} \ No newline at end of file +} diff --git a/src/selectors/index.js b/src/selectors/index.js index 421e61a..58b7659 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -22,4 +22,13 @@ export const filtratedArticles = createSelector(articleListSelector, filtersSele export const articleSelector = createSelector(articlesMapSelector, idSelector, (articles, id) => articles.get(id)) -export const createCommentSelector = () => createSelector(commentsSelector, idSelector, (comments, id) => comments.get(id)) \ No newline at end of file +export const createCommentSelector = () => createSelector(commentsSelector, idSelector, (comments, id) => comments.get(id)) + +const allCommentsSelector = state => state.comments.loadedPages.toJS() +const getPage = (_, props) => props.page +export const commentsByPage = createSelector(allCommentsSelector, getPage, (comments, page) => comments[page]) + +const totalCommentsSelector = state => state.comments.total +export const totalComments = createSelector(totalCommentsSelector, total => total) + +export const commentsLoading = state => state.comments.loading