diff --git a/lib/actions/activity-actions.js b/lib/actions/activity-actions.js index ce77fd9d0..d2d2ed91d 100644 --- a/lib/actions/activity-actions.js +++ b/lib/actions/activity-actions.js @@ -1,161 +1,171 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import { extractKeyserverIDFromID, extractKeyserverIDFromIDOptional, } from '../keyserver-conn/keyserver-call-utils.js'; import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import type { OutboundDMOperationSpecification } from '../shared/dm-ops/dm-op-utils.js'; import { dmOperationSpecificationTypes } from '../shared/dm-ops/dm-op-utils.js'; import { useProcessAndSendDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import type { ActivityUpdate, ActivityUpdateSuccessPayload, SetThreadUnreadStatusPayload, SetThreadUnreadStatusRequest, } from '../types/activity-types.js'; import type { DMChangeThreadReadStatusOperation } from '../types/dm-ops.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types'; -import { threadTypeIsThick } from '../types/thread-types-enum.js'; import { useSelector } from '../utils/redux-utils.js'; export type UpdateActivityInput = { +activityUpdates: $ReadOnlyArray, }; const updateActivityActionTypes = Object.freeze({ started: 'UPDATE_ACTIVITY_STARTED', success: 'UPDATE_ACTIVITY_SUCCESS', failed: 'UPDATE_ACTIVITY_FAILED', }); const updateActivity = ( callKeyserverEndpoint: CallKeyserverEndpoint, ): ((input: UpdateActivityInput) => Promise) => async input => { const { activityUpdates } = input; const requests: { [string]: { +updates: ActivityUpdate[] } } = {}; for (const update of activityUpdates) { const optionalKeyserverID = extractKeyserverIDFromIDOptional( update.threadID, ); if (!optionalKeyserverID) { continue; } const keyserverID: string = optionalKeyserverID; if (!requests[keyserverID]) { requests[keyserverID] = { updates: [] }; } requests[keyserverID].updates.push(update); } const responses = await callKeyserverEndpoint('update_activity', requests); let unfocusedToUnread: $ReadOnlyArray = []; for (const keyserverID in responses) { unfocusedToUnread = unfocusedToUnread.concat( responses[keyserverID].unfocusedToUnread, ); } const sortedActivityUpdates: { [keyserverID: string]: $ReadOnlyArray, } = {}; for (const keyserverID in requests) { sortedActivityUpdates[keyserverID] = requests[keyserverID].updates; } return { activityUpdates: sortedActivityUpdates, result: { unfocusedToUnread, }, }; }; function useUpdateActivity(): ( input: UpdateActivityInput, ) => Promise { return useKeyserverCall(updateActivity); } const setThreadUnreadStatusActionTypes = Object.freeze({ started: 'SET_THREAD_UNREAD_STATUS_STARTED', success: 'SET_THREAD_UNREAD_STATUS_SUCCESS', failed: 'SET_THREAD_UNREAD_STATUS_FAILED', }); const setThreadUnreadStatus = ( callKeyserverEndpoint: CallKeyserverEndpoint, ): (( input: SetThreadUnreadStatusRequest, ) => Promise) => async input => { const keyserverID = extractKeyserverIDFromID(input.threadID); const requests = { [keyserverID]: input }; const responses = await callKeyserverEndpoint( 'set_thread_unread_status', requests, ); return { resetToUnread: responses[keyserverID].resetToUnread, threadID: input.threadID, }; }; -function useSetThreadUnreadStatus( - threadInfo: ThreadInfo, -): ( - request: SetThreadUnreadStatusRequest, +export type UseSetThreadUnreadStatusInput = $ReadOnly< + | { + +thick: false, + ...SetThreadUnreadStatusRequest, + } + | { + +thick: true, + +threadInfo: ThreadInfo, + ...SetThreadUnreadStatusRequest, + }, +>; +function useSetThreadUnreadStatus(): ( + imput: UseSetThreadUnreadStatusInput, ) => Promise { const viewerID = useSelector( state => state.currentUserInfo && state.currentUserInfo.id, ); const processAndSendDMOperation = useProcessAndSendDMOperation(); const keyserverCall = useKeyserverCall(setThreadUnreadStatus); return React.useCallback( - async (input: SetThreadUnreadStatusRequest) => { - if (!threadTypeIsThick(threadInfo.type)) { - return await keyserverCall(input); + async (input: UseSetThreadUnreadStatusInput) => { + if (!input.thick) { + const { thick, ...rest } = input; + return await keyserverCall({ ...rest }); } invariant(viewerID, 'viewerID must be set'); + const { threadInfo } = input; const op: DMChangeThreadReadStatusOperation = { type: 'change_thread_read_status', time: Date.now(), threadID: threadInfo.id, creatorID: viewerID, unread: !threadInfo.currentUser.unread, }; const opSpecification: OutboundDMOperationSpecification = { type: dmOperationSpecificationTypes.OUTBOUND, op, recipients: { type: 'self_devices', }, }; await processAndSendDMOperation(opSpecification); return { resetToUnread: false, threadID: threadInfo.id, }; }, - [keyserverCall, threadInfo, viewerID, processAndSendDMOperation], + [keyserverCall, viewerID, processAndSendDMOperation], ); } export { updateActivityActionTypes, useUpdateActivity, setThreadUnreadStatusActionTypes, useSetThreadUnreadStatus, }; diff --git a/lib/hooks/toggle-unread-status.js b/lib/hooks/toggle-unread-status.js index 24de6c4cc..57c60b653 100644 --- a/lib/hooks/toggle-unread-status.js +++ b/lib/hooks/toggle-unread-status.js @@ -1,56 +1,62 @@ // @flow import * as React from 'react'; import { setThreadUnreadStatusActionTypes, useSetThreadUnreadStatus, } from '../actions/activity-actions.js'; -import type { - SetThreadUnreadStatusPayload, - SetThreadUnreadStatusRequest, -} from '../types/activity-types.js'; +import type { UseSetThreadUnreadStatusInput } from '../actions/activity-actions.js'; +import type { SetThreadUnreadStatusPayload } from '../types/activity-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; +import { threadTypeIsThick } from '../types/thread-types-enum.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; function useToggleUnreadStatus( threadInfo: ThreadInfo, mostRecentNonLocalMessage: ?string, afterAction: () => void, ): () => void { const dispatchActionPromise = useDispatchActionPromise(); const { currentUser } = threadInfo; const boundSetThreadUnreadStatus: ( - request: SetThreadUnreadStatusRequest, - ) => Promise = - useSetThreadUnreadStatus(threadInfo); + input: UseSetThreadUnreadStatusInput, + ) => Promise = useSetThreadUnreadStatus(); const toggleUnreadStatus = React.useCallback(() => { const request = { threadID: threadInfo.id, unread: !currentUser.unread, latestMessage: mostRecentNonLocalMessage, }; + const input = threadTypeIsThick(threadInfo.type) + ? { + thick: true, + threadInfo, + ...request, + } + : { thick: false, ...request }; + void dispatchActionPromise( setThreadUnreadStatusActionTypes, - boundSetThreadUnreadStatus(request), + boundSetThreadUnreadStatus(input), undefined, ({ threadID: threadInfo.id, unread: !currentUser.unread, }: { +threadID: string, +unread: boolean }), ); afterAction(); }, [ threadInfo, currentUser.unread, mostRecentNonLocalMessage, dispatchActionPromise, afterAction, boundSetThreadUnreadStatus, ]); return toggleUnreadStatus; } export default useToggleUnreadStatus;