diff --git a/lib/shared/thread-actions-utils.js b/lib/shared/thread-actions-utils.js --- a/lib/shared/thread-actions-utils.js +++ b/lib/shared/thread-actions-utils.js @@ -1,33 +1,12 @@ // @flow -import invariant from 'invariant'; - -import { threadIsPending, threadOtherMembers } from './thread-utils.js'; -import { dmThreadProtocol } from './threads/protocols/dm-thread-protocol.js'; -import { keyserverThreadProtocol } from './threads/protocols/keyserver-thread-protocol.js'; -import { - newThreadActionTypes, - removeUsersFromThreadActionTypes, -} from '../actions/thread-action-types.js'; +import { removeUsersFromThreadActionTypes } from '../actions/thread-action-types.js'; import type { RemoveUsersFromThreadInput } from '../hooks/thread-hooks.js'; -import type { CalendarQuery } from '../types/entry-types.js'; import type { RelativeMemberInfo, ThreadInfo, } from '../types/minimally-encoded-thread-permissions-types.js'; -import { - threadTypes, - assertThinThreadType, - assertThickThreadType, - threadTypeIsThick, -} from '../types/thread-types-enum.js'; -import type { ThreadType } from '../types/thread-types-enum.js'; -import type { - ChangeThreadSettingsPayload, - ClientNewThinThreadRequest, - NewThickThreadRequest, - NewThreadResult, -} from '../types/thread-types.js'; +import type { ChangeThreadSettingsPayload } from '../types/thread-types.js'; import type { DispatchActionPromise } from '../utils/redux-promise-utils.js'; function removeMemberFromThread( @@ -49,121 +28,4 @@ ); } -type CreateRealThreadParameters = { - +threadInfo: ThreadInfo, - +dispatchActionPromise: DispatchActionPromise, - +createNewThinThread: ClientNewThinThreadRequest => Promise, - +createNewThickThread: NewThickThreadRequest => Promise, - +sourceMessageID: ?string, - +viewerID: ?string, - +handleError?: () => mixed, - +calendarQuery: CalendarQuery, -}; - -async function createRealThreadFromPendingThread({ - threadInfo, - dispatchActionPromise, - createNewThinThread, - createNewThickThread, - sourceMessageID, - viewerID, - calendarQuery, -}: CreateRealThreadParameters): Promise<{ - +threadID: string, - +threadType: ThreadType, -}> { - if (!threadIsPending(threadInfo.id)) { - return { - threadID: threadInfo.id, - threadType: threadInfo.type, - }; - } - - let newThreadID; - let newThreadType = threadInfo.type; - - const otherMemberIDs = threadOtherMembers(threadInfo.members, viewerID).map( - member => member.id, - ); - let resultPromise; - if (threadInfo.type === threadTypes.SIDEBAR) { - invariant( - sourceMessageID, - 'sourceMessageID should be set when creating a sidebar', - ); - invariant( - threadInfo.parentThreadID, - 'parentThreadID should be set when creating a sidebar', - ); - resultPromise = createNewThinThread({ - type: threadTypes.SIDEBAR, - initialMemberIDs: otherMemberIDs, - color: threadInfo.color, - sourceMessageID, - parentThreadID: threadInfo.parentThreadID, - name: threadInfo.name, - calendarQuery, - }); - void dispatchActionPromise(newThreadActionTypes, resultPromise); - const result = await resultPromise; - newThreadID = result.newThreadID; - } else if (threadInfo.type === threadTypes.THICK_SIDEBAR) { - invariant( - sourceMessageID, - 'sourceMessageID should be set when creating a sidebar', - ); - invariant( - threadInfo.parentThreadID, - 'parentThreadID should be set when creating a sidebar', - ); - newThreadID = await createNewThickThread({ - type: threadTypes.THICK_SIDEBAR, - initialMemberIDs: otherMemberIDs, - color: threadInfo.color, - sourceMessageID, - parentThreadID: threadInfo.parentThreadID, - name: threadInfo.name, - }); - } else if (threadTypeIsThick(threadInfo.type)) { - const type = assertThickThreadType( - dmThreadProtocol.pendingThreadType(otherMemberIDs.length), - ); - - invariant( - type !== 16, - // Flow does not recognize that threadTypes.THICK_SIDEBAR is 16 - 'pendingThreadType should not return THICK_SIDEBAR', - ); - newThreadID = await createNewThickThread({ - type, - initialMemberIDs: otherMemberIDs, - color: threadInfo.color, - }); - newThreadType = type; - } else { - const type = assertThinThreadType( - keyserverThreadProtocol.pendingThreadType(otherMemberIDs.length), - ); - - invariant( - type !== 5, // Flow does not recognize that threadTypes.SIDEBAR is 5 - 'pendingThreadType should not return SIDEBAR', - ); - resultPromise = createNewThinThread({ - type, - initialMemberIDs: otherMemberIDs, - color: threadInfo.color, - calendarQuery, - }); - void dispatchActionPromise(newThreadActionTypes, resultPromise); - const result = await resultPromise; - newThreadID = result.newThreadID; - newThreadType = type; - } - return { - threadID: newThreadID, - threadType: newThreadType, - }; -} - -export { removeMemberFromThread, createRealThreadFromPendingThread }; +export { removeMemberFromThread }; diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js --- a/lib/shared/threads/protocols/dm-thread-protocol.js +++ b/lib/shared/threads/protocols/dm-thread-protocol.js @@ -55,6 +55,8 @@ import { createThreadTimestamps, getContainingThreadID, + threadIsPending, + threadOtherMembers, } from '../../thread-utils.js'; import type { ProtocolSendTextMessageInput, @@ -85,6 +87,7 @@ FetchMessageUtils, ProtocolFetchMessageInput, ProtocolCreatePendingThreadInput, + CreateRealThreadParameters, } from '../thread-spec.js'; const dmThreadProtocol: ThreadProtocol = @@ -732,14 +735,60 @@ canBeFrozen: () => true, - pendingThreadType: (numberOfOtherMembers: number) => { - if (numberOfOtherMembers === 0) { - return threadTypes.PRIVATE; - } else if (numberOfOtherMembers === 1) { - return threadTypes.PERSONAL; - } else { - return threadTypes.LOCAL; + pendingThreadType, + + createRealThreadFromPendingThread: async ( + params: CreateRealThreadParameters, + ) => { + const { threadInfo, viewerID, sourceMessageID, createNewThickThread } = + params; + if (!threadIsPending(threadInfo.id)) { + return { + threadID: threadInfo.id, + threadType: threadInfo.type, + }; + } + + const otherMemberIDs = threadOtherMembers( + threadInfo.members, + viewerID, + ).map(member => member.id); + + if (threadInfo.type === threadTypes.THICK_SIDEBAR) { + invariant( + sourceMessageID, + 'sourceMessageID should be set when creating a sidebar', + ); + invariant( + threadInfo.parentThreadID, + 'parentThreadID should be set when creating a sidebar', + ); + const newThreadID = await createNewThickThread({ + type: threadTypes.THICK_SIDEBAR, + initialMemberIDs: otherMemberIDs, + color: threadInfo.color, + sourceMessageID, + parentThreadID: threadInfo.parentThreadID, + name: threadInfo.name, + }); + return { + threadID: newThreadID, + threadType: threadTypes.THICK_SIDEBAR, + }; } + + const type = pendingThreadType(otherMemberIDs.length); + + const newThreadID = await createNewThickThread({ + type, + initialMemberIDs: otherMemberIDs, + color: threadInfo.color, + }); + + return { + threadID: newThreadID, + threadType: type, + }; }, allowsDeletingSidebarSource: false, @@ -772,4 +821,14 @@ threadActivityUpdatedByDMActivityHandler: true, }); +function pendingThreadType(numberOfOtherMembers: number) { + if (numberOfOtherMembers === 0) { + return threadTypes.PRIVATE; + } else if (numberOfOtherMembers === 1) { + return threadTypes.PERSONAL; + } else { + return threadTypes.LOCAL; + } +} + export { dmThreadProtocol }; diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -13,6 +13,7 @@ import { changeThreadSettingsActionTypes, leaveThreadActionTypes, + newThreadActionTypes, } from '../../../actions/thread-action-types.js'; import { type MediaMetadataReassignmentAction, @@ -67,7 +68,12 @@ import { pendingSidebarURLPrefix } from '../../../utils/validation-utils.js'; import { generatePendingThreadColor } from '../../color-utils.js'; import { getNextLocalID } from '../../id-utils.js'; -import { getCommunity, getContainingThreadID } from '../../thread-utils.js'; +import { + getCommunity, + getContainingThreadID, + threadIsPending, + threadOtherMembers, +} from '../../thread-utils.js'; import { identifyInvalidatedThreads } from '../../updates/utils.js'; import type { ThreadProtocol, @@ -98,6 +104,7 @@ FetchMessageUtils, ProtocolFetchMessageInput, ProtocolCreatePendingThreadInput, + CreateRealThreadParameters, } from '../thread-spec.js'; import { threadTypeIsSidebar } from '../thread-specs.js'; @@ -515,14 +522,72 @@ return thread.id !== genesis().id; }, - pendingThreadType: (numberOfOtherMembers: number) => { - if (numberOfOtherMembers === 0) { - return threadTypes.GENESIS_PRIVATE; - } else if (numberOfOtherMembers === 1) { - return threadTypes.GENESIS_PERSONAL; - } else { - return threadTypes.COMMUNITY_SECRET_SUBTHREAD; + pendingThreadType, + + createRealThreadFromPendingThread: async ( + params: CreateRealThreadParameters, + ) => { + const { + threadInfo, + viewerID, + sourceMessageID, + createNewThinThread, + calendarQuery, + dispatchActionPromise, + } = params; + if (!threadIsPending(threadInfo.id)) { + return { + threadID: threadInfo.id, + threadType: threadInfo.type, + }; } + + const otherMemberIDs = threadOtherMembers( + threadInfo.members, + viewerID, + ).map(member => member.id); + + if (threadInfo.type === threadTypes.SIDEBAR) { + invariant( + sourceMessageID, + 'sourceMessageID should be set when creating a sidebar', + ); + invariant( + threadInfo.parentThreadID, + 'parentThreadID should be set when creating a sidebar', + ); + const resultPromise = createNewThinThread({ + type: threadTypes.SIDEBAR, + initialMemberIDs: otherMemberIDs, + color: threadInfo.color, + sourceMessageID, + parentThreadID: threadInfo.parentThreadID, + name: threadInfo.name, + calendarQuery, + }); + void dispatchActionPromise(newThreadActionTypes, resultPromise); + const result = await resultPromise; + return { + threadID: result.newThreadID, + threadType: threadTypes.SIDEBAR, + }; + } + + const type = pendingThreadType(otherMemberIDs.length); + + const resultPromise = createNewThinThread({ + type, + initialMemberIDs: otherMemberIDs, + color: threadInfo.color, + calendarQuery, + }); + void dispatchActionPromise(newThreadActionTypes, resultPromise); + const result = await resultPromise; + + return { + threadID: result.newThreadID, + threadType: type, + }; }, allowsDeletingSidebarSource: true, @@ -555,6 +620,16 @@ threadActivityUpdatedByDMActivityHandler: false, }); +function pendingThreadType(numberOfOtherMembers: number) { + if (numberOfOtherMembers === 0) { + return threadTypes.GENESIS_PRIVATE; + } else if (numberOfOtherMembers === 1) { + return threadTypes.GENESIS_PERSONAL; + } else { + return threadTypes.COMMUNITY_SECRET_SUBTHREAD; + } +} + function mediaIDIsKeyserverID(mediaID: string): boolean { return mediaID.indexOf('|') !== -1; } diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -30,6 +30,7 @@ SetThreadUnreadStatusRequest, } from '../../types/activity-types.js'; import type { + CalendarQuery, CreateEntryInfo, CreateEntryPayload, DeleteEntryInfo, @@ -67,7 +68,10 @@ import type { ChangeThreadSettingsPayload, ClientDBThreadInfo, + ClientNewThinThreadRequest, LeaveThreadPayload, + NewThickThreadRequest, + NewThreadResult, UpdateThreadRequest, } from '../../types/thread-types.js'; import type { DispatchActionPromise } from '../../utils/redux-promise-utils.js'; @@ -239,6 +243,17 @@ +memberIDs: $ReadOnlyArray, }; +export type CreateRealThreadParameters = { + +threadInfo: ThreadInfo, + +dispatchActionPromise: DispatchActionPromise, + +createNewThinThread: ClientNewThinThreadRequest => Promise, + +createNewThickThread: NewThickThreadRequest => Promise, + +sourceMessageID: ?string, + +viewerID: ?string, + +handleError?: () => mixed, + +calendarQuery: CalendarQuery, +}; + export type ThreadProtocol< RawThreadMemberType: | MemberInfoSansPermissions @@ -315,6 +330,12 @@ // two users are the only members of a given chat. +canBeFrozen: (thread: ThreadInfo) => boolean, +pendingThreadType: (numberOfOtherMembers: number) => ThreadType, + +createRealThreadFromPendingThread: ( + params: CreateRealThreadParameters, + ) => Promise<{ + +threadID: string, + +threadType: ThreadType, + }>, +allowsDeletingSidebarSource: boolean, +presentationDetails: { +membershipChangesShownInThreadPreview: boolean, diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -44,7 +44,6 @@ useMessageCreationSideEffectsFunc, } from 'lib/shared/message-utils.js'; import type { CreationSideEffectsFunc } from 'lib/shared/messages/message-spec.js'; -import { createRealThreadFromPendingThread } from 'lib/shared/thread-actions-utils.js'; import { patchThreadInfoToIncludeMentionedMembersOfParent, threadIsPending, @@ -565,7 +564,9 @@ let threadCreationPromise = this.pendingThreadCreations.get(threadInfo.id); if (!threadCreationPromise) { const calendarQuery = this.props.calendarQuery(); - threadCreationPromise = createRealThreadFromPendingThread({ + threadCreationPromise = threadSpecs[ + threadInfo.type + ].protocol.createRealThreadFromPendingThread({ threadInfo, dispatchActionPromise: this.props.dispatchActionPromise, createNewThinThread: this.props.newThinThread, diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js --- a/web/input/input-state-container.react.js +++ b/web/input/input-state-container.react.js @@ -45,7 +45,6 @@ useMessageCreationSideEffectsFunc, } from 'lib/shared/message-utils.js'; import type { CreationSideEffectsFunc } from 'lib/shared/messages/message-spec.js'; -import { createRealThreadFromPendingThread } from 'lib/shared/thread-actions-utils.js'; import { draftKeyFromThreadID, patchThreadInfoToIncludeMentionedMembersOfParent, @@ -587,7 +586,9 @@ let threadCreationPromise = this.pendingThreadCreations.get(threadInfo.id); if (!threadCreationPromise) { const calendarQuery = this.props.calendarQuery(); - threadCreationPromise = createRealThreadFromPendingThread({ + threadCreationPromise = threadSpecs[ + threadInfo.type + ].protocol.createRealThreadFromPendingThread({ threadInfo, dispatchActionPromise: this.props.dispatchActionPromise, createNewThinThread: this.props.newThinThread,