diff --git a/src/AC/index.js b/src/AC/index.js index 401b5b1..216e59e 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, - START, SUCCESS, FAIL + LOAD_COMMENTS, START, SUCCESS, FAIL } from '../constants' export function increment() { @@ -74,4 +74,26 @@ export function loadArticleById(id) { })) }, 1000) } -} \ No newline at end of file +} + +export function loadCommentsByArticleId(id) { + return (dispatch) => { + dispatch({ + type: LOAD_COMMENTS + START, + payload: { id } + }) + + setTimeout(() => { + fetch(`/api/comment?article=${id}`) + .then(res => res.json()) + .then(response => dispatch({ + type: LOAD_COMMENTS + SUCCESS, + payload: { id, response } + })) + .catch(error => dispatch({ + type: LOAD_COMMENTS + FAIL, + payload: { id, error } + })) + }, 1000) + } +} diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js index 173cb68..045467c 100644 --- a/src/components/comment-list/index.js +++ b/src/components/comment-list/index.js @@ -4,6 +4,10 @@ import CSSTransition from 'react-addons-css-transition-group' import Comment from '../comment' import CommentForm from '../comment-form' import toggleOpen from '../../decorators/toggleOpen' +import {loadingCommentsSelect, loadedCommentsSelect} from '../../selectors' +import {connect} from 'react-redux' +import {loadCommentsByArticleId} from '../../AC' +import Loader from '../loader' import './style.css' class CommentList extends Component { @@ -18,6 +22,10 @@ class CommentList extends Component { toggleOpen: PropTypes.func } + componentWillReceiveProps({isOpen, loadCommentsByArticleId, article}){ + if (!this.props.isOpen && isOpen && !article.commentsLoaded) loadCommentsByArticleId(article.id) + } + render() { const {isOpen, toggleOpen} = this.props const text = isOpen ? 'hide comments' : 'show comments' @@ -36,19 +44,21 @@ class CommentList extends Component { } getBody() { - const {article: { comments, id }, isOpen} = this.props + const {article: { comments, id, commentsLoaded }, isOpen, loading, loaded} = this.props if (!isOpen) return null - - return ( -
- { - comments.length - ? this.getComments() - :

No comments yet

- } - -
- ) + if (loading) return + if (commentsLoaded){ + return ( +
+ { + comments.length + ? this.getComments() + :

No comments yet

+ } + +
+ ) + } } getComments() { @@ -66,4 +76,7 @@ class CommentList extends Component { } -export default toggleOpen(CommentList) \ No newline at end of file +export default connect(state => ({ + loading: loadingCommentsSelect(state), + loaded: loadedCommentsSelect(state) +}), {loadCommentsByArticleId})(toggleOpen(CommentList)) diff --git a/src/constants/index.js b/src/constants/index.js index f34f842..9ef403c 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -8,7 +8,8 @@ export const CHANGE_SELECTION = 'CHANGE_SELECTION' export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' export const ADD_COMMENT = 'ADD_COMMENT' +export const LOAD_COMMENTS = 'LOAD_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/reducer/articles.js b/src/reducer/articles.js index 26166cc..afabb7c 100644 --- a/src/reducer/articles.js +++ b/src/reducer/articles.js @@ -1,4 +1,4 @@ -import { DELETE_ARTICLE, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, START, SUCCESS, FAIL } from '../constants' +import { DELETE_ARTICLE, ADD_COMMENT, LOAD_ALL_ARTICLES, LOAD_ARTICLE, LOAD_COMMENTS, START, SUCCESS } from '../constants' import { arrToMap } from './utils' import { Record } from 'immutable' @@ -8,7 +8,8 @@ const ArticleRecord = Record({ text: null, date: null, loading: false, - comments: [] + comments: [], + commentsLoaded: false, }) const ReducerState = Record({ @@ -46,8 +47,10 @@ export default (articles = new ReducerState(), action) => { case LOAD_ARTICLE + SUCCESS: return articles.setIn(['entities', payload.id], new ArticleRecord(payload.response)) + case LOAD_COMMENTS + SUCCESS: + return articles.setIn(['entities', payload.id, 'commentsLoaded'], true) default: return articles } -} \ No newline at end of file +} diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 9f32503..98643bb 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,18 +1,37 @@ -import { ADD_COMMENT } from '../constants' -import {normalizedComments} from '../fixtures' +import { ADD_COMMENT, LOAD_COMMENTS, SUCCESS, START } from '../constants' import {arrToMap} from './utils' +import {Record} from 'immutable' -export default (state = arrToMap(normalizedComments), action) => { +const CommentRecord = Record({ + id: null, + text: null, + user: null, +}) + +const ReducerState = Record({ + entities: arrToMap([], CommentRecord), + loading: false, + loaded: false, + error: null +}) + +export default (comments = new ReducerState(), action) => { const { type, payload, randomId } = action switch (type) { case ADD_COMMENT: - return state.set(randomId, { - ...payload.comment, - id: randomId - }) + return comments.setIn(['entities', randomId], { ...payload.comment, id: randomId }) + + case LOAD_COMMENTS + START: + return comments.set('loading', true) + + case LOAD_COMMENTS + SUCCESS: + return comments + .update('entities', comments => Object.assign(comments, arrToMap(payload.response, CommentRecord))) + .set('loading', false) + .set('loaded', true) default: - return state + return comments } -} \ No newline at end of file +} diff --git a/src/selectors/index.js b/src/selectors/index.js index 0f58db6..cd5fd32 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -4,7 +4,10 @@ export const articlesMapSelector = state => state.articles.entities export const articleListSelector = createSelector(articlesMapSelector, articlesMap => articlesMap.valueSeq().toArray()) export const loadingArticlesSelector = state => state.articles.loading -const commentsSelector = state => state.comments +const commentsSelector = state => state.comments.entities +export const loadingCommentsSelect = state => state.comments.loading +export const loadedCommentsSelect = state => state.comments.loaded + const filtersSelector = state => state.filters const idSelector = (_, props) => props.id @@ -19,4 +22,4 @@ export const filtratedArticles = createSelector(articleListSelector, filtersSele }) }) -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))