import { List as ImmutableList, Map as ImmutableMap, fromJS, } from 'immutable' import compareId from '../utils/compare_id' import { CHAT_MESSAGES_SEND_SUCCESS, CHAT_MESSAGES_DELETE_REQUEST, CHAT_MESSAGES_PURGE_SUCCESS, } from '../actions/chat_messages' import { CHAT_CONVERSATION_MESSAGES_EXPAND_REQUEST, CHAT_CONVERSATION_MESSAGES_EXPAND_SUCCESS, CHAT_CONVERSATION_MESSAGES_EXPAND_FAIL, CHAT_CONVERSATION_MESSAGES_CONNECT, CHAT_CONVERSATION_MESSAGES_DISCONNECT, CHAT_CONVERSATION_MESSAGES_CLEAR, } from '../actions/chat_conversation_messages' const initialState = ImmutableMap() const initialConversation = ImmutableMap({ unread: 0, online: false, top: true, isLoading: false, isError: false, hasMore: true, items: ImmutableList(), }) const expandNormalizedChatConversation = (state, chatConversationId, chatMessages, next, isPartial, isLoadingRecent) => { return state.update(chatConversationId, initialConversation, map => map.withMutations((mMap) => { mMap.set('isLoading', false) mMap.set('isPartial', isPartial) if (!next && !isLoadingRecent) mMap.set('hasMore', false) if (!!chatMessages && !chatMessages.isEmpty()) { mMap.update('items', ImmutableList(), oldIds => { const newIds = chatMessages.map(chatMessage => chatMessage.get('id')); const lastIndex = oldIds.findLastIndex((id) => id !== null && compareId(id, newIds.last()) >= 0) + 1; const firstIndex = oldIds.take(lastIndex).findLastIndex(id => id !== null && compareId(id, newIds.first()) > 0); if (firstIndex < 0) { return (isPartial ? newIds.unshift(null) : newIds).concat(oldIds.skip(lastIndex)); } return oldIds.take(firstIndex + 1).concat( isPartial && oldIds.get(firstIndex) !== null ? newIds.unshift(null) : newIds, oldIds.skip(lastIndex) ); }); } })); }; const updateChatMessageConversation = (state, chatConversationId, chatMessage) => { const top = state.getIn([chatConversationId, 'top']); const ids = state.getIn([chatConversationId, 'items'], ImmutableList()); const includesId = ids.includes(chatMessage.get('id')); const unread = state.getIn([chatConversationId, 'unread'], 0); if (includesId) { return state; } let newIds = ids; return state.update(chatConversationId, initialConversation, map => map.withMutations(mMap => { if (!top) mMap.set('unread', unread + 1); // if (top && ids.size > 40) newIds = newIds.take(20); mMap.set('items', newIds.unshift(chatMessage.get('id'))); })); }; export default function chat_conversation_messages(state = initialState, action) { switch (action.type) { case CHAT_CONVERSATION_MESSAGES_CONNECT: return state.update(action.chatConversationId, initialConversation, map => map.set('online', true)) case CHAT_CONVERSATION_MESSAGES_DISCONNECT: return state.update( action.chatConversationId, initialConversation, map => map.set('online', false).update('items', items => items.first() ? items.unshift(null) : items) ) case CHAT_CONVERSATION_MESSAGES_CLEAR: return state.set(chatConversationId, initialTimeline) case CHAT_CONVERSATION_MESSAGES_EXPAND_REQUEST: return state.update(action.chatConversationId, initialConversation, map => map.set('isLoading', true)) case CHAT_CONVERSATION_MESSAGES_EXPAND_FAIL: return state.update(action.chatConversationId, initialConversation, map => map.withMutations((mMap) => { map.set('isLoading', false) map.set('isError', true) })) case CHAT_CONVERSATION_MESSAGES_EXPAND_SUCCESS: return expandNormalizedChatConversation(state, action.chatConversationId, fromJS(action.chatMessages), action.next, action.partial, action.isLoadingRecent) case CHAT_MESSAGES_SEND_SUCCESS: return updateChatMessageConversation(state, action.chatMessage.chat_conversation_id, fromJS(action.chatMessage)) case CHAT_MESSAGES_DELETE_REQUEST: // : todo : return state case CHAT_MESSAGES_PURGE_SUCCESS: // : todo : return state default: return state } }