twreporter-redux
Version:
redux actions and reducers for twreporter website
285 lines (249 loc) • 7.21 kB
JavaScript
/* eslint no-param-reassign: ["error", { "props": false }] */
import fieldNames from '../constants/redux-state-field-names'
import types from '../constants/action-types'
// lodash
import concat from 'lodash/concat'
import filter from 'lodash/filter'
import get from 'lodash/get'
import map from 'lodash/map'
import merge from 'lodash/merge'
import values from 'lodash/values'
const _ = {
concat,
filter,
get,
map,
merge,
values,
}
function normalizeTopic(topic, postEntities, topicEntities) {
if (typeof topic !== 'object') {
return {
postEntities,
topicEntities,
}
}
if (topic.full) {
const relatedPosts = _.get(topic, 'relateds', [])
topic.relateds = relatedPosts.map((post) => {
if (typeof post === 'object') {
if (!postEntities[post.slug] || post.full) {
postEntities[post.slug] = post
}
}
return _.get(post, 'slug', '')
})
}
if (!topicEntities[topic.slug] || topic.full) {
topicEntities[topic.slug] = topic
}
return {
postEntities,
topicEntities,
}
}
function normalizePost(post, _postEntities, _topicEntities) {
let postEntities = _postEntities
let topicEntities = _topicEntities
if (typeof post !== 'object') {
return {
postEntities,
topicEntities,
}
}
const postSlug = post.slug
if (post.full) {
const topic = _.get(post, 'topics')
const normalizedObj = normalizeTopic(topic, postEntities, topicEntities)
postEntities = normalizedObj.postEntities
topicEntities = normalizedObj.topicEntities
post.topics = _.get(topic, 'slug', topic)
post.relateds = _.map(post.relateds, (_post) => {
if (typeof _post === 'object') {
if (!postEntities[_post.slug] || _post.full) {
postEntities[_post.slug] = _post
}
}
return _.get(_post, 'slug', _post)
})
}
if (!postEntities[postSlug] || post.full) {
postEntities[postSlug] = post
}
return {
postEntities,
topicEntities,
}
}
function normalizeAssets(assets, _postEntities, _topicEntities, style) {
let postEntities = _postEntities
let topicEntities = _topicEntities
if (!Array.isArray(assets)) {
return {
postEntities,
topicEntities,
}
}
const normalize = style === 'post' ? normalizePost : normalizeTopic
assets.forEach((asset) => {
const normalizedObj = normalize(asset, postEntities, topicEntities)
postEntities = normalizedObj.postEntities
topicEntities = normalizedObj.topicEntities
})
return {
postEntities,
topicEntities,
}
}
// This will normalize the posts and topics.
// EX:
// action = {
// latest: [{
// slug: 'post_1'
// is_feature: false,
// style: 'article'
// }, {
// slug: 'post_2'
// is_feature: false,
// style: 'article'
// }],
// editor_picks: [{
// slug: 'post_3',
// is_feature: true
// style: 'article'
// }],
// reviews: [{
// slug: 'post_4',
// is_feature: false
// style: 'review'
// }],
// latest_topics: {
// slug: 'topic_1',
// relateds: [{
// slug: 'post_5'
// is_feature: false
// style: 'article'
// },{
// slug: 'post_6'
// is_feature: false
// style: 'article'
// }]
// }
// }
//
// the result will be
// {
// posts: {
// 'post_1': {
// slug: 'post_1'
// is_feature: false,
// style: 'article'
// },
// 'post_2': {
// slug: 'post_2'
// is_feature: false,
// style: 'article'
// },
// 'post_3': {
// slug: 'post_3'
// is_feature: true,
// style: 'article'
// },
// 'post_4': {
// slug: 'post_4'
// is_feature: false,
// style: 'review'
// },
// 'post_5': {
// slug: 'post_5'
// is_feature: false,
// style: 'article'
// },
// 'post_6': {
// slug: 'post_6'
// is_feature: false,
// style: 'article'
// },
// },
// topics: {
// 'topic_1': {
// slug: 'topic_1',
// relateds: [ 'post_5', 'post_6']
// }
// }
// }
function entities(state = {}, action = {}) {
let payload
let normalizedObj = {
postEntities: _.get(state, fieldNames.postsInEntities, {}),
topicEntities: _.get(state, fieldNames.topicsInEntities, {}),
}
switch (action.type) {
case types.GET_CONTENT_FOR_INDEX_PAGE: {
payload = action.payload
const sections = _.filter(_.values(fieldNames.sections), (section) => {
return section !== fieldNames.sections.latestTopicSection &&
section !== fieldNames.sections.topicsSection
})
const categories = _.values(fieldNames.categories)
const fields = _.concat(sections, categories)
fields.forEach((field) => {
const posts = _.get(payload, field, [])
normalizedObj = normalizeAssets(posts, normalizedObj.postEntities,
normalizedObj.topicEntities, 'post')
})
normalizedObj = normalizeTopic(_.get(payload, [fieldNames.sections.latestTopicSection, 0]),
normalizedObj.postEntities, normalizedObj.topicEntities)
normalizedObj = normalizeAssets(_.get(payload, fieldNames.sections.topicsSection, []),
normalizedObj.postEntities, normalizedObj.topicEntities, 'topic')
return _.merge({}, state, {
[fieldNames.postsInEntities]: normalizedObj.postEntities,
[fieldNames.topicsInEntities]: normalizedObj.topicEntities,
})
}
case types.GET_TOPICS:
case types.GET_TOPICS_FOR_INDEX_PAGE: {
payload = _.get(action, 'payload.items', [])
normalizedObj = normalizeAssets(payload, normalizedObj.postEntities,
normalizedObj.topicEntities, 'topic')
return _.merge({}, state, {
[fieldNames.postsInEntities]: normalizedObj.postEntities,
[fieldNames.topicsInEntities]: normalizedObj.topicEntities,
})
}
case types.GET_EDITOR_PICKED_POSTS:
case types.GET_PHOTOGRAPHY_POSTS_FOR_INDEX_PAGE:
case types.GET_INFOGRAPHIC_POSTS_FOR_INDEX_PAGE:
case types.GET_LISTED_POSTS: {
payload = _.get(action, 'payload.items', [])
normalizedObj = normalizeAssets(payload, normalizedObj.postEntities,
normalizedObj.topicEntities, 'post')
return _.merge({}, state, {
[fieldNames.postsInEntities]: normalizedObj.postEntities,
[fieldNames.topicsInEntities]: normalizedObj.topicEntities,
})
}
case types.GET_A_FULL_POST: {
const post = _.get(action, 'payload', {})
normalizedObj = normalizePost(post, normalizedObj.postEntities,
normalizedObj.topicEntities)
return _.merge({}, state, {
[fieldNames.postsInEntities]: normalizedObj.postEntities,
[fieldNames.topicsInEntities]: normalizedObj.topicEntities,
})
}
case types.GET_A_FULL_TOPIC: {
const topic = _.get(action, 'payload', {})
normalizedObj = normalizeTopic(topic, normalizedObj.postEntities,
normalizedObj.topicEntities)
return _.merge({}, state, {
[fieldNames.postsInEntities]: normalizedObj.postEntities,
[fieldNames.topicsInEntities]: normalizedObj.topicEntities,
})
}
default: {
return state
}
}
}
export default entities