diff --git a/src/ac/index.js b/src/ac/index.js index 6acd6da..462aa20 100644 --- a/src/ac/index.js +++ b/src/ac/index.js @@ -2,7 +2,8 @@ import { INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, - CHANGE_SELECTION + CHANGE_SELECTION, + ADD_COMMENT } from '../constants' export function increment() { @@ -31,3 +32,10 @@ export function changeSelection(selected) { payload: { selected } } } + +export function addComment(payload) { + return { + type: ADD_COMMENT, + payload: payload + } +} diff --git a/src/components/article-list.js b/src/components/article-list.js index 9650e42..2068197 100644 --- a/src/components/article-list.js +++ b/src/components/article-list.js @@ -7,7 +7,7 @@ import { filtratedArticlesSelector } from '../selectors' export class ArticleList extends Component { static propTypes = { - articles: PropTypes.array.isRequired, + articles: PropTypes.object.isRequired, fetchData: PropTypes.func, //from accordion decorator @@ -22,11 +22,11 @@ export class ArticleList extends Component { get items() { const { articles, openItemId, toggleOpenItem } = this.props - return articles.map((article) => ( -
  • + return Object.keys(articles).map((id) => ( +
  • diff --git a/src/components/article/index.js b/src/components/article/index.js index 41fb2d5..becb29e 100644 --- a/src/components/article/index.js +++ b/src/components/article/index.js @@ -63,7 +63,7 @@ class Article extends PureComponent { return (
    {article.text} - +
    ) } diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js index 7412972..221fbae 100644 --- a/src/components/comment-list/index.js +++ b/src/components/comment-list/index.js @@ -1,8 +1,11 @@ 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 PublishForm from '../publish-form' import toggleOpen from '../../decorators/toggleOpen' +import { addComment } from '../../ac' import './style.css' class CommentList extends Component { @@ -49,6 +52,7 @@ class CommentList extends Component { ) : (

    No comments yet

    )} + ) } @@ -64,6 +68,14 @@ class CommentList extends Component { ) } + + submitComment(data) { + const { articleId, addComment } = this.props + addComment({ ...data, articleId }) + } } -export default toggleOpen(CommentList) +export default connect( + null, + { addComment } +)(toggleOpen(CommentList)) diff --git a/src/components/filters/select.js b/src/components/filters/select.js index a56ed53..ff1b984 100644 --- a/src/components/filters/select.js +++ b/src/components/filters/select.js @@ -6,7 +6,7 @@ import { changeSelection } from '../../ac' class SelectFilter extends Component { static propTypes = { - articles: PropTypes.array.isRequired + articles: PropTypes.object.isRequired } handleChange = (selected) => { @@ -14,9 +14,10 @@ class SelectFilter extends Component { } get options() { - return this.props.articles.map((article) => ({ - label: article.title, - value: article.id + const { articles } = this.props + return Object.keys(articles).map((id) => ({ + label: articles[id].title, + value: id })) } diff --git a/src/components/publish-form.js b/src/components/publish-form.js new file mode 100644 index 0000000..d50d567 --- /dev/null +++ b/src/components/publish-form.js @@ -0,0 +1,47 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' + +class PublishForm extends Component { + static propTypes = { + handler: PropTypes.func.isRequired + } + + state = { + text: '', + user: '' + } + + render() { + return ( +
    + + + +
    + ) + } + + handleInputChange(e) { + const val = e.target.value + const prop = e.target.name + this.setState({ [prop]: val }) + } + + handlePublishClick() { + const { handler } = this.props + + handler({ ...this.state }) + } +} + +export default PublishForm diff --git a/src/constants/index.js b/src/constants/index.js index e1fd7eb..4f21432 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -4,3 +4,5 @@ export const DELETE_ARTICLE = 'DELETE_ARTICLE' export const CHANGE_SELECTION = 'CHANGE_SELECTION' export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE' + +export const ADD_COMMENT = 'ADD_COMMENT' diff --git a/src/middlewares/id-generator.js b/src/middlewares/id-generator.js new file mode 100644 index 0000000..e0ae3a2 --- /dev/null +++ b/src/middlewares/id-generator.js @@ -0,0 +1,9 @@ +import crypto from 'crypto' +import { ADD_COMMENT } from '../constants' + +export default (store) => (next) => (action) => { + if (action.type === ADD_COMMENT) { + action.payload.id = crypto.randomBytes(16).toString('hex') + } + next(action) +} diff --git a/src/middlewares/index.js b/src/middlewares/index.js new file mode 100644 index 0000000..d8cd25c --- /dev/null +++ b/src/middlewares/index.js @@ -0,0 +1,4 @@ +import logger from './logger' +import idGenerator from './id-generator' + +export default [logger, idGenerator] diff --git a/src/reducer/articles.js b/src/reducer/articles.js index 8a41996..ee83565 100644 --- a/src/reducer/articles.js +++ b/src/reducer/articles.js @@ -1,5 +1,13 @@ -import { normalizedArticles as defaultArticles } from '../fixtures' -import { DELETE_ARTICLE } from '../constants' +import { normalizedArticles } from '../fixtures' +import { DELETE_ARTICLE, ADD_COMMENT } from '../constants' + +const defaultArticles = normalizedArticles.reduce( + (acc, article) => ({ + ...acc, + [article.id]: article + }), + {} +) export default (articlesState = defaultArticles, action) => { const { type, payload } = action @@ -8,6 +16,16 @@ export default (articlesState = defaultArticles, action) => { case DELETE_ARTICLE: return articlesState.filter((article) => article.id !== payload.id) + case ADD_COMMENT: + const comments = articlesState[payload.articleId].comments || [] + return { + ...articlesState, + [payload.articleId]: { + ...articlesState[payload.articleId], + comments: [].concat(payload.id, comments) + } + } + default: return articlesState } diff --git a/src/reducer/comments.js b/src/reducer/comments.js index 1cb52e1..e800f99 100644 --- a/src/reducer/comments.js +++ b/src/reducer/comments.js @@ -1,4 +1,4 @@ -import {} from '../constants' +import { ADD_COMMENT } from '../constants' import { normalizedComments } from '../fixtures' const defaultComments = normalizedComments.reduce( @@ -10,9 +10,19 @@ const defaultComments = normalizedComments.reduce( ) export default (state = defaultComments, action) => { - const { type } = action + const { type, payload } = action switch (type) { + case ADD_COMMENT: + return { + ...state, + [payload.id]: { + id: payload.id, + user: payload.user, + text: payload.text + } + } + default: return state } diff --git a/src/selectors/index.js b/src/selectors/index.js index b4a2b29..39fce19 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -13,15 +13,20 @@ export const filtratedArticlesSelector = createSelector( (selected, dateRange, articles) => { console.log('---', 'article list selector') const { from, to } = dateRange + const ids = selected.length + ? selected.map((item) => item.value) + : Object.keys(articles) - return articles.filter((article) => { + return ids.reduce((acc, id) => { + const article = articles[id] const published = Date.parse(article.date) - return ( - (!selected.length || - selected.find((selected) => selected.value === article.id)) && - (!from || !to || (published > from && published < to)) - ) - }) + return !from || !to || (published > from && published < to) + ? { + ...acc, + [id]: article + } + : { ...acc } + }, {}) } ) diff --git a/src/store/index.js b/src/store/index.js index 847f3d6..78883ee 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,8 +1,8 @@ import { createStore, applyMiddleware } from 'redux' import reducer from '../reducer' -import logger from '../middlewares/logger' +import middlewares from '../middlewares' -const enhancer = applyMiddleware(logger) +const enhancer = applyMiddleware(...middlewares) const store = createStore(reducer, enhancer)