From acbdf2864b6014880f86ebe6021339de09740780 Mon Sep 17 00:00:00 2001 From: Neil Marcellini Date: Fri, 18 Mar 2022 12:17:32 -0700 Subject: [PATCH 01/13] Sign in, out, or navigate on transition mount --- src/pages/LogInWithShortLivedTokenPage.js | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index acd8c659104b..50efaccbae7c 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -58,24 +58,12 @@ class LogInWithShortLivedTokenPage extends Component { Session.signInWithShortLivedToken(accountID, email, shortLivedToken); return; } - - this.signOutIfNeeded(email); - } - - componentDidUpdate() { - if (!lodashGet(this.props, 'session.authToken', null)) { + if (this.signOutIfNeeded(email)) { return; } - const email = lodashGet(this.props.route.params, 'email', ''); - // exitTo is URI encoded because it could contain a variable number of slashes (i.e. "workspace/new" vs "workspace//card") const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); - - if (this.signOutIfNeeded(email)) { - return; - } - if (exitTo === ROUTES.WORKSPACE_NEW) { // New workspace creation is handled in AuthScreens, not in its own screen return; @@ -121,10 +109,4 @@ export default withOnyx({ session: { key: ONYXKEYS.SESSION, }, - - // We need to subscribe to the betas so that componentDidUpdate will run, - // causing us to exit to the proper page. - betas: { - key: ONYXKEYS.BETAS, - }, })(LogInWithShortLivedTokenPage); From a87363078ea0837119cfab1faf24f6c0b4538ec4 Mon Sep 17 00:00:00 2001 From: Neil Marcellini Date: Mon, 21 Mar 2022 19:55:32 -0700 Subject: [PATCH 02/13] Queue requests to sign in with a short lived token --- src/libs/actions/Session/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index d58583855e66..dcf0476065a2 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -174,9 +174,10 @@ function fetchAccountDetails(login) { * * @param {String} authToken * @param {String} email + * @param {Boolean} shouldProcessImmediately * @return {Promise} */ -function createTemporaryLogin(authToken, email) { +function createTemporaryLogin(authToken, email, shouldProcessImmediately = true) { const autoGeneratedLogin = Str.guid('expensify.cash-'); const autoGeneratedPassword = Str.guid(); @@ -188,6 +189,7 @@ function createTemporaryLogin(authToken, email) { partnerUserSecret: autoGeneratedPassword, shouldRetry: false, forceNetworkRequest: true, + shouldProcessImmediately, email, includeEncryptedAuthToken: true, }) @@ -268,7 +270,7 @@ function signIn(password, twoFactorAuthCode) { function signInWithShortLivedToken(accountID, email, shortLivedToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); - createTemporaryLogin(shortLivedToken, email).then((response) => { + createTemporaryLogin(shortLivedToken, email, false).then((response) => { Onyx.merge(ONYXKEYS.SESSION, { accountID, email, From 191c02f6ca1281ae0979ad99792b492efd7927ea Mon Sep 17 00:00:00 2001 From: Neil Marcellini Date: Tue, 22 Mar 2022 10:58:13 -0700 Subject: [PATCH 03/13] Retry growls when the ref is not available --- src/libs/Growl.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/Growl.js b/src/libs/Growl.js index b4915c22bad4..416b32be0e33 100644 --- a/src/libs/Growl.js +++ b/src/libs/Growl.js @@ -4,13 +4,17 @@ import CONST from '../CONST'; const growlRef = React.createRef(); /** - * Show the growl notification + * Show the growl notification. If the ref is not available, retry until it is. * * @param {String} bodyText * @param {String} type * @param {Number} [duration] */ function show(bodyText, type, duration = CONST.GROWL.DURATION) { + if (!growlRef.current) { + setTimeout(() => show(bodyText, type, duration), 100); + return; + } growlRef.current.show(bodyText, type, duration); } From e527f2e5945d5f61dc5d61199a4fed265287ea50 Mon Sep 17 00:00:00 2001 From: Neil Marcellini Date: Tue, 22 Mar 2022 12:02:45 -0700 Subject: [PATCH 04/13] Show a loading screen when the betas are loading --- src/ONYXKEYS.js | 1 + src/libs/Navigation/AppNavigator/MainDrawerNavigator.js | 9 ++++++++- src/libs/actions/User.js | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index e701f99ab6a1..8810856c1660 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -74,6 +74,7 @@ export default { // Information about the current session (authToken, accountID, email, loading, error) SESSION: 'session', BETAS: 'betas', + IS_LOADING_BETAS: 'isLoadingBetas', // NVP keys // Contains the user's payPalMe address diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index c326ece31769..62f1702c83ff 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -22,11 +22,15 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), + + /** Are the betas currently loading from the api? */ + isLoadingBetas: PropTypes.bool, }; const defaultProps = { reports: {}, betas: [], + isLoadingBetas: true, }; /** @@ -48,7 +52,7 @@ const MainDrawerNavigator = (props) => { const initialParams = getInitialReportScreenParams(props.reports, !Permissions.canUseDefaultRooms(props.betas)); // Wait until reports are fetched and there is a reportID in initialParams - if (!initialParams.reportID) { + if (!initialParams.reportID || props.isLoadingBetas) { return ; } @@ -81,5 +85,8 @@ export default withOnyx({ betas: { key: ONYXKEYS.BETAS, }, + isLoadingBetas: { + key: ONYXKEYS.IS_LOADING_BETAS, + }, })(MainDrawerNavigator); export {getInitialReportScreenParams}; diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 657558bf6dfb..5809ef1fe72e 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -86,12 +86,14 @@ function closeAccount(message) { } function getBetas() { + Onyx.set(ONYXKEYS.IS_LOADING_BETAS, true); API.User_GetBetas().then((response) => { if (response.jsonCode !== 200) { return; } Onyx.set(ONYXKEYS.BETAS, response.betas); + Onyx.set(ONYXKEYS.IS_LOADING_BETAS, false); }); } From 2d63d2b43fdf2c2d66e14ac687d02c36e25dedd4 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 11:41:12 -1000 Subject: [PATCH 05/13] Remove setTimeout on Growl --- src/libs/Growl.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libs/Growl.js b/src/libs/Growl.js index 416b32be0e33..c4209fcff51a 100644 --- a/src/libs/Growl.js +++ b/src/libs/Growl.js @@ -11,10 +11,6 @@ const growlRef = React.createRef(); * @param {Number} [duration] */ function show(bodyText, type, duration = CONST.GROWL.DURATION) { - if (!growlRef.current) { - setTimeout(() => show(bodyText, type, duration), 100); - return; - } growlRef.current.show(bodyText, type, duration); } From 6e375bbd9c35731801df531a71059b964dc57ebc Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 12:17:38 -1000 Subject: [PATCH 06/13] Fix CreateMenu from popping up when navigating to workspace page on small screen sizes --- src/libs/actions/WelcomeActions.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/WelcomeActions.js b/src/libs/actions/WelcomeActions.js index c3b6c7f18d1f..9d940bf83f4b 100644 --- a/src/libs/actions/WelcomeActions.js +++ b/src/libs/actions/WelcomeActions.js @@ -1,3 +1,4 @@ +import {Dimensions} from 'react-native'; import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; @@ -8,6 +9,7 @@ import * as Policy from './Policy'; import ONYXKEYS from '../../ONYXKEYS'; import NameValuePair from './NameValuePair'; import CONST from '../../CONST'; +import variables from '../../styles/variables'; /* Flag for new users used to show welcome actions on first load */ let isFirstTimeNewExpensifyUser = false; @@ -68,7 +70,11 @@ function show({routes, toggleCreateMenu}) { // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global // create menu right now. const topRouteName = lodashGet(_.last(routes), 'name', ''); - const isDisplayingWorkspaceRoute = topRouteName.toLowerCase().includes('workspace'); + const loginWithShortLivedTokenRoute = _.find(routes, route => route.name === 'LogInWithShortLivedToken'); + const exitingToWorkspaceRoute = lodashGet(loginWithShortLivedTokenRoute, 'params.exitTo', '') === 'workspace/new'; + const initialDimensions = Dimensions.get('window'); + const isSmallScreenWidth = initialDimensions.width <= variables.mobileResponsiveWidthBreakpoint; + const isDisplayingWorkspaceRoute = topRouteName.toLowerCase().includes('workspace') || (exitingToWorkspaceRoute && isSmallScreenWidth); // It's also possible that we already have a workspace policy. In either case we will not toggle the menu but do still want to set the NVP in this case // since the user does not need to create a workspace. From 151571b929cd5256d8ea73f8a82903d4469f3ea6 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 12:19:14 -1000 Subject: [PATCH 07/13] do it for large screens too --- src/libs/actions/WelcomeActions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/libs/actions/WelcomeActions.js b/src/libs/actions/WelcomeActions.js index 9d940bf83f4b..f1db29c89f1e 100644 --- a/src/libs/actions/WelcomeActions.js +++ b/src/libs/actions/WelcomeActions.js @@ -1,4 +1,3 @@ -import {Dimensions} from 'react-native'; import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; @@ -9,7 +8,6 @@ import * as Policy from './Policy'; import ONYXKEYS from '../../ONYXKEYS'; import NameValuePair from './NameValuePair'; import CONST from '../../CONST'; -import variables from '../../styles/variables'; /* Flag for new users used to show welcome actions on first load */ let isFirstTimeNewExpensifyUser = false; @@ -72,9 +70,7 @@ function show({routes, toggleCreateMenu}) { const topRouteName = lodashGet(_.last(routes), 'name', ''); const loginWithShortLivedTokenRoute = _.find(routes, route => route.name === 'LogInWithShortLivedToken'); const exitingToWorkspaceRoute = lodashGet(loginWithShortLivedTokenRoute, 'params.exitTo', '') === 'workspace/new'; - const initialDimensions = Dimensions.get('window'); - const isSmallScreenWidth = initialDimensions.width <= variables.mobileResponsiveWidthBreakpoint; - const isDisplayingWorkspaceRoute = topRouteName.toLowerCase().includes('workspace') || (exitingToWorkspaceRoute && isSmallScreenWidth); + const isDisplayingWorkspaceRoute = topRouteName.toLowerCase().includes('workspace') || exitingToWorkspaceRoute; // It's also possible that we already have a workspace policy. In either case we will not toggle the menu but do still want to set the NVP in this case // since the user does not need to create a workspace. From a77553c5d01e1ebfa9faaf3a165e7007ca6249da Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 12:37:56 -1000 Subject: [PATCH 08/13] add logs --- src/pages/LogInWithShortLivedTokenPage.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index 50efaccbae7c..cfd4ad40d967 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -7,6 +7,7 @@ import ONYXKEYS from '../ONYXKEYS'; import * as Session from '../libs/actions/Session'; import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; import Navigation from '../libs/Navigation/Navigation'; +import Log from '../libs/Log'; const propTypes = { /** The parameters needed to authenticate with a short lived token are in the URL */ @@ -55,26 +56,29 @@ class LogInWithShortLivedTokenPage extends Component { const isUserSignedIn = this.props.session && this.props.session.authToken; if (!isUserSignedIn) { + Log.info('[LoginWithShortLivedTokenPage] User not signed in - signing in with short lived token'); Session.signInWithShortLivedToken(accountID, email, shortLivedToken); return; } + if (this.signOutIfNeeded(email)) { return; } + Log.info('[LoginWithShortLivedTokenPage] User signed in'); + // exitTo is URI encoded because it could contain a variable number of slashes (i.e. "workspace/new" vs "workspace//card") const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); if (exitTo === ROUTES.WORKSPACE_NEW) { // New workspace creation is handled in AuthScreens, not in its own screen + Log.info('[LoginWithShortLivedTokenPage] exitTo is workspace/new - handling new workspace creation in AuthScreens'); return; } - // In order to navigate to a modal, we first have to dismiss the current modal. But there is no current - // modal you say? I know, it confuses me too. Without dismissing the current modal, if the user cancels out - // of the workspace modal, then they will be routed back to - // /transition////workspace//card and we don't want that. We want them to go back to `/` - // and by calling dismissModal(), the /transition/... route is removed from history so the user will get taken to `/` - // if they cancel out of the new workspace modal. + // In order to navigate to a modal, we first have to dismiss the current modal. Without dismissing the current modal, if the user cancels out of the workspace modal, + // then they will be routed back to /transition////workspace//card and we don't want that. We want them to go back to `/` + // and by calling dismissModal(), the /transition/... route is removed from history so the user will get taken to `/` if they cancel out of the new workspace modal. + Log.info('[LoginWithShortLivedTokenPage] Dismissing LoginWithShortLivedTokenPage and navigating to exitTo'); Navigation.dismissModal(); Navigation.navigate(exitTo); } @@ -93,6 +97,7 @@ class LogInWithShortLivedTokenPage extends Component { return false; } + Log.info('[LoginWithShortLivedTokenPage] Different user signed in - signing out'); Session.signOutAndRedirectToSignIn(); return true; } From 7e6570800ac926527e818e4dd331b549667fb680 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 12:49:44 -1000 Subject: [PATCH 09/13] revert growl changes improve log --- src/libs/Growl.js | 2 +- src/pages/LogInWithShortLivedTokenPage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Growl.js b/src/libs/Growl.js index f0dfb9247e83..85ba042b71a0 100644 --- a/src/libs/Growl.js +++ b/src/libs/Growl.js @@ -6,7 +6,7 @@ const growlRef = React.createRef(); const [isGrowlReady, setIsReady] = createOnReadyTask(); /** - * Show the growl notification. If the ref is not available, retry until it is. + * Show the growl notification * * @param {String} bodyText * @param {String} type diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index cfd4ad40d967..3ad9090c3426 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -65,7 +65,7 @@ class LogInWithShortLivedTokenPage extends Component { return; } - Log.info('[LoginWithShortLivedTokenPage] User signed in'); + Log.info('[LoginWithShortLivedTokenPage] User is signed in'); // exitTo is URI encoded because it could contain a variable number of slashes (i.e. "workspace/new" vs "workspace//card") const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); From 38c4b8a112a3f3e62fe4a9e4d86c6fec410e0f4e Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 13:02:57 -1000 Subject: [PATCH 10/13] Remove IS_LOADING_BETAS --- src/ONYXKEYS.js | 1 - src/libs/Navigation/AppNavigator/MainDrawerNavigator.js | 5 +---- src/libs/actions/User.js | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 8810856c1660..e701f99ab6a1 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -74,7 +74,6 @@ export default { // Information about the current session (authToken, accountID, email, loading, error) SESSION: 'session', BETAS: 'betas', - IS_LOADING_BETAS: 'isLoadingBetas', // NVP keys // Contains the user's payPalMe address diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index 62f1702c83ff..c76fc5326b78 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -52,7 +52,7 @@ const MainDrawerNavigator = (props) => { const initialParams = getInitialReportScreenParams(props.reports, !Permissions.canUseDefaultRooms(props.betas)); // Wait until reports are fetched and there is a reportID in initialParams - if (!initialParams.reportID || props.isLoadingBetas) { + if (!initialParams.reportID) { return ; } @@ -85,8 +85,5 @@ export default withOnyx({ betas: { key: ONYXKEYS.BETAS, }, - isLoadingBetas: { - key: ONYXKEYS.IS_LOADING_BETAS, - }, })(MainDrawerNavigator); export {getInitialReportScreenParams}; diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 5809ef1fe72e..657558bf6dfb 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -86,14 +86,12 @@ function closeAccount(message) { } function getBetas() { - Onyx.set(ONYXKEYS.IS_LOADING_BETAS, true); API.User_GetBetas().then((response) => { if (response.jsonCode !== 200) { return; } Onyx.set(ONYXKEYS.BETAS, response.betas); - Onyx.set(ONYXKEYS.IS_LOADING_BETAS, false); }); } From 282a9d11330a18901cae1741814475b525d4063a Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 13:03:27 -1000 Subject: [PATCH 11/13] remove isLoadingBetas --- src/libs/Navigation/AppNavigator/MainDrawerNavigator.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js index c76fc5326b78..c326ece31769 100644 --- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js +++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js @@ -22,15 +22,11 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), - - /** Are the betas currently loading from the api? */ - isLoadingBetas: PropTypes.bool, }; const defaultProps = { reports: {}, betas: [], - isLoadingBetas: true, }; /** From 25bb9c40396868d1705e8d5a18bd3a8cb1caa8b0 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 13:07:25 -1000 Subject: [PATCH 12/13] Remove shouldProcessImmediately --- src/libs/actions/Session/index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index dcf0476065a2..d58583855e66 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -174,10 +174,9 @@ function fetchAccountDetails(login) { * * @param {String} authToken * @param {String} email - * @param {Boolean} shouldProcessImmediately * @return {Promise} */ -function createTemporaryLogin(authToken, email, shouldProcessImmediately = true) { +function createTemporaryLogin(authToken, email) { const autoGeneratedLogin = Str.guid('expensify.cash-'); const autoGeneratedPassword = Str.guid(); @@ -189,7 +188,6 @@ function createTemporaryLogin(authToken, email, shouldProcessImmediately = true) partnerUserSecret: autoGeneratedPassword, shouldRetry: false, forceNetworkRequest: true, - shouldProcessImmediately, email, includeEncryptedAuthToken: true, }) @@ -270,7 +268,7 @@ function signIn(password, twoFactorAuthCode) { function signInWithShortLivedToken(accountID, email, shortLivedToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); - createTemporaryLogin(shortLivedToken, email, false).then((response) => { + createTemporaryLogin(shortLivedToken, email).then((response) => { Onyx.merge(ONYXKEYS.SESSION, { accountID, email, From 2996c88959a216fd7a33468e7dccbf3731947ec1 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 23 Mar 2022 13:12:22 -1000 Subject: [PATCH 13/13] remove parseInt --- src/pages/LogInWithShortLivedTokenPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index 3ad9090c3426..5e091ead6f83 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -50,7 +50,7 @@ const defaultProps = { class LogInWithShortLivedTokenPage extends Component { componentDidMount() { - const accountID = parseInt(lodashGet(this.props.route.params, 'accountID', ''), 10); + const accountID = lodashGet(this.props.route.params, 'accountID', ''); const email = lodashGet(this.props.route.params, 'email', ''); const shortLivedToken = lodashGet(this.props.route.params, 'shortLivedToken', '');