From 0ed9b5889f61d0915706478417f0e3b98a66966c Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Fri, 7 Jul 2023 18:44:19 -0700 Subject: [PATCH 01/15] remove canUsePasswordless --- src/libs/Permissions.js | 9 ------- src/pages/ValidateLoginPage/index.js | 6 ++--- src/pages/ValidateLoginPage/index.website.js | 15 ----------- .../settings/Payments/AddDebitCardPage.js | 25 ------------------- .../Payments/PaymentsPage/BasePaymentsPage.js | 9 +------ .../Profile/Contacts/NewContactMethodPage.js | 21 +--------------- src/pages/signin/SignInPage.js | 12 +++------ 7 files changed, 8 insertions(+), 89 deletions(-) diff --git a/src/libs/Permissions.js b/src/libs/Permissions.js index 3617900109f2..80f2f8d6ce65 100644 --- a/src/libs/Permissions.js +++ b/src/libs/Permissions.js @@ -86,14 +86,6 @@ function canUsePolicyExpenseChat(betas) { return _.contains(betas, CONST.BETAS.POLICY_EXPENSE_CHAT) || canUseAllBetas(betas); } -/** - * @param {Array} betas - * @returns {Boolean} - */ -function canUsePasswordlessLogins(betas) { - return _.contains(betas, CONST.BETAS.PASSWORDLESS) || canUseAllBetas(betas); -} - /** * @param {Array} betas * @returns {Boolean} @@ -120,7 +112,6 @@ export default { canUseCommentLinking, canUsePolicyRooms, canUsePolicyExpenseChat, - canUsePasswordlessLogins, canUseTasks, canUseScanReceipts, }; diff --git a/src/pages/ValidateLoginPage/index.js b/src/pages/ValidateLoginPage/index.js index 57893a03b8bc..4fa9c4f8e6d0 100644 --- a/src/pages/ValidateLoginPage/index.js +++ b/src/pages/ValidateLoginPage/index.js @@ -7,7 +7,6 @@ import * as User from '../../libs/actions/User'; import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; import ONYXKEYS from '../../ONYXKEYS'; import * as Session from '../../libs/actions/Session'; -import usePermissions from '../../hooks/usePermissions'; import useLocalize from '../../hooks/useLocalize'; import Navigation from '../../libs/Navigation/Navigation'; @@ -37,7 +36,6 @@ const defaultProps = { }; function ValidateLoginPage(props) { - const {canUsePasswordlessLogins} = usePermissions(); const {preferredLocale} = useLocalize(); useEffect(() => { @@ -45,9 +43,9 @@ function ValidateLoginPage(props) { const accountID = lodashGet(props.route.params, 'accountID', ''); const validateCode = lodashGet(props.route.params, 'validateCode', ''); - // A fresh session will not have credentials.login and user permission betas available. + // A fresh session will not have credentials.login available. // In that case, we directly allow users to go through password less flow - if (!login || canUsePasswordlessLogins) { + if (!login) { if (lodashGet(props, 'session.authToken')) { // If already signed in, do not show the validate code if not on web, // because we don't want to block the user with the interstitial page. diff --git a/src/pages/ValidateLoginPage/index.website.js b/src/pages/ValidateLoginPage/index.website.js index cdb7e2ad064f..2f6fb26bc988 100644 --- a/src/pages/ValidateLoginPage/index.website.js +++ b/src/pages/ValidateLoginPage/index.website.js @@ -3,13 +3,11 @@ import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; import {propTypes as validateLinkPropTypes, defaultProps as validateLinkDefaultProps} from './validateLinkPropTypes'; -import * as User from '../../libs/actions/User'; import compose from '../../libs/compose'; import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; import ValidateCodeModal from '../../components/ValidateCode/ValidateCodeModal'; import ONYXKEYS from '../../ONYXKEYS'; import * as Session from '../../libs/actions/Session'; -import Permissions from '../../libs/Permissions'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import ExpiredValidateCodeModal from '../../components/ValidateCode/ExpiredValidateCodeModal'; import Navigation from '../../libs/Navigation/Navigation'; @@ -21,9 +19,6 @@ const propTypes = { /** The accountID and validateCode are passed via the URL */ route: validateLinkPropTypes, - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - /** Session of currently logged in user */ session: PropTypes.shape({ /** Currently logged in user authToken */ @@ -50,7 +45,6 @@ const propTypes = { const defaultProps = { route: validateLinkDefaultProps, - betas: [], session: { authToken: null, }, @@ -61,14 +55,6 @@ const defaultProps = { class ValidateLoginPage extends Component { componentDidMount() { const login = lodashGet(this.props, 'credentials.login', null); - - // A fresh session will not have credentials.login and user permission betas available. - // In that case, we directly allow users to go through password less flow - if (login && !Permissions.canUsePasswordlessLogins(this.props.betas)) { - User.validateLogin(this.getAccountID(), this.getValidateCode()); - return; - } - const isSignedIn = Boolean(lodashGet(this.props, 'session.authToken', null)); const cachedAutoAuthState = lodashGet(this.props, 'session.autoAuthState', null); if (!login && isSignedIn && (cachedAutoAuthState === CONST.AUTO_AUTH_STATE.SIGNING_IN || cachedAutoAuthState === CONST.AUTO_AUTH_STATE.JUST_SIGNED_IN)) { @@ -144,7 +130,6 @@ export default compose( withLocalize, withOnyx({ account: {key: ONYXKEYS.ACCOUNT}, - betas: {key: ONYXKEYS.BETAS}, credentials: {key: ONYXKEYS.CREDENTIALS}, session: {key: ONYXKEYS.SESSION}, }), diff --git a/src/pages/settings/Payments/AddDebitCardPage.js b/src/pages/settings/Payments/AddDebitCardPage.js index 87b3a774ef85..1d9ff09581ec 100644 --- a/src/pages/settings/Payments/AddDebitCardPage.js +++ b/src/pages/settings/Payments/AddDebitCardPage.js @@ -1,6 +1,5 @@ import React, {Component} from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import compose from '../../../libs/compose'; @@ -18,9 +17,7 @@ import TextInput from '../../../components/TextInput'; import CONST from '../../../CONST'; import ONYXKEYS from '../../../ONYXKEYS'; import AddressSearch from '../../../components/AddressSearch'; -import * as ComponentUtils from '../../../libs/ComponentUtils'; import Form from '../../../components/Form'; -import Permissions from '../../../libs/Permissions'; import Navigation from '../../../libs/Navigation/Navigation'; import ROUTES from '../../../ROUTES'; @@ -30,9 +27,6 @@ const propTypes = { setupComplete: PropTypes.bool, }), - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - ...withLocalizePropTypes, }; @@ -40,7 +34,6 @@ const defaultProps = { formData: { setupComplete: false, }, - betas: [], }; class DebitCardPage extends Component { @@ -101,10 +94,6 @@ class DebitCardPage extends Component { errors.addressState = 'addDebitCardPage.error.addressState'; } - if (!Permissions.canUsePasswordlessLogins(this.props.betas) && (!values.password || _.isEmpty(values.password.trim()))) { - errors.password = 'addDebitCardPage.error.password'; - } - if (!values.acceptTerms) { errors.acceptTerms = 'common.error.acceptTerms'; } @@ -175,17 +164,6 @@ class DebitCardPage extends Component { - {!Permissions.canUsePasswordlessLogins(this.props.betas) && ( - - - - )} { - if (Permissions.canUsePasswordlessLogins(this.props.betas)) { - this.makeDefaultPaymentMethod(); - } else { - this.setState({ - shouldShowPasswordPrompt: true, - passwordButtonText: this.props.translate('paymentsPage.setDefaultConfirmation'), - }); - } + this.makeDefaultPaymentMethod(); }); }} text={this.props.translate('paymentsPage.setDefaultConfirmation')} diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js index b949ab1b351d..fdeeb6166433 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js @@ -13,7 +13,6 @@ import Text from '../../../../components/Text'; import TextInput from '../../../../components/TextInput'; import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize'; import Navigation from '../../../../libs/Navigation/Navigation'; -import Permissions from '../../../../libs/Permissions'; import ONYXKEYS from '../../../../ONYXKEYS'; import ROUTES from '../../../../ROUTES'; import styles from '../../../../styles/styles'; @@ -26,9 +25,6 @@ import CONST from '../../../../CONST'; const propTypes = { /* Onyx Props */ - /** List of betas available to current user */ - betas: PropTypes.arrayOf(PropTypes.string), - /** Login list for the user that is signed in */ loginList: PropTypes.shape({ /** The partner creating the account. It depends on the source: website, mobile, integrations, ... */ @@ -50,7 +46,6 @@ const propTypes = { ...withLocalizePropTypes, }; const defaultProps = { - betas: [], loginList: {}, }; @@ -102,10 +97,6 @@ function NewContactMethodPage(props) { ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.enteredMethodIsAlreadySubmited'); } - if (!Permissions.canUsePasswordlessLogins(props.betas) && _.isEmpty(values.password)) { - errors.password = 'contacts.genericFailureMessages.passwordRequired'; - } - return errors; }, // We don't need `props.loginList` because when submitting this form @@ -146,18 +137,9 @@ function NewContactMethodPage(props) { ref={(el) => (loginInputRef.current = el)} inputID="phoneOrEmail" autoCapitalize="none" - returnKeyType={Permissions.canUsePasswordlessLogins(props.betas) ? 'done' : 'next'} + returnKeyType="done" /> - {!Permissions.canUsePasswordlessLogins(props.betas) && ( - - - - )} ); @@ -169,7 +151,6 @@ NewContactMethodPage.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ - betas: {key: ONYXKEYS.BETAS}, loginList: {key: ONYXKEYS.LOGIN_LIST}, }), )(NewContactMethodPage); diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index 042837401751..a5c49b43b35e 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -18,7 +18,6 @@ import UnlinkLoginForm from './UnlinkLoginForm'; import * as Localize from '../../libs/Localize'; import * as StyleUtils from '../../styles/StyleUtils'; import useLocalize from '../../hooks/useLocalize'; -import usePermissions from '../../hooks/usePermissions'; import useWindowDimensions from '../../hooks/useWindowDimensions'; import Log from '../../libs/Log'; @@ -62,15 +61,14 @@ const defaultProps = { * @param {Boolean} isPrimaryLogin * @param {Boolean} isAccountValidated * @param {Boolean} didForgetPassword - * @param {Boolean} canUsePasswordlessLogins * @returns {Object} */ -function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated, didForgetPassword, canUsePasswordlessLogins}) { +function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated, didForgetPassword}) { const shouldShowLoginForm = !hasLogin && !hasValidateCode; const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !isAccountValidated; - const shouldShowPasswordForm = hasLogin && isAccountValidated && !hasPassword && !didForgetPassword && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins; - const shouldShowValidateCodeForm = hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin && canUsePasswordlessLogins; - const shouldShowResendValidationForm = hasLogin && (!isAccountValidated || didForgetPassword) && !isUnvalidatedSecondaryLogin && !canUsePasswordlessLogins; + const shouldShowPasswordForm = hasLogin && isAccountValidated && !hasPassword && !didForgetPassword && !isUnvalidatedSecondaryLogin; + const shouldShowValidateCodeForm = hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin; + const shouldShowResendValidationForm = hasLogin && (!isAccountValidated || didForgetPassword) && !isUnvalidatedSecondaryLogin; const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm || isUnvalidatedSecondaryLogin; const shouldShowWelcomeText = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm; return { @@ -86,7 +84,6 @@ function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, i function SignInPage({credentials, account}) { const {translate, formatPhoneNumber} = useLocalize(); - const {canUsePasswordlessLogins} = usePermissions(); const {isSmallScreenWidth} = useWindowDimensions(); const safeAreaInsets = useSafeAreaInsets(); @@ -111,7 +108,6 @@ function SignInPage({credentials, account}) { isPrimaryLogin: !account.primaryLogin || account.primaryLogin === credentials.login, isAccountValidated: Boolean(account.validated), didForgetPassword: Boolean(account.forgotPassword), - canUsePasswordlessLogins, }); let welcomeHeader; From 12f524b24f052f62bbd3bb700200820224472609 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Fri, 7 Jul 2023 18:47:11 -0700 Subject: [PATCH 02/15] remove password form and resendvalidatecode form from sign in --- src/pages/signin/SignInPage.js | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js index a5c49b43b35e..9d2b98435c84 100644 --- a/src/pages/signin/SignInPage.js +++ b/src/pages/signin/SignInPage.js @@ -33,9 +33,6 @@ const propTypes = { /** The primaryLogin associated with the account */ primaryLogin: PropTypes.string, - /** Has the user pressed the forgot password button? */ - forgotPassword: PropTypes.bool, - /** Does this account require 2FA? */ requiresTwoFactorAuth: PropTypes.bool, }), @@ -43,7 +40,6 @@ const propTypes = { /** The credentials of the person signing in */ credentials: PropTypes.shape({ login: PropTypes.string, - password: PropTypes.string, twoFactorAuthCode: PropTypes.string, validateCode: PropTypes.string, }), @@ -56,27 +52,21 @@ const defaultProps = { /** * @param {Boolean} hasLogin - * @param {Boolean} hasPassword * @param {Boolean} hasValidateCode * @param {Boolean} isPrimaryLogin * @param {Boolean} isAccountValidated - * @param {Boolean} didForgetPassword * @returns {Object} */ -function getRenderOptions({hasLogin, hasPassword, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated, didForgetPassword}) { +function getRenderOptions({hasLogin, hasValidateCode, hasAccount, isPrimaryLogin, isAccountValidated}) { const shouldShowLoginForm = !hasLogin && !hasValidateCode; const isUnvalidatedSecondaryLogin = hasLogin && !isPrimaryLogin && !isAccountValidated; - const shouldShowPasswordForm = hasLogin && isAccountValidated && !hasPassword && !didForgetPassword && !isUnvalidatedSecondaryLogin; const shouldShowValidateCodeForm = hasAccount && (hasLogin || hasValidateCode) && !isUnvalidatedSecondaryLogin; - const shouldShowResendValidationForm = hasLogin && (!isAccountValidated || didForgetPassword) && !isUnvalidatedSecondaryLogin; - const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm || isUnvalidatedSecondaryLogin; - const shouldShowWelcomeText = shouldShowLoginForm || shouldShowPasswordForm || shouldShowValidateCodeForm; + const shouldShowWelcomeHeader = shouldShowLoginForm || shouldShowValidateCodeForm || isUnvalidatedSecondaryLogin; + const shouldShowWelcomeText = shouldShowLoginForm || shouldShowValidateCodeForm; return { shouldShowLoginForm, shouldShowUnlinkLoginForm: isUnvalidatedSecondaryLogin, - shouldShowPasswordForm, shouldShowValidateCodeForm, - shouldShowResendValidationForm, shouldShowWelcomeHeader, shouldShowWelcomeText, }; @@ -95,19 +85,15 @@ function SignInPage({credentials, account}) { const { shouldShowLoginForm, shouldShowUnlinkLoginForm, - shouldShowPasswordForm, shouldShowValidateCodeForm, - shouldShowResendValidationForm, shouldShowWelcomeHeader, shouldShowWelcomeText, } = getRenderOptions({ hasLogin: Boolean(credentials.login), - hasPassword: Boolean(credentials.password), hasValidateCode: Boolean(credentials.validateCode), hasAccount: !_.isEmpty(account), isPrimaryLogin: !account.primaryLogin || account.primaryLogin === credentials.login, isAccountValidated: Boolean(account.validated), - didForgetPassword: Boolean(account.forgotPassword), }); let welcomeHeader; @@ -134,9 +120,6 @@ function SignInPage({credentials, account}) { : translate('welcomeText.newFaceEnterMagicCode', {login: userLoginToDisplay}); } } - } else if (shouldShowPasswordForm) { - welcomeHeader = isSmallScreenWidth ? '' : translate('welcomeText.welcomeBack'); - welcomeText = isSmallScreenWidth ? `${translate('welcomeText.welcomeBack')} ${translate('welcomeText.enterPassword')}` : translate('welcomeText.enterPassword'); } else if (shouldShowUnlinkLoginForm) { welcomeHeader = isSmallScreenWidth ? translate('login.hero.header') : translate('welcomeText.welcomeBack'); } else if (!shouldShowResendValidationForm) { @@ -160,8 +143,7 @@ function SignInPage({credentials, account}) { isVisible={shouldShowLoginForm} blurOnSubmit={account.validated === false} /> - {shouldShowValidateCodeForm ? : } - {shouldShowResendValidationForm && } + {shouldShowValidateCodeForm && } {shouldShowUnlinkLoginForm && } From f43cc2e3f4dfc0d5ee5b9901dbdbf3621106b134 Mon Sep 17 00:00:00 2001 From: Nikki Wines Date: Fri, 7 Jul 2023 18:52:22 -0700 Subject: [PATCH 03/15] remove forms --- src/pages/signin/PasswordForm.js | 268 ----------------------- src/pages/signin/ResendValidationForm.js | 129 ----------- src/pages/signin/SignInPage.js | 10 +- 3 files changed, 4 insertions(+), 403 deletions(-) delete mode 100644 src/pages/signin/PasswordForm.js delete mode 100755 src/pages/signin/ResendValidationForm.js diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js deleted file mode 100644 index 36bf29462e21..000000000000 --- a/src/pages/signin/PasswordForm.js +++ /dev/null @@ -1,268 +0,0 @@ -import React, {useState, useEffect, useCallback, useRef} from 'react'; -import {View} from 'react-native'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import styles from '../../styles/styles'; -import Button from '../../components/Button'; -import Text from '../../components/Text'; -import themeColors from '../../styles/themes/default'; -import * as Session from '../../libs/actions/Session'; -import ONYXKEYS from '../../ONYXKEYS'; -import CONST from '../../CONST'; -import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink'; -import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import compose from '../../libs/compose'; -import TextInput from '../../components/TextInput'; -import * as ComponentUtils from '../../libs/ComponentUtils'; -import * as ValidationUtils from '../../libs/ValidationUtils'; -import withToggleVisibilityView, {toggleVisibilityViewPropTypes} from '../../components/withToggleVisibilityView'; -import canFocusInputOnScreenFocus from '../../libs/canFocusInputOnScreenFocus'; -import * as ErrorUtils from '../../libs/ErrorUtils'; -import {withNetwork} from '../../components/OnyxProvider'; -import networkPropTypes from '../../components/networkPropTypes'; -import FormHelpMessage from '../../components/FormHelpMessage'; -import Terms from './Terms'; -import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback'; - -const propTypes = { - /* Onyx Props */ - - /** The details about the account that the user is signing in with */ - account: PropTypes.shape({ - /** Whether or not two-factor authentication is required */ - requiresTwoFactorAuth: PropTypes.bool, - - /** Whether or not a sign on form is loading (being submitted) */ - isLoading: PropTypes.bool, - }), - - /** Indicates which locale the user currently has selected */ - preferredLocale: PropTypes.string, - - /** Information about the network */ - network: networkPropTypes.isRequired, - - ...withLocalizePropTypes, - ...toggleVisibilityViewPropTypes, -}; - -const defaultProps = { - account: {}, - preferredLocale: CONST.LOCALES.DEFAULT, -}; - -function PasswordForm(props) { - const [formError, setFormError] = useState({}); - const [password, setPassword] = useState(''); - const [twoFactorAuthCode, setTwoFactorAuthCode] = useState(''); - - const inputPasswordRef = useRef(null); - const input2FA = useRef(null); - - /** - * Handle text input and clear formError upon text change - * - * @param {String} text - * @param {String} key - */ - const onTextInput = (text, key) => { - if (key === 'password') { - setPassword(text); - } - if (key === 'twoFactorAuthCode') { - setTwoFactorAuthCode(text); - } - setFormError({[key]: ''}); - - if (props.account.errors) { - Session.clearAccountMessages(); - } - }; - - /** - * Clear Password from the state - */ - const clearPassword = () => { - setPassword(''); - inputPasswordRef.current.clear(); - }; - - /** - * Trigger the reset password flow and ensure the 2FA input field is reset to avoid it being permanently hidden - */ - const resetPassword = () => { - if (input2FA.current) { - setTwoFactorAuthCode(''); - input2FA.current.clear(); - } - setFormError({}); - Session.resetPassword(); - }; - - /** - * Clears local and Onyx sign in states - */ - const clearSignInData = () => { - setTwoFactorAuthCode(''); - setFormError({}); - Session.clearSignInData(); - }; - - /** - * Check that all the form fields are valid, then trigger the submit callback - */ - const validateAndSubmitForm = useCallback(() => { - const passwordTrimmed = password.trim(); - const twoFactorCodeTrimmed = twoFactorAuthCode.trim(); - const requiresTwoFactorAuth = props.account.requiresTwoFactorAuth; - - if (!passwordTrimmed) { - setFormError({password: 'passwordForm.pleaseFillPassword'}); - return; - } - - if (!ValidationUtils.isValidPassword(passwordTrimmed)) { - setFormError({password: 'passwordForm.error.incorrectPassword'}); - return; - } - - if (requiresTwoFactorAuth && !twoFactorCodeTrimmed) { - setFormError({twoFactorAuthCode: 'passwordForm.pleaseFillTwoFactorAuth'}); - return; - } - - if (requiresTwoFactorAuth && !ValidationUtils.isValidTwoFactorCode(twoFactorCodeTrimmed)) { - setFormError({twoFactorAuthCode: 'passwordForm.error.incorrect2fa'}); - return; - } - - setFormError({}); - - Session.signIn(passwordTrimmed, '', twoFactorCodeTrimmed, props.preferredLocale); - }, [password, twoFactorAuthCode, props.account.requiresTwoFactorAuth, props.preferredLocale]); - - useEffect(() => { - if (!canFocusInputOnScreenFocus() || !inputPasswordRef.current || !props.isVisible) { - return; - } - inputPasswordRef.current.focus(); - // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want this effect to run again - }, []); - - useEffect(() => { - if (props.isVisible) { - inputPasswordRef.current.focus(); - } - if (!props.isVisible) { - clearPassword(); - } - }, [props.isVisible]); - - useEffect(() => { - if (!props.account.requiresTwoFactorAuth) { - return; - } - input2FA.current.focus(); - }, [props.account.requiresTwoFactorAuth]); - - useEffect(() => { - if (twoFactorAuthCode.length !== CONST.TFA_CODE_LENGTH) { - return; - } - validateAndSubmitForm(); - }, [twoFactorAuthCode, validateAndSubmitForm]); - - const isTwoFactorAuthRequired = Boolean(props.account.requiresTwoFactorAuth); - const hasServerError = Boolean(props.account) && !_.isEmpty(props.account.errors); - - // When the 2FA required flag is set, user has already passed/completed the password field - const passwordFieldHasError = !isTwoFactorAuthRequired && hasServerError; - const twoFactorFieldHasError = isTwoFactorAuthRequired && hasServerError; - - return ( - <> - - onTextInput(text, 'password')} - onSubmitEditing={validateAndSubmitForm} - blurOnSubmit={false} - errorText={formError.password ? props.translate(formError.password) : ''} - hasError={passwordFieldHasError} - /> - - - {props.translate('passwordForm.forgot')} - - - - - {isTwoFactorAuthRequired && ( - - onTextInput(text, 'twoFactorAuthCode')} - onSubmitEditing={validateAndSubmitForm} - keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - blurOnSubmit={false} - maxLength={CONST.TFA_CODE_LENGTH} - errorText={formError.twoFactorAuthCode ? props.translate(formError.twoFactorAuthCode) : ''} - hasError={twoFactorFieldHasError} - /> - - )} - - {hasServerError && } - - -