From e7bf8f784ba29c461cf4378f832916d16bec10b4 Mon Sep 17 00:00:00 2001
From: Rajat Parashar <parasharrajat@users.noreply.github.com>
Date: Tue, 19 Oct 2021 08:12:43 +0530
Subject: [PATCH 1/4] Added Permission check

---
 .../Navigation/AppNavigator/AuthScreens.js    | 28 +++++++++++--------
 src/libs/actions/SignInRedirect.js            |  4 ++-
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 8bd0c0658518..47fca2e77eb6 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -63,6 +63,7 @@ import defaultScreenOptions from './defaultScreenOptions';
 import * as API from '../../API';
 import {setLocale} from '../../actions/App';
 import {cleanupSession} from '../../actions/Session';
+import Permissions from '../../Permissions';
 
 Onyx.connect({
     key: ONYXKEYS.MY_PERSONAL_DETAILS,
@@ -142,17 +143,19 @@ class AuthScreens extends React.Component {
         NameValuePair.get(CONST.NVP.PRIORITY_MODE, ONYXKEYS.NVP_PRIORITY_MODE, 'default');
         NameValuePair.get(CONST.NVP.IS_FIRST_TIME_NEW_EXPENSIFY_USER, ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, true);
 
-        API.Get({
-            returnValueList: 'nameValuePairs',
-            nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
-        }).then((response) => {
-            const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
-            if ((currentPreferredLocale !== CONST.DEFAULT_LOCALE) && (preferredLocale !== currentPreferredLocale)) {
-                setLocale(currentPreferredLocale);
-            } else {
-                Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
-            }
-        });
+        if (Permissions.canUseInternationalization(this.props.betas)) {
+            API.Get({
+                returnValueList: 'nameValuePairs',
+                nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
+            }).then((response) => {
+                const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
+                if ((currentPreferredLocale !== CONST.DEFAULT_LOCALE) && (preferredLocale !== currentPreferredLocale)) {
+                    setLocale(currentPreferredLocale);
+                } else {
+                    Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
+                }
+            });
+        }
 
         PersonalDetails.fetchPersonalDetails();
         User.getUserDetails();
@@ -385,5 +388,8 @@ export default compose(
         network: {
             key: ONYXKEYS.NETWORK,
         },
+        betas: {
+            key: ONYXKEYS.BETAS,
+        },
     }),
 )(AuthScreens);
diff --git a/src/libs/actions/SignInRedirect.js b/src/libs/actions/SignInRedirect.js
index 95e8b862d8bc..a05faa8bdc8d 100644
--- a/src/libs/actions/SignInRedirect.js
+++ b/src/libs/actions/SignInRedirect.js
@@ -1,6 +1,7 @@
 import Onyx from 'react-native-onyx';
 import SignoutManager from '../SignoutManager';
 import ONYXKEYS from '../../ONYXKEYS';
+import Permissions from '../Permissions';
 
 let currentActiveClients;
 Onyx.connect({
@@ -26,7 +27,8 @@ function clearStorageAndRedirect(errorMessage) {
     // Clearing storage discards the authToken. This causes a redirect to the SignIn screen
     Onyx.clear()
         .then(() => {
-            if (preferredLocale) {
+            // Betas are only present when user is Logined
+            if (Permissions.canUseInternationalization([]) && preferredLocale) {
                 Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
             }
             if (activeClients && activeClients.length > 0) {

From 783182de276a40f689c8825f0bdf4a0a652b0eb1 Mon Sep 17 00:00:00 2001
From: Rajat Parashar <parasharrajat@users.noreply.github.com>
Date: Sat, 30 Oct 2021 06:29:35 +0530
Subject: [PATCH 2/4] race conditions resolved

---
 src/ONYXKEYS.js                               |  3 ++
 .../Navigation/AppNavigator/AuthScreens.js    | 28 ++++++----------
 src/libs/actions/User.js                      | 33 ++++++++++++++++++-
 3 files changed, 45 insertions(+), 19 deletions(-)

diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index ece47440dabe..8715dd509aee 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -69,6 +69,9 @@ export default {
     SESSION: 'session',
     BETAS: 'betas',
 
+    // Set when we are loading payment methods
+    IS_LOADING_BETAS: 'isLoadingBetas',
+
     // NVP keys
     // Contains the user's payPalMe address
     NVP_PAYPAL_ME_ADDRESS: 'nvp_paypalMeAddress',
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index c63563492a21..69a80a7545c5 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -60,10 +60,7 @@ import SCREENS from '../../../SCREENS';
 import Timers from '../../Timers';
 import LogInWithShortLivedTokenPage from '../../../pages/LogInWithShortLivedTokenPage';
 import defaultScreenOptions from './defaultScreenOptions';
-import * as API from '../../API';
-import {setLocale} from '../../actions/App';
 import {cleanupSession} from '../../actions/Session';
-import Permissions from '../../Permissions';
 
 Onyx.connect({
     key: ONYXKEYS.MY_PERSONAL_DETAILS,
@@ -117,6 +114,7 @@ const propTypes = {
 
 const defaultProps = {
     network: {isOffline: true},
+    isLoadingBetas: true,
 };
 
 class AuthScreens extends React.Component {
@@ -142,21 +140,6 @@ class AuthScreens extends React.Component {
         // Fetch some data we need on initialization
         NameValuePair.get(CONST.NVP.PRIORITY_MODE, ONYXKEYS.NVP_PRIORITY_MODE, 'default');
         NameValuePair.get(CONST.NVP.IS_FIRST_TIME_NEW_EXPENSIFY_USER, ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, true);
-
-        if (Permissions.canUseInternationalization(this.props.betas)) {
-            API.Get({
-                returnValueList: 'nameValuePairs',
-                nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
-            }).then((response) => {
-                const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
-                if ((currentPreferredLocale !== CONST.DEFAULT_LOCALE) && (preferredLocale !== currentPreferredLocale)) {
-                    setLocale(currentPreferredLocale);
-                } else {
-                    Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
-                }
-            });
-        }
-
         PersonalDetails.fetchPersonalDetails();
         User.getUserDetails();
         User.getBetas();
@@ -219,6 +202,12 @@ class AuthScreens extends React.Component {
         return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
     }
 
+    componentDidUpdate(prevProps) {
+        if (prevProps.isLoadingBetas && !this.props.isLoadingBetas) {
+            User.fetchAndSetPreferredLocale(this.props.betas, currentPreferredLocale);
+        }
+    }
+
     componentWillUnmount() {
         if (this.unsubscribeSearchShortcut) {
             this.unsubscribeSearchShortcut();
@@ -392,5 +381,8 @@ export default compose(
         betas: {
             key: ONYXKEYS.BETAS,
         },
+        isLoadingBetas: {
+            key: ONYXKEYS.IS_LOADING_BETAS,
+        },
     }),
 )(AuthScreens);
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index 3021af64d784..2f312c94cd54 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -14,6 +14,9 @@ import Log from '../Log';
 import NetworkConnection from '../NetworkConnection';
 import NameValuePair from './NameValuePair';
 import getSkinToneEmojiFromIndex from '../../pages/home/report/EmojiPickerMenu/getSkinToneEmojiFromIndex';
+import Permissions from '../Permissions';
+import {setLocale} from './App';
+
 
 let sessionAuthToken = '';
 let sessionEmail = '';
@@ -58,9 +61,36 @@ function changePassword(oldPassword, password) {
 }
 
 function getBetas() {
+    Onyx.set(ONYXKEYS.IS_LOADING_BETAS, true);
     API.User_GetBetas().then((response) => {
         if (response.jsonCode === 200) {
-            Onyx.set(ONYXKEYS.BETAS, response.betas);
+            Onyx.multiSet({
+                [ONYXKEYS.BETAS]: response.betas,
+                [ONYXKEYS.IS_LOADING_BETAS]: null,
+            });
+        }
+    });
+}
+
+/**
+ * Fetches the User's preferred Locale and set the app locale if not same.
+ *
+ * @param {Array<String>} betas
+ * @param {String} currentPreferredLocale
+ */
+function fetchAndSetPreferredLocale(betas, currentPreferredLocale) {
+    if (!Permissions.canUseInternationalization(betas)) {
+        return;
+    }
+    API.Get({
+        returnValueList: 'nameValuePairs',
+        nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
+    }).then((response) => {
+        const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
+        if ((currentPreferredLocale !== CONST.DEFAULT_LOCALE) && (preferredLocale !== currentPreferredLocale)) {
+            setLocale(currentPreferredLocale);
+        } else {
+            Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);
         }
     });
 }
@@ -312,4 +342,5 @@ export {
     setPreferredSkinTone,
     setShouldUseSecureStaging,
     clearUserErrorMessage,
+    fetchAndSetPreferredLocale,
 };

From d8d4417ca191095ee47f654eea3cef311c502dc4 Mon Sep 17 00:00:00 2001
From: Rajat Parashar <parasharrajat@users.noreply.github.com>
Date: Sat, 30 Oct 2021 07:20:39 +0530
Subject: [PATCH 3/4] allow render when betas are loaded in Authscreen

---
 src/libs/Navigation/AppNavigator/AuthScreens.js |  9 +++++++--
 src/libs/actions/User.js                        | 10 +++++-----
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 69a80a7545c5..3dcbefa8d14c 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -109,12 +109,17 @@ const propTypes = {
         isOffline: PropTypes.bool,
     }),
 
+    /** Beta features list */
+    betas: PropTypes.arrayOf(PropTypes.string).isRequired,
+
+    /** Whether betas are loading */
+    isLoadingBetas: PropTypes.bool.isRequired,
+
     ...windowDimensionsPropTypes,
 };
 
 const defaultProps = {
     network: {isOffline: true},
-    isLoadingBetas: true,
 };
 
 class AuthScreens extends React.Component {
@@ -199,7 +204,7 @@ class AuthScreens extends React.Component {
     }
 
     shouldComponentUpdate(nextProps) {
-        return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
+        return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth || nextProps.isLoadingBetas !== this.props.isLoadingBetas;
     }
 
     componentDidUpdate(prevProps) {
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index 2f312c94cd54..00197eb98a67 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -73,21 +73,21 @@ function getBetas() {
 }
 
 /**
- * Fetches the User's preferred Locale and set the app locale if not same.
+ * Fetches the User's preferred Locale and set the app locale.
  *
  * @param {Array<String>} betas
  * @param {String} currentPreferredLocale
  */
 function fetchAndSetPreferredLocale(betas, currentPreferredLocale) {
-    if (!Permissions.canUseInternationalization(betas)) {
-        return;
-    }
     API.Get({
         returnValueList: 'nameValuePairs',
         nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
     }).then((response) => {
         const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
-        if ((currentPreferredLocale !== CONST.DEFAULT_LOCALE) && (preferredLocale !== currentPreferredLocale)) {
+        if (currentPreferredLocale !== CONST.DEFAULT_LOCALE
+            && preferredLocale !== currentPreferredLocale
+            && Permissions.canUseInternationalization(betas)
+        ) {
             setLocale(currentPreferredLocale);
         } else {
             Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, preferredLocale);

From 8f9007ad7de34397e01722160a3fa409d34404e3 Mon Sep 17 00:00:00 2001
From: Rajat Parashar <parasharrajat@users.noreply.github.com>
Date: Sun, 31 Oct 2021 11:33:30 +0530
Subject: [PATCH 4/4] Refactor code to resolve race conditions

---
 src/ONYXKEYS.js                               |  3 --
 src/components/withLocalize.js                |  3 ++
 .../Navigation/AppNavigator/AuthScreens.js    | 31 +++----------------
 src/libs/actions/User.js                      | 29 +++++++++--------
 4 files changed, 22 insertions(+), 44 deletions(-)

diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js
index 8715dd509aee..ece47440dabe 100755
--- a/src/ONYXKEYS.js
+++ b/src/ONYXKEYS.js
@@ -69,9 +69,6 @@ export default {
     SESSION: 'session',
     BETAS: 'betas',
 
-    // Set when we are loading payment methods
-    IS_LOADING_BETAS: 'isLoadingBetas',
-
     // NVP keys
     // Contains the user's payPalMe address
     NVP_PAYPAL_ME_ADDRESS: 'nvp_paypalMeAddress',
diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js
index 0a6797ff027c..99c67e934a04 100755
--- a/src/components/withLocalize.js
+++ b/src/components/withLocalize.js
@@ -29,6 +29,9 @@ const withLocalizePropTypes = {
 
     /** Returns an internationally converted phone number with the country code */
     fromLocalPhone: PropTypes.func.isRequired,
+
+    /** The user's preferred locale e.g. 'en', 'es-ES' */
+    preferredLocale: PropTypes.string.isRequired,
 };
 
 const localeProviderPropTypes = {
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index 3dcbefa8d14c..13cfc7544614 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -61,6 +61,7 @@ import Timers from '../../Timers';
 import LogInWithShortLivedTokenPage from '../../../pages/LogInWithShortLivedTokenPage';
 import defaultScreenOptions from './defaultScreenOptions';
 import {cleanupSession} from '../../actions/Session';
+import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
 
 Onyx.connect({
     key: ONYXKEYS.MY_PERSONAL_DETAILS,
@@ -81,12 +82,6 @@ Onyx.connect({
     },
 });
 
-let currentPreferredLocale;
-Onyx.connect({
-    key: ONYXKEYS.NVP_PREFERRED_LOCALE,
-    callback: val => currentPreferredLocale = val || CONST.DEFAULT_LOCALE,
-});
-
 const RootStack = createCustomModalStackNavigator();
 
 // We want to delay the re-rendering for components(e.g. ReportActionCompose)
@@ -109,12 +104,7 @@ const propTypes = {
         isOffline: PropTypes.bool,
     }),
 
-    /** Beta features list */
-    betas: PropTypes.arrayOf(PropTypes.string).isRequired,
-
-    /** Whether betas are loading */
-    isLoadingBetas: PropTypes.bool.isRequired,
-
+    ...withLocalizePropTypes,
     ...windowDimensionsPropTypes,
 };
 
@@ -147,7 +137,7 @@ class AuthScreens extends React.Component {
         NameValuePair.get(CONST.NVP.IS_FIRST_TIME_NEW_EXPENSIFY_USER, ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, true);
         PersonalDetails.fetchPersonalDetails();
         User.getUserDetails();
-        User.getBetas();
+        User.fetchBetasAndSetPreferredLocale(this.props.preferredLocale);
         User.getDomainInfo();
         PersonalDetails.fetchLocalCurrency();
         fetchAllReports(true, true);
@@ -204,13 +194,7 @@ class AuthScreens extends React.Component {
     }
 
     shouldComponentUpdate(nextProps) {
-        return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth || nextProps.isLoadingBetas !== this.props.isLoadingBetas;
-    }
-
-    componentDidUpdate(prevProps) {
-        if (prevProps.isLoadingBetas && !this.props.isLoadingBetas) {
-            User.fetchAndSetPreferredLocale(this.props.betas, currentPreferredLocale);
-        }
+        return nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
     }
 
     componentWillUnmount() {
@@ -379,15 +363,10 @@ AuthScreens.propTypes = propTypes;
 AuthScreens.defaultProps = defaultProps;
 export default compose(
     withWindowDimensions,
+    withLocalize,
     withOnyx({
         network: {
             key: ONYXKEYS.NETWORK,
         },
-        betas: {
-            key: ONYXKEYS.BETAS,
-        },
-        isLoadingBetas: {
-            key: ONYXKEYS.IS_LOADING_BETAS,
-        },
     }),
 )(AuthScreens);
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index 00197eb98a67..c9714f93baee 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -61,28 +61,27 @@ function changePassword(oldPassword, password) {
 }
 
 function getBetas() {
-    Onyx.set(ONYXKEYS.IS_LOADING_BETAS, true);
-    API.User_GetBetas().then((response) => {
+    return API.User_GetBetas().then((response) => {
         if (response.jsonCode === 200) {
-            Onyx.multiSet({
-                [ONYXKEYS.BETAS]: response.betas,
-                [ONYXKEYS.IS_LOADING_BETAS]: null,
-            });
+            Onyx.set(ONYXKEYS.BETAS, response.betas);
+            return response.betas;
         }
+        return [];
     });
 }
 
 /**
- * Fetches the User's preferred Locale and set the app locale.
- *
- * @param {Array<String>} betas
+ * Fetches betas and User's preferred Locale, then set the app locale.
  * @param {String} currentPreferredLocale
  */
-function fetchAndSetPreferredLocale(betas, currentPreferredLocale) {
-    API.Get({
-        returnValueList: 'nameValuePairs',
-        nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
-    }).then((response) => {
+function fetchBetasAndSetPreferredLocale(currentPreferredLocale) {
+    Promise.all([
+        getBetas(),
+        API.Get({
+            returnValueList: 'nameValuePairs',
+            nvpNames: ONYXKEYS.NVP_PREFERRED_LOCALE,
+        }),
+    ]).then((betas, response) => {
         const preferredLocale = lodashGet(response, ['nameValuePairs', 'preferredLocale'], CONST.DEFAULT_LOCALE);
         if (currentPreferredLocale !== CONST.DEFAULT_LOCALE
             && preferredLocale !== currentPreferredLocale
@@ -342,5 +341,5 @@ export {
     setPreferredSkinTone,
     setShouldUseSecureStaging,
     clearUserErrorMessage,
-    fetchAndSetPreferredLocale,
+    fetchBetasAndSetPreferredLocale,
 };
