From df82c179c56682d9e402b5e4ad406b3dfaaac46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9C=D1=83=D1=84?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=D0=B2?= Date: Tue, 23 Oct 2018 22:54:37 +0300 Subject: [PATCH 1/4] add new comment form --- src/components/comment-list/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js index 7412972..6f25d76 100644 --- a/src/components/comment-list/index.js +++ b/src/components/comment-list/index.js @@ -49,6 +49,7 @@ class CommentList extends Component { ) : (

No comments yet

)} + {this.form} ) } @@ -64,6 +65,15 @@ class CommentList extends Component { ) } + + get form() { + return ( +
+ + +
+ ) + } } export default toggleOpen(CommentList) From fda03e3068c14714bf471e4ebc7088facc3ab259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9C=D1=83=D1=84?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=D0=B2?= Date: Tue, 23 Oct 2018 23:40:31 +0300 Subject: [PATCH 2/4] rewrite articles into key->value --- src/components/article-list.js | 10 +++++----- src/components/filters/select.js | 9 +++++---- src/reducer/articles.js | 10 +++++++++- src/selectors/index.js | 19 ++++++++++++------- 4 files changed, 31 insertions(+), 17 deletions(-) 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/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/reducer/articles.js b/src/reducer/articles.js index 8a41996..490c3db 100644 --- a/src/reducer/articles.js +++ b/src/reducer/articles.js @@ -1,6 +1,14 @@ -import { normalizedArticles as defaultArticles } from '../fixtures' +import { normalizedArticles } from '../fixtures' import { DELETE_ARTICLE } from '../constants' +const defaultArticles = normalizedArticles.reduce( + (acc, article) => ({ + ...acc, + [article.id]: article + }), + {} +) + export default (articlesState = defaultArticles, action) => { const { type, payload } = action 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 } + }, {}) } ) From b8bb1801cb72ebb57d9e2296f68350124c035a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9C=D1=83=D1=84?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=D0=B2?= Date: Wed, 24 Oct 2018 00:10:35 +0300 Subject: [PATCH 3/4] add id-generator middleware --- src/constants/index.js | 2 ++ src/middlewares/id-generator.js | 12 ++++++++++++ src/middlewares/index.js | 4 ++++ src/store/index.js | 4 ++-- 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/middlewares/id-generator.js create mode 100644 src/middlewares/index.js 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..ecc4a85 --- /dev/null +++ b/src/middlewares/id-generator.js @@ -0,0 +1,12 @@ +import crypto from 'crypto' +import { ADD_COMMENT } from '../constants' + +export default (store) => (next) => (action) => { + if (action.type === ADD_COMMENT) { + console.log('id-generator', 'before: ', action) + action.payload.id = crypto.randomBytes(24).toString('hex') + console.log('id-generator', 'udated: ', action) + } + next(action) + console.log('id-generator', 'after: ', store.getState()) +} 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/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) From 4d7a613a169fdc680a28c4021e6491ef27566461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=9C=D1=83=D1=84?= =?UTF-8?q?=D1=82=D0=B8=D0=B5=D0=B2?= Date: Wed, 24 Oct 2018 01:53:04 +0300 Subject: [PATCH 4/4] make adding comments work --- src/ac/index.js | 10 +++++- src/components/article/index.js | 2 +- src/components/comment-list/index.js | 20 ++++++------ src/components/publish-form.js | 47 ++++++++++++++++++++++++++++ src/middlewares/id-generator.js | 5 +-- src/reducer/articles.js | 12 ++++++- src/reducer/comments.js | 14 +++++++-- 7 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 src/components/publish-form.js 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/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 6f25d76..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,7 +52,7 @@ class CommentList extends Component { ) : (

    No comments yet

    )} - {this.form} + ) } @@ -66,14 +69,13 @@ class CommentList extends Component { ) } - get form() { - return ( -
    - - -
    - ) + 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/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/middlewares/id-generator.js b/src/middlewares/id-generator.js index ecc4a85..e0ae3a2 100644 --- a/src/middlewares/id-generator.js +++ b/src/middlewares/id-generator.js @@ -3,10 +3,7 @@ import { ADD_COMMENT } from '../constants' export default (store) => (next) => (action) => { if (action.type === ADD_COMMENT) { - console.log('id-generator', 'before: ', action) - action.payload.id = crypto.randomBytes(24).toString('hex') - console.log('id-generator', 'udated: ', action) + action.payload.id = crypto.randomBytes(16).toString('hex') } next(action) - console.log('id-generator', 'after: ', store.getState()) } diff --git a/src/reducer/articles.js b/src/reducer/articles.js index 490c3db..ee83565 100644 --- a/src/reducer/articles.js +++ b/src/reducer/articles.js @@ -1,5 +1,5 @@ import { normalizedArticles } from '../fixtures' -import { DELETE_ARTICLE } from '../constants' +import { DELETE_ARTICLE, ADD_COMMENT } from '../constants' const defaultArticles = normalizedArticles.reduce( (acc, article) => ({ @@ -16,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 }