From 650fe23c0636c487e4be43f17296e226444a835e Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Wed, 9 Apr 2025 16:19:29 +0200 Subject: [PATCH 01/12] initial changes to add queueFlushedData --- src/libs/API/index.ts | 1 + src/libs/Network/SequentialQueue.ts | 21 +++++++++++++++------ src/libs/actions/App.ts | 3 ++- src/types/onyx/Request.ts | 3 +++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/libs/API/index.ts b/src/libs/API/index.ts index feed7a13bd09..0ba6391d21bc 100644 --- a/src/libs/API/index.ts +++ b/src/libs/API/index.ts @@ -47,6 +47,7 @@ type OnyxData = { successData?: OnyxUpdate[]; failureData?: OnyxUpdate[]; finallyData?: OnyxUpdate[]; + queueFlushedData?: OnyxUpdate[]; }; /** diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 59df3ce78f4e..9f1efceffaa4 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,4 +1,4 @@ -import Onyx from 'react-native-onyx'; +import Onyx, { OnyxUpdate } from 'react-native-onyx'; import { deleteRequestsByIndices as deletePersistedRequestsByIndices, endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, @@ -61,7 +61,7 @@ function flushOnyxUpdatesQueue() { Log.info('[SequentialQueue] Queue already paused'); return; } - flushQueue(); + return flushQueue(); } /** @@ -142,7 +142,7 @@ function process(): Promise { * Resetting can cause unresolved READ requests to hang if tied to the old promise, * so some cases (e.g., unpausing) require skipping the reset to maintain proper behavior. */ -function flush(shouldResetPromise = true) { +function flush(shouldResetPromise = true, request?: OnyxRequest) { // When the queue is paused, return early. This will keep an requests in the queue and they will get flushed again when the queue is unpaused if (isQueuePaused) { Log.info('[SequentialQueue] Unable to flush. Queue is paused.'); @@ -193,7 +193,12 @@ function flush(shouldResetPromise = true) { // The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty if (getAllPersistedRequests().length === 0) { - flushOnyxUpdatesQueue(); + flushOnyxUpdatesQueue()?.then(() => { + if (!request?.queueFlushedData) { + return; + } + updateHandler(request?.queueFlushedData); + }); } }); }, @@ -273,11 +278,11 @@ function push(newRequest: OnyxRequest) { // If the queue is running this request will run once it has finished processing the current batch if (isSequentialQueueRunning) { - isReadyPromise.then(() => flush()); + isReadyPromise.then(() => flush(true, newRequest)); return; } - flush(); + flush(true, newRequest); } function getCurrentRequest(): Promise { @@ -310,3 +315,7 @@ function resetQueue(): void { export {flush, getCurrentRequest, isRunning, isPaused, push, waitForIdle, pause, unpause, process, resetQueue, sequentialQueueRequestThrottle}; export type {RequestError}; + function updateHandler(successData: OnyxUpdate[] | undefined) { + throw new Error('Function not implemented.'); + } + diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index 739513e110c0..c8e2e7fae3d1 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -274,6 +274,7 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals value: false, }, ], + queueFlushedData: [], }; if (isOpenApp) { @@ -283,7 +284,7 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals value: true, }); - result.finallyData?.push({ + result.queueFlushedData?.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.IS_LOADING_APP, value: false, diff --git a/src/types/onyx/Request.ts b/src/types/onyx/Request.ts index b0dcc043a5bf..c30e4329137a 100644 --- a/src/types/onyx/Request.ts +++ b/src/types/onyx/Request.ts @@ -14,6 +14,9 @@ type OnyxData = { /** Onyx instructions that are executed before request is made to the server */ optimisticData?: OnyxUpdate[]; + + /** Onyx instructions that are executed when Onyx queue is flushed */ + queueFlushedData?: OnyxUpdate[]; }; /** HTTP request method names */ From 41b1507abaa005e7894a3fe951b22419cc7421d7 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Wed, 9 Apr 2025 16:43:29 +0200 Subject: [PATCH 02/12] render withPolicy only after app is loaded --- src/libs/Network/SequentialQueue.ts | 6 +----- src/pages/workspace/withPolicy.tsx | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 9f1efceffaa4..0a90b2c22f41 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -197,7 +197,7 @@ function flush(shouldResetPromise = true, request?: OnyxRequest) { if (!request?.queueFlushedData) { return; } - updateHandler(request?.queueFlushedData); + Onyx.update(request?.queueFlushedData); }); } }); @@ -315,7 +315,3 @@ function resetQueue(): void { export {flush, getCurrentRequest, isRunning, isPaused, push, waitForIdle, pause, unpause, process, resetQueue, sequentialQueueRequestThrottle}; export type {RequestError}; - function updateHandler(successData: OnyxUpdate[] | undefined) { - throw new Error('Function not implemented.'); - } - diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 60f761c4fb78..3938a955006a 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -78,10 +78,10 @@ export default function ( ): React.ComponentType & RefAttributes> { function WithPolicy(props: Omit, ref: ForwardedRef) { const policyID = getPolicyIDFromRoute(props.route as PolicyRoute); - + const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); - const isLoadingPolicy = isLoadingOnyxValue(policyResults, policyDraftResults); + const isLoadingPolicy = isLoadingApp || isLoadingOnyxValue(policyResults, policyDraftResults); if (policyID.length > 0) { Policy.updateLastAccessedWorkspace(policyID); From 1d75141cbd29ce8b75f4e74d5f47520e4c077545 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Wed, 9 Apr 2025 18:29:24 +0200 Subject: [PATCH 03/12] Fix lint errors --- src/libs/Network/SequentialQueue.ts | 4 ++-- src/pages/workspace/withPolicy.tsx | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 0a90b2c22f41..2a68a0326efb 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,4 +1,4 @@ -import Onyx, { OnyxUpdate } from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import { deleteRequestsByIndices as deletePersistedRequestsByIndices, endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, @@ -313,5 +313,5 @@ function resetQueue(): void { resolveIsReadyPromise?.(); } -export {flush, getCurrentRequest, isRunning, isPaused, push, waitForIdle, pause, unpause, process, resetQueue, sequentialQueueRequestThrottle}; +export {flush, getCurrentRequest, isPaused, isRunning, pause, process, push, resetQueue, sequentialQueueRequestThrottle, unpause, waitForIdle}; export type {RequestError}; diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 3938a955006a..bec1a9ac6539 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -4,7 +4,8 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {AuthScreensParamList, ReimbursementAccountNavigatorParamList, SettingsNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@navigation/types'; -import * as Policy from '@userActions/Policy/Policy'; +import {updateLastAccessedWorkspace} from '@userActions/Policy/Policy'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; @@ -51,7 +52,7 @@ type PolicyRouteName = type PolicyRoute = PlatformStackRouteProp; function getPolicyIDFromRoute(route: PolicyRoute): string { - return route?.params?.policyID ?? '-1'; + return route?.params?.policyID ?? CONST.DEFAULT_NUMBER_ID.toString(); } type WithPolicyOnyxProps = { @@ -81,10 +82,11 @@ export default function ( const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); + /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */ const isLoadingPolicy = isLoadingApp || isLoadingOnyxValue(policyResults, policyDraftResults); if (policyID.length > 0) { - Policy.updateLastAccessedWorkspace(policyID); + updateLastAccessedWorkspace(policyID); } return ( From 7271eda7593256904481c6443fae06b6bc3f2e19 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Thu, 17 Apr 2025 16:27:12 +0200 Subject: [PATCH 04/12] Modify queueFlushedData stoarge functionality to accomodate offline scenario --- src/libs/Network/SequentialQueue.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 2a68a0326efb..366029b7b186 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,4 +1,4 @@ -import Onyx from 'react-native-onyx'; +import Onyx, { OnyxUpdate } from 'react-native-onyx'; import { deleteRequestsByIndices as deletePersistedRequestsByIndices, endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, @@ -64,6 +64,7 @@ function flushOnyxUpdatesQueue() { return flushQueue(); } +let queueFlushedDataToStore: OnyxUpdate[] = []; /** * Process any persisted requests, when online, one at a time until the queue is empty. * @@ -108,6 +109,10 @@ function process(): Promise { Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); endPersistedRequestAndRemoveFromQueue(requestToProcess); + if (requestToProcess.queueFlushedData) { + queueFlushedDataToStore.push(...requestToProcess.queueFlushedData); + } + sequentialQueueRequestThrottle.clear(); return process(); }) @@ -142,7 +147,7 @@ function process(): Promise { * Resetting can cause unresolved READ requests to hang if tied to the old promise, * so some cases (e.g., unpausing) require skipping the reset to maintain proper behavior. */ -function flush(shouldResetPromise = true, request?: OnyxRequest) { +function flush(shouldResetPromise = true) { // When the queue is paused, return early. This will keep an requests in the queue and they will get flushed again when the queue is unpaused if (isQueuePaused) { Log.info('[SequentialQueue] Unable to flush. Queue is paused.'); @@ -194,10 +199,14 @@ function flush(shouldResetPromise = true, request?: OnyxRequest) { // The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty if (getAllPersistedRequests().length === 0) { flushOnyxUpdatesQueue()?.then(() => { - if (!request?.queueFlushedData) { + if (queueFlushedDataToStore.length === 0) { return; } - Onyx.update(request?.queueFlushedData); + Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedDataToStore}); + Onyx.update(queueFlushedDataToStore).then(() => { + Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {queueFlushedDataToStore}); + }); + queueFlushedDataToStore.length = 0; }); } }); @@ -278,11 +287,11 @@ function push(newRequest: OnyxRequest) { // If the queue is running this request will run once it has finished processing the current batch if (isSequentialQueueRunning) { - isReadyPromise.then(() => flush(true, newRequest)); + isReadyPromise.then(() => flush(true)); return; } - flush(true, newRequest); + flush(true); } function getCurrentRequest(): Promise { From b5c8f813532a68249ffaff7b47858d0f9719cbe3 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Tue, 22 Apr 2025 10:32:51 +0200 Subject: [PATCH 05/12] Move queueFlushedData to Onyx storage --- src/ONYXKEYS.ts | 5 +++++ src/libs/Network/SequentialQueue.ts | 31 ++++++++++++++++++++++++++--- src/libs/actions/App.ts | 5 +++++ src/pages/workspace/withPolicy.tsx | 6 +++--- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 5554a1f2c33f..c3477e2723ad 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,3 +1,4 @@ +import {OnyxUpdate} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type CONST from './CONST'; import type {OnboardingCompanySize} from './CONST'; @@ -503,6 +504,9 @@ const ONYXKEYS = { /** Information about loading states while talking with AI sales */ TALK_TO_AI_SALES: 'talkToAISales', + /** Onyx updates that should be stored after sequential queue is flushed */ + QUEUE_FLUSHED_DATA: 'queueFlushedData', + /** Set when we are loading bill when downgrade */ IS_LOADING_BILL_WHEN_DOWNGRADE: 'isLoadingBillWhenDowngrade', @@ -1020,6 +1024,7 @@ type OnyxValuesMapping = { [ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf; [ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge; [ONYXKEYS.TALK_TO_AI_SALES]: OnyxTypes.TalkToAISales; + [ONYXKEYS.QUEUE_FLUSHED_DATA]: OnyxUpdate[]; // The value of this nvp is a string representation of the date when the block expires, or an empty string if the user is not blocked [ONYXKEYS.NVP_BLOCKED_FROM_CHAT]: string; diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 7a4c285df6ff..d3ed70d94616 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -1,4 +1,5 @@ -import Onyx, { OnyxUpdate } from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import { deleteRequestsByIndices as deletePersistedRequestsByIndices, endRequestAndRemoveFromQueue as endPersistedRequestAndRemoveFromQueue, @@ -76,6 +77,29 @@ function flushOnyxUpdatesQueue() { } let queueFlushedDataToStore: OnyxUpdate[] = []; + +Onyx.connect({ + key: ONYXKEYS.QUEUE_FLUSHED_DATA, + callback: (val) => { + if (!val) { + return; + } + queueFlushedDataToStore = val; + }, +}); + +function saveQueueFlushedData(...onyxUpdates: OnyxUpdate[]) { + const newValue = [...queueFlushedDataToStore, ...onyxUpdates]; + // eslint-disable-next-line rulesdir/prefer-actions-set-data + return Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, newValue).then(() => { + Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {newValue}); + }); +} +function clearQueueFlushedData() { + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, []); +} + /** * Process any persisted requests, when online, one at a time until the queue is empty. * @@ -121,9 +145,9 @@ function process(): Promise { Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); endPersistedRequestAndRemoveFromQueue(requestToProcess); if (requestToProcess.queueFlushedData) { - queueFlushedDataToStore.push(...requestToProcess.queueFlushedData); + saveQueueFlushedData(...requestToProcess.queueFlushedData); } - + sequentialQueueRequestThrottle.clear(); return process(); }) @@ -219,6 +243,7 @@ function flush(shouldResetPromise = true) { Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedDataToStore}); Onyx.update(queueFlushedDataToStore).then(() => { Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {queueFlushedDataToStore}); + clearQueueFlushedData(); }); queueFlushedDataToStore.length = 0; }); diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index c8e2e7fae3d1..a11b40b1e23a 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -259,6 +259,11 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals key: ONYXKEYS.IS_LOADING_REPORT_DATA, value: true, }, + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.QUEUE_FLUSHED_DATA, + value: [], + }, ], successData: [ { diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index bec1a9ac6539..b55cfaa66fa4 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -79,9 +79,9 @@ export default function ( ): React.ComponentType & RefAttributes> { function WithPolicy(props: Omit, ref: ForwardedRef) { const policyID = getPolicyIDFromRoute(props.route as PolicyRoute); - const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP); - const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); - const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`); + const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: false}); + const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: false}); + const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, {canBeMissing: true}); /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */ const isLoadingPolicy = isLoadingApp || isLoadingOnyxValue(policyResults, policyDraftResults); From 4a56b0868d5be2b759a60b55bfb09ec330ad6b9c Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Tue, 22 Apr 2025 10:36:07 +0200 Subject: [PATCH 06/12] Remove optimistic key update from App.ts --- src/libs/actions/App.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index a11b40b1e23a..c8e2e7fae3d1 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -259,11 +259,6 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals key: ONYXKEYS.IS_LOADING_REPORT_DATA, value: true, }, - { - onyxMethod: Onyx.METHOD.SET, - key: ONYXKEYS.QUEUE_FLUSHED_DATA, - value: [], - }, ], successData: [ { From 100452fba00507a7e14600c049970923e904c0ae Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Tue, 22 Apr 2025 10:45:20 +0200 Subject: [PATCH 07/12] policy canBeMissing set to true --- src/pages/workspace/withPolicy.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index b55cfaa66fa4..471d323b3584 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -80,7 +80,7 @@ export default function ( function WithPolicy(props: Omit, ref: ForwardedRef) { const policyID = getPolicyIDFromRoute(props.route as PolicyRoute); const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: false}); - const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: false}); + const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true}); const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, {canBeMissing: true}); /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */ const isLoadingPolicy = isLoadingApp || isLoadingOnyxValue(policyResults, policyDraftResults); From 810cd3824166f2c5488d09d342f4b420a9807f1d Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Wed, 23 Apr 2025 12:23:57 +0200 Subject: [PATCH 08/12] Lint issue fix --- src/ONYXKEYS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index e793fc4eba08..2d560e3a95ef 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,4 +1,4 @@ -import {OnyxUpdate} from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type CONST from './CONST'; import type {OnboardingCompanySize} from './CONST'; From 1bae6edb11630b3c20f9cf3b6fb46ed238714bb7 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Wed, 23 Apr 2025 12:50:21 +0200 Subject: [PATCH 09/12] use HAS_LOADED_APP instead of IS_APP_LOADING --- src/libs/actions/App.ts | 15 ++++++++++----- .../ReimbursementAccountPage.tsx | 1 + src/pages/workspace/withPolicy.tsx | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index c8e2e7fae3d1..ba5f24fde0cd 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -259,14 +259,13 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals key: ONYXKEYS.IS_LOADING_REPORT_DATA, value: true, }, - ], - successData: [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.HAS_LOADED_APP, - value: true, + value: false, }, ], + successData: [], finallyData: [ { onyxMethod: Onyx.METHOD.MERGE, @@ -274,7 +273,13 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals value: false, }, ], - queueFlushedData: [], + queueFlushedData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.HAS_LOADED_APP, + value: true, + }, + ], }; if (isOpenApp) { @@ -284,7 +289,7 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals value: true, }); - result.queueFlushedData?.push({ + result.finallyData?.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.IS_LOADING_APP, value: false, diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index f5c8ea74cd45..412e6323ef37 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -463,6 +463,7 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen isNonUSDWorkspace={isNonUSDWorkspace} setNonUSDBankAccountStep={setNonUSDBankAccountStep} setUSDBankAccountStep={setUSDBankAccountStep} + policyID={policyIDParam} /> ); } diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 471d323b3584..22edd956b4ba 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -79,11 +79,11 @@ export default function ( ): React.ComponentType & RefAttributes> { function WithPolicy(props: Omit, ref: ForwardedRef) { const policyID = getPolicyIDFromRoute(props.route as PolicyRoute); - const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: false}); + const [hasLoadedApp] = useOnyx(ONYXKEYS.HAS_LOADED_APP, {canBeMissing: false}); const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true}); const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, {canBeMissing: true}); /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */ - const isLoadingPolicy = isLoadingApp || isLoadingOnyxValue(policyResults, policyDraftResults); + const isLoadingPolicy = !hasLoadedApp || isLoadingOnyxValue(policyResults, policyDraftResults); if (policyID.length > 0) { updateLastAccessedWorkspace(policyID); From 01614a0bd451410401755052dceec05462f4705a Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Thu, 24 Apr 2025 09:16:57 +0200 Subject: [PATCH 10/12] Adjusted to PR comments --- src/libs/Network/SequentialQueue.ts | 4 +++- src/libs/actions/App.ts | 5 ----- src/pages/workspace/withPolicy.tsx | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index d3ed70d94616..81694ff25049 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -97,7 +97,9 @@ function saveQueueFlushedData(...onyxUpdates: OnyxUpdate[]) { } function clearQueueFlushedData() { // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, []); + Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, null).then(() => { + Log.info('[SequentialQueue] QueueFlushedData has been cleared.'); + }); } /** diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index ba5f24fde0cd..b29b203f01d5 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -259,11 +259,6 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false, isFullReconnect = fals key: ONYXKEYS.IS_LOADING_REPORT_DATA, value: true, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.HAS_LOADED_APP, - value: false, - }, ], successData: [], finallyData: [ diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 22edd956b4ba..1181fb28bacf 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -79,7 +79,7 @@ export default function ( ): React.ComponentType & RefAttributes> { function WithPolicy(props: Omit, ref: ForwardedRef) { const policyID = getPolicyIDFromRoute(props.route as PolicyRoute); - const [hasLoadedApp] = useOnyx(ONYXKEYS.HAS_LOADED_APP, {canBeMissing: false}); + const [hasLoadedApp] = useOnyx(ONYXKEYS.HAS_LOADED_APP, {canBeMissing: true}); const [policy, policyResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true}); const [policyDraft, policyDraftResults] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, {canBeMissing: true}); /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */ From 641b5776aadf4e693671aa45562f86b64bb6ee4a Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Thu, 24 Apr 2025 15:27:48 +0200 Subject: [PATCH 11/12] Introducing unit tests for QueueFlushedData --- src/libs/Network/SequentialQueue.ts | 35 +++++++++++++++++++++------ tests/unit/SequentialQueueTest.ts | 37 +++++++++++++++++++---------- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts index 81694ff25049..e89d1a5e4c5f 100644 --- a/src/libs/Network/SequentialQueue.ts +++ b/src/libs/Network/SequentialQueue.ts @@ -97,10 +97,14 @@ function saveQueueFlushedData(...onyxUpdates: OnyxUpdate[]) { } function clearQueueFlushedData() { // eslint-disable-next-line rulesdir/prefer-actions-set-data - Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, null).then(() => { + return Onyx.set(ONYXKEYS.QUEUE_FLUSHED_DATA, null).then(() => { + queueFlushedDataToStore.length = 0; Log.info('[SequentialQueue] QueueFlushedData has been cleared.'); }); } +function getQueueFlushedData() { + return queueFlushedDataToStore; +} /** * Process any persisted requests, when online, one at a time until the queue is empty. @@ -146,7 +150,9 @@ function process(): Promise { Log.info('[SequentialQueue] Removing persisted request because it was processed successfully.', false, {request: requestToProcess}); endPersistedRequestAndRemoveFromQueue(requestToProcess); + if (requestToProcess.queueFlushedData) { + Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedData: requestToProcess.queueFlushedData}); saveQueueFlushedData(...requestToProcess.queueFlushedData); } @@ -239,15 +245,15 @@ function flush(shouldResetPromise = true) { // The queue can be paused when we sync the data with backend so we should only update the Onyx data when the queue is empty if (getAllPersistedRequests().length === 0) { flushOnyxUpdatesQueue()?.then(() => { - if (queueFlushedDataToStore.length === 0) { + const queueFlushedData = getQueueFlushedData(); + if (queueFlushedData.length === 0) { return; } - Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedDataToStore}); - Onyx.update(queueFlushedDataToStore).then(() => { - Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {queueFlushedDataToStore}); + Log.info('[SequentialQueue] Will store queueFlushedData.', false, {queueFlushedData}); + Onyx.update(queueFlushedData).then(() => { + Log.info('[SequentialQueue] QueueFlushedData has been stored.', false, {queueFlushedData}); clearQueueFlushedData(); }); - queueFlushedDataToStore.length = 0; }); } }); @@ -363,5 +369,20 @@ function resetQueue(): void { resolveIsReadyPromise?.(); } -export {flush, getCurrentRequest, isPaused, isRunning, pause, process, push, resetQueue, sequentialQueueRequestThrottle, unpause, waitForIdle}; +export { + flush, + getCurrentRequest, + isPaused, + isRunning, + pause, + process, + push, + resetQueue, + sequentialQueueRequestThrottle, + unpause, + waitForIdle, + getQueueFlushedData, + saveQueueFlushedData, + clearQueueFlushedData, +}; export type {RequestError}; diff --git a/tests/unit/SequentialQueueTest.ts b/tests/unit/SequentialQueueTest.ts index 1808c0e19c7a..f515f29c3f7f 100644 --- a/tests/unit/SequentialQueueTest.ts +++ b/tests/unit/SequentialQueueTest.ts @@ -1,6 +1,7 @@ import Onyx from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import {waitForActiveRequestsToBeEmpty} from '@libs/E2E/utils/NetworkInterceptor'; -import {getAll, getLength, getOngoingRequest} from '@userActions/PersistedRequests'; +import {getAll, getLength, getOngoingRequest, save} from '@userActions/PersistedRequests'; import ONYXKEYS from '@src/ONYXKEYS'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import type Request from '../../src/types/onyx/Request'; @@ -13,18 +14,16 @@ const request: Request = { successData: [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}], failureData: [{key: 'userMetadata', onyxMethod: 'set', value: {}}], }; - -describe('SequentialQueue', () => { - beforeAll(() => { - Onyx.init({ - keys: ONYXKEYS, - }); +beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, }); - beforeEach(() => { - global.fetch = TestHelper.getGlobalFetchMock(); - return Onyx.clear().then(waitForBatchedUpdates); - }); - +}); +beforeEach(() => { + global.fetch = TestHelper.getGlobalFetchMock(); + return Onyx.clear().then(waitForBatchedUpdates); +}); +describe('SequentialQueue', () => { it('should push one request and persist one', () => { SequentialQueue.push(request); expect(getLength()).toBe(1); @@ -258,3 +257,17 @@ describe('SequentialQueue', () => { expect(getAll().length).toBe(1); }); }); + +describe('SequentialQueue - QueueFlushedData', () => { + it('should add to queueFlushedData', async () => { + const updates: OnyxUpdate[] = [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}]; + await SequentialQueue.saveQueueFlushedData(...updates); + expect(SequentialQueue.getQueueFlushedData()).toEqual([{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}]); + }); + it('should clear queueFlushedData', async () => { + const updates: OnyxUpdate[] = [{key: 'userMetadata', onyxMethod: 'set', value: {accountID: 1234}}]; + await SequentialQueue.saveQueueFlushedData(...updates); + await SequentialQueue.clearQueueFlushedData(); + expect(SequentialQueue.getQueueFlushedData()).toEqual([]); + }); +}); From c421417fcd71a101feb820c6ac06c461e2a4b3c6 Mon Sep 17 00:00:00 2001 From: Hubert Sosinski Date: Thu, 24 Apr 2025 15:34:43 +0200 Subject: [PATCH 12/12] remove unused import --- tests/unit/SequentialQueueTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/SequentialQueueTest.ts b/tests/unit/SequentialQueueTest.ts index f515f29c3f7f..d2896dc1ba7e 100644 --- a/tests/unit/SequentialQueueTest.ts +++ b/tests/unit/SequentialQueueTest.ts @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import {waitForActiveRequestsToBeEmpty} from '@libs/E2E/utils/NetworkInterceptor'; -import {getAll, getLength, getOngoingRequest, save} from '@userActions/PersistedRequests'; +import {getAll, getLength, getOngoingRequest} from '@userActions/PersistedRequests'; import ONYXKEYS from '@src/ONYXKEYS'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import type Request from '../../src/types/onyx/Request';