diff --git a/src/ac/index.js b/src/ac/index.js index edf08ca..151396b 100644 --- a/src/ac/index.js +++ b/src/ac/index.js @@ -6,6 +6,7 @@ import { ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, + LOAD_ALL_COMMENTS, START, SUCCESS, FAIL @@ -46,6 +47,13 @@ export function addComment(comment, articleId) { } } +export function loadAllComments(articleId) { + return { + type: LOAD_ALL_COMMENTS, + callAPI: `/api/comment?article=${articleId}` + } +} + export function loadAllArticles() { return { type: LOAD_ALL_ARTICLES, diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js index 30f2342..205c82f 100644 --- a/src/components/comment-list/index.js +++ b/src/components/comment-list/index.js @@ -1,10 +1,14 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import { connect } from 'react-redux' import CSSTransition from 'react-addons-css-transition-group' import Comment from '../comment' import CommentForm from '../comment-form' import toggleOpen from '../../decorators/toggleOpen' import './style.css' +import { commentsLoadingSelector, commentsSelector } from '../../selectors' +import { loadAllComments } from '../../ac' +import Loader from '../common/loader' class CommentList extends Component { static propTypes = { @@ -40,8 +44,11 @@ class CommentList extends Component { } getBody() { + if (this.props.loading) return + const { - article: { id, comments = [] }, + article: { id }, + comments = [], isOpen } = this.props if (!isOpen) return null @@ -61,14 +68,30 @@ class CommentList extends Component { get comments() { return ( ) } + + componentDidUpdate(oldProps) { + const { isOpen, fetchData, comments = [], article } = this.props + if (!oldProps.isOpen && isOpen && !comments.length && fetchData) + fetchData(article.id) + } +} + +const createMapStateToProps = () => { + return (state, ownProps) => ({ + comments: commentsSelector(state, ownProps), + loading: commentsLoadingSelector(state) + }) } -export default toggleOpen(CommentList) +export default connect( + createMapStateToProps(), + { fetchData: loadAllComments } +)(toggleOpen(CommentList)) diff --git a/src/constants/index.js b/src/constants/index.js index 6266326..c1e13ce 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -8,6 +8,7 @@ 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' diff --git a/src/reducer/comments.js b/src/reducer/comments.js index b88e10b..21f2d9b 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,19 +1,40 @@ -import { ADD_COMMENT } from '../constants' -import { normalizedComments } from '../fixtures' +import { ADD_COMMENT, LOAD_ALL_COMMENTS, START, SUCCESS } from '../constants' +import { Record } from 'immutable' import { arrToMap } from './utils' -export default (state = arrToMap(normalizedComments), action) => { - const { type, payload, randomId } = action +const CommentRecord = Record({ + id: null, + user: null, + text: null +}) + +const ReducerRecord = Record({ + entities: arrToMap([], CommentRecord), + loading: false, + error: null +}) + +export default (state = new ReducerRecord(), action) => { + const { type, payload, randomId, response } = action switch (type) { case ADD_COMMENT: - return { - ...state, - [randomId]: { - ...payload.comment, - id: randomId - } - } + return state.setIn( + ['entities', randomId], + new CommentRecord({ + id: randomId, + user: payload.comment.user, + text: payload.comment.text + }) + ) + + case LOAD_ALL_COMMENTS + START: + return state.set('loading', true) + + case LOAD_ALL_COMMENTS + SUCCESS: + return state + .set('entities', arrToMap(response, CommentRecord)) + .set('loading', false) default: return state diff --git a/src/selectors/index.js b/src/selectors/index.js index 8e5b7d0..4439254 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -8,7 +8,19 @@ export const articleListSelector = createSelector( articlesMapSelector, (articlesMap) => articlesMap.valueSeq().toArray() ) -export const commentsSelector = (state) => state.comments +export const commentsLoadingSelector = (state) => state.comments.loading +export const commentsMapSelector = (state, props) => { + const commentsIdsList = props.article && props.article.get('comments') + return commentsIdsList + ? state.comments.entities.filter((comment) => + commentsIdsList.includes(comment.id) + ) + : state.comments.entities +} +export const commentsSelector = createSelector( + commentsMapSelector, + (commentsMap) => commentsMap.valueSeq().toArray() +) export const idSelector = (_, props) => props.id export const filtratedArticlesSelector = createSelector( @@ -31,6 +43,6 @@ export const filtratedArticlesSelector = createSelector( ) export const createCommentSelector = () => - createSelector(commentsSelector, idSelector, (comments, id) => { - return comments[id] + createSelector(commentsMapSelector, idSelector, (commentsMap, id) => { + return commentsMap.get(id) })