From 5f71663b587a826a0a28536afc4c2e6d450ffbdc Mon Sep 17 00:00:00 2001
From: ls16 <1@1.ru>
Date: Wed, 7 Feb 2018 23:42:20 +0300
Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?=
=?UTF-8?q?=D0=B0=D0=BD=20comments=20=D1=80=D0=B5=D0=B4=D1=8E=D1=81=D0=B5?=
=?UTF-8?q?=D1=80=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=BE=D0=B3=D0=B8=D1=87=D0=BD?=
=?UTF-8?q?=D0=BE=20articles,=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B6=D0=B0?=
=?UTF-8?q?=D1=8E=D1=82=D1=81=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD?=
=?UTF-8?q?=D1=82=D1=8B=20=D0=BA=20=D1=81=D1=82=D0=B0=D1=82=D1=8C=D0=B5=20?=
=?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82=D0=B8?=
=?UTF-8?q?=D0=B8=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20=D0=BA=D0=BE?=
=?UTF-8?q?=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/AC/index.js | 12 ++++++++--
src/components/Article/index.js | 21 ++++++++++++++---
src/components/CommentList.js | 10 +++++++-
src/constants/index.js | 1 +
src/reducer/comments.js | 42 ++++++++++++++++++++++++++-------
src/selectors/index.js | 6 +++--
6 files changed, 76 insertions(+), 16 deletions(-)
diff --git a/src/AC/index.js b/src/AC/index.js
index e3a996a..430d49b 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
+ INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, LOAD_ALL_ARTICLES,
+ LOAD_ARTICLE, LOAD_COMMENTS, START, SUCCESS, FAIL
} from '../constants'
export function increment() {
@@ -72,4 +72,12 @@ export function loadArticle(id) {
}, 1000)
}
+}
+
+export function loadComments(articleId) {
+ return {
+ type: LOAD_COMMENTS,
+ payload: { articleId },
+ callAPI: `/api/comment?article=${articleId}`
+ }
}
\ No newline at end of file
diff --git a/src/components/Article/index.js b/src/components/Article/index.js
index 2e4a647..66b3257 100644
--- a/src/components/Article/index.js
+++ b/src/components/Article/index.js
@@ -6,6 +6,7 @@ import {connect} from 'react-redux'
import CommentList from '../CommentList'
import Loader from '../common/Loader'
import {deleteArticle, loadArticle} from '../../AC'
+import {commentsLoadingSelector, commentsLoadedSelector} from '../../selectors'
import './style.css'
class Article extends PureComponent {
@@ -61,14 +62,15 @@ class Article extends PureComponent {
}
getBody() {
- const { isOpen, article } = this.props
+ const { isOpen, article, loadingComments, loadedComments } = this.props
if (!isOpen) return null
if (article.loading) return
return (
-
+
)
@@ -97,5 +99,18 @@ class Article extends PureComponent {
}
+const createMapStateToProps = () => {
+ return (state, ownProps) => {
+ const articleId = ownProps.article.id
+ const loading = commentsLoadingSelector(state)
+ const loadingComments = loading.get(articleId) != null ? loading.get(articleId) : true
+ const loaded = commentsLoadedSelector(state)
+ const loadedComments = loaded.get(articleId)
+ return {
+ loadingComments: loadingComments,
+ loadedComments: loadedComments
+ }
+ }
+}
-export default connect(null, { deleteArticle, loadArticle })(Article)
\ No newline at end of file
+export default connect(createMapStateToProps, { deleteArticle, loadArticle })(Article)
\ No newline at end of file
diff --git a/src/components/CommentList.js b/src/components/CommentList.js
index 3082942..6e59d83 100644
--- a/src/components/CommentList.js
+++ b/src/components/CommentList.js
@@ -3,6 +3,9 @@ import PropTypes from 'prop-types'
import CommentForm from './CommentForm'
import Comment from './Comment'
import toggleOpen from '../decorators/toggleOpen'
+import {loadComments} from '../AC'
+import Loader from './common/Loader'
+import store from '../store'
class CommentList extends Component {
static propTypes = {
@@ -12,6 +15,10 @@ class CommentList extends Component {
toggleOpen: PropTypes.func
}
+ componentWillReceiveProps({ isOpen, article, loaded}) {
+ if (!this.props.isOpen && isOpen && !loaded) store.dispatch(loadComments(article.id))
+ }
+
render() {
const {isOpen, toggleOpen} = this.props
const text = isOpen ? 'hide comments' : 'show comments'
@@ -24,9 +31,10 @@ class CommentList extends Component {
}
getBody() {
- const {article: { comments, id }, isOpen} = this.props
+ const {article: { comments, id }, isOpen, loading} = this.props
if (!isOpen) return null
+ if (loading) return
const body = comments.length ? (
{comments.map(id => )}
diff --git a/src/constants/index.js b/src/constants/index.js
index f34f842..8a18b45 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_COMMENTS = 'LOAD_COMMENTS'
export const START = '_START'
export const SUCCESS = '_SUCCESS'
diff --git a/src/reducer/comments.js b/src/reducer/comments.js
index 764e28c..0c3cfa7 100644
--- a/src/reducer/comments.js
+++ b/src/reducer/comments.js
@@ -1,16 +1,42 @@
-import { ADD_COMMENT } from '../constants'
-import {normalizedComments} from '../fixtures'
+import { Map, Record } from 'immutable'
+import { ADD_COMMENT, LOAD_COMMENTS, START, SUCCESS } from '../constants'
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 idRecord = Record({
+ id: null
+})
+
+const ReducerRecord = Record({
+ entities: arrToMap([], CommentRecord),
+ loading: arrToMap([], idRecord),
+ loaded: arrToMap([], idRecord),
+ error: arrToMap([], idRecord)
+})
+
+export default (state = new ReducerRecord(), action) => {
+ const { type, payload, randomId} = action
switch (type) {
case ADD_COMMENT:
- return state.set(randomId, {
- ...payload.comment,
- id: randomId
- })
+ return state.mergeIn(['entities'], arrToMap([{
+ id: randomId,
+ user: payload.comment.user,
+ text: payload.comment.text
+ }], CommentRecord))
+ case LOAD_COMMENTS + START:
+ return state.setIn(['loading', payload.articleId], true)
+ case LOAD_COMMENTS + SUCCESS:
+ const { response } = action
+ return state
+ .setIn(['loading', payload.articleId], false)
+ .setIn(['loaded', payload.articleId], true)
+ .mergeIn(['entities'], arrToMap(response, CommentRecord))
}
return state
diff --git a/src/selectors/index.js b/src/selectors/index.js
index c358756..17cba00 100644
--- a/src/selectors/index.js
+++ b/src/selectors/index.js
@@ -3,7 +3,9 @@ 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 commentsMapSelector = state => state.comments.entities
+export const commentsLoadingSelector = state => state.comments.loading
+export const commentsLoadedSelector = state => state.comments.loaded
export const idSelector = (_, props) => props.id
export const articlesSelector = createSelector(articlesMapSelector, articles => articles.valueSeq().toArray())
@@ -18,6 +20,6 @@ export const filtratedArticlesSelector = createSelector(articlesSelector, filter
})
})
-export const createCommentSelector = () => createSelector(commentListSelector, idSelector, (comments, id) => {
+export const createCommentSelector = () => createSelector(commentsMapSelector, idSelector, (comments, id) => {
return comments.get(id)
})
\ No newline at end of file