diff --git a/lib/reducers/local-id-reducer.js b/lib/reducers/local-id-reducer.js index 39fbb41f4..194c1ec39 100644 --- a/lib/reducers/local-id-reducer.js +++ b/lib/reducers/local-id-reducer.js @@ -1,125 +1,119 @@ // @flow import invariant from 'invariant'; import { createLocalEntryActionType } from '../actions/entry-actions.js'; import { sendTextMessageActionTypes, sendMultimediaMessageActionTypes, createLocalMessageActionType, processMessagesActionType, fetchMessagesBeforeCursorActionTypes, fetchMostRecentMessagesActionTypes, sendReactionMessageActionTypes, } from '../actions/message-actions.js'; import { joinThreadActionTypes } from '../actions/thread-actions.js'; import { numberFromLocalID, highestLocalIDSelector, } from '../selectors/local-id-selectors.js'; +import { updateSpecs } from '../shared/updates/update-specs.js'; import type { RawMessageInfo } from '../types/message-types.js'; import type { BaseAction } from '../types/redux-types.js'; import { rehydrateActionType } from '../types/redux-types.js'; import { fullStateSyncActionType, incrementalStateSyncActionType, } from '../types/socket-types.js'; -import { updateTypes } from '../types/update-types-enum.js'; import { type ClientUpdateInfo, processUpdatesActionType, } from '../types/update-types.js'; export default function reduceNextLocalID( state: number, action: BaseAction, ): number { let newCandidate = null; if (action.type === rehydrateActionType) { newCandidate = highestLocalIDSelector(action.payload) + 1; if ( action.payload && action.payload.nextLocalID && action.payload.nextLocalID > newCandidate ) { newCandidate = action.payload.nextLocalID; } } else if ( action.type === sendTextMessageActionTypes.started || action.type === sendMultimediaMessageActionTypes.started || action.type === sendReactionMessageActionTypes.started || action.type === createLocalEntryActionType || action.type === createLocalMessageActionType ) { const { localID } = action.payload; invariant(localID, 'should be set'); newCandidate = numberFromLocalID(localID) + 1; } else if (action.type === incrementalStateSyncActionType) { const messages = [ ...action.payload.messagesResult.rawMessageInfos, ...getRawMessageInfosFromUpdates(action.payload.updatesResult.newUpdates), ]; newCandidate = findHighestLocalID(messages) + 1; } else if (action.type === processUpdatesActionType) { const messages = getRawMessageInfosFromUpdates( action.payload.updatesResult.newUpdates, ); newCandidate = findHighestLocalID(messages) + 1; } else if ( action.type === fullStateSyncActionType || action.type === processMessagesActionType ) { const messages = action.payload.messagesResult.rawMessageInfos; newCandidate = findHighestLocalID(messages) + 1; } else if ( action.type === fetchMessagesBeforeCursorActionTypes.success || action.type === fetchMostRecentMessagesActionTypes.success ) { const messages = action.payload.rawMessageInfos; newCandidate = findHighestLocalID(messages) + 1; } else if (action.type === joinThreadActionTypes.success) { const messages = [ ...action.payload.rawMessageInfos, ...getRawMessageInfosFromUpdates(action.payload.updatesResult.newUpdates), ]; newCandidate = findHighestLocalID(messages) + 1; } return newCandidate && newCandidate > state ? newCandidate : state; } function findHighestLocalID( rawMessageInfos: $ReadOnlyArray, ): number { let oldestID = -1; for (const rawMessageInfo of rawMessageInfos) { if (!rawMessageInfo.localID) { continue; } const { localID } = rawMessageInfo; if (!localID) { continue; } const thisLocalID = numberFromLocalID(localID); if (thisLocalID > oldestID) { oldestID = thisLocalID; } } return oldestID; } function getRawMessageInfosFromUpdates( updates: $ReadOnlyArray, ): RawMessageInfo[] { - const rawMessageInfos = []; - for (const updateInfo of updates) { - if (updateInfo.type !== updateTypes.JOIN_THREAD) { - continue; - } - for (const messageInfo of updateInfo.rawMessageInfos) { - rawMessageInfos.push(messageInfo); - } - } - return rawMessageInfos; + return updates + .map(update => updateSpecs[update.type].getRawMessageInfos?.(update)) + .filter(Boolean) + .flat(); } diff --git a/lib/shared/updates/join-thread-spec.js b/lib/shared/updates/join-thread-spec.js index 55442f085..9e6ab44a3 100644 --- a/lib/shared/updates/join-thread-spec.js +++ b/lib/shared/updates/join-thread-spec.js @@ -1,55 +1,58 @@ // @flow import _isEqual from 'lodash/fp/isEqual.js'; import type { UpdateSpec } from './update-spec.js'; import type { RawEntryInfo } from '../../types/entry-types.js'; import type { RawThreadInfos } from '../../types/thread-types.js'; import type { ThreadJoinUpdateInfo } from '../../types/update-types.js'; import { threadInFilterList } from '../thread-utils.js'; export const joinThreadSpec: UpdateSpec = Object.freeze({ generateOpsForThreadUpdates( storeThreadInfos: RawThreadInfos, update: ThreadJoinUpdateInfo, ) { if (_isEqual(storeThreadInfos[update.threadInfo.id])(update.threadInfo)) { return null; } return [ { type: 'replace', payload: { id: update.threadInfo.id, threadInfo: update.threadInfo, }, }, ]; }, mergeEntryInfos( entryIDs: Set, mergedEntryInfos: Array, update: ThreadJoinUpdateInfo, ) { for (const entryInfo of update.rawEntryInfos) { const entryID = entryInfo.id; if (!entryID || entryIDs.has(entryID)) { continue; } mergedEntryInfos.push(entryInfo); entryIDs.add(entryID); } }, reduceCalendarThreadFilters( filteredThreadIDs: $ReadOnlySet, update: ThreadJoinUpdateInfo, ) { if ( !threadInFilterList(update.threadInfo) || filteredThreadIDs.has(update.threadInfo.id) ) { return filteredThreadIDs; } return new Set([...filteredThreadIDs, update.threadInfo.id]); }, + getRawMessageInfos(update: ThreadJoinUpdateInfo) { + return update.rawMessageInfos; + }, }); diff --git a/lib/shared/updates/update-spec.js b/lib/shared/updates/update-spec.js index bbb47eef2..d02126fb2 100644 --- a/lib/shared/updates/update-spec.js +++ b/lib/shared/updates/update-spec.js @@ -1,28 +1,30 @@ // @flow import type { ThreadStoreOperation } from '../../ops/thread-store-ops.js'; import type { RawEntryInfo } from '../../types/entry-types.js'; +import type { RawMessageInfo } from '../../types/message-types.js'; import type { RawThreadInfos } from '../../types/thread-types.js'; import type { ClientUpdateInfo } from '../../types/update-types.js'; import type { CurrentUserInfo, UserInfos } from '../../types/user-types.js'; export type UpdateSpec = { +generateOpsForThreadUpdates?: ( storeThreadInfos: RawThreadInfos, update: UpdateInfo, ) => ?$ReadOnlyArray, +mergeEntryInfos?: ( entryIDs: Set, mergedEntryInfos: Array, update: UpdateInfo, ) => void, +reduceCurrentUser?: ( state: ?CurrentUserInfo, update: UpdateInfo, ) => ?CurrentUserInfo, +reduceUserInfos?: (state: UserInfos, update: UpdateInfo) => UserInfos, +reduceCalendarThreadFilters?: ( filteredThreadIDs: $ReadOnlySet, update: UpdateInfo, ) => $ReadOnlySet, + +getRawMessageInfos?: (update: UpdateInfo) => $ReadOnlyArray, };