Skip to content
Open

Hw 5 #73

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
16 changes: 15 additions & 1 deletion src/AC/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import {INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION} from '../constants'
import {INCREMENT, DELETE_ARTICLE, CHANGE_DATE_RANGE, CHANGE_SELECTION, ADD_COMMENT, OPEN_ARTICLE} from '../constants'

export function increment() {
return {
type: INCREMENT
}
}

export function openArticle(id) {
return {
type: OPEN_ARTICLE,
payload: { id }
}
}

export function deleteArticle(id) {
return {
type: DELETE_ARTICLE,
Expand All @@ -26,3 +33,10 @@ export function changeSelection(selected) {
payload: { selected }
}
}

export function addComment(comment) {
return {
type: ADD_COMMENT,
payload: { comment }
}
}
5 changes: 3 additions & 2 deletions src/components/ArticleList.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class ArticleList extends Accordion {
console.log('---', 'rerendering article list')
const {articles} = this.props
if (!articles.length) return <h3>No Articles</h3>
const articleElements = articles.map((article) => <li key={article.id}>
const articleElements = Object.values(articles).map((article) => <li key={article.id}>
Copy link
Owner

Choose a reason for hiding this comment

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

Лучше селектор, который достанет из в виде массива

<Article article={article}
isOpen={article.id === this.state.openItemId}
isOpen={article.id === this.props.openItemId}
toggleOpen={this.toggleOpenItemMemoized(article.id)}
/>
</li>)
Expand All @@ -36,6 +36,7 @@ ArticleList.propTypes = {
export default connect(state => {
console.log('---', 'connect updated')
return {
openItemId: state.openArticleId,
articles: filtratedArticlesSelector(state)
}
})(ArticleList)
12 changes: 11 additions & 1 deletion src/components/CommentForm/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {addComment} from '../../AC'

import './style.css'

class CommentForm extends Component {
Expand Down Expand Up @@ -26,6 +29,13 @@ class CommentForm extends Component {

handleSubmit = ev => {
ev.preventDefault()

const {addComment} = this.props
addComment({
user: this.state.user,
text: this.state.text
})

this.setState({
user: '',
text: ''
Expand Down Expand Up @@ -58,4 +68,4 @@ const limits = {
}
}

export default CommentForm
export default connect(null, { addComment })(CommentForm)
4 changes: 2 additions & 2 deletions src/components/Filters/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import 'react-select/dist/react-select.css'

class SelectFilter extends Component {
static propTypes = {
articles: PropTypes.array.isRequired
articles: PropTypes.object.isRequired
};

handleChange = selected => this.props.changeSelection(selected.map(option => option.value))

render() {
const { articles, selected } = this.props
const options = articles.map(article => ({
const options = Object.values(articles).map(article => ({
label: article.title,
value: article.id
}))
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/Accordion.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React, { Component } from 'react'
import {openArticle} from '../../AC'
import store from '../../store'

class Accordion extends Component {
state = {
openItemId: this.props.defaultOpenItemId
}

toggleOpenItem = openItemId => ev => {
this.setState({
openItemId: openItemId === this.state.openItemId ? null : openItemId
})
store.dispatch(openArticle(openItemId === this.props.openItemId ? null : openItemId))
}

toggleOpenItemMemoized = (openItemId) => {
Expand Down
5 changes: 4 additions & 1 deletion src/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export const INCREMENT = 'INCREMENT'

export const OPEN_ARTICLE = 'OPEN_ARTICLE'
export const DELETE_ARTICLE = 'DELETE_ARTICLE'

export const CHANGE_SELECTION = 'CHANGE_SELECTION'
export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE'
export const CHANGE_DATE_RANGE = 'CHANGE_DATE_RANGE'

export const ADD_COMMENT = 'ADD_COMMENT'
25 changes: 25 additions & 0 deletions src/middlewares/idGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {ADD_COMMENT} from '../constants'

export default store => next => action => {
function genId(len) {
function getRandomChar() {
let number = Math.round(Math.random() * 15);
return number < 10 ? String.fromCharCode(97 + number) : String.fromCharCode(39 + number)
}

let result = getRandomChar();
for (let i = 0; i < len - 1; i++) {
result += getRandomChar();
}
return result;
}

switch (action.type) {
case ADD_COMMENT:
Copy link
Owner

Choose a reason for hiding this comment

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

через мидлвары будет проходить каждый экшин, они должны быть максимально общими, завязывать на конкретные экшины - не лучшее решение

action.payload.id = genId(10)
Copy link
Owner

Choose a reason for hiding this comment

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

лучше не мутировать payload, мало-ли что там станут передавать

action.payload.articleId = store.getState().openArticleId
break;
}

next(action)
}
24 changes: 21 additions & 3 deletions src/reducer/articles.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { DELETE_ARTICLE } from '../constants'
import { DELETE_ARTICLE, ADD_COMMENT, OPEN_ARTICLE } from '../constants'
import {normalizedArticles as defaultArticles} from '../fixtures'

export default (articlesState = defaultArticles, action) => {
const articlesMap = defaultArticles.reduce((acc, article) => {
article.comments = article.comments != null ? article.comments : []
return {
...acc,
[article.id]: article
}
}, {})

export default (articlesState = articlesMap, action) => {
const { type, payload } = action

switch (type) {
case DELETE_ARTICLE:
return articlesState.filter(article => article.id !== payload.id)
articlesState = {...articlesState}
delete articlesState[payload.id]
return articlesState
case ADD_COMMENT:
let article = {...articlesState[payload.articleId]}
article.comments = [...article.comments]
Copy link
Owner

Choose a reason for hiding this comment

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

comments может быть undefined

article.comments.push(payload.id)
return {
...articlesState,
[payload.articleId]: article
}
}

return articlesState
Expand Down
12 changes: 10 additions & 2 deletions src/reducer/comments.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { } from '../constants'
import { ADD_COMMENT } from '../constants'
import {normalizedComments as defaultComments} from '../fixtures'

const commentsMap = defaultComments.reduce((acc, comment) => ({
Expand All @@ -10,7 +10,15 @@ export default (state = commentsMap, action) => {
const { type } = action

switch (type) {

case ADD_COMMENT:
state = {
...state,
[action.payload.id]: {
...action.payload.comment,
id: action.payload.id
}
}
return state;
}

return state
Expand Down
4 changes: 3 additions & 1 deletion src/reducer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import counterReducer from './counter'
import articles from './articles'
import comments from './comments'
import filters from './filters'
import openArticle from './openArticle';

export default combineReducers({
counter: counterReducer,
articles, comments, filters
articles, comments, filters,
openArticleId: openArticle
})
5 changes: 5 additions & 0 deletions src/reducer/openArticle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {OPEN_ARTICLE} from '../constants'

export default (openArticleId = null, action) => {
return action.type === OPEN_ARTICLE ? action.payload.id : openArticleId
}
2 changes: 1 addition & 1 deletion src/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const filtratedArticlesSelector = createSelector(articlesSelector, filter
console.log('---', 'computing filters')
const {selected, dateRange: {from, to}} = filters

return articles.filter(article => {
return Object.values(articles).filter(article => {
const published = Date.parse(article.date)
return (!selected.length || selected.includes(article.id)) &&
(!from || !to || (published > from && published < to))
Expand Down
3 changes: 2 additions & 1 deletion src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {createStore, applyMiddleware, compose} from 'redux'
import rootReducer from '../reducer'
import logger from '../middlewares/logger'
import idGenerator from '../middlewares/idGenerator'

const composeEnhancers =
typeof window === 'object' &&
Expand All @@ -10,7 +11,7 @@ const composeEnhancers =
}) : compose

const enhancer = composeEnhancers(
applyMiddleware(logger)
applyMiddleware(logger, idGenerator)
Copy link
Owner

Choose a reason for hiding this comment

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

лучше логгер в конце ставить

)
const store = createStore(rootReducer, enhancer)

Expand Down