| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  | import { findIndex, property, merge, union } from 'lodash'; | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | import uuid from 'uuid/v4'; | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  | import { | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  |   combineActions, | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |   composeReducers, | 
					
						
							|  |  |  |   createAction, | 
					
						
							|  |  |  |   createTypes, | 
					
						
							|  |  |  |   handleActions | 
					
						
							|  |  |  | } from 'berkeleys-redux-utils'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  | import { themes } from '../../utils/themes'; | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  | import { usernameSelector, types as app } from '../redux'; | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  | import { types as challenges } from '../routes/Challenges/redux'; | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  | import { types as map } from '../Map/redux'; | 
					
						
							| 
									
										
										
										
											2018-03-06 10:36:45 +00:00
										 |  |  | import legacyProjects from '../../utils/legacyProjectData'; | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export const ns = 'entities'; | 
					
						
							|  |  |  | export const getNS = state => state[ns]; | 
					
						
							|  |  |  | export const entitiesSelector = getNS; | 
					
						
							|  |  |  | export const types = createTypes([ | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |   'addPortfolioItem', | 
					
						
							|  |  |  |   'optoUpdatePortfolio', | 
					
						
							|  |  |  |   'regresPortfolio', | 
					
						
							| 
									
										
										
										
											2018-03-23 19:42:33 +00:00
										 |  |  |   'resetFullBlocks', | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |   'updateMultipleUserFlags', | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |   'updateTheme', | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |   'updateUserFlag', | 
					
						
							|  |  |  |   'updateUserEmail', | 
					
						
							|  |  |  |   'updateUserLang', | 
					
						
							|  |  |  |   'updateUserCurrentChallenge' | 
					
						
							|  |  |  | ], ns); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | // addPortfolioItem(...PortfolioItem) => Action
 | 
					
						
							|  |  |  | export const addPortfolioItem = createAction(types.addPortfolioItem); | 
					
						
							|  |  |  | // optoUpdatePortfolio(...PortfolioItem) => Action
 | 
					
						
							|  |  |  | export const optoUpdatePortfolio = createAction(types.optoUpdatePortfolio); | 
					
						
							|  |  |  | // regresPortfolio(id: String) => Action
 | 
					
						
							|  |  |  | export const regresPortfolio = createAction(types.regresPortfolio); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // updateMultipleUserFlags({ username: String, flags: { String }) => Action
 | 
					
						
							|  |  |  | export const updateMultipleUserFlags = createAction( | 
					
						
							|  |  |  |   types.updateMultipleUserFlags | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | // updateUserFlag(username: String, flag: String) => Action
 | 
					
						
							|  |  |  | export const updateUserFlag = createAction( | 
					
						
							|  |  |  |   types.updateUserFlag, | 
					
						
							|  |  |  |   (username, flag) => ({ username, flag }) | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | // updateUserEmail(username: String, email: String) => Action
 | 
					
						
							|  |  |  | export const updateUserEmail = createAction( | 
					
						
							| 
									
										
										
										
											2017-12-05 11:55:41 +05:30
										 |  |  |   types.updateUserEmail, | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |   (username, email) => ({ username, email }) | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | // updateUserLang(username: String, lang: String) => Action
 | 
					
						
							|  |  |  | export const updateUserLang = createAction( | 
					
						
							|  |  |  |   types.updateUserLang, | 
					
						
							|  |  |  |   (username, lang) => ({ username, languageTag: lang }) | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 19:42:33 +00:00
										 |  |  | export const resetFullBlocks = createAction(types.resetFullBlocks); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | export const updateUserCurrentChallenge = createAction( | 
					
						
							|  |  |  |   types.updateUserCurrentChallenge | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  | // entity meta creators
 | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | const getEntityAction = property('meta.entitiesAction'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  | export const updateThemeMetacreator = (username, theme) => ({ | 
					
						
							|  |  |  |   entitiesAction: { | 
					
						
							|  |  |  |     type: types.updateTheme, | 
					
						
							|  |  |  |     payload: { | 
					
						
							|  |  |  |       username, | 
					
						
							|  |  |  |       theme: !theme || theme === themes.default ? themes.default : themes.night | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | export function emptyPortfolio() { | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |   id: uuid(), | 
					
						
							|  |  |  |   title: '', | 
					
						
							|  |  |  |   description: '', | 
					
						
							|  |  |  |   url: '', | 
					
						
							|  |  |  |   image: '' | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  | const defaultState = { | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |   superBlock: {}, | 
					
						
							|  |  |  |   block: {}, | 
					
						
							|  |  |  |   challenge: {}, | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  |   user: {}, | 
					
						
							|  |  |  |   fullBlocks: [] | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | export function portfolioSelector(state, props) { | 
					
						
							|  |  |  |   const username = usernameSelector(state); | 
					
						
							|  |  |  |   const { portfolio } = getNS(state).user[username]; | 
					
						
							|  |  |  |   const pIndex = findIndex(portfolio, p => p.id === props.id); | 
					
						
							|  |  |  |   return portfolio[pIndex]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function projectsSelector(state) { | 
					
						
							| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  |   const { | 
					
						
							|  |  |  |     block: blocks, | 
					
						
							|  |  |  |     challenge: challengeMap | 
					
						
							|  |  |  |   } = getNS(state); | 
					
						
							|  |  |  |   const idToNameMap = challengeIdToNameMapSelector(state); | 
					
						
							|  |  |  |   const legacyWithDashedNames = legacyProjects | 
					
						
							|  |  |  |     .reduce((list, current) => ([ | 
					
						
							|  |  |  |       ...list, | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         ...current, | 
					
						
							|  |  |  |         challenges: current.challenges.map(id => idToNameMap[id]) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     ]), | 
					
						
							|  |  |  |     [] | 
					
						
							|  |  |  |   ); | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |   return Object.keys(blocks) | 
					
						
							|  |  |  |     .filter(key => | 
					
						
							|  |  |  |       key.includes('projects') && !key.includes('coding-interview') | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     .map(key => blocks[key]) | 
					
						
							| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  |     .concat(legacyWithDashedNames) | 
					
						
							| 
									
										
										
										
											2018-02-27 14:29:37 +00:00
										 |  |  |     .map(({ title, challenges, superBlock }) => { | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |       const projectChallengeDashNames = challenges | 
					
						
							| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  |         // challengeIdToName is not available on appMount
 | 
					
						
							|  |  |  |         .filter(Boolean) | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |         // remove any project intros
 | 
					
						
							|  |  |  |         .filter(chal => !chal.includes('get-set-for')); | 
					
						
							|  |  |  |       const projectChallenges = projectChallengeDashNames | 
					
						
							| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  |         .map(dashedName => { | 
					
						
							|  |  |  |           const { id, title } = challengeMap[dashedName]; | 
					
						
							|  |  |  |           return { id, title, dashedName }; | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |       return { | 
					
						
							| 
									
										
										
										
											2018-02-27 14:29:37 +00:00
										 |  |  |         projectBlockName: title, | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |         superBlock, | 
					
						
							| 
									
										
										
										
											2018-03-05 14:15:30 +00:00
										 |  |  |         challenges: projectChallenges | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |       }; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function challengeIdToNameMapSelector(state) { | 
					
						
							|  |  |  |   return getNS(state).challengeIdToName || {}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | export const challengeMapSelector = state => getNS(state).challenge || {}; | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | export function makeBlockSelector(block) { | 
					
						
							|  |  |  |   return state => { | 
					
						
							|  |  |  |     const blockMap = getNS(state).block || {}; | 
					
						
							|  |  |  |     return blockMap[block] || {}; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  | export function makeSuperBlockSelector(name) { | 
					
						
							|  |  |  |   return state => { | 
					
						
							|  |  |  |     const superBlock = getNS(state).superBlock || {}; | 
					
						
							|  |  |  |     return superBlock[name] || {}; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  | export const isChallengeLoaded = (state, { dashedName }) => | 
					
						
							|  |  |  |   !!challengeMapSelector(state)[dashedName]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  | export const fullBlocksSelector = state => getNS(state).fullBlocks; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  | export default composeReducers( | 
					
						
							|  |  |  |   ns, | 
					
						
							|  |  |  |   function metaReducer(state = defaultState, action) { | 
					
						
							| 
									
										
										
										
											2018-02-19 20:32:14 +00:00
										 |  |  |     const { meta } = action; | 
					
						
							|  |  |  |     if (meta && meta.entities) { | 
					
						
							|  |  |  |       if (meta.entities.user) { | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           ...state, | 
					
						
							|  |  |  |           user: { | 
					
						
							|  |  |  |             ...state.user, | 
					
						
							|  |  |  |             ...meta.entities.user | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-03-06 10:25:33 +00:00
										 |  |  |       return merge({}, state, action.meta.entities); | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return state; | 
					
						
							|  |  |  |   }, | 
					
						
							| 
									
										
										
										
											2018-02-19 20:32:14 +00:00
										 |  |  |   function entitiesReducer(state = defaultState, action) { | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |     if (getEntityAction(action)) { | 
					
						
							|  |  |  |       const { payload: { username, theme } } = getEntityAction(action); | 
					
						
							|  |  |  |       return { | 
					
						
							|  |  |  |         ...state, | 
					
						
							|  |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             theme | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return state; | 
					
						
							|  |  |  |   }, | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |   handleActions( | 
					
						
							|  |  |  |     () => ({ | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  |       [ | 
					
						
							|  |  |  |         combineActions( | 
					
						
							| 
									
										
										
										
											2018-03-08 15:47:48 +00:00
										 |  |  |           app.fetchNewBlock.complete, | 
					
						
							| 
									
										
										
										
											2018-02-23 12:20:13 +00:00
										 |  |  |           map.fetchMapUi.complete | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2018-03-02 12:06:58 +00:00
										 |  |  |       ]: (state, { payload: { entities } }) => merge({}, state, entities), | 
					
						
							| 
									
										
										
										
											2018-03-23 19:42:33 +00:00
										 |  |  |       [app.fetchNewBlock.complete]: ( | 
					
						
							|  |  |  |         state, | 
					
						
							|  |  |  |         { payload: { entities: { block } } } | 
					
						
							|  |  |  |       ) => ({ | 
					
						
							| 
									
										
										
										
											2018-03-02 12:06:58 +00:00
										 |  |  |         ...state, | 
					
						
							|  |  |  |         fullBlocks: union(state.fullBlocks, [ Object.keys(block)[0] ]) | 
					
						
							|  |  |  |       }), | 
					
						
							| 
									
										
										
										
											2018-03-23 19:42:33 +00:00
										 |  |  |       [types.resetFullBlocks]: state => ({ ...state, fullBlocks: [] }), | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |       [ | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         challenges.submitChallenge.complete | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |       ]: (state, { payload: { username, points, challengeInfo } }) => ({ | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         ...state, | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             points, | 
					
						
							|  |  |  |             challengeMap: { | 
					
						
							|  |  |  |               ...state.user[username].challengeMap, | 
					
						
							|  |  |  |               [challengeInfo.id]: challengeInfo | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							| 
									
										
										
										
											2018-02-16 23:18:53 +00:00
										 |  |  |       [types.addPortfolioItem]: (state, { payload: username }) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							|  |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             portfolio: [ | 
					
						
							|  |  |  |               ...state.user[username].portfolio, | 
					
						
							|  |  |  |               emptyPortfolio() | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       [types.optoUpdatePortfolio]: ( | 
					
						
							|  |  |  |         state, | 
					
						
							|  |  |  |         { payload: { username, portfolio }} | 
					
						
							|  |  |  |       ) => { | 
					
						
							|  |  |  |         const currentPortfolio = state.user[username].portfolio.slice(0); | 
					
						
							|  |  |  |         const pIndex = findIndex(currentPortfolio, p => p.id === portfolio.id); | 
					
						
							|  |  |  |         const updatedPortfolio = currentPortfolio; | 
					
						
							|  |  |  |         updatedPortfolio[pIndex] = portfolio; | 
					
						
							|  |  |  |         return { | 
					
						
							|  |  |  |           ...state, | 
					
						
							|  |  |  |           user: { | 
					
						
							|  |  |  |             ...state.user, | 
					
						
							|  |  |  |             [username]: { | 
					
						
							|  |  |  |               ...state.user[username], | 
					
						
							|  |  |  |               portfolio: updatedPortfolio | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       [types.regresPortfolio]: (state, { payload: { username, id } }) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							|  |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             portfolio: state.user[username].portfolio.filter(p => p.id !== id) | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       [types.updateMultipleUserFlags]: ( | 
					
						
							|  |  |  |         state, | 
					
						
							|  |  |  |         { payload: { username, flags }} | 
					
						
							|  |  |  |       ) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							|  |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             ...flags | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |       [types.updateUserFlag]: (state, { payload: { username, flag } }) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             [flag]: !state.user[username][flag] | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       [types.updateUserEmail]: (state, { payload: { username, email } }) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             email | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       [types.updateUserLang]: | 
					
						
							|  |  |  |       ( | 
					
						
							|  |  |  |         state, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           payload: { username, languageTag } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       ) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             languageTag | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       [types.updateUserCurrentChallenge]: | 
					
						
							|  |  |  |       ( | 
					
						
							|  |  |  |         state, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           payload: { username, currentChallengeId } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       ) => ({ | 
					
						
							|  |  |  |         ...state, | 
					
						
							| 
									
										
										
										
											2017-12-07 16:13:19 -08:00
										 |  |  |         user: { | 
					
						
							|  |  |  |           ...state.user, | 
					
						
							|  |  |  |           [username]: { | 
					
						
							|  |  |  |             ...state.user[username], | 
					
						
							|  |  |  |             currentChallengeId | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-07-31 20:04:01 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2017-11-09 17:10:30 -08:00
										 |  |  |     }), | 
					
						
							|  |  |  |     defaultState | 
					
						
							|  |  |  |   ) | 
					
						
							|  |  |  | ); |