diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js --- a/lib/actions/thread-actions.js +++ b/lib/actions/thread-actions.js @@ -11,14 +11,19 @@ import { type OutboundDMOperationSpecification, dmOperationSpecificationTypes, + getCreateThickRawThreadInfoInputFromThreadInfo, } from '../shared/dm-ops/dm-op-utils.js'; import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import { permissionsAndAuthRelatedRequestTimeout } from '../shared/timeouts.js'; import type { DMChangeThreadSettingsOperation, DMThreadSettingsChanges, + DMJoinThreadOperation, } from '../types/dm-ops.js'; -import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; +import type { + ThreadInfo, + RawThreadInfo, +} from '../types/minimally-encoded-thread-permissions-types.js'; import { thickThreadTypes, threadTypeIsThick, @@ -346,10 +351,56 @@ }; }; -function useJoinThread(): ( - input: ClientThreadJoinRequest, -) => Promise { - return useKeyserverCall(joinThread); +function useJoinThread( + rawThreadInfo: ?RawThreadInfo, +): (input: ClientThreadJoinRequest) => Promise { + const processAndSendDMOperation = useProcessAndSendDMOperation(); + const viewerID = useSelector( + state => state.currentUserInfo && state.currentUserInfo.id, + ); + const keyserverCall = useKeyserverCall(joinThread); + return React.useCallback( + async (input: ClientThreadJoinRequest) => { + if (!rawThreadInfo || !rawThreadInfo.thick) { + return await keyserverCall(input); + } + + invariant(viewerID, 'viewerID should be set'); + + const existingThreadDetails = + getCreateThickRawThreadInfoInputFromThreadInfo(rawThreadInfo); + + const op: DMJoinThreadOperation = { + type: 'join_thread', + joinerID: viewerID, + time: Date.now(), + messageID: uuid.v4(), + existingThreadDetails, + }; + + const opSpecification: OutboundDMOperationSpecification = { + type: dmOperationSpecificationTypes.OUTBOUND, + op, + recipients: { + type: 'all_thread_members', + threadID: + rawThreadInfo.type === thickThreadTypes.THICK_SIDEBAR && + rawThreadInfo.parentThreadID + ? rawThreadInfo.parentThreadID + : rawThreadInfo.id, + }, + }; + + await processAndSendDMOperation(opSpecification); + return ({ + updatesResult: { newUpdates: [] }, + rawMessageInfos: [], + truncationStatuses: {}, + userInfos: [], + }: ThreadJoinPayload); + }, + [keyserverCall, processAndSendDMOperation, viewerID, rawThreadInfo], + ); } export type LeaveThreadInput = { diff --git a/lib/shared/community-utils.js b/lib/shared/community-utils.js --- a/lib/shared/community-utils.js +++ b/lib/shared/community-utils.js @@ -210,7 +210,12 @@ const dispatch = useDispatch(); const dispatchActionPromise = useDispatchActionPromise(); - const callJoinThread = useJoinThread(); + const rawThreadInfo = useSelector(state => + threadID ? state.threadStore.threadInfos[threadID] : null, + ); + + const callJoinThread = useJoinThread(rawThreadInfo); + const callJoinCommunityThread = useJoinThread(); let keyserverID = keyserverOverride?.keyserverID; if (!keyserverID && communityID) { @@ -338,7 +343,7 @@ } const communityThreadID = ongoingJoinData.communityID; const query = calendarQuery(); - const joinThreadPromise = callJoinThread({ + const joinThreadPromise = callJoinCommunityThread({ threadID: communityThreadID, calendarQuery: { startDate: query.startDate, @@ -372,6 +377,7 @@ } })(); }, [ + callJoinCommunityThread, calendarQuery, callJoinThread, defaultSubscription, diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js --- a/lib/shared/dm-ops/dm-op-utils.js +++ b/lib/shared/dm-ops/dm-op-utils.js @@ -238,4 +238,8 @@ ); } -export { createMessagesToPeersFromDMOp, useAddDMThreadMembers }; +export { + createMessagesToPeersFromDMOp, + useAddDMThreadMembers, + getCreateThickRawThreadInfoInputFromThreadInfo, +}; diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -365,7 +365,7 @@ +rawMessageInfos: $ReadOnlyArray, +truncationStatuses: MessageTruncationStatuses, +userInfos: $ReadOnlyArray, - +keyserverID: string, + +keyserverID?: string, }; export type ThreadFetchMediaResult = { diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js --- a/native/chat/chat-input-bar.react.js +++ b/native/chat/chat-input-bar.react.js @@ -1243,7 +1243,10 @@ const dispatch = useDispatch(); const dispatchActionPromise = useDispatchActionPromise(); - const callJoinThread = useJoinThread(); + const rawThreadInfo = useSelector( + state => state.threadStore.threadInfos[props.threadInfo.id], + ); + const callJoinThread = useJoinThread(rawThreadInfo); const { getChatMentionSearchIndex } = useChatMentionContext(); const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo); diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js --- a/web/chat/chat-input-bar.react.js +++ b/web/chat/chat-input-bar.react.js @@ -573,7 +573,10 @@ const threadCreationInProgress = createThreadLoadingStatus === 'loading'; const calendarQuery = useSelector(nonThreadCalendarQuery); const dispatchActionPromise = useDispatchActionPromise(); - const callJoinThread = useJoinThread(); + const rawThreadInfo = useSelector( + state => state.threadStore.threadInfos[props.threadInfo.id], + ); + const callJoinThread = useJoinThread(rawThreadInfo); const { getChatMentionSearchIndex } = useChatMentionContext(); const chatMentionSearchIndex = getChatMentionSearchIndex(props.threadInfo);