From 4f3c7a1a6945134b9bd7bf69e221eba7ca3a7029 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Sat, 19 Mar 2022 21:19:14 +0100 Subject: [PATCH] [Refactoring] TeactN: Support async action handlers --- src/global/actions/api/bots.ts | 153 ++--- src/global/actions/api/calls.async.ts | 312 ++++----- src/global/actions/api/chats.ts | 599 ++++++++-------- src/global/actions/api/globalSearch.ts | 6 +- src/global/actions/api/initial.ts | 84 +-- src/global/actions/api/management.ts | 446 ++++++------ src/global/actions/api/messages.ts | 190 +++--- src/global/actions/api/reactions.ts | 121 ++-- src/global/actions/api/settings.ts | 643 +++++++++--------- src/global/actions/api/statistics.ts | 51 +- src/global/actions/api/symbols.ts | 117 ++-- src/global/actions/api/twoFaSettings.ts | 76 +-- src/global/actions/api/users.ts | 106 ++- src/global/actions/apiUpdaters/chats.ts | 203 +++--- src/global/actions/apiUpdaters/initial.ts | 3 +- src/global/actions/apiUpdaters/messages.ts | 19 +- src/global/actions/apiUpdaters/misc.ts | 3 +- src/global/actions/apiUpdaters/payments.ts | 4 +- src/global/actions/apiUpdaters/settings.ts | 4 +- src/global/actions/apiUpdaters/symbols.ts | 4 +- .../actions/apiUpdaters/twoFaSettings.ts | 5 +- src/global/actions/apiUpdaters/users.ts | 4 +- src/global/actions/ui/calls.ts | 201 +++--- src/global/actions/ui/messages.ts | 14 +- src/global/actions/ui/misc.ts | 7 +- src/global/actions/ui/payments.ts | 5 +- src/global/selectors/messages.ts | 2 +- src/lib/teact/teactn.tsx | 20 +- 28 files changed, 1603 insertions(+), 1799 deletions(-) diff --git a/src/global/actions/api/bots.ts b/src/global/actions/api/bots.ts index 5fc3dcd6a..a774612dc 100644 --- a/src/global/actions/api/bots.ts +++ b/src/global/actions/api/bots.ts @@ -101,7 +101,7 @@ addActionHandler('sendBotCommand', (global, actions, payload) => { ); }); -addActionHandler('restartBot', (global, actions, payload) => { +addActionHandler('restartBot', async (global, actions, payload) => { const { chatId } = payload; const { currentUserId } = global; const chat = selectCurrentChat(global); @@ -110,101 +110,92 @@ addActionHandler('restartBot', (global, actions, payload) => { return; } - (async () => { - const result = await callApi('unblockContact', bot.id, bot.accessHash); - if (!result) { - return; - } - - setGlobal(removeBlockedContact(getGlobal(), bot.id)); - void sendBotCommand(chat, currentUserId, '/start', undefined, selectSendAs(global, chatId)); - })(); -}); - -addActionHandler('loadTopInlineBots', (global) => { - const { lastRequestedAt } = global.topInlineBots; - - if (lastRequestedAt && getServerTime(global.serverTimeOffset) - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) { + const result = await callApi('unblockContact', bot.id, bot.accessHash); + if (!result) { return; } - (async () => { - const result = await callApi('fetchTopInlineBots'); - if (!result) { - return; - } - - const { ids, users } = result; - - let newGlobal = getGlobal(); - newGlobal = addUsers(newGlobal, buildCollectionByKey(users, 'id')); - newGlobal = { - ...newGlobal, - topInlineBots: { - ...newGlobal.topInlineBots, - userIds: ids, - lastRequestedAt: getServerTime(global.serverTimeOffset), - }, - }; - setGlobal(newGlobal); - })(); + setGlobal(removeBlockedContact(getGlobal(), bot.id)); + void sendBotCommand(chat, currentUserId, '/start', undefined, selectSendAs(global, chatId)); }); -addActionHandler('queryInlineBot', ((global, actions, payload) => { +addActionHandler('loadTopInlineBots', async (global) => { + const { lastRequestedAt } = global.topInlineBots; + if (lastRequestedAt && getServerTime(global.serverTimeOffset) - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) { + return undefined; + } + + const result = await callApi('fetchTopInlineBots'); + if (!result) { + return undefined; + } + + const { ids, users } = result; + + global = getGlobal(); + global = addUsers(global, buildCollectionByKey(users, 'id')); + global = { + ...global, + topInlineBots: { + ...global.topInlineBots, + userIds: ids, + lastRequestedAt: getServerTime(global.serverTimeOffset), + }, + }; + return global; +}); + +addActionHandler('queryInlineBot', async (global, actions, payload) => { const { chatId, username, query, offset, } = payload; - (async () => { - let inlineBotData = global.inlineBots.byUsername[username]; + let inlineBotData = global.inlineBots.byUsername[username]; + if (inlineBotData === false) { + return; + } - if (inlineBotData === false) { + if (inlineBotData === undefined) { + const { user: inlineBot, chat } = await callApi('fetchInlineBot', { username }) || {}; + global = getGlobal(); + if (!inlineBot || !chat) { + setGlobal(replaceInlineBotSettings(global, username, false)); return; } - if (inlineBotData === undefined) { - const { user: inlineBot, chat } = await callApi('fetchInlineBot', { username }) || {}; - global = getGlobal(); - if (!inlineBot || !chat) { - setGlobal(replaceInlineBotSettings(global, username, false)); - return; - } + global = addUsers(global, { [inlineBot.id]: inlineBot }); + global = addChats(global, { [chat.id]: chat }); + inlineBotData = { + id: inlineBot.id, + query: '', + offset: '', + switchPm: undefined, + canLoadMore: true, + results: [], + }; - global = addUsers(global, { [inlineBot.id]: inlineBot }); - global = addChats(global, { [chat.id]: chat }); - inlineBotData = { - id: inlineBot.id, - query: '', - offset: '', - switchPm: undefined, - canLoadMore: true, - results: [], - }; + global = replaceInlineBotSettings(global, username, inlineBotData); + setGlobal(global); + } - global = replaceInlineBotSettings(global, username, inlineBotData); - setGlobal(global); - } + if (query === inlineBotData.query && !inlineBotData.canLoadMore) { + return; + } - if (query === inlineBotData.query && !inlineBotData.canLoadMore) { - return; - } - - void runDebouncedForSearch(() => { - searchInlineBot({ - username, - inlineBotData: inlineBotData as InlineBotSettings, - chatId, - query, - offset, - }); + void runDebouncedForSearch(() => { + searchInlineBot({ + username, + inlineBotData: inlineBotData as InlineBotSettings, + chatId, + query, + offset, }); - })(); -})); + }); +}); addActionHandler('sendInlineBotResult', (global, actions, payload) => { const { id, queryId } = payload; const currentMessageList = selectCurrentMessageList(global); - if (!currentMessageList || !id) { return; } @@ -246,7 +237,7 @@ addActionHandler('resetInlineBot', (global, actions, payload) => { setGlobal(replaceInlineBotSettings(global, username, inlineBotData)); }); -addActionHandler('startBot', (global, actions, payload) => { +addActionHandler('startBot', async (global, actions, payload) => { const { botId, param } = payload; const bot = selectUser(global, botId); @@ -254,12 +245,10 @@ addActionHandler('startBot', (global, actions, payload) => { return; } - (async () => { - await callApi('startBot', { - bot, - startParam: param, - }); - })(); + await callApi('startBot', { + bot, + startParam: param, + }); }); async function searchInlineBot({ diff --git a/src/global/actions/api/calls.async.ts b/src/global/actions/api/calls.async.ts index 0953d2280..43e23cdca 100644 --- a/src/global/actions/api/calls.async.ts +++ b/src/global/actions/api/calls.async.ts @@ -9,8 +9,6 @@ import { handleUpdateGroupCallParticipants, handleUpdateGroupCallConnection, } from '../../../lib/secret-sauce'; -import { ApiUpdate } from '../../../api/types'; - import { GROUP_CALL_VOLUME_MULTIPLIER } from '../../../config'; import { callApi } from '../../../api/gramjs'; import { selectChat, selectCurrentMessageList, selectUser } from '../../selectors'; @@ -35,7 +33,7 @@ import callFallbackAvatarPath from '../../../assets/call-fallback-avatar.png'; const FALLBACK_INVITE_EXPIRE_SECONDS = 1800; // 30 min -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { const { activeGroupCallId } = global.groupCalls; switch (update['@type']) { @@ -88,7 +86,7 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { return undefined; }); -addActionHandler('leaveGroupCall', (global, actions, payload) => { +addActionHandler('leaveGroupCall', async (global, actions, payload) => { const { isFromLibrary, shouldDiscard, shouldRemove, rejoin, } = payload || {}; @@ -99,74 +97,70 @@ addActionHandler('leaveGroupCall', (global, actions, payload) => { setGlobal(updateActiveGroupCall(global, { connectionState: 'disconnected' }, groupCall.participantsCount - 1)); - (async () => { - await callApi('leaveGroupCall', { - call: groupCall, - }); + await callApi('leaveGroupCall', { + call: groupCall, + }); - let shouldResetFallbackState = false; - if (shouldDiscard) { - global = getGlobal(); + let shouldResetFallbackState = false; + if (shouldDiscard) { + global = getGlobal(); - if (global.groupCalls.fallbackChatId === groupCall.chatId) { - shouldResetFallbackState = true; + if (global.groupCalls.fallbackChatId === groupCall.chatId) { + shouldResetFallbackState = true; - global.groupCalls.fallbackUserIdsToRemove?.forEach((userId) => { - actions.deleteChatMember({ chatId: global.groupCalls.fallbackChatId, userId }); - }); - } - - await callApi('discardGroupCall', { - call: groupCall, + global.groupCalls.fallbackUserIdsToRemove?.forEach((userId) => { + actions.deleteChatMember({ chatId: global.groupCalls.fallbackChatId, userId }); }); } - global = getGlobal(); - if (shouldRemove) { - global = removeGroupCall(global, groupCall.id); - } - - removeGroupCallAudioElement(); - - setGlobal({ - ...global, - groupCalls: { - ...global.groupCalls, - isGroupCallPanelHidden: true, - activeGroupCallId: undefined, - ...(shouldResetFallbackState && { - fallbackChatId: undefined, - fallbackUserIdsToRemove: undefined, - }), - }, + await callApi('discardGroupCall', { + call: groupCall, }); + } - if (!isFromLibrary) { - leaveGroupCall(); - } + global = getGlobal(); + if (shouldRemove) { + global = removeGroupCall(global, groupCall.id); + } - if (rejoin) { - actions.joinGroupCall(rejoin); - } - })(); + removeGroupCallAudioElement(); + + setGlobal({ + ...global, + groupCalls: { + ...global.groupCalls, + isGroupCallPanelHidden: true, + activeGroupCallId: undefined, + ...(shouldResetFallbackState && { + fallbackChatId: undefined, + fallbackUserIdsToRemove: undefined, + }), + }, + }); + + if (!isFromLibrary) { + leaveGroupCall(); + } + + if (rejoin) { + actions.joinGroupCall(rejoin); + } }); -addActionHandler('toggleGroupCallVideo', (global) => { +addActionHandler('toggleGroupCallVideo', async (global) => { const groupCall = selectActiveGroupCall(global); const user = selectUser(global, global.currentUserId!); if (!user || !groupCall) { return; } - (async () => { - await toggleStream('video'); + await toggleStream('video'); - await callApi('editGroupCallParticipant', { - call: groupCall, - videoStopped: !isStreamEnabled('video'), - participant: user, - }); - })(); + await callApi('editGroupCallParticipant', { + call: groupCall, + videoStopped: !isStreamEnabled('video'), + participant: user, + }); }); addActionHandler('requestToSpeak', (global, actions, payload) => { @@ -202,7 +196,7 @@ addActionHandler('setGroupCallParticipantVolume', (global, actions, payload) => }); }); -addActionHandler('toggleGroupCallMute', (global, actions, payload) => { +addActionHandler('toggleGroupCallMute', async (global, actions, payload) => { const { participantId, value } = payload || {}; const groupCall = selectActiveGroupCall(global); const user = selectUser(global, participantId || global.currentUserId!); @@ -210,58 +204,54 @@ addActionHandler('toggleGroupCallMute', (global, actions, payload) => { return; } - (async () => { - const muted = value === undefined ? isStreamEnabled('audio', user.id) : value; + const muted = value === undefined ? isStreamEnabled('audio', user.id) : value; - if (!participantId) { - await toggleStream('audio'); - } else { - setVolume(participantId, muted ? 0 : 1); - } + if (!participantId) { + await toggleStream('audio'); + } else { + setVolume(participantId, muted ? 0 : 1); + } - await callApi('editGroupCallParticipant', { - call: groupCall, - muted, - participant: user, - }); - })(); + await callApi('editGroupCallParticipant', { + call: groupCall, + muted, + participant: user, + }); }); -addActionHandler('toggleGroupCallPresentation', (global, actions, payload) => { +addActionHandler('toggleGroupCallPresentation', async (global, actions, payload) => { const groupCall = selectActiveGroupCall(global); const user = selectUser(global, global.currentUserId!); if (!user || !groupCall) { return; } - (async () => { - const value = payload?.value !== undefined ? payload?.value : !isStreamEnabled('presentation'); - if (value) { - const params = await startSharingScreen(); - if (!params) { - return; - } - - await callApi('joinGroupCallPresentation', { - call: groupCall, - params, - }); - } else { - await toggleStream('presentation', false); - await callApi('leaveGroupCallPresentation', { - call: groupCall, - }); + const value = payload?.value !== undefined ? payload?.value : !isStreamEnabled('presentation'); + if (value) { + const params = await startSharingScreen(); + if (!params) { + return; } - await callApi('editGroupCallParticipant', { + await callApi('joinGroupCallPresentation', { call: groupCall, - presentationPaused: !isStreamEnabled('presentation'), - participant: user, + params, }); - })(); + } else { + await toggleStream('presentation', false); + await callApi('leaveGroupCallPresentation', { + call: groupCall, + }); + } + + await callApi('editGroupCallParticipant', { + call: groupCall, + presentationPaused: !isStreamEnabled('presentation'), + participant: user, + }); }); -addActionHandler('connectToActiveGroupCall', (global, actions) => { +addActionHandler('connectToActiveGroupCall', async (global, actions) => { const groupCall = selectActiveGroupCall(global); if (!groupCall) return; @@ -283,28 +273,26 @@ addActionHandler('connectToActiveGroupCall', (global, actions) => { if (!currentUserId) return; - (async () => { - const params = await joinGroupCall(currentUserId, audioContext, audioElement, actions.apiUpdate); + const params = await joinGroupCall(currentUserId, audioContext, audioElement, actions.apiUpdate); - const result = await callApi('joinGroupCall', { - call: groupCall, - params, - inviteHash: groupCall.inviteHash, - }); + const result = await callApi('joinGroupCall', { + call: groupCall, + params, + inviteHash: groupCall.inviteHash, + }); - if (!result) return; + if (!result) return; - actions.loadMoreGroupCallParticipants(); + actions.loadMoreGroupCallParticipants(); - if (groupCall.chatId) { - const chat = selectChat(getGlobal(), groupCall.chatId); - if (!chat) return; - await loadFullChat(chat); - } - })(); + if (groupCall.chatId) { + const chat = selectChat(getGlobal(), groupCall.chatId); + if (!chat) return; + await loadFullChat(chat); + } }); -addActionHandler('inviteToCallFallback', (global, actions, payload) => { +addActionHandler('inviteToCallFallback', async (global, actions, payload) => { const { chatId } = selectCurrentMessageList(global) || {}; if (!chatId) { return; @@ -317,67 +305,65 @@ addActionHandler('inviteToCallFallback', (global, actions, payload) => { const { shouldRemove } = payload; - (async () => { - const fallbackChannelTitle = selectCallFallbackChannelTitle(global); + const fallbackChannelTitle = selectCallFallbackChannelTitle(global); - let fallbackChannel = Object.values(global.chats.byId).find((channel) => { - return ( - channel.title === fallbackChannelTitle - && channel.isCreator - && !channel.isRestricted - ); + let fallbackChannel = Object.values(global.chats.byId).find((channel) => { + return ( + channel.title === fallbackChannelTitle + && channel.isCreator + && !channel.isRestricted + ); + }); + if (!fallbackChannel) { + fallbackChannel = await callApi('createChannel', { + title: fallbackChannelTitle, + users: [user], }); + if (!fallbackChannel) { - fallbackChannel = await callApi('createChannel', { - title: fallbackChannelTitle, - users: [user], - }); - - if (!fallbackChannel) { - return; - } - - const photo = await fetchFile(callFallbackAvatarPath, 'avatar.png'); - void callApi('editChatPhoto', { - chatId: fallbackChannel.id, - accessHash: fallbackChannel.accessHash, - photo, - }); - } else { - actions.updateChatMemberBannedRights({ - chatId: fallbackChannel.id, - userId: chatId, - bannedRights: {}, - }); - - void callApi('addChatMembers', fallbackChannel, [user], true); - } - - const inviteLink = await callApi('updatePrivateLink', { - chat: fallbackChannel, - usageLimit: 1, - expireDate: getServerTime(global.serverTimeOffset) + FALLBACK_INVITE_EXPIRE_SECONDS, - }); - if (!inviteLink) { return; } - if (shouldRemove) { - global = getGlobal(); - const fallbackUserIdsToRemove = global.groupCalls.fallbackUserIdsToRemove || []; - setGlobal({ - ...global, - groupCalls: { - ...global.groupCalls, - fallbackChatId: fallbackChannel.id, - fallbackUserIdsToRemove: [...fallbackUserIdsToRemove, chatId], - }, - }); - } + const photo = await fetchFile(callFallbackAvatarPath, 'avatar.png'); + void callApi('editChatPhoto', { + chatId: fallbackChannel.id, + accessHash: fallbackChannel.accessHash, + photo, + }); + } else { + actions.updateChatMemberBannedRights({ + chatId: fallbackChannel.id, + userId: chatId, + bannedRights: {}, + }); - actions.sendMessage({ text: `Join a call: ${inviteLink}` }); - actions.openChat({ id: fallbackChannel.id }); - actions.createGroupCall({ chatId: fallbackChannel.id }); - actions.closeCallFallbackConfirm(); - })(); + void callApi('addChatMembers', fallbackChannel, [user], true); + } + + const inviteLink = await callApi('updatePrivateLink', { + chat: fallbackChannel, + usageLimit: 1, + expireDate: getServerTime(global.serverTimeOffset) + FALLBACK_INVITE_EXPIRE_SECONDS, + }); + if (!inviteLink) { + return; + } + + if (shouldRemove) { + global = getGlobal(); + const fallbackUserIdsToRemove = global.groupCalls.fallbackUserIdsToRemove || []; + setGlobal({ + ...global, + groupCalls: { + ...global.groupCalls, + fallbackChatId: fallbackChannel.id, + fallbackUserIdsToRemove: [...fallbackUserIdsToRemove, chatId], + }, + }); + } + + actions.sendMessage({ text: `Join a call: ${inviteLink}` }); + actions.openChat({ id: fallbackChannel.id }); + actions.createGroupCall({ chatId: fallbackChannel.id }); + actions.closeCallFallbackConfirm(); }); diff --git a/src/global/actions/api/chats.ts b/src/global/actions/api/chats.ts index 6bc643ca4..cca131d7f 100644 --- a/src/global/actions/api/chats.ts +++ b/src/global/actions/api/chats.ts @@ -48,25 +48,23 @@ const INFINITE_LOOP_MARKER = 100; const runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true); const runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true); -addActionHandler('preloadTopChatMessages', (global, actions) => { - (async () => { - const preloadedChatIds = new Set(); +addActionHandler('preloadTopChatMessages', async (global, actions) => { + const preloadedChatIds = new Set(); - for (let i = 0; i < TOP_CHAT_MESSAGES_PRELOAD_LIMIT; i++) { - await pause(TOP_CHAT_MESSAGES_PRELOAD_INTERVAL); + for (let i = 0; i < TOP_CHAT_MESSAGES_PRELOAD_LIMIT; i++) { + await pause(TOP_CHAT_MESSAGES_PRELOAD_INTERVAL); - const { chatId: currentChatId } = selectCurrentMessageList(global) || {}; - const folderAllOrderedIds = getOrderedIds(ALL_FOLDER_ID); - const nextChatId = folderAllOrderedIds?.find((id) => id !== currentChatId && !preloadedChatIds.has(id)); - if (!nextChatId) { - return; - } - - preloadedChatIds.add(nextChatId); - - actions.loadViewportMessages({ chatId: nextChatId, threadId: MAIN_THREAD_ID }); + const { chatId: currentChatId } = selectCurrentMessageList(global) || {}; + const folderAllOrderedIds = getOrderedIds(ALL_FOLDER_ID); + const nextChatId = folderAllOrderedIds?.find((id) => id !== currentChatId && !preloadedChatIds.has(id)); + if (!nextChatId) { + return; } - })(); + + preloadedChatIds.add(nextChatId); + + actions.loadViewportMessages({ chatId: nextChatId, threadId: MAIN_THREAD_ID }); + } }); addActionHandler('openChat', (global, actions, payload) => { @@ -107,40 +105,36 @@ addActionHandler('openChat', (global, actions, payload) => { } }); -addActionHandler('openLinkedChat', (global, actions, payload) => { +addActionHandler('openLinkedChat', async (global, actions, payload) => { const { id } = payload!; const chat = selectChat(global, id); if (!chat) { return; } - (async () => { - const chatFullInfo = await callApi('fetchFullChat', chat); + const chatFullInfo = await callApi('fetchFullChat', chat); - if (chatFullInfo?.fullInfo?.linkedChatId) { - actions.openChat({ id: chatFullInfo.fullInfo.linkedChatId }); - } - })(); + if (chatFullInfo?.fullInfo?.linkedChatId) { + actions.openChat({ id: chatFullInfo.fullInfo.linkedChatId }); + } }); -addActionHandler('focusMessageInComments', (global, actions, payload) => { +addActionHandler('focusMessageInComments', async (global, actions, payload) => { const { chatId, threadId, messageId } = payload!; const chat = selectChat(global, chatId); if (!chat) { return; } - (async () => { - const result = await callApi('requestThreadInfoUpdate', { chat, threadId }); - if (!result) { - return; - } + const result = await callApi('requestThreadInfoUpdate', { chat, threadId }); + if (!result) { + return; + } - actions.focusMessage({ chatId, threadId, messageId }); - })(); + actions.focusMessage({ chatId, threadId, messageId }); }); -addActionHandler('openSupportChat', (global, actions) => { +addActionHandler('openSupportChat', async (global, actions) => { const chat = selectSupportChat(global); if (chat) { actions.openChat({ id: chat.id, shouldReplaceHistory: true }); @@ -149,12 +143,10 @@ addActionHandler('openSupportChat', (global, actions) => { actions.openChat({ id: TMP_CHAT_ID, shouldReplaceHistory: true }); - (async () => { - const result = await callApi('fetchChat', { type: 'support' }); - if (result) { - actions.openChat({ id: result.chatId, shouldReplaceHistory: true }); - } - })(); + const result = await callApi('fetchChat', { type: 'support' }); + if (result) { + actions.openChat({ id: result.chatId, shouldReplaceHistory: true }); + } }); addActionHandler('openTipsChat', (global, actions, payload) => { @@ -167,47 +159,45 @@ addActionHandler('openTipsChat', (global, actions, payload) => { actions.openChatByUsername({ username: `${TIPS_USERNAME}${usernamePostfix}` }); }); -addActionHandler('loadAllChats', (global, actions, payload) => { +addActionHandler('loadAllChats', async (global, actions, payload) => { const listType = payload.listType as 'active' | 'archived'; const { onReplace } = payload; let { shouldReplace } = payload; let i = 0; - (async () => { - while (shouldReplace || !getGlobal().chats.isFullyLoaded[listType]) { - if (i++ >= INFINITE_LOOP_MARKER) { - if (DEBUG) { - // eslint-disable-next-line no-console - console.error('`actions/loadAllChats`: Infinite loop detected'); - } - - return; + while (shouldReplace || !getGlobal().chats.isFullyLoaded[listType]) { + if (i++ >= INFINITE_LOOP_MARKER) { + if (DEBUG) { + // eslint-disable-next-line no-console + console.error('`actions/loadAllChats`: Infinite loop detected'); } - global = getGlobal(); - - if (global.connectionState !== 'connectionStateReady' || global.authState !== 'authorizationStateReady') { - return; - } - - const listIds = !shouldReplace && global.chats.listIds[listType]; - const oldestChat = listIds - ? listIds - /* eslint-disable @typescript-eslint/no-loop-func */ - .map((id) => global.chats.byId[id]) - .filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(global, chat.id)) - /* eslint-enable @typescript-eslint/no-loop-func */ - .sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0] - : undefined; - - await loadChats(listType, oldestChat?.id, oldestChat?.lastMessage!.date, shouldReplace); - - if (shouldReplace) { - onReplace?.(); - shouldReplace = false; - } + return; } - })(); + + global = getGlobal(); + + if (global.connectionState !== 'connectionStateReady' || global.authState !== 'authorizationStateReady') { + return; + } + + const listIds = !shouldReplace && global.chats.listIds[listType]; + const oldestChat = listIds + ? listIds + /* eslint-disable @typescript-eslint/no-loop-func */ + .map((id) => global.chats.byId[id]) + .filter((chat) => Boolean(chat?.lastMessage) && !selectIsChatPinned(global, chat.id)) + /* eslint-enable @typescript-eslint/no-loop-func */ + .sort((chat1, chat2) => (chat1.lastMessage!.date - chat2.lastMessage!.date))[0] + : undefined; + + await loadChats(listType, oldestChat?.id, oldestChat?.lastMessage!.date, shouldReplace); + + if (shouldReplace) { + onReplace?.(); + shouldReplace = false; + } + } }); addActionHandler('loadFullChat', (global, actions, payload) => { @@ -503,37 +493,33 @@ addActionHandler('toggleChatUnread', (global, actions, payload) => { } }); -addActionHandler('openChatByInvite', (global, actions, payload) => { +addActionHandler('openChatByInvite', async (global, actions, payload) => { const { hash } = payload!; - (async () => { - const result = await callApi('openChatByInvite', hash); - if (!result) { - return; - } + const result = await callApi('openChatByInvite', hash); + if (!result) { + return; + } - actions.openChat({ id: result.chatId }); - })(); + actions.openChat({ id: result.chatId }); }); -addActionHandler('openChatByPhoneNumber', (global, actions, payload) => { +addActionHandler('openChatByPhoneNumber', async (global, actions, payload) => { const { phoneNumber } = payload!; - (async () => { - // Open temporary empty chat to make the click response feel faster - actions.openChat({ id: TMP_CHAT_ID }); + // Open temporary empty chat to make the click response feel faster + actions.openChat({ id: TMP_CHAT_ID }); - const chat = await fetchChatByPhoneNumber(phoneNumber); - if (!chat) { - actions.openPreviousChat(); - actions.showNotification({ - message: langProvider.getTranslation('lng_username_by_phone_not_found').replace('{phone}', phoneNumber), - }); - return; - } + const chat = await fetchChatByPhoneNumber(phoneNumber); + if (!chat) { + actions.openPreviousChat(); + actions.showNotification({ + message: langProvider.getTranslation('lng_username_by_phone_not_found').replace('{phone}', phoneNumber), + }); + return; + } - actions.openChat({ id: chat.id }); - })(); + actions.openChat({ id: chat.id }); }); addActionHandler('openTelegramLink', (global, actions, payload) => { @@ -604,77 +590,71 @@ addActionHandler('openTelegramLink', (global, actions, payload) => { } }); -addActionHandler('acceptInviteConfirmation', (global, actions, payload) => { +addActionHandler('acceptInviteConfirmation', async (global, actions, payload) => { const { hash } = payload!; - (async () => { - const result = await callApi('importChatInvite', { hash }); - if (!result) { - return; - } + const result = await callApi('importChatInvite', { hash }); + if (!result) { + return; + } - actions.openChat({ id: result.id }); - })(); + actions.openChat({ id: result.id }); }); -addActionHandler('openChatByUsername', (global, actions, payload) => { +addActionHandler('openChatByUsername', async (global, actions, payload) => { const { username, messageId, commentId, startParam, } = payload!; - (async () => { - const chat = selectCurrentChat(global); + const chat = selectCurrentChat(global); - if (!commentId) { - if (chat && chat.username === username) { - actions.focusMessage({ chatId: chat.id, messageId }); - return; - } - await openChatByUsername(actions, username, messageId, startParam); + if (!commentId) { + if (chat && chat.username === username) { + actions.focusMessage({ chatId: chat.id, messageId }); return; } + await openChatByUsername(actions, username, messageId, startParam); + return; + } - const { chatId, type } = selectCurrentMessageList(global) || {}; - const usernameChat = selectChatByUsername(global, username); - if (chatId && usernameChat && type === 'thread') { - const threadInfo = selectThreadInfo(global, chatId, messageId); + const { chatId, type } = selectCurrentMessageList(global) || {}; + const usernameChat = selectChatByUsername(global, username); + if (chatId && usernameChat && type === 'thread') { + const threadInfo = selectThreadInfo(global, chatId, messageId); - if (threadInfo && threadInfo.chatId === chatId) { - actions.focusMessage({ - chatId: threadInfo.chatId, - threadId: threadInfo.threadId, - messageId: commentId, - }); - return; - } + if (threadInfo && threadInfo.chatId === chatId) { + actions.focusMessage({ + chatId: threadInfo.chatId, + threadId: threadInfo.threadId, + messageId: commentId, + }); + return; } + } - if (!messageId) return; + if (!messageId) return; - await openCommentsByUsername(actions, username, messageId, commentId); - })(); + void openCommentsByUsername(actions, username, messageId, commentId); }); -addActionHandler('togglePreHistoryHidden', (global, actions, payload) => { +addActionHandler('togglePreHistoryHidden', async (global, actions, payload) => { const { chatId, isEnabled } = payload!; - let chat = selectChat(global, chatId); + let chat = selectChat(global, chatId); if (!chat) { return; } - (async () => { - if (isChatBasicGroup(chat)) { - chat = await callApi('migrateChat', chat); + if (isChatBasicGroup(chat)) { + chat = await callApi('migrateChat', chat); - if (!chat) { - return; - } - - actions.openChat({ id: chat.id }); + if (!chat) { + return; } - void callApi('togglePreHistoryHidden', { chat, isEnabled }); - })(); + actions.openChat({ id: chat.id }); + } + + void callApi('togglePreHistoryHidden', { chat, isEnabled }); }); addActionHandler('updateChatDefaultBannedRights', (global, actions, payload) => { @@ -688,143 +668,136 @@ addActionHandler('updateChatDefaultBannedRights', (global, actions, payload) => void callApi('updateChatDefaultBannedRights', { chat, bannedRights }); }); -addActionHandler('updateChatMemberBannedRights', (global, actions, payload) => { +addActionHandler('updateChatMemberBannedRights', async (global, actions, payload) => { const { chatId, userId, bannedRights } = payload!; let chat = selectChat(global, chatId); const user = selectUser(global, userId); if (!chat || !user) { - return; + return undefined; } - (async () => { - if (isChatBasicGroup(chat)) { - chat = await callApi('migrateChat', chat); + if (isChatBasicGroup(chat)) { + chat = await callApi('migrateChat', chat); - if (!chat) { - return; - } - - actions.openChat({ id: chat.id }); + if (!chat) { + return undefined; } - await callApi('updateChatMemberBannedRights', { chat, user, bannedRights }); + actions.openChat({ id: chat.id }); + } - const newGlobal = getGlobal(); - const chatAfterUpdate = selectChat(newGlobal, chatId); + await callApi('updateChatMemberBannedRights', { chat, user, bannedRights }); - if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) { - return; - } + global = getGlobal(); - const { members, kickedMembers } = chatAfterUpdate.fullInfo; + const chatAfterUpdate = selectChat(global, chatId); - const isBanned = Boolean(bannedRights.viewMessages); - const isUnblocked = !Object.keys(bannedRights).length; + if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) { + return undefined; + } - setGlobal(updateChat(newGlobal, chatId, { - fullInfo: { - ...chatAfterUpdate.fullInfo, - ...(members && isBanned && { - members: members.filter((m) => m.userId !== userId), - }), - ...(members && !isBanned && { - members: members.map((m) => ( - m.userId === userId - ? { ...m, bannedRights } - : m - )), - }), - ...(isUnblocked && kickedMembers && { - kickedMembers: kickedMembers.filter((m) => m.userId !== userId), - }), - }, - })); - })(); + const { members, kickedMembers } = chatAfterUpdate.fullInfo; + + const isBanned = Boolean(bannedRights.viewMessages); + const isUnblocked = !Object.keys(bannedRights).length; + + return updateChat(global, chatId, { + fullInfo: { + ...chatAfterUpdate.fullInfo, + ...(members && isBanned && { + members: members.filter((m) => m.userId !== userId), + }), + ...(members && !isBanned && { + members: members.map((m) => ( + m.userId === userId + ? { ...m, bannedRights } + : m + )), + }), + ...(isUnblocked && kickedMembers && { + kickedMembers: kickedMembers.filter((m) => m.userId !== userId), + }), + }, + }); }); -addActionHandler('updateChatAdmin', (global, actions, payload) => { +addActionHandler('updateChatAdmin', async (global, actions, payload) => { const { chatId, userId, adminRights, customTitle, } = payload!; + let chat = selectChat(global, chatId); const user = selectUser(global, userId); - if (!chat || !user) { - return; + return undefined; } - (async () => { - if (isChatBasicGroup(chat)) { - chat = await callApi('migrateChat', chat); - - if (!chat) { - return; - } - - actions.openChat({ id: chat.id }); + if (isChatBasicGroup(chat)) { + chat = await callApi('migrateChat', chat); + if (!chat) { + return undefined; } - await callApi('updateChatAdmin', { - chat, user, adminRights, customTitle, - }); + actions.openChat({ id: chat.id }); + } - const chatAfterUpdate = await callApi('fetchFullChat', chat); - const newGlobal = getGlobal(); + await callApi('updateChatAdmin', { + chat, user, adminRights, customTitle, + }); - if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) { - return; - } + const chatAfterUpdate = await callApi('fetchFullChat', chat); + if (!chatAfterUpdate?.fullInfo) { + return undefined; + } - const { adminMembers } = chatAfterUpdate.fullInfo; + const { adminMembers } = chatAfterUpdate.fullInfo; + const isDismissed = !Object.keys(adminRights).length; - const isDismissed = !Object.keys(adminRights).length; + global = getGlobal(); - setGlobal(updateChat(newGlobal, chatId, { - fullInfo: { - ...chatAfterUpdate.fullInfo, - ...(adminMembers && isDismissed && { - adminMembers: adminMembers.filter((m) => m.userId !== userId), - }), - ...(adminMembers && !isDismissed && { - adminMembers: adminMembers.map((m) => ( - m.userId === userId - ? { ...m, adminRights, customTitle } - : m - )), - }), - }, - })); - })(); + return updateChat(global, chatId, { + fullInfo: { + ...chatAfterUpdate.fullInfo, + ...(adminMembers && isDismissed && { + adminMembers: adminMembers.filter((m) => m.userId !== userId), + }), + ...(adminMembers && !isDismissed && { + adminMembers: adminMembers.map((m) => ( + m.userId === userId + ? { ...m, adminRights, customTitle } + : m + )), + }), + }, + }); }); -addActionHandler('updateChat', (global, actions, payload) => { +addActionHandler('updateChat', async (global, actions, payload) => { const { chatId, title, about, photo, } = payload!; const chat = selectChat(global, chatId); if (!chat) { - return; + return undefined; } - (async () => { - setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.InProgress)); + setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.InProgress)); - await Promise.all([ - chat.title !== title - ? callApi('updateChatTitle', chat, title) - : undefined, - chat.fullInfo && chat.fullInfo.about !== about - ? callApi('updateChatAbout', chat, about) - : undefined, - photo - ? callApi('editChatPhoto', { chatId, accessHash: chat.accessHash, photo }) - : undefined, - ]); + await Promise.all([ + chat.title !== title + ? callApi('updateChatTitle', chat, title) + : undefined, + chat.fullInfo && chat.fullInfo.about !== about + ? callApi('updateChatAbout', chat, about) + : undefined, + photo + ? callApi('editChatPhoto', { chatId, accessHash: chat.accessHash, photo }) + : undefined, + ]); - setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.Complete)); - })(); + return updateManagementProgress(getGlobal(), ManagementProgress.Complete); }); addActionHandler('toggleSignatures', (global, actions, payload) => { @@ -838,33 +811,32 @@ addActionHandler('toggleSignatures', (global, actions, payload) => { void callApi('toggleSignatures', { chat, isEnabled }); }); -addActionHandler('loadGroupsForDiscussion', () => { - (async () => { - const groups = await callApi('fetchGroupsForDiscussion'); - if (!groups) { - return; +addActionHandler('loadGroupsForDiscussion', async (global) => { + const groups = await callApi('fetchGroupsForDiscussion'); + if (!groups) { + return undefined; + } + + const addedById = groups.reduce((result, group) => { + if (group) { + result[group.id] = group; } - const addedById = groups.reduce((result, group) => { - if (group) { - result[group.id] = group; - } + return result; + }, {} as Record); - return result; - }, {} as Record); - - const global = addChats(getGlobal(), addedById); - setGlobal({ - ...global, - chats: { - ...global.chats, - forDiscussionIds: Object.keys(addedById), - }, - }); - })(); + global = getGlobal(); + global = addChats(global, addedById); + return { + ...global, + chats: { + ...global.chats, + forDiscussionIds: Object.keys(addedById), + }, + }; }); -addActionHandler('linkDiscussionGroup', (global, actions, payload) => { +addActionHandler('linkDiscussionGroup', async (global, actions, payload) => { const { channelId, chatId } = payload!; const channel = selectChat(global, channelId); @@ -873,36 +845,34 @@ addActionHandler('linkDiscussionGroup', (global, actions, payload) => { return; } - (async () => { - if (isChatBasicGroup(chat)) { - chat = await callApi('migrateChat', chat); + if (isChatBasicGroup(chat)) { + chat = await callApi('migrateChat', chat); - if (!chat) { - return; - } - - actions.openChat({ id: chat.id }); + if (!chat) { + return; } - let { fullInfo } = chat; - if (!fullInfo) { - const fullChat = await callApi('fetchFullChat', chat); - if (!fullChat) { - return; - } + actions.openChat({ id: chat.id }); + } - fullInfo = fullChat.fullInfo; + let { fullInfo } = chat; + if (!fullInfo) { + const fullChat = await callApi('fetchFullChat', chat); + if (!fullChat) { + return; } - if (fullInfo!.isPreHistoryHidden) { - await callApi('togglePreHistoryHidden', { chat, isEnabled: false }); - } + fullInfo = fullChat.fullInfo; + } - void callApi('setDiscussionGroup', { channel, chat }); - })(); + if (fullInfo!.isPreHistoryHidden) { + await callApi('togglePreHistoryHidden', { chat, isEnabled: false }); + } + + void callApi('setDiscussionGroup', { channel, chat }); }); -addActionHandler('unlinkDiscussionGroup', (global, actions, payload) => { +addActionHandler('unlinkDiscussionGroup', async (global, actions, payload) => { const { channelId } = payload!; const channel = selectChat(global, channelId); @@ -915,12 +885,10 @@ addActionHandler('unlinkDiscussionGroup', (global, actions, payload) => { chat = selectChat(global, channel.fullInfo.linkedChatId); } - (async () => { - await callApi('setDiscussionGroup', { channel }); - if (chat) { - loadFullChat(chat); - } - })(); + await callApi('setDiscussionGroup', { channel }); + if (chat) { + loadFullChat(chat); + } }); addActionHandler('setActiveChatFolder', (global, actions, payload) => { @@ -933,33 +901,31 @@ addActionHandler('setActiveChatFolder', (global, actions, payload) => { }; }); -addActionHandler('loadMoreMembers', (global) => { - (async () => { - const { chatId } = selectCurrentMessageList(global) || {}; - const chat = chatId ? selectChat(global, chatId) : undefined; - if (!chat || isChatBasicGroup(chat)) { - return; - } +addActionHandler('loadMoreMembers', async (global) => { + const { chatId } = selectCurrentMessageList(global) || {}; + const chat = chatId ? selectChat(global, chatId) : undefined; + if (!chat || isChatBasicGroup(chat)) { + return undefined; + } - const offset = (chat.fullInfo?.members?.length) || undefined; - const result = await callApi('fetchMembers', chat.id, chat.accessHash!, 'recent', offset); - if (!result) { - return; - } + const offset = (chat.fullInfo?.members?.length) || undefined; + const result = await callApi('fetchMembers', chat.id, chat.accessHash!, 'recent', offset); + if (!result) { + return undefined; + } - const { members, users } = result; - if (!members || !members.length) { - return; - } + const { members, users } = result; + if (!members || !members.length) { + return undefined; + } - global = getGlobal(); - global = addUsers(global, buildCollectionByKey(users, 'id')); - global = addChatMembers(global, chat, members); - setGlobal(global); - })(); + global = getGlobal(); + global = addUsers(global, buildCollectionByKey(users, 'id')); + global = addChatMembers(global, chat, members); + return global; }); -addActionHandler('addChatMembers', (global, actions, payload) => { +addActionHandler('addChatMembers', async (global, actions, payload) => { const { chatId, memberIds } = payload; const chat = selectChat(global, chatId); const users = (memberIds as string[]).map((userId) => selectUser(global, userId)).filter(Boolean as any); @@ -969,14 +935,12 @@ addActionHandler('addChatMembers', (global, actions, payload) => { } actions.setNewChatMembersDialogState(NewChatMembersProgress.Loading); - (async () => { - await callApi('addChatMembers', chat, users); - actions.setNewChatMembersDialogState(NewChatMembersProgress.Closed); - loadFullChat(chat); - })(); + await callApi('addChatMembers', chat, users); + actions.setNewChatMembersDialogState(NewChatMembersProgress.Closed); + loadFullChat(chat); }); -addActionHandler('deleteChatMember', (global, actions, payload) => { +addActionHandler('deleteChatMember', async (global, actions, payload) => { const { chatId, userId } = payload; const chat = selectChat(global, chatId); const user = selectUser(global, userId); @@ -985,10 +949,8 @@ addActionHandler('deleteChatMember', (global, actions, payload) => { return; } - (async () => { - await callApi('deleteChatMember', chat, user); - loadFullChat(chat); - })(); + await callApi('deleteChatMember', chat, user); + loadFullChat(chat); }); addActionHandler('toggleIsProtected', (global, actions, payload) => { @@ -1002,20 +964,17 @@ addActionHandler('toggleIsProtected', (global, actions, payload) => { void callApi('toggleIsProtected', { chat, isProtected }); }); -addActionHandler('setChatEnabledReactions', (global, actions, payload) => { +addActionHandler('setChatEnabledReactions', async (global, actions, payload) => { const { chatId, enabledReactions } = payload; const chat = selectChat(global, chatId); - if (!chat) return; - (async () => { - await callApi('setChatEnabledReactions', { - chat, - enabledReactions, - }); + await callApi('setChatEnabledReactions', { + chat, + enabledReactions, + }); - await loadFullChat(chat); - })(); + void loadFullChat(chat); }); async function loadChats( diff --git a/src/global/actions/api/globalSearch.ts b/src/global/actions/api/globalSearch.ts index 99c360a52..6581ca3ef 100644 --- a/src/global/actions/api/globalSearch.ts +++ b/src/global/actions/api/globalSearch.ts @@ -33,7 +33,8 @@ addActionHandler('setGlobalSearchQuery', (global, actions, payload) => { addActionHandler('setGlobalSearchDate', (global, actions, payload) => { const { date } = payload!; const maxDate = date ? timestampPlusDay(date) : date; - const newGlobal = updateGlobalSearch(global, { + + global = updateGlobalSearch(global, { date, query: '', resultsByType: { @@ -45,7 +46,8 @@ addActionHandler('setGlobalSearchDate', (global, actions, payload) => { }, }, }); - setGlobal(newGlobal); + setGlobal(global); + const { chatId } = global.globalSearch; const chat = chatId ? selectChat(global, chatId) : undefined; searchMessagesGlobal('', 'text', undefined, chat, maxDate, date); diff --git a/src/global/actions/api/initial.ts b/src/global/actions/api/initial.ts index d511c41cb..cbf3dbdce 100644 --- a/src/global/actions/api/initial.ts +++ b/src/global/actions/api/initial.ts @@ -1,9 +1,6 @@ -import { - addActionHandler, getActions, getGlobal, setGlobal, -} from '../../index'; +import { addActionHandler, getActions, getGlobal } from '../../index'; import { initApi, callApi } from '../../../api/gramjs'; -import { GlobalState } from '../../types'; import { LANG_CACHE_NAME, @@ -26,22 +23,20 @@ import { } from '../../../util/sessions'; import { forceWebsync } from '../../../util/websync'; -addActionHandler('initApi', (global: GlobalState, actions) => { - (async () => { - if (!IS_TEST) { - await importLegacySession(); - void clearLegacySessions(); - } +addActionHandler('initApi', async (global, actions) => { + if (!IS_TEST) { + await importLegacySession(); + void clearLegacySessions(); + } - void initApi(actions.apiUpdate, { - userAgent: navigator.userAgent, - platform: PLATFORM_ENV, - sessionData: loadStoredSession(), - isTest: window.location.search.includes('test'), - isMovSupported: IS_MOV_SUPPORTED, - isWebmSupported: IS_WEBM_SUPPORTED, - }); - })(); + void initApi(actions.apiUpdate, { + userAgent: navigator.userAgent, + platform: PLATFORM_ENV, + sessionData: loadStoredSession(), + isTest: window.location.search.includes('test'), + isMovSupported: IS_MOV_SUPPORTED, + isWebmSupported: IS_WEBM_SUPPORTED, + }); }); addActionHandler('setAuthPhoneNumber', (global, actions, payload) => { @@ -127,18 +122,16 @@ addActionHandler('saveSession', (global, actions, payload) => { } }); -addActionHandler('signOut', () => { - (async () => { - try { - await unsubscribe(); - await callApi('destroy'); - await forceWebsync(false); - } catch (err) { - // Do nothing - } +addActionHandler('signOut', async () => { + try { + await unsubscribe(); + await callApi('destroy'); + await forceWebsync(false); + } catch (err) { + // Do nothing + } - getActions().reset(); - })(); + getActions().reset(); }); addActionHandler('reset', () => { @@ -163,38 +156,35 @@ addActionHandler('reset', () => { }); addActionHandler('disconnect', () => { - (async () => { - await callApi('disconnect'); - })(); + void callApi('disconnect'); }); -addActionHandler('loadNearestCountry', (global) => { +addActionHandler('loadNearestCountry', async (global) => { if (global.connectionState !== 'connectionStateReady') { - return; + return undefined; } - (async () => { - const authNearestCountry = await callApi('fetchNearestCountry'); + const authNearestCountry = await callApi('fetchNearestCountry'); - setGlobal({ - ...getGlobal(), - authNearestCountry, - }); - })(); + return { + ...getGlobal(), + authNearestCountry, + }; }); addActionHandler('setDeviceToken', (global, actions, deviceToken) => { - setGlobal({ + return { ...global, push: { deviceToken, subscribedAt: Date.now(), }, - }); + }; }); addActionHandler('deleteDeviceToken', (global) => { - const newGlobal = { ...global }; - delete newGlobal.push; - setGlobal(newGlobal); + return { + ...global, + push: undefined, + }; }); diff --git a/src/global/actions/api/management.ts b/src/global/actions/api/management.ts index 916315e1a..f2f36fae7 100644 --- a/src/global/actions/api/management.ts +++ b/src/global/actions/api/management.ts @@ -6,65 +6,61 @@ import { updateChat, updateManagement, updateManagementProgress } from '../../re import { selectChat, selectCurrentMessageList, selectUser } from '../../selectors'; import { isChatBasicGroup } from '../../helpers'; -addActionHandler('checkPublicLink', (global, actions, payload) => { +addActionHandler('checkPublicLink', async (global, actions, payload) => { const { chatId } = selectCurrentMessageList(global) || {}; if (!chatId) { - return; + return undefined; } // No need to check the username if already in progress if (global.management.progress === ManagementProgress.InProgress) { - return; + return undefined; } const { username } = payload!; - (async () => { - global = updateManagementProgress(global, ManagementProgress.InProgress); - global = updateManagement(global, chatId, { isUsernameAvailable: undefined }); - setGlobal(global); + global = updateManagementProgress(global, ManagementProgress.InProgress); + global = updateManagement(global, chatId, { isUsernameAvailable: undefined }); + setGlobal(global); - const isUsernameAvailable = await callApi('checkChatUsername', { username })!; + const isUsernameAvailable = await callApi('checkChatUsername', { username })!; - global = getGlobal(); - global = updateManagementProgress( - global, isUsernameAvailable ? ManagementProgress.Complete : ManagementProgress.Error, - ); - global = updateManagement(global, chatId, { isUsernameAvailable }); - setGlobal(global); - })(); + global = getGlobal(); + global = updateManagementProgress( + global, isUsernameAvailable ? ManagementProgress.Complete : ManagementProgress.Error, + ); + global = updateManagement(global, chatId, { isUsernameAvailable }); + return global; }); -addActionHandler('updatePublicLink', (global, actions, payload) => { +addActionHandler('updatePublicLink', async (global, actions, payload) => { const { chatId } = selectCurrentMessageList(global) || {}; let chat = chatId && selectChat(global, chatId); if (!chatId || !chat) { - return; + return undefined; } const { username } = payload!; - (async () => { - global = updateManagementProgress(global, ManagementProgress.InProgress); - setGlobal(global); + global = updateManagementProgress(global, ManagementProgress.InProgress); + setGlobal(global); - if (isChatBasicGroup(chat)) { - chat = await callApi('migrateChat', chat); + if (isChatBasicGroup(chat)) { + chat = await callApi('migrateChat', chat); - if (!chat) { - return; - } - - actions.openChat({ id: chat.id }); + if (!chat) { + return undefined; } - const result = await callApi('setChatUsername', { chat, username }); + actions.openChat({ id: chat.id }); + } - global = getGlobal(); - global = updateManagementProgress(global, result ? ManagementProgress.Complete : ManagementProgress.Error); - global = updateManagement(global, chatId, { isUsernameAvailable: undefined }); - setGlobal(global); - })(); + const result = await callApi('setChatUsername', { chat, username }); + + global = getGlobal(); + global = updateManagementProgress(global, result ? ManagementProgress.Complete : ManagementProgress.Error); + global = updateManagement(global, chatId, { isUsernameAvailable: undefined }); + return global; }); addActionHandler('updatePrivateLink', (global) => { @@ -91,275 +87,273 @@ addActionHandler('setOpenedInviteInfo', (global, actions, payload) => { setGlobal(updateManagement(global, chatId, update)); }); -addActionHandler('loadExportedChatInvites', (global, actions, payload) => { +addActionHandler('loadExportedChatInvites', async (global, actions, payload) => { const { chatId, adminId, isRevoked, limit, } = payload!; const peer = selectChat(global, chatId); const admin = selectUser(global, adminId || global.currentUserId); - if (!peer || !admin) return; + if (!peer || !admin) return undefined; - (async () => { - const result = await callApi('fetchExportedChatInvites', { - peer, admin, isRevoked, limit, - }); - if (!result) { - return; - } - const update = isRevoked ? { revokedInvites: result } : { invites: result }; + const result = await callApi('fetchExportedChatInvites', { + peer, admin, isRevoked, limit, + }); + if (!result) { + return undefined; + } - setGlobal(updateManagement(getGlobal(), chatId, update)); - })(); + const update = isRevoked ? { revokedInvites: result } : { invites: result }; + + return updateManagement(getGlobal(), chatId, update); }); -addActionHandler('editExportedChatInvite', (global, actions, payload) => { +addActionHandler('editExportedChatInvite', async (global, actions, payload) => { const { chatId, link, isRevoked, expireDate, usageLimit, isRequestNeeded, title, } = payload!; const peer = selectChat(global, chatId); - if (!peer) return; + if (!peer) return undefined; - (async () => { - const result = await callApi('editExportedChatInvite', { - peer, - link, - isRevoked, - expireDate, - usageLimit, - isRequestNeeded, - title, - }); - if (!result) { - return; - } - global = getGlobal(); - let invites = global.management.byChatId[chatId].invites || []; - const revokedInvites = global.management.byChatId[chatId].revokedInvites || []; - const { oldInvite, newInvite } = result; - invites = invites.filter((current) => current.link !== oldInvite.link); - if (newInvite.isRevoked) { - revokedInvites.unshift(newInvite); - } else { - invites.push(newInvite); - } - setGlobal(updateManagement(global, chatId, { - invites, - revokedInvites, - })); - })(); + const result = await callApi('editExportedChatInvite', { + peer, + link, + isRevoked, + expireDate, + usageLimit, + isRequestNeeded, + title, + }); + if (!result) { + return undefined; + } + + const { oldInvite, newInvite } = result; + + global = getGlobal(); + const invites = (global.management.byChatId[chatId].invites || []) + .filter((current) => current.link !== oldInvite.link); + const revokedInvites = [...(global.management.byChatId[chatId].revokedInvites || [])]; + + if (newInvite.isRevoked) { + revokedInvites.unshift(newInvite); + } else { + invites.push(newInvite); + } + + return updateManagement(global, chatId, { + invites, + revokedInvites, + }); }); -addActionHandler('exportChatInvite', (global, actions, payload) => { +addActionHandler('exportChatInvite', async (global, actions, payload) => { const { chatId, expireDate, usageLimit, isRequestNeeded, title, } = payload!; const peer = selectChat(global, chatId); - if (!peer) return; + if (!peer) return undefined; - (async () => { - const result = await callApi('exportChatInvite', { - peer, - expireDate, - usageLimit, - isRequestNeeded, - title, - }); - if (!result) { - return; - } - global = getGlobal(); - const invites = global.management.byChatId[chatId].invites || []; - setGlobal(updateManagement(global, chatId, { - invites: [...invites, result], - })); - })(); + const result = await callApi('exportChatInvite', { + peer, + expireDate, + usageLimit, + isRequestNeeded, + title, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + const invites = global.management.byChatId[chatId].invites || []; + return updateManagement(global, chatId, { + invites: [...invites, result], + }); }); -addActionHandler('deleteExportedChatInvite', (global, actions, payload) => { +addActionHandler('deleteExportedChatInvite', async (global, actions, payload) => { const { chatId, link, } = payload!; const peer = selectChat(global, chatId); - if (!peer) return; + if (!peer) return undefined; - (async () => { - const result = await callApi('deleteExportedChatInvite', { - peer, - link, - }); - if (!result) { - return; - } - global = getGlobal(); - const managementState = global.management.byChatId[chatId]; - setGlobal(updateManagement(global, chatId, { - invites: managementState?.invites?.filter((invite) => invite.link !== link), - revokedInvites: managementState?.revokedInvites?.filter((invite) => invite.link !== link), - })); - })(); + const result = await callApi('deleteExportedChatInvite', { + peer, + link, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + const managementState = global.management.byChatId[chatId]; + return updateManagement(global, chatId, { + invites: managementState?.invites?.filter((invite) => invite.link !== link), + revokedInvites: managementState?.revokedInvites?.filter((invite) => invite.link !== link), + }); }); -addActionHandler('deleteRevokedExportedChatInvites', (global, actions, payload) => { +addActionHandler('deleteRevokedExportedChatInvites', async (global, actions, payload) => { const { chatId, adminId, } = payload!; const peer = selectChat(global, chatId); const admin = selectUser(global, adminId || global.currentUserId); - if (!peer || !admin) return; + if (!peer || !admin) return undefined; - (async () => { - const result = await callApi('deleteRevokedExportedChatInvites', { - peer, - admin, - }); - if (!result) { - return; - } - global = getGlobal(); - setGlobal(updateManagement(global, chatId, { - revokedInvites: [], - })); - })(); + const result = await callApi('deleteRevokedExportedChatInvites', { + peer, + admin, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + return updateManagement(global, chatId, { + revokedInvites: [], + }); }); -addActionHandler('loadChatInviteImporters', (global, actions, payload) => { +addActionHandler('loadChatInviteImporters', async (global, actions, payload) => { const { chatId, link, offsetDate, offsetUserId, limit, } = payload!; const peer = selectChat(global, chatId); const offsetUser = selectUser(global, offsetUserId); - if (!peer || (offsetUserId && !offsetUser)) return; + if (!peer || (offsetUserId && !offsetUser)) return undefined; - (async () => { - const result = await callApi('fetchChatInviteImporters', { - peer, - link, - offsetDate, - offsetUser, - limit, - }); - if (!result) { - return; - } - global = getGlobal(); - const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo; - if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) return; - setGlobal(updateManagement(global, chatId, { - inviteInfo: { - ...currentInviteInfo, - importers: result, - }, - })); - })(); + const result = await callApi('fetchChatInviteImporters', { + peer, + link, + offsetDate, + offsetUser, + limit, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo; + if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) { + return undefined; + } + + return updateManagement(global, chatId, { + inviteInfo: { + ...currentInviteInfo, + importers: result, + }, + }); }); -addActionHandler('loadChatInviteRequesters', (global, actions, payload) => { +addActionHandler('loadChatInviteRequesters', async (global, actions, payload) => { const { chatId, link, offsetDate, offsetUserId, limit, } = payload!; const peer = selectChat(global, chatId); const offsetUser = selectUser(global, offsetUserId); - if (!peer || (offsetUserId && !offsetUser)) return; + if (!peer || (offsetUserId && !offsetUser)) return undefined; - (async () => { - const result = await callApi('fetchChatInviteImporters', { - peer, - link, - offsetDate, - offsetUser, - limit, - isRequested: true, - }); - if (!result) { - return; - } - global = getGlobal(); - const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo; - if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) return; - setGlobal(updateManagement(global, chatId, { - inviteInfo: { - ...currentInviteInfo, - requesters: result, - }, - })); - })(); + const result = await callApi('fetchChatInviteImporters', { + peer, + link, + offsetDate, + offsetUser, + limit, + isRequested: true, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo; + if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) { + return undefined; + } + + return updateManagement(global, chatId, { + inviteInfo: { + ...currentInviteInfo, + requesters: result, + }, + }); }); -addActionHandler('loadChatJoinRequests', (global, actions, payload) => { +addActionHandler('loadChatJoinRequests', async (global, actions, payload) => { const { chatId, offsetDate, offsetUserId, limit, } = payload!; const peer = selectChat(global, chatId); const offsetUser = selectUser(global, offsetUserId); - if (!peer || (offsetUserId && !offsetUser)) return; + if (!peer || (offsetUserId && !offsetUser)) return undefined; - (async () => { - const result = await callApi('fetchChatInviteImporters', { - peer, - offsetDate, - offsetUser, - limit, - isRequested: true, - }); - if (!result) { - return; - } - global = getGlobal(); - setGlobal(updateChat(global, chatId, { joinRequests: result })); - })(); + const result = await callApi('fetchChatInviteImporters', { + peer, + offsetDate, + offsetUser, + limit, + isRequested: true, + }); + if (!result) { + return undefined; + } + + global = getGlobal(); + return updateChat(global, chatId, { joinRequests: result }); }); -addActionHandler('hideChatJoinRequest', (global, actions, payload) => { +addActionHandler('hideChatJoinRequest', async (global, actions, payload) => { const { chatId, userId, isApproved, } = payload!; const peer = selectChat(global, chatId); const user = selectUser(global, userId); - if (!peer || !user) return; + if (!peer || !user) return undefined; - (async () => { - const result = await callApi('hideChatJoinRequest', { - peer, - user, - isApproved, - }); + const result = await callApi('hideChatJoinRequest', { + peer, + user, + isApproved, + }); + if (!result) return undefined; - if (!result) return; - global = getGlobal(); - const targetChat = selectChat(global, chatId); - if (!targetChat) return; - setGlobal(updateChat(global, chatId, { - joinRequests: targetChat.joinRequests?.filter((importer) => importer.userId !== userId), - })); - })(); + global = getGlobal(); + const targetChat = selectChat(global, chatId); + if (!targetChat) return undefined; + + return updateChat(global, chatId, { + joinRequests: targetChat.joinRequests?.filter((importer) => importer.userId !== userId), + }); }); -addActionHandler('hideAllChatJoinRequests', (global, actions, payload) => { +addActionHandler('hideAllChatJoinRequests', async (global, actions, payload) => { const { chatId, isApproved, link, } = payload!; const peer = selectChat(global, chatId); - if (!peer) return; + if (!peer) return undefined; - (async () => { - const result = await callApi('hideAllChatJoinRequests', { - peer, - isApproved, - link, - }); + const result = await callApi('hideAllChatJoinRequests', { + peer, + isApproved, + link, + }); + if (!result) return undefined; - if (!result) return; - global = getGlobal(); - const targetChat = selectChat(global, chatId); - if (!targetChat) return; + global = getGlobal(); + const targetChat = selectChat(global, chatId); + if (!targetChat) return undefined; - setGlobal(updateChat(global, chatId, { - joinRequests: [], - fullInfo: { - ...targetChat.fullInfo, - recentRequesterIds: [], - requestsPending: 0, - }, - })); - })(); + return updateChat(global, chatId, { + joinRequests: [], + fullInfo: { + ...targetChat.fullInfo, + recentRequesterIds: [], + requestsPending: 0, + }, + }); }); diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index 338de5f1e..6bd6e9fec 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -157,30 +157,30 @@ async function loadWithBudget( } } -addActionHandler('loadMessage', (global, actions, payload) => { +addActionHandler('loadMessage', async (global, actions, payload) => { const { chatId, messageId, replyOriginForId, threadUpdate, } = payload!; - const chat = selectChat(global, chatId); + const chat = selectChat(global, chatId); if (!chat) { - return; + return undefined; } - (async () => { - const message = await loadMessage(chat, messageId, replyOriginForId); - if (message && threadUpdate) { - const { lastMessageId, isDeleting } = threadUpdate; + const message = await loadMessage(chat, messageId, replyOriginForId); + if (message && threadUpdate) { + const { lastMessageId, isDeleting } = threadUpdate; - setGlobal(updateThreadUnreadFromForwardedMessage( - getGlobal(), - message, - chatId, - lastMessageId, - isDeleting, - )); - } - })(); + return updateThreadUnreadFromForwardedMessage( + getGlobal(), + message, + chatId, + lastMessageId, + isDeleting, + ); + } + + return undefined; }); addActionHandler('sendMessage', (global, actions, payload) => { @@ -425,62 +425,56 @@ addActionHandler('deleteScheduledMessages', (global, actions, payload) => { } }); -addActionHandler('deleteHistory', (global, actions, payload) => { - (async () => { - const { chatId, shouldDeleteForAll } = payload!; - const chat = selectChat(global, chatId); - if (!chat) { - return; - } +addActionHandler('deleteHistory', async (global, actions, payload) => { + const { chatId, shouldDeleteForAll } = payload!; + const chat = selectChat(global, chatId); + if (!chat) { + return; + } - const maxId = chat.lastMessage?.id; + const maxId = chat.lastMessage?.id; - await callApi('deleteHistory', { chat, shouldDeleteForAll, maxId }); + await callApi('deleteHistory', { chat, shouldDeleteForAll, maxId }); - const activeChat = selectCurrentMessageList(global); - if (activeChat && activeChat.chatId === chatId) { - actions.openChat({ id: undefined }); - } - })(); + const activeChat = selectCurrentMessageList(global); + if (activeChat && activeChat.chatId === chatId) { + actions.openChat({ id: undefined }); + } }); -addActionHandler('reportMessages', (global, actions, payload) => { - (async () => { - const { - messageIds, reason, description, - } = payload!; - const currentMessageList = selectCurrentMessageList(global); - if (!currentMessageList) { - return; - } +addActionHandler('reportMessages', async (global, actions, payload) => { + const { + messageIds, reason, description, + } = payload!; + const currentMessageList = selectCurrentMessageList(global); + if (!currentMessageList) { + return; + } - const { chatId } = currentMessageList; - const chat = selectChat(global, chatId)!; + const { chatId } = currentMessageList; + const chat = selectChat(global, chatId)!; - const result = await callApi('reportMessages', { - peer: chat, messageIds, reason, description, - }); + const result = await callApi('reportMessages', { + peer: chat, messageIds, reason, description, + }); - actions.showNotification({ - message: result - ? 'Thank you! Your report will be reviewed by our team.' - : 'Error occured while submiting report. Please, try again later.', - }); - })(); + actions.showNotification({ + message: result + ? 'Thank you! Your report will be reviewed by our team.' + : 'Error occured while submiting report. Please, try again later.', + }); }); -addActionHandler('sendMessageAction', (global, actions, payload) => { - (async () => { - const { action, chatId, threadId } = payload!; - if (chatId === global.currentUserId) return; // Message actions are disabled in Saved Messages +addActionHandler('sendMessageAction', async (global, actions, payload) => { + const { action, chatId, threadId } = payload!; + if (chatId === global.currentUserId) return; // Message actions are disabled in Saved Messages - const chat = selectChat(global, chatId)!; - if (!chat) return; + const chat = selectChat(global, chatId)!; + if (!chat) return; - await callApi('sendMessageAction', { - peer: chat, threadId, action, - }); - })(); + await callApi('sendMessageAction', { + peer: chat, threadId, action, + }); }); addActionHandler('markMessageListRead', (global, actions, payload) => { @@ -960,23 +954,21 @@ addActionHandler('loadPinnedMessages', (global, actions, payload) => { void loadPinnedMessages(chat); }); -addActionHandler('loadSeenBy', (global, actions, payload) => { +addActionHandler('loadSeenBy', async (global, actions, payload) => { const { chatId, messageId } = payload; const chat = selectChat(global, chatId); if (!chat) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchSeenBy', { chat, messageId }); - if (!result) { - return; - } + const result = await callApi('fetchSeenBy', { chat, messageId }); + if (!result) { + return undefined; + } - setGlobal(updateChatMessage(getGlobal(), chatId, messageId, { - seenByUserIds: result, - })); - })(); + return updateChatMessage(getGlobal(), chatId, messageId, { + seenByUserIds: result, + }); }); addActionHandler('saveDefaultSendAs', (global, actions, payload) => { @@ -997,31 +989,25 @@ addActionHandler('saveDefaultSendAs', (global, actions, payload) => { }); }); -addActionHandler('loadSendAs', (global, actions, payload) => { +addActionHandler('loadSendAs', async (global, actions, payload) => { const { chatId } = payload; const chat = selectChat(global, chatId); if (!chat) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchSendAs', { chat }); - if (!result) { - global = updateChat(global, chatId, { - sendAsIds: [], - }); - setGlobal(global); - return; - } - - global = getGlobal(); - global = addUsers(global, buildCollectionByKey(result.users, 'id')); - global = addChats(global, buildCollectionByKey(result.chats, 'id')); - global = updateChat(global, chatId, { - sendAsIds: result.ids, + const result = await callApi('fetchSendAs', { chat }); + if (!result) { + return updateChat(getGlobal(), chatId, { + sendAsIds: [], }); - setGlobal(global); - })(); + } + + global = getGlobal(); + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + global = addChats(global, buildCollectionByKey(result.chats, 'id')); + global = updateChat(global, chatId, { sendAsIds: result.ids }); + return global; }); async function loadPinnedMessages(chat: ApiChat) { @@ -1060,25 +1046,23 @@ async function loadScheduledHistory(chat: ApiChat) { setGlobal(global); } -addActionHandler('loadSponsoredMessages', (global, actions, payload) => { +addActionHandler('loadSponsoredMessages', async (global, actions, payload) => { const { chatId } = payload; const chat = selectChat(global, chatId); if (!chat) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchSponsoredMessages', { chat }); - if (!result) { - return; - } + const result = await callApi('fetchSponsoredMessages', { chat }); + if (!result) { + return undefined; + } - let newGlobal = updateSponsoredMessage(getGlobal(), chatId, result.messages[0]); - newGlobal = addUsers(newGlobal, buildCollectionByKey(result.users, 'id')); - newGlobal = addChats(newGlobal, buildCollectionByKey(result.chats, 'id')); - - setGlobal(newGlobal); - })(); + global = getGlobal(); + global = updateSponsoredMessage(global, chatId, result.messages[0]); + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + global = addChats(global, buildCollectionByKey(result.chats, 'id')); + return global; }); addActionHandler('viewSponsoredMessage', (global, actions, payload) => { diff --git a/src/global/actions/api/reactions.ts b/src/global/actions/api/reactions.ts index d333a435a..5c9ef0e1c 100644 --- a/src/global/actions/api/reactions.ts +++ b/src/global/actions/api/reactions.ts @@ -1,4 +1,4 @@ -import { addActionHandler, getGlobal, setGlobal } from '../../index'; +import { addActionHandler, getGlobal } from '../../index'; import { callApi } from '../../../api/gramjs'; import * as mediaLoader from '../../../util/mediaLoader'; import { ApiAppConfig, ApiMediaFormat } from '../../../api/types'; @@ -19,29 +19,26 @@ const INTERACTION_RANDOM_OFFSET = 40; let interactionLocalId = 0; -addActionHandler('loadAvailableReactions', () => { - (async () => { - const result = await callApi('getAvailableReactions'); +addActionHandler('loadAvailableReactions', async () => { + const result = await callApi('getAvailableReactions'); + if (!result) { + return undefined; + } - if (!result) { - return; + // Preload animations + result.forEach((availableReaction) => { + if (availableReaction.aroundAnimation) { + mediaLoader.fetch(`sticker${availableReaction.aroundAnimation.id}`, ApiMediaFormat.Lottie); } + if (availableReaction.centerIcon) { + mediaLoader.fetch(`sticker${availableReaction.centerIcon.id}`, ApiMediaFormat.Lottie); + } + }); - // Preload animations - result.forEach((availableReaction) => { - if (availableReaction.aroundAnimation) { - mediaLoader.fetch(`sticker${availableReaction.aroundAnimation.id}`, ApiMediaFormat.Lottie); - } - if (availableReaction.centerIcon) { - mediaLoader.fetch(`sticker${availableReaction.centerIcon.id}`, ApiMediaFormat.Lottie); - } - }); - - setGlobal({ - ...getGlobal(), - availableReactions: result, - }); - })(); + return { + ...getGlobal(), + availableReactions: result, + }; }); addActionHandler('interactWithAnimatedEmoji', (global, actions, payload) => { @@ -196,25 +193,21 @@ addActionHandler('stopActiveReaction', (global, actions, payload) => { }; }); -addActionHandler('setDefaultReaction', (global, actions, payload) => { +addActionHandler('setDefaultReaction', async (global, actions, payload) => { const { reaction } = payload; - (async () => { - const result = await callApi('setDefaultReaction', { reaction }); + const result = await callApi('setDefaultReaction', { reaction }); + if (!result) { + return undefined; + } - if (!result) { - return; - } - - global = getGlobal(); - setGlobal({ - ...global, - appConfig: { - ...global.appConfig, - defaultReaction: reaction, - } as ApiAppConfig, - }); - })(); + return { + ...getGlobal(), + appConfig: { + ...global.appConfig, + defaultReaction: reaction, + } as ApiAppConfig, + }; }); addActionHandler('stopActiveEmojiInteraction', (global, actions, payload) => { @@ -226,46 +219,44 @@ addActionHandler('stopActiveEmojiInteraction', (global, actions, payload) => { }; }); -addActionHandler('loadReactors', (global, actions, payload) => { +addActionHandler('loadReactors', async (global, actions, payload) => { const { chatId, messageId, reaction } = payload; const chat = selectChat(global, chatId); const message = selectChatMessage(global, chatId, messageId); if (!chat || !message) { - return; + return undefined; } const offset = message.reactors?.nextOffset; + const result = await callApi('fetchMessageReactionsList', { + reaction, + chat, + messageId, + offset, + }); - (async () => { - const result = await callApi('fetchMessageReactionsList', { - reaction, - chat, - messageId, - offset, - }); + if (!result) { + return undefined; + } - if (!result) { - return; - } + global = getGlobal(); - global = getGlobal(); - if (result.users?.length) { - global = addUsers(global, buildCollectionByKey(result.users, 'id')); - } + if (result.users?.length) { + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + } - const { nextOffset, count, reactions } = result; + const { nextOffset, count, reactions } = result; - setGlobal(updateChatMessage(global, chatId, messageId, { - reactors: { - nextOffset, - count, - reactions: [ - ...(message.reactors?.reactions || []), - ...reactions, - ], - }, - })); - })(); + return updateChatMessage(global, chatId, messageId, { + reactors: { + nextOffset, + count, + reactions: [ + ...(message.reactors?.reactions || []), + ...reactions, + ], + }, + }); }); addActionHandler('loadMessageReactions', (global, actions, payload) => { diff --git a/src/global/actions/api/settings.ts b/src/global/actions/api/settings.ts index 01fa8afea..7a6647a4b 100644 --- a/src/global/actions/api/settings.ts +++ b/src/global/actions/api/settings.ts @@ -18,116 +18,110 @@ import { } from '../../reducers'; import { isUserId } from '../../helpers'; -addActionHandler('updateProfile', (global, actions, payload) => { +addActionHandler('updateProfile', async (global, actions, payload) => { const { photo, firstName, lastName, bio: about, username, } = payload!; - (async () => { - const { currentUserId } = global; - if (!currentUserId) { - return; - } + const { currentUserId } = global; + if (!currentUserId) { + return undefined; + } - setGlobal({ - ...getGlobal(), - profileEdit: { - progress: ProfileEditProgress.InProgress, - }, - }); + setGlobal({ + ...getGlobal(), + profileEdit: { + progress: ProfileEditProgress.InProgress, + }, + }); - if (photo) { - await callApi('updateProfilePhoto', photo); - } + if (photo) { + await callApi('updateProfilePhoto', photo); + } - if (firstName || lastName || about) { - const result = await callApi('updateProfile', { firstName, lastName, about }); - if (result) { - global = getGlobal(); - const currentUser = currentUserId && selectUser(global, currentUserId); + if (firstName || lastName || about) { + const result = await callApi('updateProfile', { firstName, lastName, about }); + if (result) { + global = getGlobal(); + const currentUser = currentUserId && selectUser(global, currentUserId); - if (currentUser) { - setGlobal(updateUser( - global, - currentUser.id, - { - firstName, - lastName, - fullInfo: { - ...currentUser.fullInfo, - bio: about, - }, + if (currentUser) { + setGlobal(updateUser( + global, + currentUser.id, + { + firstName, + lastName, + fullInfo: { + ...currentUser.fullInfo, + bio: about, }, - )); - } + }, + )); } } + } - if (username) { - const result = await callApi('updateUsername', username); - if (result && currentUserId) { - setGlobal(updateUser(getGlobal(), currentUserId, { username })); - } + if (username) { + const result = await callApi('updateUsername', username); + if (result && currentUserId) { + setGlobal(updateUser(getGlobal(), currentUserId, { username })); } + } - setGlobal({ - ...getGlobal(), - profileEdit: { - progress: ProfileEditProgress.Complete, - }, - }); - })(); + return { + ...getGlobal(), + profileEdit: { + progress: ProfileEditProgress.Complete, + }, + }; }); -addActionHandler('checkUsername', (global, actions, payload) => { +addActionHandler('checkUsername', async (global, actions, payload) => { const { username } = payload!; - (async () => { - // No need to check the username if profile update is already in progress - if (global.profileEdit && global.profileEdit.progress === ProfileEditProgress.InProgress) { - return; - } + // No need to check the username if profile update is already in progress + if (global.profileEdit && global.profileEdit.progress === ProfileEditProgress.InProgress) { + return undefined; + } - setGlobal({ - ...global, - profileEdit: { - progress: global.profileEdit ? global.profileEdit.progress : ProfileEditProgress.Idle, - isUsernameAvailable: undefined, - }, - }); + setGlobal({ + ...global, + profileEdit: { + progress: global.profileEdit ? global.profileEdit.progress : ProfileEditProgress.Idle, + isUsernameAvailable: undefined, + }, + }); - const isUsernameAvailable = await callApi('checkUsername', username); + const isUsernameAvailable = await callApi('checkUsername', username); - global = getGlobal(); - setGlobal({ - ...global, - profileEdit: { - ...global.profileEdit!, - isUsernameAvailable, - }, - }); - })(); + global = getGlobal(); + return { + ...global, + profileEdit: { + ...global.profileEdit!, + isUsernameAvailable, + }, + }; }); -addActionHandler('loadWallpapers', () => { - (async () => { - const result = await callApi('fetchWallpapers'); - if (!result) { - return; - } +addActionHandler('loadWallpapers', async () => { + const result = await callApi('fetchWallpapers'); + if (!result) { + return undefined; + } - const global = getGlobal(); - setGlobal({ - ...global, - settings: { - ...global.settings, - loadedWallpapers: result.wallpapers, - }, - }); - })(); + const global = getGlobal(); + return { + ...global, + settings: { + ...global.settings, + loadedWallpapers: result.wallpapers, + }, + }; }); -addActionHandler('uploadWallpaper', (global, actions, payload) => { +addActionHandler('uploadWallpaper', async (global, actions, payload) => { const file = payload; const previewBlobUrl = URL.createObjectURL(file); @@ -150,91 +144,82 @@ addActionHandler('uploadWallpaper', (global, actions, payload) => { }, }); - (async () => { - const result = await callApi('uploadWallpaper', file); - if (!result) { - return; - } + const result = await callApi('uploadWallpaper', file); + if (!result) { + return undefined; + } - const { wallpaper } = result; + const { wallpaper } = result; - global = getGlobal(); - if (!global.settings.loadedWallpapers) { - return; - } + global = getGlobal(); + if (!global.settings.loadedWallpapers) { + return undefined; + } - const firstWallpaper = global.settings.loadedWallpapers[0]; - if (!firstWallpaper || firstWallpaper.slug !== UPLOADING_WALLPAPER_SLUG) { - return; - } + const firstWallpaper = global.settings.loadedWallpapers[0]; + if (!firstWallpaper || firstWallpaper.slug !== UPLOADING_WALLPAPER_SLUG) { + return undefined; + } - const withLocalMedia = { - ...wallpaper, - document: { - ...wallpaper.document, - previewBlobUrl, - }, - }; + const withLocalMedia = { + ...wallpaper, + document: { + ...wallpaper.document, + previewBlobUrl, + }, + }; - setGlobal({ - ...global, - settings: { - ...global.settings, - loadedWallpapers: [ - withLocalMedia, - ...global.settings.loadedWallpapers.slice(1), - ], - }, - }); - })(); + return { + ...global, + settings: { + ...global.settings, + loadedWallpapers: [ + withLocalMedia, + ...global.settings.loadedWallpapers.slice(1), + ], + }, + }; }); -addActionHandler('loadBlockedContacts', () => { - (async () => { - const result = await callApi('fetchBlockedContacts'); +addActionHandler('loadBlockedContacts', async (global) => { + const result = await callApi('fetchBlockedContacts'); + if (!result) { + return undefined; + } - if (!result) { - return; - } + global = getGlobal(); - let newGlobal = getGlobal(); + if (result.users?.length) { + global = addUsers(global, buildCollectionByKey(result.users, 'id')); + } + if (result.chats?.length) { + global = updateChats(global, buildCollectionByKey(result.chats, 'id')); + } - if (result.users?.length) { - newGlobal = addUsers(newGlobal, buildCollectionByKey(result.users, 'id')); - } - if (result.chats?.length) { - newGlobal = updateChats(newGlobal, buildCollectionByKey(result.chats, 'id')); - } + global = { + ...global, + blocked: { + ...global.blocked, + ids: [...(global.blocked.ids || []), ...result.blockedIds], + totalCount: result.totalCount, + }, + }; - newGlobal = { - ...newGlobal, - blocked: { - ...newGlobal.blocked, - ids: [...(newGlobal.blocked.ids || []), ...result.blockedIds], - totalCount: result.totalCount, - }, - }; - - setGlobal(newGlobal); - })(); + return global; }); -addActionHandler('blockContact', (global, actions, payload) => { +addActionHandler('blockContact', async (global, actions, payload) => { const { contactId, accessHash } = payload!; - (async () => { - const result = await callApi('blockContact', contactId, accessHash); - if (!result) { - return; - } + const result = await callApi('blockContact', contactId, accessHash); + if (!result) { + return undefined; + } - const newGlobal = getGlobal(); - - setGlobal(addBlockedContact(newGlobal, contactId)); - })(); + return addBlockedContact(getGlobal(), contactId); }); -addActionHandler('unblockContact', (global, actions, payload) => { +addActionHandler('unblockContact', async (global, actions, payload) => { const { contactId } = payload!; let accessHash: string | undefined; const isPrivate = isUserId(contactId); @@ -242,181 +227,156 @@ addActionHandler('unblockContact', (global, actions, payload) => { if (isPrivate) { const user = selectUser(global, contactId); if (!user) { - return; + return undefined; } accessHash = user.accessHash; } - (async () => { - const result = await callApi('unblockContact', contactId, accessHash); - if (!result) { - return; - } + const result = await callApi('unblockContact', contactId, accessHash); + if (!result) { + return undefined; + } - const newGlobal = getGlobal(); - - setGlobal(removeBlockedContact(newGlobal, contactId)); - })(); + return removeBlockedContact(getGlobal(), contactId); }); -addActionHandler('loadAuthorizations', () => { - (async () => { - const result = await callApi('fetchAuthorizations'); - if (!result) { - return; - } +addActionHandler('loadAuthorizations', async () => { + const result = await callApi('fetchAuthorizations'); + if (!result) { + return undefined; + } - setGlobal({ - ...getGlobal(), - activeSessions: result, - }); - })(); + return { + ...getGlobal(), + activeSessions: result, + }; }); -addActionHandler('terminateAuthorization', (global, actions, payload) => { +addActionHandler('terminateAuthorization', async (global, actions, payload) => { const { hash } = payload!; - (async () => { - const result = await callApi('terminateAuthorization', hash); - if (!result) { - return; - } + const result = await callApi('terminateAuthorization', hash); + if (!result) { + return undefined; + } - const newGlobal = getGlobal(); + global = getGlobal(); - setGlobal({ - ...newGlobal, - activeSessions: newGlobal.activeSessions.filter((session) => session.hash !== hash), - }); - })(); + return { + ...global, + activeSessions: global.activeSessions.filter((session) => session.hash !== hash), + }; }); -addActionHandler('terminateAllAuthorizations', () => { - (async () => { - const result = await callApi('terminateAllAuthorizations'); - if (!result) { - return; - } +addActionHandler('terminateAllAuthorizations', async (global) => { + const result = await callApi('terminateAllAuthorizations'); + if (!result) { + return undefined; + } - const global = getGlobal(); + global = getGlobal(); - setGlobal({ - ...global, - activeSessions: global.activeSessions.filter((session) => session.isCurrent), - }); - })(); + return { + ...global, + activeSessions: global.activeSessions.filter((session) => session.isCurrent), + }; }); -addActionHandler('loadNotificationExceptions', (global) => { +addActionHandler('loadNotificationExceptions', async (global) => { const { serverTimeOffset } = global; - (async () => { - const result = await callApi('fetchNotificationExceptions', { serverTimeOffset }); - if (!result) { - return; - } + const result = await callApi('fetchNotificationExceptions', { serverTimeOffset }); + if (!result) { + return undefined; + } - setGlobal(addNotifyExceptions(getGlobal(), result)); - })(); + return addNotifyExceptions(getGlobal(), result); }); -addActionHandler('loadNotificationSettings', (global) => { +addActionHandler('loadNotificationSettings', async (global) => { const { serverTimeOffset } = global; - (async () => { - const result = await callApi('fetchNotificationSettings', { - serverTimeOffset, - }); - if (!result) { - return; - } + const result = await callApi('fetchNotificationSettings', { + serverTimeOffset, + }); + if (!result) { + return undefined; + } - setGlobal(replaceSettings(getGlobal(), result)); - })(); + return replaceSettings(getGlobal(), result); }); -addActionHandler('updateNotificationSettings', (global, actions, payload) => { +addActionHandler('updateNotificationSettings', async (global, actions, payload) => { const { peerType, isSilent, shouldShowPreviews } = payload!; - (async () => { - const result = await callApi('updateNotificationSettings', peerType, { isSilent, shouldShowPreviews }); + const result = await callApi('updateNotificationSettings', peerType, { isSilent, shouldShowPreviews }); + if (!result) { + return undefined; + } - if (!result) { - return; - } - - setGlobal(updateNotifySettings(getGlobal(), peerType, isSilent, shouldShowPreviews)); - })(); + return updateNotifySettings(getGlobal(), peerType, isSilent, shouldShowPreviews); }); addActionHandler('updateWebNotificationSettings', (global, actions, payload) => { - (async () => { - setGlobal(replaceSettings(getGlobal(), payload)); - const newGlobal = getGlobal(); - const { hasPushNotifications, hasWebNotifications } = newGlobal.settings.byKey; - if (hasWebNotifications && hasPushNotifications) { - await subscribe(); - } else { - await unsubscribe(); - } - })(); + setGlobal(replaceSettings(global, payload)); + + const { hasPushNotifications, hasWebNotifications } = global.settings.byKey; + if (hasWebNotifications && hasPushNotifications) { + void subscribe(); + } else { + void unsubscribe(); + } }); -addActionHandler('updateContactSignUpNotification', (global, actions, payload) => { +addActionHandler('updateContactSignUpNotification', async (global, actions, payload) => { const { isSilent } = payload!; - (async () => { - const result = await callApi('updateContactSignUpNotification', isSilent); - if (!result) { - return; - } + const result = await callApi('updateContactSignUpNotification', isSilent); + if (!result) { + return undefined; + } - setGlobal(replaceSettings(getGlobal(), { hasContactJoinedNotifications: !isSilent })); - })(); + return replaceSettings(getGlobal(), { hasContactJoinedNotifications: !isSilent }); }); -addActionHandler('loadLanguages', () => { - (async () => { - const result = await callApi('fetchLanguages'); - if (!result) { - return; - } +addActionHandler('loadLanguages', async () => { + const result = await callApi('fetchLanguages'); + if (!result) { + return undefined; + } - setGlobal(replaceSettings(getGlobal(), { languages: result })); - })(); + return replaceSettings(getGlobal(), { languages: result }); }); -addActionHandler('loadPrivacySettings', () => { - (async () => { - const [ - phoneNumberSettings, lastSeenSettings, profilePhotoSettings, forwardsSettings, chatInviteSettings, - ] = await Promise.all([ - callApi('fetchPrivacySettings', 'phoneNumber'), - callApi('fetchPrivacySettings', 'lastSeen'), - callApi('fetchPrivacySettings', 'profilePhoto'), - callApi('fetchPrivacySettings', 'forwards'), - callApi('fetchPrivacySettings', 'chatInvite'), - ]); +addActionHandler('loadPrivacySettings', async (global) => { + const [ + phoneNumberSettings, lastSeenSettings, profilePhotoSettings, forwardsSettings, chatInviteSettings, + ] = await Promise.all([ + callApi('fetchPrivacySettings', 'phoneNumber'), + callApi('fetchPrivacySettings', 'lastSeen'), + callApi('fetchPrivacySettings', 'profilePhoto'), + callApi('fetchPrivacySettings', 'forwards'), + callApi('fetchPrivacySettings', 'chatInvite'), + ]); - if ( - !phoneNumberSettings || !lastSeenSettings || !profilePhotoSettings || !forwardsSettings || !chatInviteSettings - ) { - return; - } + if ( + !phoneNumberSettings || !lastSeenSettings || !profilePhotoSettings || !forwardsSettings || !chatInviteSettings + ) { + return undefined; + } - const global = getGlobal(); + global = getGlobal(); - global.settings.privacy.phoneNumber = phoneNumberSettings; - global.settings.privacy.lastSeen = lastSeenSettings; - global.settings.privacy.profilePhoto = profilePhotoSettings; - global.settings.privacy.forwards = forwardsSettings; - global.settings.privacy.chatInvite = chatInviteSettings; + global.settings.privacy.phoneNumber = phoneNumberSettings; + global.settings.privacy.lastSeen = lastSeenSettings; + global.settings.privacy.profilePhoto = profilePhotoSettings; + global.settings.privacy.forwards = forwardsSettings; + global.settings.privacy.chatInvite = chatInviteSettings; - setGlobal(global); - })(); + return global; }); -addActionHandler('setPrivacyVisibility', (global, actions, payload) => { +addActionHandler('setPrivacyVisibility', async (global, actions, payload) => { const { privacyKey, visibility } = payload!; const { @@ -424,7 +384,7 @@ addActionHandler('setPrivacyVisibility', (global, actions, payload) => { } = global.settings; if (!settings) { - return; + return undefined; } const rules = buildInputPrivacyRules(global, { @@ -433,27 +393,33 @@ addActionHandler('setPrivacyVisibility', (global, actions, payload) => { deniedIds: [...settings.blockUserIds, ...settings.blockChatIds], }); - (async () => { - const result = await callApi('setPrivacySettings', privacyKey, rules); + const result = await callApi('setPrivacySettings', privacyKey, rules); + if (!result) { + return undefined; + } - if (result) { - const newGlobal = getGlobal(); + global = getGlobal(); - newGlobal.settings.privacy[privacyKey as ApiPrivacyKey] = result; - - setGlobal(newGlobal); - } - })(); + return { + ...global, + settings: { + ...global.settings, + privacy: { + ...global.settings.privacy, + [privacyKey]: result, + }, + }, + }; }); -addActionHandler('setPrivacySettings', (global, actions, payload) => { +addActionHandler('setPrivacySettings', async (global, actions, payload) => { const { privacyKey, isAllowList, contactsIds } = payload!; const { privacy: { [privacyKey as ApiPrivacyKey]: settings }, } = global.settings; if (!settings) { - return; + return undefined; } const rules = buildInputPrivacyRules(global, { @@ -462,17 +428,23 @@ addActionHandler('setPrivacySettings', (global, actions, payload) => { deniedIds: !isAllowList ? contactsIds : [...settings.blockUserIds, ...settings.blockChatIds], }); - (async () => { - const result = await callApi('setPrivacySettings', privacyKey, rules); + const result = await callApi('setPrivacySettings', privacyKey, rules); + if (!result) { + return undefined; + } - if (result) { - const newGlobal = getGlobal(); + global = getGlobal(); - newGlobal.settings.privacy[privacyKey as ApiPrivacyKey] = result; - - setGlobal(newGlobal); - } - })(); + return { + ...global, + settings: { + ...global.settings, + privacy: { + ...global.settings.privacy, + [privacyKey]: result, + }, + }, + }; }); function buildInputPrivacyRules(global: GlobalState, { @@ -547,71 +519,62 @@ addActionHandler('updateIsOnline', (global, actions, payload) => { callApi('updateIsOnline', payload); }); -addActionHandler('loadContentSettings', () => { - (async () => { - const result = await callApi('fetchContentSettings'); - if (!result) return; +addActionHandler('loadContentSettings', async () => { + const result = await callApi('fetchContentSettings'); + if (!result) return undefined; - setGlobal(replaceSettings(getGlobal(), result)); - })(); + return replaceSettings(getGlobal(), result); }); -addActionHandler('updateContentSettings', (global, actions, payload) => { - (async () => { - setGlobal(replaceSettings(getGlobal(), { isSensitiveEnabled: payload })); +addActionHandler('updateContentSettings', async (global, actions, payload) => { + setGlobal(replaceSettings(getGlobal(), { isSensitiveEnabled: payload })); - const result = await callApi('updateContentSettings', payload); - if (!result) { - setGlobal(replaceSettings(getGlobal(), { isSensitiveEnabled: !payload })); - } - })(); + const result = await callApi('updateContentSettings', payload); + if (!result) { + return replaceSettings(getGlobal(), { isSensitiveEnabled: !payload }); + } + + return undefined; }); -addActionHandler('loadCountryList', (global, actions, payload = {}) => { +addActionHandler('loadCountryList', async (global, actions, payload = {}) => { let { langCode } = payload; if (!langCode) langCode = global.settings.byKey.language; - (async () => { - const countryList = await callApi('fetchCountryList', { langCode }); - if (!countryList) return; + const countryList = await callApi('fetchCountryList', { langCode }); + if (!countryList) return undefined; - setGlobal({ - ...getGlobal(), - countryList, - }); - })(); + return { + ...getGlobal(), + countryList, + }; }); -addActionHandler('ensureTimeFormat', (global, actions) => { +addActionHandler('ensureTimeFormat', async (global, actions) => { if (global.authNearestCountry) { const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(global.authNearestCountry.toUpperCase()) ? '12h' : '24h'; actions.setSettingOption({ timeFormat }); setTimeFormat(timeFormat); } - (async () => { - if (getGlobal().settings.byKey.wasTimeFormatSetManually) { - return; - } + if (global.settings.byKey.wasTimeFormatSetManually) { + return; + } - const nearestCountryCode = await callApi('fetchNearestCountry'); - if (nearestCountryCode) { - const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(nearestCountryCode.toUpperCase()) ? '12h' : '24h'; - actions.setSettingOption({ timeFormat }); - setTimeFormat(timeFormat); - } - })(); + const nearestCountryCode = await callApi('fetchNearestCountry'); + if (nearestCountryCode) { + const timeFormat = COUNTRIES_WITH_12H_TIME_FORMAT.has(nearestCountryCode.toUpperCase()) ? '12h' : '24h'; + actions.setSettingOption({ timeFormat }); + setTimeFormat(timeFormat); + } }); -addActionHandler('loadAppConfig', () => { - (async () => { - const appConfig = await callApi('fetchAppConfig'); +addActionHandler('loadAppConfig', async () => { + const appConfig = await callApi('fetchAppConfig'); + if (!appConfig) return undefined; - if (!appConfig) return; - - setGlobal({ - ...getGlobal(), - appConfig, - }); - })(); + return { + ...getGlobal(), + appConfig, + }; }); diff --git a/src/global/actions/api/statistics.ts b/src/global/actions/api/statistics.ts index adfc00425..bff47ca2a 100644 --- a/src/global/actions/api/statistics.ts +++ b/src/global/actions/api/statistics.ts @@ -1,55 +1,50 @@ -import { addActionHandler, getGlobal, setGlobal } from '../../index'; +import { addActionHandler, getGlobal } from '../../index'; import { callApi } from '../../../api/gramjs'; import { updateStatistics, updateStatisticsGraph } from '../../reducers'; import { selectChatMessages, selectChat } from '../../selectors'; -addActionHandler('loadStatistics', (global, actions, payload) => { +addActionHandler('loadStatistics', async (global, actions, payload) => { const { chatId } = payload; const chat = selectChat(global, chatId); if (!chat?.fullInfo) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchStatistics', { chat }); + const result = await callApi('fetchStatistics', { chat }); + if (!result) { + return undefined; + } - if (!result) { - return; - } + global = getGlobal(); - global = getGlobal(); + if (result?.recentTopMessages.length) { + const messages = selectChatMessages(global, chatId); - if (result?.recentTopMessages.length) { - const messages = selectChatMessages(global, chatId); + result.recentTopMessages = result.recentTopMessages + .map((message) => ({ ...message, ...messages[message.msgId] })); + } - result.recentTopMessages = result.recentTopMessages - .map((message) => ({ ...message, ...messages[message.msgId] })); - } + global = updateStatistics(global, chatId, result); - global = updateStatistics(global, chatId, result); - - setGlobal(global); - })(); + return global; }); -addActionHandler('loadStatisticsAsyncGraph', (global, actions, payload) => { +addActionHandler('loadStatisticsAsyncGraph', async (global, actions, payload) => { const { chatId, token, name, isPercentage, } = payload; const chat = selectChat(global, chatId); if (!chat?.fullInfo) { - return; + return undefined; } - (async () => { - const dcId = chat.fullInfo!.statisticsDcId; - const result = await callApi('fetchStatisticsAsyncGraph', { token, dcId, isPercentage }); + const dcId = chat.fullInfo!.statisticsDcId; + const result = await callApi('fetchStatisticsAsyncGraph', { token, dcId, isPercentage }); - if (!result) { - return; - } + if (!result) { + return undefined; + } - setGlobal(updateStatisticsGraph(getGlobal(), chatId, name, result)); - })(); + return updateStatisticsGraph(getGlobal(), chatId, name, result); }); diff --git a/src/global/actions/api/symbols.ts b/src/global/actions/api/symbols.ts index f2c956371..5f24247d2 100644 --- a/src/global/actions/api/symbols.ts +++ b/src/global/actions/api/symbols.ts @@ -25,26 +25,24 @@ addActionHandler('loadStickerSets', (global) => { void loadStickerSets(hash); }); -addActionHandler('loadAddedStickers', (global, actions) => { +addActionHandler('loadAddedStickers', async (global, actions) => { const { setIds: addedSetIds } = global.stickers.added; const cached = global.stickers.setsById; if (!addedSetIds || !addedSetIds.length) { return; } - (async () => { - for (let i = 0; i < addedSetIds.length; i++) { - const id = addedSetIds[i]; - if (cached[id].stickers) { - continue; // Already loaded - } - actions.loadStickers({ stickerSetId: id }); - - if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) { - await pause(ADDED_SETS_THROTTLE); - } + for (let i = 0; i < addedSetIds.length; i++) { + const id = addedSetIds[i]; + if (cached[id].stickers) { + continue; // Already loaded } - })(); + actions.loadStickers({ stickerSetId: id }); + + if (i % ADDED_SETS_THROTTLE_CHUNK === 0 && i > 0) { + await pause(ADDED_SETS_THROTTLE); + } + } }); addActionHandler('loadRecentStickers', (global) => { @@ -57,29 +55,26 @@ addActionHandler('loadFavoriteStickers', (global) => { void loadFavoriteStickers(hash); }); -addActionHandler('loadGreetingStickers', (global) => { +addActionHandler('loadGreetingStickers', async (global) => { const { hash } = global.stickers.greeting || {}; - (async () => { - const greeting = await callApi('fetchStickersForEmoji', { emoji: '👋⭐️', hash }); + const greeting = await callApi('fetchStickersForEmoji', { emoji: '👋⭐️', hash }); + if (!greeting) { + return undefined; + } - if (!greeting) { - return; - } + global = getGlobal(); - const newGlobal = getGlobal(); - - setGlobal({ - ...newGlobal, - stickers: { - ...newGlobal.stickers, - greeting: { - hash: greeting.hash, - stickers: greeting.stickers.filter((sticker) => sticker.emoji === '👋'), - }, + return { + ...global, + stickers: { + ...global.stickers, + greeting: { + hash: greeting.hash, + stickers: greeting.stickers.filter((sticker) => sticker.emoji === '👋'), }, - }); - })(); + }, + }; }); addActionHandler('loadFeaturedStickers', (global) => { @@ -141,12 +136,12 @@ addActionHandler('toggleStickerSet', (global, actions, payload) => { void callApi(!installedDate ? 'installStickerSet' : 'uninstallStickerSet', { stickerSetId, accessHash }); }); -addActionHandler('loadEmojiKeywords', (global, actions, payload: { language: LangCode }) => { +addActionHandler('loadEmojiKeywords', async (global, actions, payload: { language: LangCode }) => { const { language } = payload; let currentEmojiKeywords = global.emojiKeywords[language]; if (currentEmojiKeywords?.isLoading) { - return; + return undefined; } setGlobal({ @@ -160,45 +155,41 @@ addActionHandler('loadEmojiKeywords', (global, actions, payload: { language: Lan }, }); - (async () => { - const emojiKeywords = await callApi('fetchEmojiKeywords', { - language, - fromVersion: currentEmojiKeywords ? currentEmojiKeywords.version : 0, - }); + const emojiKeywords = await callApi('fetchEmojiKeywords', { + language, + fromVersion: currentEmojiKeywords ? currentEmojiKeywords.version : 0, + }); - global = getGlobal(); - currentEmojiKeywords = global.emojiKeywords[language]; + global = getGlobal(); + currentEmojiKeywords = global.emojiKeywords[language]; - if (!emojiKeywords) { - setGlobal({ - ...global, - emojiKeywords: { - ...global.emojiKeywords, - [language]: { - ...currentEmojiKeywords, - isLoading: false, - }, - }, - }); - - return; - } - - setGlobal({ + if (!emojiKeywords) { + return { ...global, emojiKeywords: { ...global.emojiKeywords, [language]: { + ...currentEmojiKeywords, isLoading: false, - version: emojiKeywords.version, - keywords: { - ...(currentEmojiKeywords?.keywords), - ...emojiKeywords.keywords, - }, }, }, - }); - })(); + }; + } + + return { + ...global, + emojiKeywords: { + ...global.emojiKeywords, + [language]: { + isLoading: false, + version: emojiKeywords.version, + keywords: { + ...(currentEmojiKeywords?.keywords), + ...emojiKeywords.keywords, + }, + }, + }, + }; }); async function loadStickerSets(hash?: string) { diff --git a/src/global/actions/api/twoFaSettings.ts b/src/global/actions/api/twoFaSettings.ts index 26c714026..579ddbf97 100644 --- a/src/global/actions/api/twoFaSettings.ts +++ b/src/global/actions/api/twoFaSettings.ts @@ -3,86 +3,76 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { callApi } from '../../../api/gramjs'; import { replaceSettings, updateTwoFaSettings } from '../../reducers'; -addActionHandler('loadPasswordInfo', () => { - (async () => { - const result = await callApi('getPasswordInfo'); - if (!result) { - return; - } +addActionHandler('loadPasswordInfo', async (global) => { + const result = await callApi('getPasswordInfo'); + if (!result) { + return undefined; + } - let global = getGlobal(); - global = replaceSettings(global, { hasPassword: result.hasPassword }); - global = updateTwoFaSettings(global, { hint: result.hint }); - setGlobal(global); - })(); + global = getGlobal(); + global = replaceSettings(global, { hasPassword: result.hasPassword }); + global = updateTwoFaSettings(global, { hint: result.hint }); + return global; }); -addActionHandler('checkPassword', (global, actions, payload) => { +addActionHandler('checkPassword', async (global, actions, payload) => { const { currentPassword, onSuccess } = payload; setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined })); - (async () => { - const isSuccess = await callApi('checkPassword', currentPassword); + const isSuccess = await callApi('checkPassword', currentPassword); - setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); + setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); - if (isSuccess) { - onSuccess(); - } - })(); + if (isSuccess) { + onSuccess(); + } }); -addActionHandler('clearPassword', (global, actions, payload) => { +addActionHandler('clearPassword', async (global, actions, payload) => { const { currentPassword, onSuccess } = payload; setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined })); - (async () => { - const isSuccess = await callApi('clearPassword', currentPassword); + const isSuccess = await callApi('clearPassword', currentPassword); - setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); + setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); - if (isSuccess) { - onSuccess(); - } - })(); + if (isSuccess) { + onSuccess(); + } }); -addActionHandler('updatePassword', (global, actions, payload) => { +addActionHandler('updatePassword', async (global, actions, payload) => { const { currentPassword, password, hint, email, onSuccess, } = payload; setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined })); - (async () => { - const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email); + const isSuccess = await callApi('updatePassword', currentPassword, password, hint, email); - setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); + setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false })); - if (isSuccess) { - onSuccess(); - } - })(); + if (isSuccess) { + onSuccess(); + } }); -addActionHandler('updateRecoveryEmail', (global, actions, payload) => { +addActionHandler('updateRecoveryEmail', async (global, actions, payload) => { const { currentPassword, email, onSuccess, } = payload; setGlobal(updateTwoFaSettings(global, { isLoading: true, error: undefined })); - (async () => { - const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email); + const isSuccess = await callApi('updateRecoveryEmail', currentPassword, email); - setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false, waitingEmailCodeLength: undefined })); + setGlobal(updateTwoFaSettings(getGlobal(), { isLoading: false, waitingEmailCodeLength: undefined })); - if (isSuccess) { - onSuccess(); - } - })(); + if (isSuccess) { + onSuccess(); + } }); addActionHandler('provideTwoFaEmailCode', (global, actions, payload) => { diff --git a/src/global/actions/api/users.ts b/src/global/actions/api/users.ts index 1516d6338..1f870839a 100644 --- a/src/global/actions/api/users.ts +++ b/src/global/actions/api/users.ts @@ -32,31 +32,29 @@ addActionHandler('loadFullUser', (global, actions, payload) => { runDebouncedForFetchFullUser(() => callApi('fetchFullUser', { id, accessHash })); }); -addActionHandler('loadUser', (global, actions, payload) => { +addActionHandler('loadUser', async (global, actions, payload) => { const { userId } = payload!; const user = selectUser(global, userId); if (!user) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchUsers', { users: [user] }); - if (!result) { - return; - } + const result = await callApi('fetchUsers', { users: [user] }); + if (!result) { + return undefined; + } - const { users, userStatusesById } = result; + const { users, userStatusesById } = result; - global = getGlobal(); + global = getGlobal(); - global = updateUsers(global, buildCollectionByKey(users, 'id')); - setGlobal(replaceUserStatuses(global, { - ...global.users.statusesById, - ...userStatusesById, - })); + global = updateUsers(global, buildCollectionByKey(users, 'id')); + global = replaceUserStatuses(global, { + ...global.users.statusesById, + ...userStatusesById, + }); - setGlobal(global); - })(); + return global; }); addActionHandler('loadTopUsers', (global) => { @@ -75,35 +73,34 @@ addActionHandler('loadCurrentUser', () => { void callApi('fetchCurrentUser'); }); -addActionHandler('loadCommonChats', (global) => { +addActionHandler('loadCommonChats', async (global) => { const { chatId } = selectCurrentMessageList(global) || {}; const user = chatId ? selectUser(global, chatId) : undefined; if (!user || isUserBot(user) || user.commonChats?.isFullyLoaded) { - return; + return undefined; } - (async () => { - const maxId = user.commonChats?.maxId; - const result = await callApi('fetchCommonChats', user.id, user.accessHash!, maxId); - if (!result) { - return; - } + const maxId = user.commonChats?.maxId; + const result = await callApi('fetchCommonChats', user.id, user.accessHash!, maxId); + if (!result) { + return undefined; + } - const { chats, chatIds, isFullyLoaded } = result; + const { chats, chatIds, isFullyLoaded } = result; - global = getGlobal(); - if (chats.length) { - global = addChats(global, buildCollectionByKey(chats, 'id')); - } - global = updateUser(global, user.id, { - commonChats: { - maxId: chatIds.length ? chatIds[chatIds.length - 1] : '0', - ids: unique((user.commonChats?.ids || []).concat(chatIds)), - isFullyLoaded, - }, - }); - setGlobal(global); - })(); + global = getGlobal(); + if (chats.length) { + global = addChats(global, buildCollectionByKey(chats, 'id')); + } + global = updateUser(global, user.id, { + commonChats: { + maxId: chatIds.length ? chatIds[chatIds.length - 1] : '0', + ids: unique((user.commonChats?.ids || []).concat(chatIds)), + isFullyLoaded, + }, + }); + + return global; }); addActionHandler('updateContact', (global, actions, payload) => { @@ -223,32 +220,31 @@ async function deleteContact(userId: string) { await callApi('deleteContact', { id, accessHash }); } -addActionHandler('loadProfilePhotos', (global, actions, payload) => { +addActionHandler('loadProfilePhotos', async (global, actions, payload) => { const { profileId } = payload!; const isPrivate = isUserId(profileId); + const user = isPrivate ? selectUser(global, profileId) : undefined; const chat = !isPrivate ? selectChat(global, profileId) : undefined; - if (!user && !chat) { - return; + return undefined; } - (async () => { - const result = await callApi('fetchProfilePhotos', user, chat); - if (!result || !result.photos) { - return; - } + const result = await callApi('fetchProfilePhotos', user, chat); + if (!result || !result.photos) { + return undefined; + } - let newGlobal = getGlobal(); - if (isPrivate) { - newGlobal = updateUser(newGlobal, profileId, { photos: result.photos }); - } else { - newGlobal = addUsers(newGlobal, buildCollectionByKey(result.users!, 'id')); - newGlobal = updateChat(newGlobal, profileId, { photos: result.photos }); - } + global = getGlobal(); - setGlobal(newGlobal); - })(); + if (isPrivate) { + global = updateUser(global, profileId, { photos: result.photos }); + } else { + global = addUsers(global, buildCollectionByKey(result.users!, 'id')); + global = updateChat(global, profileId, { photos: result.photos }); + } + + return global; }); addActionHandler('setUserSearchQuery', (global, actions, payload) => { diff --git a/src/global/actions/apiUpdaters/chats.ts b/src/global/actions/apiUpdaters/chats.ts index 2b36fdba0..37f312f9f 100644 --- a/src/global/actions/apiUpdaters/chats.ts +++ b/src/global/actions/apiUpdaters/chats.ts @@ -1,6 +1,6 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; -import { ApiUpdate, MAIN_THREAD_ID } from '../../../api/types'; +import { MAIN_THREAD_ID } from '../../../api/types'; import { ARCHIVED_FOLDER_ID, MAX_ACTIVE_PINNED_CHATS } from '../../../config'; import { pick } from '../../../util/iteratees'; @@ -25,7 +25,7 @@ const TYPING_STATUS_CLEAR_DELAY = 6000; // 6 seconds // Enough to animate and mark as read in Message List const CURRENT_CHAT_UNREAD_DELAY = 1500; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updateChat': { if (!update.noTopChatsRequest && !selectIsChatListed(global, update.id)) { @@ -33,8 +33,7 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { actions.loadTopChats(); } - const newGlobal = updateChat(global, update.id, update.chat, update.newProfilePhoto); - setGlobal(newGlobal); + setGlobal(updateChat(global, update.id, update.chat, update.newProfilePhoto)); if (update.chat.id) { closeMessageNotifications({ @@ -42,13 +41,14 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { lastReadInboxMessageId: update.chat.lastReadInboxMessageId, }); } - break; + + return undefined; } case 'updateChatJoin': { const listType = selectChatListType(global, update.id); if (!listType) { - break; + return undefined; } global = updateChatListIds(global, listType, [update.id]); @@ -59,19 +59,16 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { if (chat) { actions.requestChatUpdate({ chatId: chat.id }); } - break; + + return undefined; } case 'updateChatLeave': { - setGlobal(leaveChat(global, update.id)); - - break; + return leaveChat(global, update.id); } case 'updateChatInbox': { - setGlobal(updateChat(global, update.id, update.chat)); - - break; + return updateChat(global, update.id, update.chat); } case 'updateChatTypingStatus': { @@ -79,14 +76,14 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { setGlobal(updateChat(global, id, { typingStatus })); setTimeout(() => { - const newGlobal = getGlobal(); - const chat = selectChat(newGlobal, id); + global = getGlobal(); + const chat = selectChat(global, id); if (chat && typingStatus && chat.typingStatus && chat.typingStatus.timestamp === typingStatus.timestamp) { - setGlobal(updateChat(newGlobal, id, { typingStatus: undefined })); + setGlobal(updateChat(global, id, { typingStatus: undefined })); } }, TYPING_STATUS_CLEAR_DELAY); - break; + return undefined; } case 'newMessage': { @@ -94,12 +91,12 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { const { chatId: currentChatId, threadId, type: messageListType } = selectCurrentMessageList(global) || {}; if (message.senderId === global.currentUserId && !message.isFromScheduled) { - return; + return undefined; } const chat = selectChat(global, update.chatId); if (!chat) { - return; + return undefined; } const isActiveChat = ( @@ -126,14 +123,14 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { message, }); - break; + return undefined; } case 'updateMessage': { const { message } = update; const chat = selectChat(global, update.chatId); if (!chat) { - return; + return undefined; } if (getMessageRecentReaction(message)) { @@ -142,14 +139,15 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { message, }); } - break; + + return undefined; } case 'updateCommonBoxMessages': case 'updateChannelMessages': { const { ids, messageUpdate } = update; if (messageUpdate.hasUnreadMention !== false) { - return; + return undefined; } ids.forEach((id) => { @@ -162,34 +160,29 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { } }); - setGlobal(global); - - break; + return global; } case 'updateChatFullInfo': { const { fullInfo } = update; const targetChat = global.chats.byId[update.id]; if (!targetChat) { - return; + return undefined; } - setGlobal(updateChat(global, update.id, { + return updateChat(global, update.id, { fullInfo: { ...targetChat.fullInfo, ...fullInfo, }, - })); - - break; + }); } case 'updatePinnedChatIds': { const { ids, folderId } = update; - const listType = folderId === ARCHIVED_FOLDER_ID ? 'archived' : 'active'; - global = { + return { ...global, chats: { ...global.chats, @@ -199,57 +192,49 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { }, }, }; - - setGlobal(global); - - break; } case 'updateChatPinned': { const { id, isPinned } = update; const listType = selectChatListType(global, id); - if (listType) { - const { [listType]: orderedPinnedIds } = global.chats.orderedPinnedIds; - - let newOrderedPinnedIds = orderedPinnedIds || []; - if (!isPinned) { - newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => pinnedId !== id); - } else if (!newOrderedPinnedIds.includes(id)) { - // When moving pinned chats to archive, active ordered pinned ids don't get updated - // (to preserve chat pinned state when it returns from archive) - // If user already has max pinned chats, we should check for orderedIds - // that don't point to listed chats - if (listType === 'active' && newOrderedPinnedIds.length >= MAX_ACTIVE_PINNED_CHATS) { - const listIds = global.chats.listIds.active; - newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => listIds && listIds.includes(pinnedId)); - } - - newOrderedPinnedIds = [id, ...newOrderedPinnedIds]; - } - - global = { - ...global, - chats: { - ...global.chats, - orderedPinnedIds: { - ...global.chats.orderedPinnedIds, - [listType]: newOrderedPinnedIds.length ? newOrderedPinnedIds : undefined, - }, - }, - }; + if (!listType) { + return undefined; } - setGlobal(global); + const { [listType]: orderedPinnedIds } = global.chats.orderedPinnedIds; - break; + let newOrderedPinnedIds = orderedPinnedIds || []; + if (!isPinned) { + newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => pinnedId !== id); + } else if (!newOrderedPinnedIds.includes(id)) { + // When moving pinned chats to archive, active ordered pinned ids don't get updated + // (to preserve chat pinned state when it returns from archive) + // If user already has max pinned chats, we should check for orderedIds + // that don't point to listed chats + if (listType === 'active' && newOrderedPinnedIds.length >= MAX_ACTIVE_PINNED_CHATS) { + const listIds = global.chats.listIds.active; + newOrderedPinnedIds = newOrderedPinnedIds.filter((pinnedId) => listIds && listIds.includes(pinnedId)); + } + + newOrderedPinnedIds = [id, ...newOrderedPinnedIds]; + } + + return { + ...global, + chats: { + ...global.chats, + orderedPinnedIds: { + ...global.chats.orderedPinnedIds, + [listType]: newOrderedPinnedIds.length ? newOrderedPinnedIds : undefined, + }, + }, + }; } case 'updateChatListType': { const { id, folderId } = update; - setGlobal(updateChatListType(global, id, folderId)); - - break; + return updateChatListType(global, id, folderId); } case 'updateChatFolder': { @@ -267,51 +252,45 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { ? orderedIds && orderedIds.includes(id) ? orderedIds : [...(orderedIds || []), id] : orderedIds ? orderedIds.filter((orderedId) => orderedId !== id) : undefined; - setGlobal({ + return { ...global, chatFolders: { ...global.chatFolders, byId: newChatFoldersById, orderedIds: newOrderedIds, }, - }); - - break; + }; } case 'updateChatFoldersOrder': { const { orderedIds } = update; - setGlobal({ + return { ...global, chatFolders: { ...global.chatFolders, orderedIds, }, - }); - - break; + }; } case 'updateRecommendedChatFolders': { const { folders } = update; - setGlobal({ + return { ...global, chatFolders: { ...global.chatFolders, recommended: folders, }, - }); - - break; + }; } case 'updateChatMembers': { const targetChat = global.chats.byId[update.id]; const { replacedMembers, addedMember, deletedMemberId } = update; if (!targetChat) { - return; + return undefined; } let shouldUpdate = false; @@ -342,17 +321,17 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { const adminMembers = members.filter(({ isOwner, isAdmin }) => isOwner || isAdmin); // TODO Kicked members? - setGlobal(updateChat(global, update.id, { + return updateChat(global, update.id, { membersCount: members.length, fullInfo: { ...targetChat.fullInfo, members, adminMembers, }, - })); + }); } - break; + return undefined; } case 'deleteProfilePhotos': { @@ -360,11 +339,12 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { const chat = global.chats.byId[chatId]; if (chat?.photos) { - setGlobal(updateChat(global, chatId, { + return updateChat(global, chatId, { photos: chat.photos.filter((photo) => !ids.includes(photo.id)), - })); + }); } - break; + + return undefined; } case 'draftMessage': { @@ -372,38 +352,43 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { chatId, formattedText, date, replyingToId, } = update; const chat = global.chats.byId[chatId]; - - if (chat) { - global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', formattedText); - global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'replyingToId', replyingToId); - global = updateChat(global, chatId, { draftDate: date }); - - setGlobal(global); + if (!chat) { + return undefined; } - break; + + global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'draft', formattedText); + global = replaceThreadParam(global, chatId, MAIN_THREAD_ID, 'replyingToId', replyingToId); + global = updateChat(global, chatId, { draftDate: date }); + return global; } case 'showInvite': { const { data } = update; actions.showDialog({ data }); - break; + + return undefined; } case 'updatePendingJoinRequests': { const { chatId, requestsPending, recentRequesterIds } = update; const chat = global.chats.byId[chatId]; - if (chat) { - global = updateChat(global, chatId, { - fullInfo: { - ...chat.fullInfo, - requestsPending, - recentRequesterIds, - }, - }); - setGlobal(global); - actions.loadChatJoinRequests({ chatId }); + if (!chat) { + return undefined; } + + global = updateChat(global, chatId, { + fullInfo: { + ...chat.fullInfo, + requestsPending, + recentRequesterIds, + }, + }); + setGlobal(global); + + actions.loadChatJoinRequests({ chatId }); } } + + return undefined; }); diff --git a/src/global/actions/apiUpdaters/initial.ts b/src/global/actions/apiUpdaters/initial.ts index 5d3c56965..3ed2df6da 100644 --- a/src/global/actions/apiUpdaters/initial.ts +++ b/src/global/actions/apiUpdaters/initial.ts @@ -5,7 +5,6 @@ import { import { GlobalState } from '../../types'; import { - ApiUpdate, ApiUpdateAuthorizationState, ApiUpdateAuthorizationError, ApiUpdateConnectionState, @@ -20,7 +19,7 @@ import { selectNotifySettings } from '../../selectors'; import { forceWebsync } from '../../../util/websync'; import { getShippingError } from '../../../util/getReadableErrorText'; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { if (DEBUG) { if (update['@type'] !== 'updateUserStatus' && update['@type'] !== 'updateServerTimeOffset') { // eslint-disable-next-line no-console diff --git a/src/global/actions/apiUpdaters/messages.ts b/src/global/actions/apiUpdaters/messages.ts index ee3b557ae..b86249585 100644 --- a/src/global/actions/apiUpdaters/messages.ts +++ b/src/global/actions/apiUpdaters/messages.ts @@ -1,13 +1,12 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; import { - ApiUpdate, ApiMessage, ApiPollResult, ApiThreadInfo, MAIN_THREAD_ID, + ApiMessage, ApiPollResult, ApiThreadInfo, MAIN_THREAD_ID, } from '../../../api/types'; import { unique } from '../../../util/iteratees'; import { areDeepEqual } from '../../../util/areDeepEqual'; import { notifyAboutMessage } from '../../../util/notifications'; -import { checkIfReactionAdded } from '../../helpers/reactions'; import { updateChat, deleteChatMessages, @@ -34,7 +33,7 @@ import { selectPinnedIds, selectScheduledMessage, selectScheduledMessages, - isMessageInCurrentMessageList, + selectIsMessageInCurrentMessageList, selectScheduledIds, selectCurrentMessageList, selectViewportIds, @@ -46,12 +45,12 @@ import { selectLocalAnimatedEmoji, } from '../../selectors'; import { - getMessageContent, isUserId, isMessageLocal, getMessageText, + getMessageContent, isUserId, isMessageLocal, getMessageText, checkIfReactionAdded, } from '../../helpers'; const ANIMATION_DELAY = 350; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'newMessage': { const { @@ -73,7 +72,7 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { const newMessage = selectChatMessage(global, chatId, id)!; - if (isMessageInCurrentMessageList(global, chatId, message as ApiMessage)) { + if (selectIsMessageInCurrentMessageList(global, chatId, message as ApiMessage)) { if (message.isOutgoing && !(message.content?.action)) { const currentMessageList = selectCurrentMessageList(global); if (currentMessageList) { @@ -186,7 +185,7 @@ addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { && !message.isOutgoing && chat.lastMessage?.id === message.id && selectIsChatWithBot(global, chat) - && isMessageInCurrentMessageList(global, chatId, message as ApiMessage) + && selectIsMessageInCurrentMessageList(global, chatId, message as ApiMessage) && selectIsViewportNewest(global, chatId, message.threadInfo?.threadId || MAIN_THREAD_ID) ) { actions.focusLastMessage(); @@ -602,11 +601,11 @@ function updateListedAndViewportIds(global: GlobalState, actions: GlobalActions, if (selectIsViewportNewest(global, chatId, MAIN_THREAD_ID)) { // Always keep the first unread message in the viewport list const firstUnreadId = selectFirstUnreadId(global, chatId, MAIN_THREAD_ID); - const newGlobal = addViewportId(global, chatId, MAIN_THREAD_ID, id); - const newViewportIds = selectViewportIds(newGlobal, chatId, MAIN_THREAD_ID); + const candidateGlobal = addViewportId(global, chatId, MAIN_THREAD_ID, id); + const newViewportIds = selectViewportIds(candidateGlobal, chatId, MAIN_THREAD_ID); if (!firstUnreadId || newViewportIds!.includes(firstUnreadId)) { - global = newGlobal; + global = candidateGlobal; } } diff --git a/src/global/actions/apiUpdaters/misc.ts b/src/global/actions/apiUpdaters/misc.ts index a3a04b92a..f2b83ac9b 100644 --- a/src/global/actions/apiUpdaters/misc.ts +++ b/src/global/actions/apiUpdaters/misc.ts @@ -1,13 +1,12 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; -import { ApiUpdate } from '../../../api/types'; import { ApiPrivacyKey, PaymentStep } from '../../../types'; import { addBlockedContact, removeBlockedContact, setConfirmPaymentUrl, setPaymentStep, } from '../../reducers'; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updatePeerBlocked': if (update.isBlocked) { diff --git a/src/global/actions/apiUpdaters/payments.ts b/src/global/actions/apiUpdaters/payments.ts index 0ff279172..43bc33aff 100644 --- a/src/global/actions/apiUpdaters/payments.ts +++ b/src/global/actions/apiUpdaters/payments.ts @@ -1,10 +1,8 @@ import { addActionHandler } from '../../index'; -import { ApiUpdate } from '../../../api/types'; - import { clearPayment } from '../../reducers'; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updatePaymentStateCompleted': { return clearPayment(global); diff --git a/src/global/actions/apiUpdaters/settings.ts b/src/global/actions/apiUpdaters/settings.ts index 9153d398a..6e5dc07b0 100644 --- a/src/global/actions/apiUpdaters/settings.ts +++ b/src/global/actions/apiUpdaters/settings.ts @@ -1,10 +1,8 @@ import { addActionHandler, setGlobal } from '../../index'; -import { ApiUpdate } from '../../../api/types'; -import { GlobalState } from '../../types'; import { addNotifyException, updateChat, updateNotifySettings } from '../../reducers'; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | undefined => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updateNotifySettings': { return updateNotifySettings(global, update.peerType, update.isSilent, update.shouldShowPreviews); diff --git a/src/global/actions/apiUpdaters/symbols.ts b/src/global/actions/apiUpdaters/symbols.ts index 3deae0ae6..d9d8c6c6a 100644 --- a/src/global/actions/apiUpdaters/symbols.ts +++ b/src/global/actions/apiUpdaters/symbols.ts @@ -1,10 +1,8 @@ import { addActionHandler } from '../../index'; -import { ApiUpdate } from '../../../api/types'; - import { updateStickerSet } from '../../reducers'; -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updateStickerSet': { return updateStickerSet(global, update.id, update.stickerSet); diff --git a/src/global/actions/apiUpdaters/twoFaSettings.ts b/src/global/actions/apiUpdaters/twoFaSettings.ts index 345266ea4..f7cb72c60 100644 --- a/src/global/actions/apiUpdaters/twoFaSettings.ts +++ b/src/global/actions/apiUpdaters/twoFaSettings.ts @@ -1,9 +1,6 @@ import { addActionHandler } from '../../index'; -import { ApiUpdate } from '../../../api/types'; -import { GlobalState } from '../../types'; - -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | undefined => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'updateTwoFaStateWaitCode': { return { diff --git a/src/global/actions/apiUpdaters/users.ts b/src/global/actions/apiUpdaters/users.ts index c4ee741df..277696735 100644 --- a/src/global/actions/apiUpdaters/users.ts +++ b/src/global/actions/apiUpdaters/users.ts @@ -1,6 +1,6 @@ import { addActionHandler, getGlobal, setGlobal } from '../../index'; -import { ApiUpdate, ApiUserStatus } from '../../../api/types'; +import { ApiUserStatus } from '../../../api/types'; import { deleteContact, replaceUserStatuses, updateUser } from '../../reducers'; import { throttle } from '../../../util/schedulers'; @@ -27,7 +27,7 @@ function flushStatusUpdates() { pendingStatusUpdates = {}; } -addActionHandler('apiUpdate', (global, actions, update: ApiUpdate) => { +addActionHandler('apiUpdate', (global, actions, update) => { switch (update['@type']) { case 'deleteContact': { return deleteContact(global, update.id); diff --git a/src/global/actions/ui/calls.ts b/src/global/actions/ui/calls.ts index de8f30cf9..d457bb227 100644 --- a/src/global/actions/ui/calls.ts +++ b/src/global/actions/ui/calls.ts @@ -102,26 +102,24 @@ addActionHandler('toggleGroupCallPanel', (global) => { }; }); -addActionHandler('subscribeToGroupCallUpdates', (global, actions, payload) => { +addActionHandler('subscribeToGroupCallUpdates', async (global, actions, payload) => { const { subscribed, id } = payload!; const groupCall = selectGroupCall(global, id); if (!groupCall) return; - (async () => { - if (subscribed) { - await fetchGroupCall(groupCall); - await fetchGroupCallParticipants(groupCall); - } + if (subscribed) { + await fetchGroupCall(groupCall); + await fetchGroupCallParticipants(groupCall); + } - await callApi('toggleGroupCallStartSubscription', { - subscribed, - call: groupCall, - }); - })(); + await callApi('toggleGroupCallStartSubscription', { + subscribed, + call: groupCall, + }); }); -addActionHandler('createGroupCall', (global, actions, payload) => { +addActionHandler('createGroupCall', async (global, actions, payload) => { const { chatId } = payload; const chat = selectChat(global, chatId); @@ -129,24 +127,22 @@ addActionHandler('createGroupCall', (global, actions, payload) => { return; } - (async () => { - const result = await callApi('createGroupCall', { - peer: chat, - }); + const result = await callApi('createGroupCall', { + peer: chat, + }); - if (!result) return; + if (!result) return; - global = getGlobal(); - setGlobal(updateGroupCall(global, result.id, { - ...result, - chatId, - })); + global = getGlobal(); + setGlobal(updateGroupCall(global, result.id, { + ...result, + chatId, + })); - actions.joinGroupCall({ id: result.id, accessHash: result.accessHash }); - })(); + actions.joinGroupCall({ id: result.id, accessHash: result.accessHash }); }); -addActionHandler('createGroupCallInviteLink', (global, actions) => { +addActionHandler('createGroupCallInviteLink', async (global, actions) => { const groupCall = selectActiveGroupCall(global); if (!groupCall || !groupCall.chatId) { @@ -160,47 +156,43 @@ addActionHandler('createGroupCallInviteLink', (global, actions) => { const canInvite = Boolean(chat.username); - (async () => { - let { inviteLink } = chat.fullInfo!; - if (canInvite) { - inviteLink = await callApi('exportGroupCallInvite', { - call: groupCall, - canSelfUnmute: false, - }); - } - - if (!inviteLink) { - return; - } - - copyTextToClipboard(inviteLink); - actions.showNotification({ - message: 'Link copied to clipboard', + let { inviteLink } = chat.fullInfo!; + if (canInvite) { + inviteLink = await callApi('exportGroupCallInvite', { + call: groupCall, + canSelfUnmute: false, }); - })(); + } + + if (!inviteLink) { + return; + } + + copyTextToClipboard(inviteLink); + actions.showNotification({ + message: 'Link copied to clipboard', + }); }); -addActionHandler('joinVoiceChatByLink', (global, actions, payload) => { +addActionHandler('joinVoiceChatByLink', async (global, actions, payload) => { const { username, inviteHash } = payload!; - (async () => { - const chat = await fetchChatByUsername(username); + const chat = await fetchChatByUsername(username); - if (!chat) { - actions.showNotification({ message: langProvider.getTranslation('NoUsernameFound') }); - return; - } + if (!chat) { + actions.showNotification({ message: langProvider.getTranslation('NoUsernameFound') }); + return; + } - const full = await loadFullChat(chat); + const full = await loadFullChat(chat); - if (full?.groupCall) { - actions.joinGroupCall({ id: full.groupCall.id, accessHash: full.groupCall.accessHash, inviteHash }); - } - })(); + if (full?.groupCall) { + actions.joinGroupCall({ id: full.groupCall.id, accessHash: full.groupCall.accessHash, inviteHash }); + } }); -addActionHandler('joinGroupCall', (global, actions, payload) => { - if (!ARE_CALLS_SUPPORTED) return; +addActionHandler('joinGroupCall', async (global, actions, payload) => { + if (!ARE_CALLS_SUPPORTED) return undefined; const { chatId, id, accessHash, inviteHash, @@ -208,59 +200,56 @@ addActionHandler('joinGroupCall', (global, actions, payload) => { createAudioElement(); - (async () => { - await initializeSoundsForSafari(); - const { groupCalls: { activeGroupCallId } } = global; - let groupCall = id ? selectGroupCall(global, id) : selectChatGroupCall(global, chatId); + await initializeSoundsForSafari(); + const { groupCalls: { activeGroupCallId } } = global; + let groupCall = id ? selectGroupCall(global, id) : selectChatGroupCall(global, chatId); - if (groupCall?.id === activeGroupCallId) { - actions.toggleGroupCallPanel(); - return; - } + if (groupCall?.id === activeGroupCallId) { + actions.toggleGroupCallPanel(); + return undefined; + } - if (activeGroupCallId) { - actions.leaveGroupCall({ - rejoin: payload, - }); - return; - } - - if (groupCall && activeGroupCallId === groupCall.id) { - actions.toggleGroupCallPanel(); - return; - } - - if (!groupCall && (!id || !accessHash)) { - groupCall = await fetchGroupCall({ - id, - accessHash, - }); - } - - if (!groupCall) return; - - global = getGlobal(); - - global = updateGroupCall( - global, - groupCall.id, - { - ...groupCall, - inviteHash, - }, - undefined, - groupCall.participantsCount + 1, - ); - - setGlobal({ - ...global, - groupCalls: { - ...global.groupCalls, - activeGroupCallId: groupCall.id, - isGroupCallPanelHidden: false, - }, + if (activeGroupCallId) { + actions.leaveGroupCall({ + rejoin: payload, }); - })(); + return undefined; + } + + if (groupCall && activeGroupCallId === groupCall.id) { + actions.toggleGroupCallPanel(); + return undefined; + } + + if (!groupCall && (!id || !accessHash)) { + groupCall = await fetchGroupCall({ + id, + accessHash, + }); + } + + if (!groupCall) return undefined; + + global = getGlobal(); + global = updateGroupCall( + global, + groupCall.id, + { + ...groupCall, + inviteHash, + }, + undefined, + groupCall.participantsCount + 1, + ); + global = { + ...global, + groupCalls: { + ...global.groupCalls, + activeGroupCallId: groupCall.id, + isGroupCallPanelHidden: false, + }, + }; + return global; }); addActionHandler('playGroupCallSound', (global, actions, payload) => { diff --git a/src/global/actions/ui/messages.ts b/src/global/actions/ui/messages.ts index 92449b3cb..1bb55fae1 100644 --- a/src/global/actions/ui/messages.ts +++ b/src/global/actions/ui/messages.ts @@ -265,10 +265,10 @@ addActionHandler('openPollResults', (global, actions, payload) => { if (!shouldOpenInstantly) { window.setTimeout(() => { - const newGlobal = getGlobal(); + global = getGlobal(); setGlobal({ - ...newGlobal, + ...global, pollResults: { chatId, messageId, @@ -277,22 +277,24 @@ addActionHandler('openPollResults', (global, actions, payload) => { }); }, POLL_RESULT_OPEN_DELAY_MS); } else if (chatId !== global.pollResults.chatId || messageId !== global.pollResults.messageId) { - setGlobal({ + return { ...global, pollResults: { chatId, messageId, voters: {}, }, - }); + }; } + + return undefined; }); addActionHandler('closePollResults', (global) => { - setGlobal({ + return { ...global, pollResults: {}, - }); + }; }); addActionHandler('focusLastMessage', (global, actions) => { diff --git a/src/global/actions/ui/misc.ts b/src/global/actions/ui/misc.ts index 296f2d493..ceecea47c 100644 --- a/src/global/actions/ui/misc.ts +++ b/src/global/actions/ui/misc.ts @@ -1,6 +1,5 @@ import { addActionHandler } from '../../index'; -import { GlobalState } from '../../types'; import { ApiError } from '../../../api/types'; import { IS_SINGLE_COLUMN_LAYOUT, IS_TABLET_COLUMN_LAYOUT } from '../../../util/environment'; @@ -33,7 +32,7 @@ addActionHandler('resetLeftColumnWidth', (global) => { }; }); -addActionHandler('toggleManagement', (global): GlobalState | undefined => { +addActionHandler('toggleManagement', (global) => { const { chatId } = selectCurrentMessageList(global) || {}; if (!chatId) { @@ -54,7 +53,7 @@ addActionHandler('toggleManagement', (global): GlobalState | undefined => { }; }); -addActionHandler('requestNextManagementScreen', (global, actions, payload): GlobalState | undefined => { +addActionHandler('requestNextManagementScreen', (global, actions, payload) => { const { screen } = payload || {}; const { chatId } = selectCurrentMessageList(global) || {}; @@ -77,7 +76,7 @@ addActionHandler('requestNextManagementScreen', (global, actions, payload): Glob }; }); -addActionHandler('closeManagement', (global): GlobalState | undefined => { +addActionHandler('closeManagement', (global) => { const { chatId } = selectCurrentMessageList(global) || {}; if (!chatId) { diff --git a/src/global/actions/ui/payments.ts b/src/global/actions/ui/payments.ts index 6cc676888..fc1d23aaf 100644 --- a/src/global/actions/ui/payments.ts +++ b/src/global/actions/ui/payments.ts @@ -16,8 +16,9 @@ addActionHandler('openPaymentModal', (global, actions, payload) => { }); addActionHandler('closePaymentModal', (global) => { - const newGlobal = clearPayment(global); - return closeInvoice(newGlobal); + global = clearPayment(global); + global = closeInvoice(global); + return global; }); addActionHandler('addPaymentError', (global, actions, payload) => { diff --git a/src/global/selectors/messages.ts b/src/global/selectors/messages.ts index 5747ad827..069ef6e71 100644 --- a/src/global/selectors/messages.ts +++ b/src/global/selectors/messages.ts @@ -202,7 +202,7 @@ export function selectThreadByMessage(global: GlobalState, chatId: string, messa }); } -export function isMessageInCurrentMessageList(global: GlobalState, chatId: string, message: ApiMessage) { +export function selectIsMessageInCurrentMessageList(global: GlobalState, chatId: string, message: ApiMessage) { const currentMessageList = selectCurrentMessageList(global); if (!currentMessageList) { return false; diff --git a/src/lib/teact/teactn.tsx b/src/lib/teact/teactn.tsx index c868d6676..b85e19915 100644 --- a/src/lib/teact/teactn.tsx +++ b/src/lib/teact/teactn.tsx @@ -29,7 +29,7 @@ type ActionHandler = ( global: GlobalState, actions: Actions, payload: any, -) => GlobalState | void; +) => GlobalState | void | Promise; type MapStateToProps = ((global: GlobalState, ownProps: OwnProps) => AnyLiteral); @@ -80,9 +80,19 @@ export function getActions() { function handleAction(name: string, payload?: ActionPayload, options?: ActionOptions) { actionHandlers[name]?.forEach((handler) => { - const newGlobal = handler(currentGlobal, actions, payload); - if (newGlobal) { - setGlobal(newGlobal, options); + const response = handler(currentGlobal, actions, payload); + if (!response) { + return; + } + + if (typeof response.then === 'function') { + response.then((newGlobal: GlobalState | void) => { + if (newGlobal) { + setGlobal(newGlobal, options); + } + }); + } else { + setGlobal(response, options); } }); } @@ -244,7 +254,7 @@ export function typify ProjectGlobalState | void; + ) => ProjectGlobalState | void | Promise; }; return {