import { reducerWithInitialState } from 'typescript-fsa-reducers' import { combineReducers } from 'redux' import { reduce, mapValues, get } from 'lodash' import * as actions from './actions' import { IReadReceiptPayload, IConversation, IConversationsById, IMessageNewPayload, IMessagesById, IParticipantsById, IMessageReadReceipts, } from './interfaces' const conversationIconStatus = reducerWithInitialState(false) .case(actions.toggleConversationIcon, (state, status) => status) const conversations = reducerWithInitialState({}) .case(actions.fetchConversationsFromInboxSuccess, (state, conversations: IConversation[]) => { return reduce(conversations, (acc, conversation) => { return { ...acc, [conversation.id]: conversation } }, state) }) .case(actions.newConversation, (state, payload: IConversation) => { return { ...state, [payload.id]: payload } }) .case(actions.updateConversation, (state, payload: IConversation) => { const conversationId = payload.id return get(state, [conversationId, 'updatedAt'], 0) < payload.updatedAt ? { ...state, [conversationId]: payload } : state }) .case(actions.resetConversations, () => { return {} }) .case(actions.deleteConversation, (state, payload: IConversation) => { delete state[payload.id] return state }) const participants = reducerWithInitialState({}) .case(actions.storeParticipantIds, (state, conversations: IConversation[]) => { const participantsById: IParticipantsById = reduce(conversations, (acc, conversation) => ({ ...acc, [conversation.id]: { updatedAt: conversation.updatedAt, participantIds: conversation.participantIds } }), {}) return { ...state, ...participantsById } }) .case(actions.participantChange, (state, payload: IMessageNewPayload) => { if (get(state, [payload.conversationId, 'updatedAt'], 0) < payload.updatedAt) { return { ...state, [payload.conversationId]: { updatedAt: payload.updatedAt, participantIds: payload.conversationEvent.currentParticipantIds }, } } else { return state } }) .case(actions.resetConversations, () => { return {} }) const messagesForConversation = reducerWithInitialState({}) .case(actions.fetchMessagesForConversationSuccess, (state, payload) => { return { ...state, ...payload } }) .case(actions.newMessageInConversation, (state, payload) => { const conversationId = payload.conversationId return { ...state, [conversationId]: state[conversationId] ? [...state[conversationId], payload] : [payload] } }) .case(actions.deleteMessagesByConversationId, (state, payload: IConversation) => { delete state[payload.id] return state }) const messageReadReceipts = reducerWithInitialState({}) .case(actions.fetchMessagesForConversationSuccess, (state, messagesById) => { const messageReadReceiptsById = mapValues(messagesById, messages => reduce(messages, (acc, message) => ( { ...acc, [message.id]: message.viewerRecipientStatus === 'Read' } ), {})) return { ...state, ...messageReadReceiptsById } }) .case(actions.receiveReadReceipt, (state, payload: IReadReceiptPayload) => { const receiptsForConversation = state[payload.conversationId] if (get(receiptsForConversation, [payload.messageId])) { return state } else { return { ...state, [payload.conversationId]: { ...receiptsForConversation, [payload.messageId]: true } } } }) .case(actions.resetConversations, () => { return {} }) export default combineReducers({ conversationIconStatus, conversations, messagesForConversation, participants, messageReadReceipts, })