const { omit, omitBy, isNil, mapValues } = require('lodash') const { JOIN_MAP, LEAVE_MAP, JOIN_CALL, LEAVE_CALL } = require('../frontend/src/Metamaps/Realtime/events') const NOT_IN_CONVERSATION = 0 const IN_CONVERSATION = 1 const addMapperToMap = (map, userId) => { return Object.assign({}, map, { [userId]: NOT_IN_CONVERSATION }) } const reducer = (state = { connectedPeople: {}, liveMaps: {} }, action) => { const { type, payload } = action const { connectedPeople, liveMaps } = state const map = payload && liveMaps[payload.mapid] const mapWillEmpty = map && Object.keys(map).length === 1 const callWillFinish = map && (type === LEAVE_CALL || type === 'DISCONNECT') && Object.keys(map).length === 2 switch (type) { case JOIN_MAP: return Object.assign({}, state, { connectedPeople: Object.assign({}, connectedPeople, { [payload.userid]: { id: payload.userid, username: payload.username, avatar: payload.avatar } }), liveMaps: Object.assign({}, liveMaps, { [payload.mapid]: addMapperToMap(map || {}, payload.userid) }) }) case LEAVE_MAP: // if the map will empty, remove it from liveMaps, if the map will not empty, just remove the mapper const newLiveMaps = mapWillEmpty ? omit(liveMaps, payload.mapid) : Object.assign({}, liveMaps, { [payload.mapid]: omit(map, payload.userid) }) return { connectedPeople: omit(connectedPeople, payload.userid), liveMaps: omitBy(newLiveMaps, isNil) } case JOIN_CALL: // update the user (payload.id is user id) in the given map to be marked in the conversation return Object.assign({}, state, { liveMaps: Object.assign({}, liveMaps, { [payload.mapid]: Object.assign({}, map, { [payload.id]: IN_CONVERSATION }) }) }) case LEAVE_CALL: const newMap = callWillFinish ? mapValues(map, () => NOT_IN_CONVERSATION) : Object.assign({}, map, { [payload.userid]: NOT_IN_CONVERSATION }) return Object.assign({}, state, { liveMaps: Object.assign({}, liveMaps, { map: newMap }) }) case 'DISCONNECT': const mapWithoutUser = omit(map, payload.userid) const newMapWithoutUser = callWillFinish ? mapValues(mapWithoutUser, () => NOT_IN_CONVERSATION) : mapWithoutUser const newLiveMapsWithoutUser = mapWillEmpty ? omit(liveMaps, payload.mapid) : Object.assign({}, liveMaps, { [payload.mapid]: newMapWithoutUser }) return { connectedPeople: omit(connectedPeople, payload.userid), liveMaps: omitBy(newLiveMapsWithoutUser, isNil) } default: return state } } module.exports = reducer