@@ -4,6 +4,7 @@ import type {OnyxEntry, OnyxKey, OnyxUpdate} from 'react-native-onyx';
44import * as API from '@libs/API' ;
55import type { AddDelegateParams as APIAddDelegateParams , RemoveDelegateParams as APIRemoveDelegateParams , UpdateDelegateRoleParams as APIUpdateDelegateRoleParams } from '@libs/API/parameters' ;
66import { READ_COMMANDS , SIDE_EFFECT_REQUEST_COMMANDS , WRITE_COMMANDS } from '@libs/API/types' ;
7+ import DateUtils from '@libs/DateUtils' ;
78import * as ErrorUtils from '@libs/ErrorUtils' ;
89import Log from '@libs/Log' ;
910import { clearPreservedSearchNavigatorStates } from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveNavigatorState' ;
@@ -41,6 +42,20 @@ const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [
4142 ONYXKEYS . COLLECTION . DEVICE_BIOMETRICS ,
4243] ;
4344
45+ /**
46+ * Reset Onyx for a delegate-access transition while seeding LAST_FULL_RECONNECT_TIME=now.
47+ *
48+ * subscribeToFullReconnect compares this timestamp against the server-supplied
49+ * NVP_RECONNECT_APP_IF_FULL_RECONNECT_BEFORE that lands in OpenApp's response.onyxData.
50+ * Because applyHTTPSOnyxUpdates applies response.onyxData before successData, the
51+ * timestamp would still be empty when the comparison runs, falsely triggering a
52+ * duplicate ReconnectApp on top of the OpenApp that follows the transition. Seeding
53+ * it to `now` short-circuits the subscriber until OpenApp's successData refreshes it.
54+ */
55+ function clearOnyxForDelegateTransition ( ) : Promise < void > {
56+ return Onyx . merge ( ONYXKEYS . LAST_FULL_RECONNECT_TIME , DateUtils . getDBTime ( ) ) . then ( ( ) => Onyx . clear ( [ ...KEYS_TO_PRESERVE_DELEGATE_ACCESS , ONYXKEYS . LAST_FULL_RECONNECT_TIME ] ) ) ;
57+ }
58+
4459type WithDelegatedAccess = {
4560 // Optional keeps call sites clean, but still encourages passing `account?.delegatedAccess`.
4661 delegatedAccess : DelegatedAccess | undefined ;
@@ -195,7 +210,7 @@ function connect({email, delegatedAccess, credentials, session, activePolicyID,
195210 } )
196211 . then ( ( ) => {
197212 NetworkStore . setAuthToken ( response ?. restrictedToken ?? null ) ;
198- return Onyx . clear ( KEYS_TO_PRESERVE_DELEGATE_ACCESS ) ;
213+ return clearOnyxForDelegateTransition ( ) ;
199214 } )
200215 . then ( ( ) => {
201216 confirmReadyToOpenApp ( ) ;
@@ -294,7 +309,7 @@ function disconnect({stashedCredentials, stashedSession}: DisconnectParams) {
294309 } )
295310 . then ( ( ) => {
296311 NetworkStore . setAuthToken ( response ?. authToken ?? null ) ;
297- return Onyx . clear ( KEYS_TO_PRESERVE_DELEGATE_ACCESS ) ;
312+ return clearOnyxForDelegateTransition ( ) ;
298313 } )
299314 . then ( ( ) => {
300315 Onyx . set ( ONYXKEYS . CREDENTIALS , {
@@ -663,7 +678,7 @@ function updateDelegateRole({email, role, validateCode, delegatedAccess}: Update
663678}
664679
665680function restoreDelegateSession < TKey extends OnyxKey > ( authenticateResponse : Response < TKey > ) {
666- Onyx . clear ( KEYS_TO_PRESERVE_DELEGATE_ACCESS ) . then ( ( ) => {
681+ clearOnyxForDelegateTransition ( ) . then ( ( ) => {
667682 updateSessionAuthTokens ( authenticateResponse ?. authToken , authenticateResponse ?. encryptedAuthToken ) ;
668683 updateSessionUser ( authenticateResponse ?. accountID , authenticateResponse ?. email ) ;
669684
@@ -690,5 +705,5 @@ export {
690705 updateDelegateRole ,
691706 removeDelegate ,
692707 openSecuritySettingsPage ,
693- KEYS_TO_PRESERVE_DELEGATE_ACCESS ,
708+ clearOnyxForDelegateTransition ,
694709} ;
0 commit comments