Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion src/ac/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
LOAD_ARTICLE,
SUCCESS,
FAIL,
START
START,
LOAD_COMMENTS
} from '../constants'
import { fetchData } from './service'

Expand Down Expand Up @@ -88,3 +89,28 @@ export function loadArticle(id) {
)
}
}

export function loadComments(articleId) {
return (dispatch) => {
dispatch({
type: LOAD_COMMENTS + START,
payload: { articleId }
})

fetchData(`comment?article=${articleId}`)
.then((response) =>
dispatch({
type: LOAD_COMMENTS + SUCCESS,
payload: { articleId },
response
})
)
.catch((error) =>
dispatch({
type: LOAD_COMMENTS + FAIL,
payload: { articleId },
error
})
)
}
}
45 changes: 41 additions & 4 deletions src/components/comment-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,36 @@ import Comment from '../comment'
import CommentForm from '../comment-form'
import toggleOpen from '../../decorators/toggleOpen'
import './style.css'
import { loadComments } from '../../ac'
import {
loadingCommentsSelector,
isCommentsLoadedSelector
} from '../../selectors'
import { connect } from 'react-redux'
import Loader from '../common/loader'

class CommentList extends Component {
static propTypes = {
article: PropTypes.object.isRequired,
//from toggleOpen decorator
isOpen: PropTypes.bool,
toggleOpen: PropTypes.func
toggleOpen: PropTypes.func,
loadComments: PropTypes.func,
isCommentsLoaded: PropTypes.bool,
loading: PropTypes.bool
}

componentDidUpdate(oldProps) {
const {
isOpen,
isCommentsLoaded,
article,
loadComments,
loading
} = this.props

if (!oldProps.isOpen && isOpen && !loading && !isCommentsLoaded)
loadComments(article.id)
}

render() {
Expand All @@ -36,13 +59,16 @@ class CommentList extends Component {
getBody() {
const {
article: { comments = [], id },
isOpen
isOpen,
loading,
isCommentsLoaded
} = this.props
if (!isOpen) return null
if (loading) return <Loader />

return (
<div className="test__comment-list--body">
{comments.length ? (
{comments.length && isCommentsLoaded ? (
this.getComments()
) : (
<h3 className="test__comment-list--empty">No comments yet</h3>
Expand All @@ -65,4 +91,15 @@ class CommentList extends Component {
}
}

export default toggleOpen(CommentList)
const createMapStateToProps = () => {
const isCommentsLoaded = isCommentsLoadedSelector()

return (state, ownProps) => ({
loading: loadingCommentsSelector(state),
isCommentsLoaded: isCommentsLoaded(state, ownProps)
})
}

export default toggleOpen(
connect(createMapStateToProps, { loadComments })(CommentList)
)
1 change: 1 addition & 0 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
48 changes: 40 additions & 8 deletions src/reducer/comments.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,48 @@
import { ADD_COMMENT } from '../constants'
import { normalizedComments } from '../fixtures'
import { ADD_COMMENT, LOAD_COMMENTS, START, SUCCESS, FAIL } from '../constants'
import { arrToMap } from './utils'
import { Record } from 'immutable'

export default (state = arrToMap(normalizedComments), action) => {
const { type, payload, randomId } = action
const CommentModel = new Record({
id: null,
user: null,
text: null
})

const ReducerRecord = new Record({
entities: arrToMap([], CommentModel),
loading: false,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

здесь не достаточно повесить loading на весь comments, ведь ты для конкрентной статьи загружаешь

error: null
})

export default (state = new ReducerRecord(), action) => {
const { type, payload, randomId, response } = action

switch (type) {
case ADD_COMMENT:
return state.set(randomId, {
...payload.comment,
id: randomId
})
return state.set(
'entities',
state.get('entities').set(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.setIn для этого есть

randomId,
new CommentModel({
...payload.comment,
id: randomId
})
)
)

case LOAD_COMMENTS + SUCCESS:
return state
.set(
'entities',
state.get('entities').merge(arrToMap(response, CommentModel))
)
.set('loading', false)

case LOAD_COMMENTS + START:
return state.set('loading', true)

case LOAD_COMMENTS + FAIL:
return state.set('loading', false).set('error', action.error)

default:
return state
Expand Down
24 changes: 22 additions & 2 deletions src/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export const articleListSelector = createSelector(
export const loadingArticlesSelector = (state) => state.articles.loading

const filtersSelector = (state) => state.filters
const commentListSelector = (state) => state.comments
const commentMapSelector = (state) => state.comments.entities
const commentListSelector = createSelector(commentMapSelector, (commentsMap) =>
commentsMap.valueSeq().toArray()
)

export const filtersSelectionSelector = createSelector(
filtersSelector,
(filters) => filters.selected
Expand Down Expand Up @@ -40,6 +44,22 @@ export const filtratedArticlesSelector = createSelector(

export const createCommentSelector = () => {
return createSelector(commentListSelector, idSelector, (comments, id) => {
return comments.get(id)
return comments.find((comment) => comment.id === id)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

просто из Map читай, а не List

})
}

const commentIdsSelector = (_, props) => props.article.comments

export const isCommentsLoadedSelector = () => {
return createSelector(
commentListSelector,
commentIdsSelector,
(comments, commentIds) => {
return commentIds.every((commentId) =>
comments.find((comment) => comment.id === commentId)
)
}
)
}

export const loadingCommentsSelector = (state) => state.comments.loading