diff --git a/src/AC/index.js b/src/AC/index.js index e3a996a..a6176de 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() { @@ -70,6 +70,25 @@ export function loadArticle(id) { payload: { id, response } })) - }, 1000) + }, 300) + } +} + +export function loadComments(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 } + })) + + }, 300) } } \ No newline at end of file diff --git a/src/components/Comment.js b/src/components/Comment.js index 4b123ce..27480f3 100644 --- a/src/components/Comment.js +++ b/src/components/Comment.js @@ -1,7 +1,7 @@ import React from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' -import {createCommentSelector} from '../selectors' +import {commentSelector} from '../selectors' function Comment({comment}) { return ( @@ -20,13 +20,8 @@ Comment.propTypes = { }).isRequired } -const createMapStateToProps = () => { - const commentSelector = createCommentSelector() - return (state, ownProps) => { - return { - comment: commentSelector(state, ownProps) - } +export default connect((state, ownProps) => { + return { + comment: commentSelector(state, ownProps) } -} - -export default connect(createMapStateToProps)(Comment) \ No newline at end of file +})(Comment) \ No newline at end of file diff --git a/src/components/CommentList.js b/src/components/CommentList.js index 3082942..516e0e5 100644 --- a/src/components/CommentList.js +++ b/src/components/CommentList.js @@ -1,8 +1,12 @@ import React, {Component} from 'react' +import { connect } from 'react-redux' import PropTypes from 'prop-types' import CommentForm from './CommentForm' import Comment from './Comment' import toggleOpen from '../decorators/toggleOpen' +import Loader from './common/Loader' +import {loadComments} from '../AC' +import { commentsLoadingSelector, commentListSelector, commentsCacheSelector, commentsLoadedIdSelector } from '../selectors' class CommentList extends Component { static propTypes = { @@ -12,6 +16,11 @@ class CommentList extends Component { toggleOpen: PropTypes.func } + componentWillReceiveProps({ isOpen, article, loadComments }) { + //console.log('-', this.props); + if (!this.props.isOpen && isOpen && (this.props.loadedId != article.id)) loadComments(article.id) + } + render() { const {isOpen, toggleOpen} = this.props const text = isOpen ? 'hide comments' : 'show comments' @@ -24,12 +33,13 @@ class CommentList extends Component { } getBody() { - const {article: { comments, id }, isOpen} = this.props + const { comments, article: { id }, isOpen, loading} = this.props if (!isOpen) return null + if (loading) return const body = comments.length ? ( ) :

No comments yet

@@ -43,4 +53,11 @@ class CommentList extends Component { } -export default toggleOpen(CommentList) \ No newline at end of file +export default connect(state => { + return { + loading: commentsLoadingSelector(state), + comments: commentListSelector(state), + //cache: commentsCacheSelector(state), + loadedId: commentsLoadedIdSelector(state) + } +}, {loadComments})(toggleOpen(CommentList)) \ No newline at end of file diff --git a/src/constants/index.js b/src/constants/index.js index f34f842..817345f 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -3,6 +3,7 @@ export const INCREMENT = 'INCREMENT' export const DELETE_ARTICLE = 'DELETE_ARTICLE' export const LOAD_ALL_ARTICLES = 'LOAD_ALL_ARTICLES' export const LOAD_ARTICLE = 'LOAD_ARTICLE' +export const LOAD_COMMENTS = 'LOAD_COMMENTS' export const CHANGE_SELECTION = 'CHANGE_SELECTION' export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' diff --git a/src/middlewares/api.js b/src/middlewares/api.js index 52ed209..25ab7d1 100644 --- a/src/middlewares/api.js +++ b/src/middlewares/api.js @@ -16,5 +16,5 @@ export default store => next => action => { .then(res => res.json()) .then(response => next({...rest, response, type: type + SUCCESS})) .catch(error => next({...rest, error, type: type + FAIL})) - }, 1000) + }, 300) } \ No newline at end of file diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 764e28c..e5c3901 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,16 +1,46 @@ -import { ADD_COMMENT } from '../constants' -import {normalizedComments} from '../fixtures' +import { Map, Record } from 'immutable' +import { ADD_COMMENT, LOAD_COMMENTS, START, SUCCESS, FAIL } from '../constants' import {arrToMap} from './utils' -export default (state = arrToMap(normalizedComments), action) => { - const { type, payload, randomId } = action +const CommentsRecord = Record({ + id: null, + user: null, + text: null +}) + +const ReducerRecord = Record({ + entities: arrToMap([], CommentsRecord), + loading: false, + loaded: false, + error: null, + //cache: false, + loadedId: null +}) + +export default (state = new ReducerRecord(), action) => { + const { type, payload, randomId, error } = action switch (type) { case ADD_COMMENT: - return state.set(randomId, { - ...payload.comment, - id: randomId - }) + return state.setIn(['entities', randomId], + new CommentsRecord({ ...payload.comment, id: randomId})) + + case LOAD_COMMENTS + START: + return state + .set('loading', true) + .set('loadedId', payload.id) + + case LOAD_COMMENTS + FAIL: + return state + .set('loading', false) + .set('error', error) + + case LOAD_COMMENTS + SUCCESS: + return state + .set('loading', false) + .set('loaded', true) + //.set('cache', true) + .set('entities', arrToMap(payload.response, CommentsRecord)) } return state diff --git a/src/selectors/index.js b/src/selectors/index.js index c358756..e5cd983 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -3,7 +3,10 @@ import {createSelector} from 'reselect' export const articlesMapSelector = state => state.articles.entities export const articlesLoadingSelector = state => state.articles.loading export const filtersSelector = state => state.filters -export const commentListSelector = state => state.comments +export const commentListMapSelector = state => state.comments.entities +export const commentsLoadingSelector = state => state.comments.loading +export const commentsLoadedIdSelector = state => state.comments.loadedId +//export const commentsCacheSelector = state => state.comments.cache export const idSelector = (_, props) => props.id export const articlesSelector = createSelector(articlesMapSelector, articles => articles.valueSeq().toArray()) @@ -18,6 +21,8 @@ export const filtratedArticlesSelector = createSelector(articlesSelector, filter }) }) -export const createCommentSelector = () => createSelector(commentListSelector, idSelector, (comments, id) => { - return comments.get(id) +export const commentListSelector = createSelector(commentListMapSelector, comments => comments.valueSeq().toArray()) + +export const commentSelector = createSelector(commentListSelector, idSelector, (comments, id) => { + return comments.find(item => item.id == id) }) \ No newline at end of file