Skip to content

Commit b1959fd

Browse files
committed
Generalize seed-full-reconnect helper across Onyx clear flows
1 parent 7873aac commit b1959fd

4 files changed

Lines changed: 43 additions & 18 deletions

File tree

src/libs/actions/App.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import ROUTES from '@src/ROUTES';
2525
import type * as OnyxTypes from '@src/types/onyx';
2626
import type Locale from '@src/types/onyx/Locale';
2727
import type {OnyxData} from '@src/types/onyx/Request';
28+
import clearOnyxAndSeedFullReconnect from './clearOnyxAndSeedFullReconnect';
2829
import {setShouldForceOffline} from './Network';
2930
import {getAll, rollbackOngoingRequest, save} from './PersistedRequests';
3031
import {createDraftInitialWorkspace, createWorkspace, generateDefaultWorkspaceName, generatePolicyID} from './Policy/Policy';
@@ -849,7 +850,9 @@ function clearOnyxAndResetApp(shouldNavigateToHomepage?: boolean) {
849850
const sequentialQueue = getAll();
850851

851852
Navigation.clearPreloadedRoutes();
852-
const resetPromise = Onyx.clear(KEYS_TO_PRESERVE)
853+
// Seed LAST_FULL_RECONNECT_TIME so subscribeToFullReconnect doesn't fire a duplicate
854+
// ReconnectApp once the openApp() below lands NVP_RECONNECT_APP_IF_FULL_RECONNECT_BEFORE.
855+
const resetPromise = clearOnyxAndSeedFullReconnect(KEYS_TO_PRESERVE)
853856
.then(() => {
854857
// Network key is preserved, so when exiting imported state, we should:
855858
// 1. Stop forcing offline mode so the app can reconnect

src/libs/actions/Delegate.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import type {OnyxEntry, OnyxKey, OnyxUpdate} from 'react-native-onyx';
44
import * as API from '@libs/API';
55
import type {AddDelegateParams as APIAddDelegateParams, RemoveDelegateParams as APIRemoveDelegateParams, UpdateDelegateRoleParams as APIUpdateDelegateRoleParams} from '@libs/API/parameters';
66
import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
7-
import DateUtils from '@libs/DateUtils';
87
import * as ErrorUtils from '@libs/ErrorUtils';
98
import Log from '@libs/Log';
109
import {clearPreservedSearchNavigatorStates} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState';
@@ -18,6 +17,7 @@ import type Credentials from '@src/types/onyx/Credentials';
1817
import type Response from '@src/types/onyx/Response';
1918
import type Session from '@src/types/onyx/Session';
2019
import {confirmReadyToOpenApp, openApp} from './App';
20+
import clearOnyxAndSeedFullReconnect from './clearOnyxAndSeedFullReconnect';
2121
import updateSessionAuthTokens from './Session/updateSessionAuthTokens';
2222
import updateSessionUser from './Session/updateSessionUser';
2323

@@ -43,25 +43,17 @@ const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [
4343
];
4444

4545
/**
46-
* Atomically reset Onyx for a delegate-access transition while seeding two values that
47-
* subscribers would otherwise misinterpret on the post-clear state and double up calls
48-
* the caller is about to make explicitly:
46+
* Atomically reset Onyx for a delegate-access transition. The IS_LOADING_APP=true
47+
* seed is delegate-specific: without it, consumers observe HAS_LOADED_APP=true and
48+
* IS_LOADING_APP=undefined together, which looks like a stuck app and triggers
49+
* DelegateAccessHandler's recovery effect, queueing a duplicate openApp.
4950
*
50-
* - IS_LOADING_APP=true: without it, consumers observe HAS_LOADED_APP=true and
51-
* IS_LOADING_APP=undefined together, which looks like a stuck app and triggers
52-
* DelegateAccessHandler's recovery effect, queueing a duplicate openApp.
53-
* - LAST_FULL_RECONNECT_TIME=now: subscribeToFullReconnect compares this against the
54-
* server-supplied NVP_RECONNECT_APP_IF_FULL_RECONNECT_BEFORE that lands in OpenApp's
55-
* response.onyxData. Because applyHTTPSOnyxUpdates applies response.onyxData before
56-
* successData, the timestamp would still be empty when the comparison runs, falsely
57-
* triggering a duplicate ReconnectApp. Seeding to `now` short-circuits the subscriber
58-
* until OpenApp's successData refreshes it.
51+
* The reconnect-time seed is handled by clearOnyxAndSeedFullReconnect.
5952
*/
6053
function clearOnyxForDelegateTransition(): Promise<void> {
61-
return Onyx.multiSet({
54+
return clearOnyxAndSeedFullReconnect(KEYS_TO_PRESERVE_DELEGATE_ACCESS, {
6255
[ONYXKEYS.IS_LOADING_APP]: true,
63-
[ONYXKEYS.LAST_FULL_RECONNECT_TIME]: DateUtils.getDBTime(),
64-
}).then(() => Onyx.clear([...KEYS_TO_PRESERVE_DELEGATE_ACCESS, ONYXKEYS.IS_LOADING_APP, ONYXKEYS.LAST_FULL_RECONNECT_TIME]));
56+
});
6557
}
6658

6759
type WithDelegatedAccess = {

src/libs/actions/Session/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import Timers from '@libs/Timers';
5151
import {hideContextMenu} from '@pages/inbox/report/ContextMenu/ReportActionContextMenu';
5252
import {confirmReadyToOpenApp, KEYS_TO_PRESERVE, openApp} from '@userActions/App';
5353
import {clearCachedAttachments} from '@userActions/Attachment';
54+
import clearOnyxAndSeedFullReconnect from '@userActions/clearOnyxAndSeedFullReconnect';
5455
import {clearOnyxForDelegateTransition} from '@userActions/Delegate';
5556
import * as Device from '@userActions/Device';
5657
import type HybridAppSettings from '@userActions/HybridApp/types';
@@ -448,7 +449,9 @@ function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSess
448449
});
449450
} else if (shouldRestoreStashedSession && !shouldStashSession && hasStashedSession(stashedSession, stashedCredentials)) {
450451
// Preserve SESSION during clear to avoid a login page flash, then restore the stashed session.
451-
Onyx.clear(KEYS_TO_PRESERVE_SUPPORTAL).then(() => {
452+
// Seed LAST_FULL_RECONNECT_TIME so subscribeToFullReconnect doesn't fire a duplicate
453+
// ReconnectApp once the openApp() below lands NVP_RECONNECT_APP_IF_FULL_RECONNECT_BEFORE.
454+
clearOnyxAndSeedFullReconnect(KEYS_TO_PRESERVE_SUPPORTAL).then(() => {
452455
Onyx.multiSet(onyxSetParams).then(() => {
453456
Onyx.set(ONYXKEYS.STASHED_CREDENTIALS, {});
454457
Onyx.set(ONYXKEYS.STASHED_SESSION, {});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Onyx from 'react-native-onyx';
2+
import type {OnyxKey} from 'react-native-onyx';
3+
import type {OnyxMultiSetInput} from 'react-native-onyx/dist/types';
4+
import DateUtils from '@libs/DateUtils';
5+
import ONYXKEYS from '@src/ONYXKEYS';
6+
7+
/**
8+
* Atomically clears Onyx while seeding LAST_FULL_RECONNECT_TIME=now so that
9+
* subscribeToFullReconnect doesn't fire a redundant ReconnectApp when the caller
10+
* runs an OpenApp right after the clear: OpenApp's response.onyxData carries
11+
* NVP_RECONNECT_APP_IF_FULL_RECONNECT_BEFORE and applyHTTPSOnyxUpdates applies
12+
* response.onyxData before successData, so without the seed the timestamp would
13+
* still be empty when the comparison runs and trigger a duplicate reconnect.
14+
*
15+
* Pass `extraSeeds` to seed additional keys atomically with the timestamp (e.g.
16+
* IS_LOADING_APP=true for delegate transitions). Seeded keys are appended to the
17+
* preserve list automatically so they survive the clear.
18+
*/
19+
function clearOnyxAndSeedFullReconnect(keysToPreserve: OnyxKey[], extraSeeds?: OnyxMultiSetInput): Promise<void> {
20+
const seeds: OnyxMultiSetInput = {
21+
...extraSeeds,
22+
[ONYXKEYS.LAST_FULL_RECONNECT_TIME]: DateUtils.getDBTime(),
23+
};
24+
return Onyx.multiSet(seeds).then(() => Onyx.clear([...keysToPreserve, ...(Object.keys(seeds) as OnyxKey[])]));
25+
}
26+
27+
export default clearOnyxAndSeedFullReconnect;

0 commit comments

Comments
 (0)