diff --git a/src/Expensify.js b/src/Expensify.js index 15a41f9b2482..6f08789e9c0c 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import React, {PureComponent} from 'react'; import {View, AppState} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import BootSplash from './libs/BootSplash'; import * as ActiveClientManager from './libs/ActiveClientManager'; @@ -17,8 +16,6 @@ import Visibility from './libs/Visibility'; import GrowlNotification from './components/GrowlNotification'; import {growlRef} from './libs/Growl'; import StartupTimer from './libs/StartupTimer'; -import {setRedirectToWorkspaceNewAfterSignIn} from './libs/actions/Session'; -import {create} from './libs/actions/Policy'; const propTypes = { /* Onyx Props */ @@ -31,9 +28,6 @@ const propTypes = { /** Currently logged in user accountID */ accountID: PropTypes.number, - - /** Should app immediately redirect to new workspace route once authenticated */ - redirectToWorkspaceNewAfterSignIn: PropTypes.bool, }), /** Whether a new update is available and ready to install. */ @@ -44,21 +38,16 @@ const propTypes = { /** Tells us if the sidebar has rendered */ isSidebarLoaded: PropTypes.bool, - - /** List of betas */ - betas: PropTypes.arrayOf(PropTypes.string), }; const defaultProps = { session: { authToken: null, accountID: null, - redirectToWorkspaceNewAfterSignIn: false, }, updateAvailable: false, initialReportDataLoaded: false, isSidebarLoaded: false, - betas: [], }; class Expensify extends PureComponent { @@ -111,13 +100,6 @@ class Expensify extends PureComponent { BootSplash.show({fade: true}); } - if (this.getAuthToken() - && !_.isEmpty(this.props.betas) - && lodashGet(this.props, 'session.redirectToWorkspaceNewAfterSignIn', false)) { - setRedirectToWorkspaceNewAfterSignIn(false); - create(); - } - if (this.getAuthToken() && this.props.initialReportDataLoaded && this.props.isSidebarLoaded) { BootSplash.getVisibilityStatus() .then((value) => { @@ -172,9 +154,6 @@ export default withOnyx({ session: { key: ONYXKEYS.SESSION, }, - betas: { - key: ONYXKEYS.BETAS, - }, updateAvailable: { key: ONYXKEYS.UPDATE_AVAILABLE, initWithStoredValues: false, diff --git a/src/ROUTES.js b/src/ROUTES.js index 4adf292a87b1..255deebcdbd9 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -70,8 +70,10 @@ export default { // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. - VALIDATE_LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'v/:accountID/:validateCode/new-workspace', - VALIDATE_LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'v/:accountID/:validateCode/2fa/new-workspace', + LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'v/:accountID/:validateCode/new-workspace', + LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'v/:accountID/:validateCode/2fa/new-workspace', + LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: 'v/:accountID/:validateCode/workspace/:policyID/card', + LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD: 'v/:accountID/:validateCode/2fa/workspace/:policyID/card', ENABLE_PAYMENTS: 'enable-payments', WORKSPACE: 'workspace', WORKSPACE_CARD: ':policyID/card', diff --git a/src/SCREENS.js b/src/SCREENS.js index 521e5a471852..764965e7335c 100644 --- a/src/SCREENS.js +++ b/src/SCREENS.js @@ -6,6 +6,8 @@ export default { HOME: 'Home', LOADING: 'Loading', REPORT: 'Report', - VALIDATE_LOGIN_NEW_WORKSPACE: 'ValidateLoginNewWorkspace', - VALIDATE_LOGIN_2FA_NEW_WORKSPACE: 'ValidateLogin2FANewWorkspace', + LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'LoginWithValidateCodeNewWorkspace', + LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'LoginWithValidateCode2FANewWorkspace', + LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: 'LoginWithValidateCodeWorkspaceCard', + LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD: 'LoginWithValidateCode2FAWorkspaceCard', }; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index fe7424ba16b3..618b99be40b3 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -61,8 +61,8 @@ import { } from './ModalStackNavigators'; import SCREENS from '../../../SCREENS'; import Timers from '../../Timers'; -import ValidateLoginNewWorkspacePage from '../../../pages/ValidateLoginNewWorkspacePage'; -import ValidateLogin2FANewWorkspacePage from '../../../pages/ValidateLogin2FANewWorkspacePage'; +import LoginWithValidateCodePage from '../../../pages/LoginWithValidateCodePage'; +import LoginWithValidateCode2FAPage from '../../../pages/LoginWithValidateCode2FAPage'; import WorkspaceSettingsDrawerNavigator from './WorkspaceSettingsDrawerNavigator'; import spacing from '../../../styles/utilities/spacing'; import CardOverlay from '../../../components/CardOverlay'; @@ -298,14 +298,24 @@ class AuthScreens extends React.Component { component={ValidateLoginPage} /> + + {/* These are the various modal routes */} diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index bfe32607bdcf..2ea797d0ddbc 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -2,11 +2,10 @@ import React from 'react'; import {createStackNavigator} from '@react-navigation/stack'; import SignInPage from '../../../pages/signin/SignInPage'; import SetPasswordPage from '../../../pages/SetPasswordPage'; -import PublicWorkspaceNewView from '../../../pages/workspace/PublicWorkspaceNewView'; import ValidateLoginPage from '../../../pages/ValidateLoginPage'; import SCREENS from '../../../SCREENS'; -import ValidateLoginNewWorkspacePage from '../../../pages/ValidateLoginNewWorkspacePage'; -import ValidateLogin2FANewWorkspacePage from '../../../pages/ValidateLogin2FANewWorkspacePage'; +import LoginWithValidateCodePage from '../../../pages/LoginWithValidateCodePage'; +import LoginWithValidateCode2FAPage from '../../../pages/LoginWithValidateCode2FAPage'; import defaultScreenOptions from './defaultScreenOptions'; const RootStack = createStackNavigator(); @@ -29,18 +28,24 @@ export default () => ( component={SetPasswordPage} /> + ); diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index ebe345c5bdbc..344e2a8a8fdc 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -27,8 +27,10 @@ export default { // Public Routes SetPassword: ROUTES.SET_PASSWORD_WITH_VALIDATE_CODE, ValidateLogin: ROUTES.VALIDATE_LOGIN_WITH_VALIDATE_CODE, - [SCREENS.VALIDATE_LOGIN_NEW_WORKSPACE]: ROUTES.VALIDATE_LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE, - [SCREENS.VALIDATE_LOGIN_2FA_NEW_WORKSPACE]: ROUTES.VALIDATE_LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE, + [SCREENS.LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE]: ROUTES.LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE, + [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE, + [SCREENS.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD, + [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD, // Modal Screens Settings: { diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index eeb303a25c54..75922c7bf794 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -303,15 +303,6 @@ function continueSessionFromECom(accountID, validateCode, twoFactorAuthCode) { }); } -/** - * Sets the redirectToWorkspaceNewAfterSignIn flag in the session variable - * - * @param {Boolean} shouldRedirect - */ -function setRedirectToWorkspaceNewAfterSignIn(shouldRedirect) { - Onyx.merge(ONYXKEYS.SESSION, {redirectToWorkspaceNewAfterSignIn: shouldRedirect}); -} - export { continueSessionFromECom, fetchAccountDetails, @@ -322,5 +313,4 @@ export { resendValidationLink, resetPassword, restartSignin, - setRedirectToWorkspaceNewAfterSignIn, }; diff --git a/src/pages/ValidateLogin2FANewWorkspacePage.js b/src/pages/LoginWithValidateCode2FAPage.js similarity index 66% rename from src/pages/ValidateLogin2FANewWorkspacePage.js rename to src/pages/LoginWithValidateCode2FAPage.js index aedfb631ff2f..5484242544d7 100644 --- a/src/pages/ValidateLogin2FANewWorkspacePage.js +++ b/src/pages/LoginWithValidateCode2FAPage.js @@ -3,10 +3,9 @@ import {TextInput, View} from 'react-native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import validateLinkPropTypes from './validateLinkPropTypes'; -import {continueSessionFromECom, setRedirectToWorkspaceNewAfterSignIn} from '../libs/actions/Session'; +import {continueSessionFromECom} from '../libs/actions/Session'; import styles from '../styles/styles'; import ExpensifyCashLogo from '../components/ExpensifyCashLogo'; import variables from '../styles/variables'; @@ -17,7 +16,11 @@ import Text from '../components/Text'; import compose from '../libs/compose'; import ONYXKEYS from '../ONYXKEYS'; import Navigation from '../libs/Navigation/Navigation'; -import {create} from '../libs/actions/Policy'; +import ROUTES from '../ROUTES'; +import SCREENS from '../SCREENS'; +import * as Policy from '../libs/actions/Policy'; +import Permissions from '../libs/Permissions'; +import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; const propTypes = { /* Onyx Props */ @@ -28,7 +31,7 @@ const propTypes = { authToken: PropTypes.string, }), - /** The accountID and validateCode are passed via the URL */ + /** The route name, accountID, and validateCode are passed via the URL */ route: validateLinkPropTypes, /** List of betas */ @@ -44,7 +47,7 @@ const defaultProps = { session: {}, betas: [], }; -class ValidateLogin2FANewWorkspacePage extends Component { +class LoginWithValidateCode2FAPage extends Component { constructor(props) { super(props); @@ -58,24 +61,47 @@ class ValidateLogin2FANewWorkspacePage extends Component { } componentDidMount() { - // If the user has an active session already, they need to be redirected straight to the new workspace page + // If the user has an active session already, they need to be redirected straight to the relevant page if (this.props.session.authToken) { // 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 they user cancels - // out of the new workspace modal, then they will be routed back to - // /v///new-workspace and we don't want that. We want them to go back to `/` and - // by calling dismissModal(), the /v/... route is removed from history so the user will get taken to `/` + // modal you say? I know, it confuses me too. Without dismissing the current modal, if the user cancels out + // of the new workspace modal, then they will be routed back to + // /v///workspace/123/card and we don't want that. We want them to go back to `/` + // and by calling dismissModal(), the /v/... route is removed from history so the user will get taken to `/` // if they cancel out of the new workspace modal. Navigation.dismissModal(); - - if (_.isEmpty(this.props.betas)) { - setRedirectToWorkspaceNewAfterSignIn(true); - } else { - create(); + if (Permissions.canUseFreePlan(this.props.betas)) { + this.rerouteToRelevantPage(); } } } + componentDidUpdate() { + // Betas can be loaded a little after a user is authenticated, so check again if the betas have been updated + if (this.props.session.authToken && Permissions.canUseFreePlan(this.props.betas)) { + this.rerouteToRelevantPage(); + } + } + + rerouteToRelevantPage() { + // Since all 2FA validate code login routes lead to this component, redirect to the appropriate page based on + // the original route. + switch (this.props.route.name) { + case SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD: + Navigation.navigate(ROUTES.getWorkspaceCardRoute(this.props.route.params.policyID)); + break; + + case SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: + // Creating a policy will reroute the user to the settings page afterwards + Policy.create(); + break; + + default: + Navigation.navigate(ROUTES.HOME); + break; + } + } + validateAndSubmitForm() { if (!this.state.twoFactorAuthCode.trim()) { this.setState({formError: this.props.translate('passwordForm.pleaseFillOutAllFields')}); @@ -93,18 +119,17 @@ class ValidateLogin2FANewWorkspacePage extends Component { } render() { - // If the user is already logged in, don't need to display anything because they will get redirected to the - // new workspace page in componentDidMount + // Show a loader so that the user isn't immediately kicked to the home page before rerouteToRelevantPage runs if (this.props.session.authToken) { - return null; + return ; } return ( - + - + {this.props.translate('signInPage.expensifyDotCash')} @@ -145,8 +170,8 @@ class ValidateLogin2FANewWorkspacePage extends Component { } } -ValidateLogin2FANewWorkspacePage.propTypes = propTypes; -ValidateLogin2FANewWorkspacePage.defaultProps = defaultProps; +LoginWithValidateCode2FAPage.propTypes = propTypes; +LoginWithValidateCode2FAPage.defaultProps = defaultProps; export default compose( withLocalize, @@ -158,4 +183,4 @@ export default compose( key: ONYXKEYS.BETAS, }, }), -)(ValidateLogin2FANewWorkspacePage); +)(LoginWithValidateCode2FAPage); diff --git a/src/pages/LoginWithValidateCodePage.js b/src/pages/LoginWithValidateCodePage.js new file mode 100644 index 000000000000..c01fcbcc52e2 --- /dev/null +++ b/src/pages/LoginWithValidateCodePage.js @@ -0,0 +1,105 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; +import validateLinkPropTypes from './validateLinkPropTypes'; +import compose from '../libs/compose'; +import ONYXKEYS from '../ONYXKEYS'; +import Navigation from '../libs/Navigation/Navigation'; +import ROUTES from '../ROUTES'; +import SCREENS from '../SCREENS'; +import {continueSessionFromECom} from '../libs/actions/Session'; +import * as Policy from '../libs/actions/Policy'; +import Permissions from '../libs/Permissions'; +import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; + +const propTypes = { + /* Onyx Props */ + + /** The data about the current session */ + session: PropTypes.shape({ + /** The authToken for the current session */ + authToken: PropTypes.string, + }), + + /** The accountID and validateCode are passed via the URL */ + route: validateLinkPropTypes, + + /** List of betas */ + betas: PropTypes.arrayOf(PropTypes.string), +}; + +const defaultProps = { + route: { + params: {}, + }, + session: {}, + betas: [], +}; +class LoginWithValidateCodePage extends Component { + componentDidMount() { + // If the user has an active session already, they need to be redirected straight to the relevant page + if (this.props.session.authToken) { + // 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 new workspace modal, then they will be routed back to + // /v///workspace/123/card and we don't want that. We want them to go back to `/` + // and by calling dismissModal(), the /v/... route is removed from history so the user will get taken to `/` + // if they cancel out of the new workspace modal. + Navigation.dismissModal(); + if (Permissions.canUseFreePlan(this.props.betas)) { + this.rerouteToRelevantPage(); + } + return; + } + + const accountID = lodashGet(this.props.route.params, 'accountID', ''); + const validateCode = lodashGet(this.props.route.params, 'validateCode', ''); + continueSessionFromECom(accountID, validateCode); + } + + componentDidUpdate() { + // Betas can be loaded a little after a user is authenticated, so check again if the betas have been updated + if (this.props.session.authToken && Permissions.canUseFreePlan(this.props.betas)) { + this.rerouteToRelevantPage(); + } + } + + rerouteToRelevantPage() { + // Since all validate code login routes lead to this component, redirect to the appropriate page based on + // the original route. + switch (this.props.route.name) { + case SCREENS.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: + Navigation.navigate(ROUTES.getWorkspaceCardRoute(this.props.route.params.policyID)); + break; + + case SCREENS.LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: + // Creating a policy will reroute the user to the settings page afterwards + Policy.create(); + break; + + default: + Navigation.navigate(ROUTES.HOME); + break; + } + } + + render() { + // Show a loader so that the user isn't immediately kicked to the home page before rerouteToRelevantPage runs + return ; + } +} + +LoginWithValidateCodePage.propTypes = propTypes; +LoginWithValidateCodePage.defaultProps = defaultProps; + +export default compose( + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(LoginWithValidateCodePage); diff --git a/src/pages/ValidateLoginNewWorkspacePage.js b/src/pages/ValidateLoginNewWorkspacePage.js deleted file mode 100644 index d80d60d17171..000000000000 --- a/src/pages/ValidateLoginNewWorkspacePage.js +++ /dev/null @@ -1,79 +0,0 @@ -import {Component} from 'react'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import lodashGet from 'lodash/get'; -import _ from 'underscore'; -import validateLinkPropTypes from './validateLinkPropTypes'; -import compose from '../libs/compose'; -import ONYXKEYS from '../ONYXKEYS'; -import Navigation from '../libs/Navigation/Navigation'; -import {continueSessionFromECom, setRedirectToWorkspaceNewAfterSignIn} from '../libs/actions/Session'; -import {create} from '../libs/actions/Policy'; - -const propTypes = { - /* Onyx Props */ - - /** The data about the current session */ - session: PropTypes.shape({ - /** The authToken for the current session */ - authToken: PropTypes.string, - }), - - /** The accountID and validateCode are passed via the URL */ - route: validateLinkPropTypes, - - /** List of betas */ - betas: PropTypes.arrayOf(PropTypes.string), -}; - -const defaultProps = { - route: { - params: {}, - }, - session: {}, - betas: [], -}; -class ValidateLoginNewWorkspacePage extends Component { - componentDidMount() { - // If the user has an active session already, they need to be redirected straight to the new workspace page - if (this.props.session.authToken) { - // 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 they user cancels - // out of the new workspace modal, then they will be routed back to - // /v///new-workspace and we don't want that. We want them to go back to `/` and - // by calling dismissModal(), the /v/... route is removed from history so the user will get taken to `/` - // if they cancel out of the new workspace modal. - Navigation.dismissModal(); - if (_.isEmpty(this.props.betas)) { - setRedirectToWorkspaceNewAfterSignIn(true); - } else { - create(); - } - return; - } - - const accountID = lodashGet(this.props.route.params, 'accountID', ''); - const validateCode = lodashGet(this.props.route.params, 'validateCode', ''); - continueSessionFromECom(accountID, validateCode); - } - - render() { - // Don't render anything here since the user is redirected to the new workspace page - // once we've attempted to validate their login in continueSessionFromECom() - return null; - } -} - -ValidateLoginNewWorkspacePage.propTypes = propTypes; -ValidateLoginNewWorkspacePage.defaultProps = defaultProps; - -export default compose( - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - betas: { - key: ONYXKEYS.BETAS, - }, - }), -)(ValidateLoginNewWorkspacePage); diff --git a/src/pages/workspace/PublicWorkspaceNewView.js b/src/pages/workspace/PublicWorkspaceNewView.js deleted file mode 100644 index 3d4a62f581a7..000000000000 --- a/src/pages/workspace/PublicWorkspaceNewView.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import SCREENS from '../../SCREENS'; -import {setRedirectToWorkspaceNewAfterSignIn} from '../../libs/actions/Session'; - -const propTypes = { - /** react-navigation navigation object available to screen components */ - navigation: PropTypes.shape({ - /** Method used to navigate to a new page and not keep the current route in the history */ - replace: PropTypes.func.isRequired, - }).isRequired, -}; - -class PublicWorkspaceNewView extends React.PureComponent { - componentDidMount() { - setRedirectToWorkspaceNewAfterSignIn(true); - this.props.navigation.replace(SCREENS.HOME); - } - - render() { - return null; - } -} - -PublicWorkspaceNewView.propTypes = propTypes; - -export default PublicWorkspaceNewView; diff --git a/src/pages/workspace/WorkspaceSidebar.js b/src/pages/workspace/WorkspaceSidebar.js index 0dd7990db4e1..35f780924915 100644 --- a/src/pages/workspace/WorkspaceSidebar.js +++ b/src/pages/workspace/WorkspaceSidebar.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {useEffect} from 'react'; +import React from 'react'; import {View, ScrollView, Pressable} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -37,15 +37,24 @@ const propTypes = { name: PropTypes.string, }), + /** All the polices that we have loaded in Onyx */ + allPolicies: PropTypes.shape({ + /** ID of the policy */ + id: PropTypes.string, + }), + ...withLocalizePropTypes, ...windowDimensionsPropTypes, }; const defaultProps = { policy: {}, + allPolicies: null, }; -const WorkspaceSidebar = ({translate, isSmallScreenWidth, policy}) => { +const WorkspaceSidebar = ({ + translate, isSmallScreenWidth, policy, allPolicies, +}) => { const menuItems = [ { translationKey: 'workspace.common.card', @@ -65,14 +74,15 @@ const WorkspaceSidebar = ({translate, isSmallScreenWidth, policy}) => { }, ]; - useEffect(() => { - if (_.isEmpty(policy)) { - Growl.error(translate('workspace.error.growlMessageInvalidPolicy'), CONST.GROWL.DURATION_LONG); - Navigation.dismissModal(); - create(); - return null; - } - }, [policy]); + // After all the policies have loaded, we can know if the given policyID points to a nonexistant workspace + // When free plan is out of beta and Permissions.canUseFreePlan() gets removed, + // all code involving 'allPolicies' can be removed since policy loading will no longer be delayed on login. + if (allPolicies !== null && _.isEmpty(policy)) { + Growl.error(translate('workspace.error.growlMessageInvalidPolicy'), CONST.GROWL.DURATION_LONG); + Navigation.dismissModal(); + create(); + return null; + } const openEditor = () => Navigation.navigate(ROUTES.getWorkspaceEditorRoute(policy.id)); @@ -172,5 +182,8 @@ export default compose( return `${ONYXKEYS.COLLECTION.POLICY}${policyID}`; }, }, + allPolicies: { + key: ONYXKEYS.COLLECTION.POLICY, + }, }), )(WorkspaceSidebar);