diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js --- a/lib/shared/dm-ops/process-dm-ops.js +++ b/lib/shared/dm-ops/process-dm-ops.js @@ -16,7 +16,14 @@ import { useProcessBlobHolders } from '../../actions/holder-actions.js'; import { processNewUserIDsActionType } from '../../actions/user-actions.js'; import { useDebugLogs } from '../../components/debug-logs-context.js'; +import { useGetLatestMessageEdit } from '../../hooks/latest-message-edit.js'; import { useDispatchWithMetadata } from '../../hooks/ops-hooks.js'; +import { mergeUpdatesWithMessageInfos } from '../../reducers/message-reducer.js'; +import { + type MessageNotifyType, + messageNotifyTypes, +} from '../../shared/messages/message-spec.js'; +import { messageSpecs } from '../../shared/messages/message-specs.js'; import { usePeerToPeerCommunication, type ProcessOutboundP2PMessagesResult, @@ -26,9 +33,12 @@ processDMOpsActionType, queueDMOpsActionType, dmOperationValidator, + type ProcessDMOpsPayload, } from '../../types/dm-ops.js'; +import type { RawMessageInfo } from '../../types/message-types.js'; import type { DispatchMetadata } from '../../types/redux-types.js'; import type { OutboundP2PMessage } from '../../types/sqlite-types.js'; +import type { ClientUpdateInfo } from '../../types/update-types.js'; import { extractUserIDsFromPayload } from '../../utils/conversion-utils.js'; import { useSelector, useDispatch } from '../../utils/redux-utils.js'; @@ -41,6 +51,7 @@ const processBlobHolders = useProcessBlobHolders(); const createMessagesToPeersFromDMOp = useCreateMessagesToPeersFromDMOp(); const confirmPeerToPeerMessage = useConfirmPeerToPeerMessage(); + const getMessageNotifyTypes = useGetMessageNotifyTypes(); const dispatch = useDispatch(); @@ -109,17 +120,16 @@ dmOp.type ].processDMOperation(dmOp, utilities); + const payload: ProcessDMOpsPayload = { + rawMessageInfos: [], + updateInfos: [], + outboundP2PMessages, + composableMessageID, + notificationsCreationData, + messagesNotifyTypes: {}, + }; dispatchWithMetadata( - { - type: processDMOpsActionType, - payload: { - rawMessageInfos: [], - updateInfos: [], - outboundP2PMessages, - composableMessageID, - notificationsCreationData, - }, - }, + { type: processDMOpsActionType, payload }, dispatchMetadata, ); @@ -214,6 +224,12 @@ notificationsCreationData, } = await dmOpSpecs[dmOp.type].processDMOperation(dmOp, utilities); + const messagesNotifyTypes = await getMessageNotifyTypes( + viewerID, + rawMessageInfos, + updateInfos, + ); + const outboundNotificationsCreationData = dmOperationSpecification.type === dmOperationSpecificationTypes.OUTBOUND ? notificationsCreationData @@ -236,17 +252,16 @@ .filter(Boolean); void processBlobHolders(holderOps); + const payload: ProcessDMOpsPayload = { + rawMessageInfos, + updateInfos, + outboundP2PMessages, + composableMessageID, + notificationsCreationData: outboundNotificationsCreationData, + messagesNotifyTypes, + }; dispatchWithMetadata( - { - type: processDMOpsActionType, - payload: { - rawMessageInfos, - updateInfos, - outboundP2PMessages, - composableMessageID, - notificationsCreationData: outboundNotificationsCreationData, - }, - }, + { type: processDMOpsActionType, payload }, dispatchMetadata, ); }, @@ -258,6 +273,7 @@ createMessagesToPeersFromDMOp, confirmPeerToPeerMessage, dispatch, + getMessageNotifyTypes, ], ); } @@ -287,6 +303,7 @@ const { processOutboundMessages } = usePeerToPeerCommunication(); const localMessageInfos = useSelector(state => state.messageStore.local); const createMessagesToPeersFromDMOp = useCreateMessagesToPeersFromDMOp(); + const getMessageNotifyTypes = useGetMessageNotifyTypes(); return React.useCallback( async ( @@ -338,20 +355,23 @@ const { rawMessageInfos, updateInfos, notificationsCreationData } = await dmOpSpecs[op.type].processDMOperation(op, utilities); + const messagesNotifyTypes = await getMessageNotifyTypes( + viewerID, + rawMessageInfos, + updateInfos, + ); + + const payload: ProcessDMOpsPayload = { + rawMessageInfos, + updateInfos, + outboundP2PMessages, + composableMessageID, + notificationsCreationData, + messagesNotifyTypes, + }; dispatchWithMetadata( - { - type: processDMOpsActionType, - payload: { - rawMessageInfos, - updateInfos, - outboundP2PMessages, - composableMessageID, - notificationsCreationData, - }, - }, - { - dmOpID, - }, + { type: processDMOpsActionType, payload }, + { dmOpID }, ); try { @@ -373,10 +393,50 @@ createMessagesToPeersFromDMOp, dispatchWithMetadata, processOutboundMessages, + getMessageNotifyTypes, ], ); } +function useGetMessageNotifyTypes(): ( + viewerID: string, + rawMessageInfos: $ReadOnlyArray<RawMessageInfo>, + updateInfos: $ReadOnlyArray<ClientUpdateInfo>, +) => Promise<{ [messageID: string]: MessageNotifyType }> { + const getLatestMessageEdit = useGetLatestMessageEdit(); + return React.useCallback( + async (viewerID, rawMessageInfos, updateInfos) => { + const { rawMessageInfos: allNewMessageInfos } = + mergeUpdatesWithMessageInfos(rawMessageInfos, updateInfos); + + const messageNotifyTypePairPromises = allNewMessageInfos.map( + async (rawMessageInfo: RawMessageInfo) => { + const { id, type } = rawMessageInfo; + invariant(id, 'Thick thread RawMessageInfos should always have ID'); + const { getMessageNotifyType } = messageSpecs[type]; + + let messageNotifyType = messageNotifyTypes.SET_UNREAD; + if (getMessageNotifyType) { + messageNotifyType = await getMessageNotifyType(rawMessageInfo, { + notifTargetUserID: viewerID, + userNotMemberOfSubthreads: new Set(), + fetchMessageInfoByID: getLatestMessageEdit, + }); + } + + return [id, messageNotifyType]; + }, + ); + + const messageNotifyTypePairs = await Promise.all( + messageNotifyTypePairPromises, + ); + return Object.fromEntries(messageNotifyTypePairs); + }, + [getLatestMessageEdit], + ); +} + export { useProcessDMOperation, useProcessAndSendDMOperation, diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js --- a/lib/types/dm-ops.js +++ b/lib/types/dm-ops.js @@ -24,6 +24,7 @@ type ThreadTimestamps, } from './thread-types.js'; import type { ClientUpdateInfo } from './update-types.js'; +import type { MessageNotifyType } from '../shared/messages/message-spec.js'; import { values } from '../utils/objects.js'; import { tColor, @@ -530,6 +531,7 @@ // were queued on Tunnelbroker. +composableMessageID: ?string, +notificationsCreationData: ?NotificationsCreationData, + +messagesNotifyTypes: { +[messageID: string]: MessageNotifyType }, }; export const queueDMOpsActionType = 'QUEUE_DM_OPS';