Skip to content

Commit

Permalink
Dont sign in in old dot (#150)
Browse files Browse the repository at this point in the history
* wip

* wip

* remove comment

* clean

* remove unused parameters and fix sign up flow

* block sign in logic when OD sign-in was performed

* simplify blocking logic

* fix crash when switching apps

* Fix bug where OpenApp is called after opening app from background

---------

Co-authored-by: war-in <[email protected]>
Co-authored-by: Mateusz Rajski <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent bddba03 commit 68ed516
Show file tree
Hide file tree
Showing 15 changed files with 105 additions and 276 deletions.
2 changes: 0 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import Expensify from './Expensify';
import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
import {ReportIDsContextProvider} from './hooks/useReportIDs';
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
import HybridApp from './libs/HybridApp';
import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
import type {Route} from './ROUTES';
import {SplashScreenStateContextProvider} from './SplashScreenStateContext';
Expand Down Expand Up @@ -65,7 +64,6 @@ const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode
function App({url, hybridAppSettings}: AppProps) {
useDefaultDragAndDrop();
OnyxUpdateManager();
HybridApp.init();

return (
<StrictModeWrapper>
Expand Down
3 changes: 0 additions & 3 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6299,9 +6299,6 @@ const CONST = {
NOT_STARTED: 'notStarted',
STARTED: 'started',
FINISHED: 'finished',
WAITING_FOR_SIGN_OUT: 'waitingForSignOut',
RETRYING_AFTER_FAILURE: 'retryingAfterFailure',
FAILED_AGAIN: 'failedAgain',
},

CSV_IMPORT_COLUMNS: {
Expand Down
19 changes: 13 additions & 6 deletions src/components/InitialURLContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {createContext, useEffect, useMemo, useState} from 'react';
import React, {createContext, useEffect, useMemo, useRef, useState} from 'react';
import type {ReactNode} from 'react';
import {Linking} from 'react-native';
import {useOnyx} from 'react-native-onyx';
Expand All @@ -9,6 +9,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Route} from '@src/ROUTES';
import {useSplashScreenStateContext} from '@src/SplashScreenStateContext';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';

type InitialUrlContextType = {
initialURL: Route | undefined;
Expand All @@ -35,6 +36,9 @@ function InitialURLContextProvider({children, url, hybridAppSettings}: InitialUR
const [initialURL, setInitialURL] = useState<Route | ValueOf<typeof CONST.HYBRID_APP> | undefined>(url);
const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH);
const {splashScreenState, setSplashScreenState} = useSplashScreenStateContext();
const [tryNewDot, tryNewDotMetadata] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT);
// We use `setupCalled` ref to guarantee that `signInAfterTransitionFromOldDot` is called once.
const setupCalled = useRef(false);

useEffect(() => {
if (url !== CONST.HYBRID_APP.REORDERING_REACT_NATIVE_ACTIVITY_TO_FRONT) {
Expand All @@ -53,16 +57,19 @@ function InitialURLContextProvider({children, url, hybridAppSettings}: InitialUR
}

if (url && hybridAppSettings) {
setupNewDotAfterTransitionFromOldDot(url, hybridAppSettings).then((route) => {
setInitialURL(route);
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
});
if (!isLoadingOnyxValue(tryNewDotMetadata) && !setupCalled.current) {
setupCalled.current = true;
setupNewDotAfterTransitionFromOldDot(url, hybridAppSettings, tryNewDot).then((route) => {
setInitialURL(route);
setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN);
});
}
return;
}
Linking.getInitialURL().then((initURL) => {
setInitialURL(initURL as Route);
});
}, [hybridAppSettings, setSplashScreenState, url]);
}, [hybridAppSettings, setSplashScreenState, tryNewDot, tryNewDotMetadata, url]);

const initialUrlContext = useMemo(
() => ({
Expand Down
4 changes: 2 additions & 2 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ const WRITE_COMMANDS = {
TRANSACTION_MERGE: 'Transaction_Merge',
RESOLVE_DUPLICATES: 'ResolveDuplicates',
UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
SIGN_UP_USER: 'SignUpUser',
UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew',
UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically',
UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize',
Expand Down Expand Up @@ -756,7 +755,6 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.TRANSACTION_MERGE]: Parameters.TransactionMergeParams;
[WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams;
Expand Down Expand Up @@ -1030,6 +1028,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = {
COMPLETE_HYBRID_APP_ONBOARDING: 'CompleteHybridAppOnboarding',
CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP: 'ConnectPolicyToQuickbooksDesktop',
SIGN_IN_USER: 'SigninUser',
SIGN_UP_USER: 'SignUpUser',

// PayMoneyRequestOnSearch only works online (pattern C) and we need to play the success sound only when the request is successful
PAY_MONEY_REQUEST_ON_SEARCH: 'PayMoneyRequestOnSearch',
Expand All @@ -1054,6 +1053,7 @@ type SideEffectRequestCommandParameters = {
[SIDE_EFFECT_REQUEST_COMMANDS.COMPLETE_HYBRID_APP_ONBOARDING]: EmptyObject;
[SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP]: Parameters.ConnectPolicyToQuickBooksDesktopParams;
[SIDE_EFFECT_REQUEST_COMMANDS.SIGN_IN_USER]: SignInUserParams;
[SIDE_EFFECT_REQUEST_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[SIDE_EFFECT_REQUEST_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH]: Parameters.PayMoneyRequestOnSearchParams;
};

Expand Down
103 changes: 40 additions & 63 deletions src/libs/HybridApp.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import {DeviceEventEmitter, NativeModules} from 'react-native';
import {NativeModules} from 'react-native';
import Onyx from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Credentials, HybridApp, Session, TryNewDot} from '@src/types/onyx';
import * as HybridAppActions from './actions/HybridApp';
import type {Init} from './ActiveClientManager/types';
import Log from './Log';
import {getCurrentUserEmail} from './Network/NetworkStore';

let currentHybridApp: OnyxEntry<HybridApp>;
let currentTryNewDot: OnyxEntry<TryNewDot>;
let currentCredentials: OnyxEntry<Credentials>;

Onyx.connect({
key: ONYXKEYS.HYBRID_APP,
callback: (hybridApp) => {
handleChangeInHybridAppSignInFlow(hybridApp, currentTryNewDot);
handleChangeInHybridAppSignInFlow(hybridApp, currentTryNewDot, currentCredentials);
},
});

Onyx.connect({
key: ONYXKEYS.NVP_TRYNEWDOT,
callback: (tryNewDot) => {
handleChangeInHybridAppSignInFlow(currentHybridApp, tryNewDot);
handleChangeInHybridAppSignInFlow(currentHybridApp, tryNewDot, currentCredentials);
},
});

Onyx.connect({
key: ONYXKEYS.CREDENTIALS,
callback: (credentials) => {
currentCredentials = credentials;
handleChangeInHybridAppSignInFlow(currentHybridApp, currentTryNewDot, credentials);
},
});

Expand All @@ -36,83 +45,51 @@ Onyx.connect({
},
});

let credentials: OnyxEntry<Credentials>;
let activePolicyID: OnyxEntry<string>;
Onyx.connect({
key: ONYXKEYS.CREDENTIALS,
callback: (newCredentials) => {
credentials = newCredentials;
key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
callback: (newActivePolicyID) => {
activePolicyID = newActivePolicyID;
},
});

function shouldUseOldApp(tryNewDot?: TryNewDot) {
return tryNewDot?.classicRedirect.dismissed === true;
}

function handleChangeInHybridAppSignInFlow(hybridApp: OnyxEntry<HybridApp>, tryNewDot: OnyxEntry<TryNewDot>) {
function handleChangeInHybridAppSignInFlow(hybridApp: OnyxEntry<HybridApp>, tryNewDot: OnyxEntry<TryNewDot>, credentials: OnyxEntry<Credentials>) {
if (!NativeModules.HybridAppModule) {
return;
}

if (currentHybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.RETRYING_AFTER_FAILURE && hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED) {
if (hybridApp?.oldDotSignInError) {
Log.info('[HybridApp] Unable to open OldDot. Sign-in has failed again');
HybridAppActions.setOldDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.FAILED_AGAIN);
return;
}

Log.info('[HybridApp] Closing NewDot as retrying sign-in to OldDot succeeded');
NativeModules.HybridAppModule.closeReactNativeApp(false, true);
}

if (
currentHybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.STARTED &&
hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED &&
tryNewDot !== undefined &&
shouldUseOldApp(tryNewDot)
) {
if (hybridApp?.oldDotSignInError) {
Log.info('[HybridApp] Unable to open OldDot. Sign-in has failed');
return;
}

Log.info('[HybridApp] Closing NewDot as sign-in to OldDot succeeded');
NativeModules.HybridAppModule.closeReactNativeApp(false, true);
if (!hybridApp?.useNewDotSignInPage) {
currentHybridApp = hybridApp;
currentTryNewDot = tryNewDot;
return;
}

if (
hybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED &&
hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED &&
credentials?.autoGeneratedLogin &&
credentials?.autoGeneratedPassword &&
tryNewDot !== undefined
) {
if (!shouldUseOldApp(tryNewDot)) {
Log.info('[HybridApp] The user should see NewDot. There is no need to block the user on the `SignInPage` until the sign-in process is completed on the OldDot side.');
HybridAppActions.setReadyToShowAuthScreens(true);
}

if (hybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && tryNewDot !== undefined && !!credentials?.autoGeneratedLogin && !!credentials?.autoGeneratedPassword) {
Log.info(`[HybridApp] Performing sign-in${shouldUseOldApp(tryNewDot) ? '' : ' (in background)'} on OldDot side`);
HybridAppActions.startOldDotSignIn(credentials.autoGeneratedLogin, credentials.autoGeneratedPassword);
NativeModules.HybridAppModule.signInToOldDot(
credentials.autoGeneratedLogin,
credentials.autoGeneratedPassword,
currentSession?.authToken ?? '',
currentSession?.encryptedAuthToken ?? '',
getCurrentUserEmail() ?? '',
activePolicyID ?? '',
);
HybridAppActions.setUseNewDotSignInPage(false).then(() => {
if (shouldUseOldApp(tryNewDot)) {
NativeModules.HybridAppModule.closeReactNativeApp(false, false);
} else {
Log.info('[HybridApp] The user should see NewDot. There is no need to block the user on the `SignInPage` until the sign-in process is completed on the OldDot side.');
HybridAppActions.setReadyToShowAuthScreens(true);
}
});
}

currentHybridApp = hybridApp;
currentTryNewDot = tryNewDot;
}

function onOldDotSignInFinished(data: string) {
const eventData = JSON.parse(data) as {errorMessage: string};
Log.info(`[HybridApp] onSignInFinished event received`, true, {eventData});
HybridAppActions.finishOldDotSignIn(eventData.errorMessage);
}

const init: Init = () => {
if (!NativeModules.HybridAppModule) {
return;
}

DeviceEventEmitter.addListener(CONST.EVENTS.HYBRID_APP.ON_SIGN_IN_FINISHED, onOldDotSignInFinished);
};

export default {init};

export {shouldUseOldApp};
export default {shouldUseOldApp};
1 change: 0 additions & 1 deletion src/libs/Navigation/AppNavigator/PublicScreens.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import {NativeModules} from 'react-native';
import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
import type {PublicScreensParamList} from '@navigation/types';
import ConnectionCompletePage from '@pages/ConnectionCompletePage';
Expand Down
7 changes: 2 additions & 5 deletions src/libs/Navigation/AppNavigator/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {memo, useContext, useEffect, useMemo} from 'react';
import {NativeModules} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import {InitialURLContext} from '@components/InitialURLContextProvider';
import HybridApp from '@libs/HybridApp';
import Navigation from '@libs/Navigation/Navigation';
import ONYXKEYS from '@src/ONYXKEYS';
import type {TryNewDot} from '@src/types/onyx';
Expand All @@ -12,10 +13,6 @@ type AppNavigatorProps = {
authenticated: boolean;
};

function shouldUseOldApp(tryNewDot?: TryNewDot) {
return tryNewDot?.classicRedirect.dismissed === true;
}

function AppNavigator({authenticated}: AppNavigatorProps) {
const {initialURL, setInitialURL} = useContext(InitialURLContext);
const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT);
Expand All @@ -25,7 +22,7 @@ function AppNavigator({authenticated}: AppNavigatorProps) {
if (!NativeModules.HybridAppModule) {
return authenticated;
}
if (shouldUseOldApp(tryNewDot) && !hybridApp?.isSingleNewDotEntry) {
if (HybridApp.shouldUseOldApp(tryNewDot) && !hybridApp?.isSingleNewDotEntry) {
return false;
}

Expand Down
Loading

0 comments on commit 68ed516

Please sign in to comment.