import type { ApiUpdateAuthorizationError, ApiUpdateAuthorizationState, ApiUpdateConnectionState, ApiUpdateCurrentUser, ApiUpdateServerTimeOffset, ApiUpdateSession, } from '../../../api/types'; import type { RequiredGlobalActions } from '../../index'; import type { ActionReturnType, GlobalState } from '../../types'; import { SESSION_USER_KEY } from '../../../config'; import { getCurrentTabId } from '../../../util/establishMultitabRole'; import { getShippingError, shouldClosePaymentModal } from '../../../util/getReadableErrorText'; import { unique } from '../../../util/iteratees'; import { oldSetLanguage } from '../../../util/oldLangProvider'; import { clearWebTokenAuth } from '../../../util/routing'; import { setServerTimeOffset } from '../../../util/serverTime'; import { forceWebsync } from '../../../util/websync'; import { isChatChannel, isChatSuperGroup } from '../../helpers'; import { addActionHandler, getGlobal, setGlobal, } from '../../index'; import { updateUser, updateUserFullInfo } from '../../reducers'; import { updateTabState } from '../../reducers/tabs'; import { selectTabState } from '../../selectors'; addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { switch (update['@type']) { case 'updateApiReady': onUpdateApiReady(global); break; case 'updateAuthorizationState': onUpdateAuthorizationState(global, update); break; case 'updateAuthorizationError': onUpdateAuthorizationError(global, update); break; case 'updateWebAuthTokenFailed': onUpdateWebAuthTokenFailed(global); break; case 'updateConnectionState': onUpdateConnectionState(global, actions, update); break; case 'updateSession': onUpdateSession(global, actions, update); break; case 'updateServerTimeOffset': onUpdateServerTimeOffset(update); break; case 'updateCurrentUser': onUpdateCurrentUser(global, update); break; case 'requestReconnectApi': global = { ...global, isSynced: false }; setGlobal(global); onUpdateConnectionState(global, actions, { '@type': 'updateConnectionState', connectionState: 'connectionStateConnecting', }); actions.initApi(); break; case 'requestSync': actions.sync(); break; case 'updateFetchingDifference': global = { ...global, isFetchingDifference: update.isFetching }; setGlobal(global); break; case 'error': { Object.values(global.byTabId).forEach(({ id: tabId }) => { const paymentShippingError = getShippingError(update.error); if (paymentShippingError) { actions.addPaymentError({ error: paymentShippingError, tabId }); } else if (shouldClosePaymentModal(update.error)) { actions.closePaymentModal({ tabId }); } else if (actions.showDialog) { actions.showDialog({ data: update.error, tabId }); } }); break; } } }); function onUpdateApiReady(global: T) { void oldSetLanguage(global.settings.byKey.language); } function onUpdateAuthorizationState(global: T, update: ApiUpdateAuthorizationState) { global = getGlobal(); const wasAuthReady = global.authState === 'authorizationStateReady'; const authState = update.authorizationState; global = { ...global, authState, authIsLoading: false, }; setGlobal(global); global = getGlobal(); switch (authState) { case 'authorizationStateLoggingOut': void forceWebsync(false); global = { ...global, isLoggingOut: true, }; setGlobal(global); break; case 'authorizationStateWaitCode': global = { ...global, authIsCodeViaApp: update.isCodeViaApp, }; setGlobal(global); break; case 'authorizationStateWaitPassword': global = { ...global, authHint: update.hint, }; if (update.noReset) { global = { ...global, hasWebAuthTokenPasswordRequired: true, }; } setGlobal(global); break; case 'authorizationStateWaitQrCode': global = { ...global, authIsLoadingQrCode: false, authQrCode: update.qrCode, }; setGlobal(global); break; case 'authorizationStateReady': { if (wasAuthReady) { break; } void forceWebsync(true); global = { ...global, isLoggingOut: false, }; Object.values(global.byTabId).forEach(({ id: tabId }) => { global = updateTabState(global, { isInactive: false, }, tabId); }); setGlobal(global); break; } } } function onUpdateAuthorizationError(global: T, update: ApiUpdateAuthorizationError) { global = getGlobal(); global = { ...global, authError: update.message, }; setGlobal(global); } function onUpdateWebAuthTokenFailed(global: T) { clearWebTokenAuth(); global = getGlobal(); global = { ...global, hasWebAuthTokenFailed: true, }; setGlobal(global); } function onUpdateConnectionState( global: T, actions: RequiredGlobalActions, update: ApiUpdateConnectionState, ) { const { connectionState } = update; global = getGlobal(); const tabState = selectTabState(global, getCurrentTabId()); if (connectionState === 'connectionStateReady' && tabState.isMasterTab && tabState.multitabNextAction) { // @ts-ignore actions[tabState.multitabNextAction.action](tabState.multitabNextAction.payload); actions.clearMultitabNextAction({ tabId: tabState.id }); } if (connectionState === global.connectionState) { return; } global = { ...global, connectionState, }; setGlobal(global); if (global.isSynced) { const channelStackIds = Object.values(global.byTabId) .flatMap((tab) => tab.messageLists) .map((messageList) => messageList.chatId) .filter((chatId) => { const chat = global.chats.byId[chatId]; return chat && (isChatChannel(chat) || isChatSuperGroup(chat)); }); if (connectionState === 'connectionStateReady' && channelStackIds.length) { unique(channelStackIds).forEach((chatId) => { actions.requestChannelDifference({ chatId }); }); } } if (connectionState === 'connectionStateBroken') { actions.signOut({ forceInitApi: true }); } } function onUpdateSession(global: T, actions: RequiredGlobalActions, update: ApiUpdateSession) { const { sessionData } = update; global = getGlobal(); const { authRememberMe, authState } = global; const isEmpty = !sessionData || !sessionData.mainDcId; if (!authRememberMe || authState !== 'authorizationStateReady' || isEmpty) { return; } actions.saveSession({ sessionData }); } function onUpdateServerTimeOffset(update: ApiUpdateServerTimeOffset) { setServerTimeOffset(update.serverTimeOffset); } function onUpdateCurrentUser(global: T, update: ApiUpdateCurrentUser) { const { currentUser, currentUserFullInfo } = update; global = { ...updateUser(global, currentUser.id, currentUser), currentUserId: currentUser.id, }; global = updateUserFullInfo(global, currentUser.id, currentUserFullInfo); setGlobal(global); updateSessionUserId(currentUser.id); } function updateSessionUserId(currentUserId: string) { const sessionUserAuth = localStorage.getItem(SESSION_USER_KEY); if (!sessionUserAuth) return; const userAuth = JSON.parse(sessionUserAuth); userAuth.id = currentUserId; localStorage.setItem(SESSION_USER_KEY, JSON.stringify(userAuth)); }