diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index f99400d87d3e..320f91f8a677 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -1,13 +1,12 @@ import {NativeModules} from 'react-native'; import Onyx from 'react-native-onyx'; -import type {OnyxUpdate} from 'react-native-onyx'; +import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import * as API from '@libs/API'; import type {AddDelegateParams, RemoveDelegateParams, UpdateDelegateRoleParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import Log from '@libs/Log'; import * as NetworkStore from '@libs/Network/NetworkStore'; -import {getCurrentUserEmail} from '@libs/Network/NetworkStore'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -16,6 +15,7 @@ import type Credentials from '@src/types/onyx/Credentials'; import type Response from '@src/types/onyx/Response'; import type Session from '@src/types/onyx/Session'; import {confirmReadyToOpenApp, openApp} from './App'; +import {getCurrentUserAccountID} from './Report'; import updateSessionAuthTokens from './Session/updateSessionAuthTokens'; import updateSessionUser from './Session/updateSessionUser'; @@ -51,6 +51,14 @@ Onyx.connect({ callback: (value) => (stashedSession = value ?? {}), }); +let activePolicyID: OnyxEntry; +Onyx.connect({ + key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, + callback: (newActivePolicyID) => { + activePolicyID = newActivePolicyID; + }, +}); + const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [ ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, @@ -73,6 +81,8 @@ function connect(email: string) { Onyx.set(ONYXKEYS.STASHED_CREDENTIALS, credentials); Onyx.set(ONYXKEYS.STASHED_SESSION, session); + const previousAccountID = getCurrentUserAccountID(); + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -130,6 +140,14 @@ function connect(email: string) { Onyx.update(failureData); return; } + if (!activePolicyID) { + Log.alert('[Delegate] Unable to access activePolicyID'); + Onyx.update(failureData); + return; + } + const restrictedToken = response.restrictedToken; + const policyID = activePolicyID; + return SequentialQueue.waitForIdle() .then(() => Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS)) .then(() => { @@ -138,9 +156,7 @@ function connect(email: string) { NetworkStore.setAuthToken(response?.restrictedToken ?? null); confirmReadyToOpenApp(); - openApp(); - - NativeModules.HybridAppModule.switchAccount(email); + openApp().then(() => NativeModules.HybridAppModule.switchAccount(email, restrictedToken, policyID, String(previousAccountID))); }); }) .catch((error) => { @@ -195,22 +211,34 @@ function disconnect() { return; } + if (!response?.requesterID || !response?.requesterEmail) { + Log.alert('[Delegate] No requester data returned while disconnecting as a delegate'); + return; + } + + const requesterEmail = response.requesterEmail; + const authToken = response.authToken; return SequentialQueue.waitForIdle() .then(() => Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS)) .then(() => { - // Update authToken in Onyx and in our local variables so that API requests will use the new authToken - updateSessionAuthTokens(response?.authToken, response?.encryptedAuthToken); + Onyx.set(ONYXKEYS.CREDENTIALS, { + ...stashedCredentials, + accountID: response.requesterID, + }); + Onyx.set(ONYXKEYS.SESSION, { + ...stashedSession, + accountID: response.requesterID, + email: requesterEmail, + authToken, + encryptedAuthToken: response.encryptedAuthToken, + }); + Onyx.set(ONYXKEYS.STASHED_CREDENTIALS, {}); + Onyx.set(ONYXKEYS.STASHED_SESSION, {}); NetworkStore.setAuthToken(response?.authToken ?? null); - Onyx.set(ONYXKEYS.CREDENTIALS, stashedCredentials); - Onyx.set(ONYXKEYS.SESSION, stashedSession); - Onyx.set(ONYXKEYS.STASHED_CREDENTIALS, {}); - Onyx.set(ONYXKEYS.STASHED_SESSION, {}); confirmReadyToOpenApp(); - openApp(); - - NativeModules.HybridAppModule.switchAccount(getCurrentUserEmail() ?? ''); + openApp().then(() => NativeModules.HybridAppModule.switchAccount(requesterEmail, authToken, '', '')); }); }) .catch((error) => { diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 11eab64a36df..416fbd52b7cd 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -33,6 +33,7 @@ import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; import * as MainQueue from '@libs/Network/MainQueue'; import * as NetworkStore from '@libs/Network/NetworkStore'; +import {getCurrentUserEmail} from '@libs/Network/NetworkStore'; import NetworkConnection from '@libs/NetworkConnection'; import * as Pusher from '@libs/Pusher/pusher'; import {getReportIDFromLink, parseReportRouteParams as parseReportRouteParamsReportUtils} from '@libs/ReportUtils'; @@ -524,7 +525,7 @@ function signInAfterTransitionFromOldDot(transitionURL: string) { nudgeMigrationTimestamp, isSingleNewDotEntry, primaryLogin, - shouldRemoveDelegatedAccess, + oldDotOriginalAccountEmail, } = Object.fromEntries( queryParams.split('&').map((param) => { const [key, value] = param.split('='); @@ -543,22 +544,39 @@ function signInAfterTransitionFromOldDot(transitionURL: string) { const setSessionDataAndOpenApp = new Promise((resolve) => { clearOnyxForNewAccount() .then(() => { - if (!shouldRemoveDelegatedAccess) { + // This section controls copilot changes + const currentUserEmail = getCurrentUserEmail(); + + // If ND and OD account are the same - do nothing + if (email === currentUserEmail) { + return; + } + + // If account was changed to original one on OD side - clear onyx + if (!oldDotOriginalAccountEmail) { + return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS); + } + + // If we're already logged in - do nothing, data will be set in next step + if (currentUserEmail) { return; } - return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS); + + // If we're not logged in - set stashed data + return Onyx.multiSet({ + [ONYXKEYS.STASHED_CREDENTIALS]: {autoGeneratedLogin, autoGeneratedPassword}, + }); }) .then(() => Onyx.multiSet({ [ONYXKEYS.SESSION]: {email, authToken, encryptedAuthToken: decodeURIComponent(encryptedAuthToken), accountID: Number(accountID)}, - [ONYXKEYS.ACCOUNT]: {primaryLogin}, [ONYXKEYS.CREDENTIALS]: {autoGeneratedLogin, autoGeneratedPassword}, [ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY]: isSingleNewDotEntry === 'true', [ONYXKEYS.NVP_TRYNEWDOT]: { classicRedirect: {completedHybridAppOnboarding: completedHybridAppOnboarding === 'true'}, nudgeMigration: nudgeMigrationTimestamp ? {timestamp: new Date(nudgeMigrationTimestamp)} : undefined, }, - }), + }).then(() => Onyx.merge(ONYXKEYS.ACCOUNT, {primaryLogin})), ) .then(() => { if (clearOnyxOnStart === 'true') { diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index c72d4bf2a653..340f396882af 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -8,7 +8,7 @@ import type StartupTimer from '@libs/StartupTimer/types'; type HybridAppModule = { closeReactNativeApp: (shouldSignOut: boolean, shouldSetNVP: boolean) => void; completeOnboarding: (status: boolean) => void; - switchAccount: (newDotCurrentAccount: string) => void; + switchAccount: (newDotCurrentAccount: string, authToken: string, policyID: string, accountID: string) => void; exitApp: () => void; }; diff --git a/src/types/onyx/Response.ts b/src/types/onyx/Response.ts index ce9acbaaccc6..146cf327dd31 100644 --- a/src/types/onyx/Response.ts +++ b/src/types/onyx/Response.ts @@ -83,6 +83,12 @@ type Response = { /** If there is newer data to load for pagination commands */ hasNewerActions?: boolean; + + /** The email of the original user (returned when in delegate mode) */ + requesterEmail?: string; + + /** The ID of the original user (returned when in delegate mode) */ + requesterID?: number; }; export default Response;