diff --git a/src/libs/actions/OnyxUpdates.js b/src/libs/actions/OnyxUpdates.ts similarity index 62% rename from src/libs/actions/OnyxUpdates.js rename to src/libs/actions/OnyxUpdates.ts index 8e45e7dd2e66..50a4fdffc3ae 100644 --- a/src/libs/actions/OnyxUpdates.js +++ b/src/libs/actions/OnyxUpdates.ts @@ -1,28 +1,25 @@ -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; +import {Merge} from 'type-fest'; import PusherUtils from '../PusherUtils'; import ONYXKEYS from '../../ONYXKEYS'; import * as QueuedOnyxUpdates from './QueuedOnyxUpdates'; import CONST from '../../CONST'; +import {OnyxUpdatesFromServer, OnyxUpdateEvent, Request} from '../../types/onyx'; +import Response from '../../types/onyx/Response'; // This key needs to be separate from ONYXKEYS.ONYX_UPDATES_FROM_SERVER so that it can be updated without triggering the callback when the server IDs are updated. If that // callback were triggered it would lead to duplicate processing of server updates. -let lastUpdateIDAppliedToClient = 0; +let lastUpdateIDAppliedToClient: OnyxEntry = 0; Onyx.connect({ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, callback: (val) => (lastUpdateIDAppliedToClient = val), }); -/** - * @param {Object} request - * @param {Object} response - * @returns {Promise} - */ -function applyHTTPSOnyxUpdates(request, response) { +function applyHTTPSOnyxUpdates(request: Request, response: Response) { console.debug('[OnyxUpdateManager] Applying https update'); // For most requests we can immediately update Onyx. For write requests we queue the updates and apply them after the sequential queue has flushed to prevent a replay effect in // the UI. See https://github.com/Expensify/App/issues/12775 for more info. - const updateHandler = request.data.apiRequestType === CONST.API_REQUEST_TYPE.WRITE ? QueuedOnyxUpdates.queueOnyxUpdates : Onyx.update; + const updateHandler = request?.data?.apiRequestType === CONST.API_REQUEST_TYPE.WRITE ? QueuedOnyxUpdates.queueOnyxUpdates : Onyx.update; // First apply any onyx data updates that are being sent back from the API. We wait for this to complete and then // apply successData or failureData. This ensures that we do not update any pending, loading, or other UI states contained @@ -46,55 +43,45 @@ function applyHTTPSOnyxUpdates(request, response) { }); } -/** - * @param {Array} updates - * @returns {Promise} - */ -function applyPusherOnyxUpdates(updates) { +function applyPusherOnyxUpdates(updates: OnyxUpdateEvent[]) { console.debug('[OnyxUpdateManager] Applying pusher update'); - const pusherEventPromises = _.map(updates, (update) => PusherUtils.triggerMultiEventHandler(update.eventType, update.data)); + const pusherEventPromises = updates.map((update) => PusherUtils.triggerMultiEventHandler(update.eventType, update.data)); return Promise.all(pusherEventPromises).then(() => { console.debug('[OnyxUpdateManager] Done applying Pusher update'); }); } /** - * @param {Object[]} updateParams - * @param {String} updateParams.type - * @param {Number} updateParams.lastUpdateID - * @param {Object} [updateParams.request] Exists if updateParams.type === 'https' - * @param {Object} [updateParams.response] Exists if updateParams.type === 'https' - * @param {Object} [updateParams.updates] Exists if updateParams.type === 'pusher' - * @returns {Promise} + * @param [updateParams.request] Exists if updateParams.type === 'https' + * @param [updateParams.response] Exists if updateParams.type === 'https' + * @param [updateParams.updates] Exists if updateParams.type === 'pusher' */ -function apply({lastUpdateID, type, request, response, updates}) { +function apply({lastUpdateID, type, request, response, updates}: Merge): Promise; +function apply({lastUpdateID, type, request, response, updates}: Merge): Promise; +function apply({lastUpdateID, type, request, response, updates}: OnyxUpdatesFromServer): Promise | undefined { console.debug(`[OnyxUpdateManager] Applying update type: ${type} with lastUpdateID: ${lastUpdateID}`, {request, response, updates}); - if (lastUpdateID && lastUpdateID < lastUpdateIDAppliedToClient) { + if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) < lastUpdateIDAppliedToClient) { console.debug('[OnyxUpdateManager] Update received was older than current state, returning without applying the updates'); return Promise.resolve(); } - if (lastUpdateID && lastUpdateID > lastUpdateIDAppliedToClient) { - Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, lastUpdateID); + if (lastUpdateID && lastUpdateIDAppliedToClient && Number(lastUpdateID) > lastUpdateIDAppliedToClient) { + Onyx.merge(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, Number(lastUpdateID)); } - if (type === CONST.ONYX_UPDATE_TYPES.HTTPS) { + if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) { return applyHTTPSOnyxUpdates(request, response); } - if (type === CONST.ONYX_UPDATE_TYPES.PUSHER) { + if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) { return applyPusherOnyxUpdates(updates); } } /** - * @param {Object[]} updateParams - * @param {String} updateParams.type - * @param {Object} [updateParams.request] Exists if updateParams.type === 'https' - * @param {Object} [updateParams.response] Exists if updateParams.type === 'https' - * @param {Object} [updateParams.updates] Exists if updateParams.type === 'pusher' - * @param {Number} [updateParams.lastUpdateID] - * @param {Number} [updateParams.previousUpdateID] + * @param [updateParams.request] Exists if updateParams.type === 'https' + * @param [updateParams.response] Exists if updateParams.type === 'https' + * @param [updateParams.updates] Exists if updateParams.type === 'pusher' */ -function saveUpdateInformation(updateParams) { +function saveUpdateInformation(updateParams: OnyxUpdatesFromServer) { // Always use set() here so that the updateParams are never merged and always unique to the request that came in Onyx.set(ONYXKEYS.ONYX_UPDATES_FROM_SERVER, updateParams); } @@ -102,10 +89,9 @@ function saveUpdateInformation(updateParams) { /** * This function will receive the previousUpdateID from any request/pusher update that has it, compare to our current app state * and return if an update is needed - * @param {Number} previousUpdateID The previousUpdateID contained in the response object - * @returns {Boolean} + * @param previousUpdateID The previousUpdateID contained in the response object */ -function doesClientNeedToBeUpdated(previousUpdateID = 0) { +function doesClientNeedToBeUpdated(previousUpdateID = 0): boolean { // If no previousUpdateID is sent, this is not a WRITE request so we don't need to update our current state if (!previousUpdateID) { return false; diff --git a/src/types/onyx/OnyxUpdatesFromServer.ts b/src/types/onyx/OnyxUpdatesFromServer.ts index 02a96d4ce230..50b1503b90bd 100644 --- a/src/types/onyx/OnyxUpdatesFromServer.ts +++ b/src/types/onyx/OnyxUpdatesFromServer.ts @@ -2,13 +2,18 @@ import {OnyxUpdate} from 'react-native-onyx'; import Request from './Request'; import Response from './Response'; +type OnyxUpdateEvent = { + eventType: string; + data: OnyxUpdate[]; +}; + type OnyxUpdatesFromServer = { type: 'https' | 'pusher'; lastUpdateID: number | string; previousUpdateID: number | string; request?: Request; response?: Response; - updates?: OnyxUpdate[]; + updates?: OnyxUpdateEvent[]; }; -export default OnyxUpdatesFromServer; +export type {OnyxUpdatesFromServer, OnyxUpdateEvent}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index d908c0b36ce1..47262a14540e 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -33,7 +33,7 @@ import ReimbursementAccountDraft from './ReimbursementAccountDraft'; import WalletTransfer from './WalletTransfer'; import ReceiptModal from './ReceiptModal'; import MapboxAccessToken from './MapboxAccessToken'; -import OnyxUpdatesFromServer from './OnyxUpdatesFromServer'; +import {OnyxUpdatesFromServer, OnyxUpdateEvent} from './OnyxUpdatesFromServer'; import Download from './Download'; import PolicyMember from './PolicyMember'; import Policy from './Policy'; @@ -93,6 +93,7 @@ export type { Form, AddDebitCardForm, OnyxUpdatesFromServer, + OnyxUpdateEvent, RecentWaypoints, RecentlyUsedCategories, };