diff --git a/src/pages/signin/PasswordForm.js b/src/pages/signin/PasswordForm.js
old mode 100755
new mode 100644
index db528560859d..48e9493be4a3
--- a/src/pages/signin/PasswordForm.js
+++ b/src/pages/signin/PasswordForm.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState, useEffect, useCallback, useRef} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
@@ -52,41 +52,13 @@ const defaultProps = {
preferredLocale: CONST.LOCALES.DEFAULT,
};
-class PasswordForm extends React.Component {
- constructor(props) {
- super(props);
- this.validateAndSubmitForm = this.validateAndSubmitForm.bind(this);
- this.resetPassword = this.resetPassword.bind(this);
- this.clearSignInData = this.clearSignInData.bind(this);
-
- this.state = {
- formError: {},
- password: '',
- twoFactorAuthCode: '',
- };
- }
-
- componentDidMount() {
- if (!canFocusInputOnScreenFocus() || !this.inputPassword || !this.props.isVisible) {
- return;
- }
- this.inputPassword.focus();
- }
+function PasswordForm(props) {
+ const [formError, setFormError] = useState({});
+ const [password, setPassword] = useState('');
+ const [twoFactorAuthCode, setTwoFactorAuthCode] = useState('');
- componentDidUpdate(prevProps, prevState) {
- if (!prevProps.isVisible && this.props.isVisible) {
- this.inputPassword.focus();
- }
- if (prevProps.isVisible && !this.props.isVisible && this.state.password) {
- this.clearPassword();
- }
- if (!prevProps.account.requiresTwoFactorAuth && this.props.account.requiresTwoFactorAuth) {
- this.input2FA.focus();
- }
- if (prevState.twoFactorAuthCode !== this.state.twoFactorAuthCode && this.state.twoFactorAuthCode.length === CONST.TFA_CODE_LENGTH) {
- this.validateAndSubmitForm();
- }
- }
+ const inputPasswordRef = useRef(null);
+ const input2FA = useRef(null);
/**
* Handle text input and clear formError upon text change
@@ -94,160 +66,196 @@ class PasswordForm extends React.Component {
* @param {String} text
* @param {String} key
*/
- onTextInput(text, key) {
- this.setState({
- [key]: text,
- formError: {[key]: ''},
- });
+ const onTextInput = (text, key) => {
+ if (key === 'password') {
+ setPassword(text);
+ }
+ if (key === 'twoFactorAuthCode') {
+ setTwoFactorAuthCode(text);
+ }
+ setFormError({[key]: ''});
- if (this.props.account.errors) {
+ if (props.account.errors) {
Session.clearAccountMessages();
}
- }
+ };
/**
* Clear Password from the state
*/
- clearPassword() {
- this.setState({password: ''}, this.inputPassword.clear);
- }
+ 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
*/
- resetPassword() {
- if (this.input2FA) {
- this.setState({twoFactorAuthCode: ''}, this.input2FA.clear);
+ const resetPassword = () => {
+ if (input2FA.current) {
+ setTwoFactorAuthCode('');
+ input2FA.current.clear();
}
- this.setState({formError: {}});
+ setFormError({});
Session.resetPassword();
- }
+ };
/**
* Clears local and Onyx sign in states
*/
- clearSignInData() {
- this.setState({twoFactorAuthCode: '', formError: {}});
+ const clearSignInData = () => {
+ setTwoFactorAuthCode('');
+ setFormError({});
Session.clearSignInData();
- }
+ };
/**
* Check that all the form fields are valid, then trigger the submit callback
*/
- validateAndSubmitForm() {
- const password = this.state.password.trim();
- const twoFactorCode = this.state.twoFactorAuthCode.trim();
- const requiresTwoFactorAuth = this.props.account.requiresTwoFactorAuth;
+ 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 (!password) {
- this.setState({formError: {password: 'passwordForm.pleaseFillPassword'}});
+ if (requiresTwoFactorAuth && !twoFactorCodeTrimmed) {
+ setFormError({twoFactorAuthCode: 'passwordForm.pleaseFillTwoFactorAuth'});
return;
}
- if (!ValidationUtils.isValidPassword(password)) {
- this.setState({formError: {password: 'passwordForm.error.incorrectPassword'}});
+ if (requiresTwoFactorAuth && !ValidationUtils.isValidTwoFactorCode(twoFactorCodeTrimmed)) {
+ setFormError({twoFactorAuthCode: 'passwordForm.error.incorrect2fa'});
return;
}
- if (requiresTwoFactorAuth && !twoFactorCode) {
- this.setState({formError: {twoFactorAuthCode: 'passwordForm.pleaseFillTwoFactorAuth'}});
+ 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]);
- if (requiresTwoFactorAuth && !ValidationUtils.isValidTwoFactorCode(twoFactorCode)) {
- this.setState({formError: {twoFactorAuthCode: 'passwordForm.error.incorrect2fa'}});
+ useEffect(() => {
+ if (twoFactorAuthCode.length !== CONST.TFA_CODE_LENGTH) {
return;
}
+ validateAndSubmitForm();
+ }, [twoFactorAuthCode, validateAndSubmitForm]);
- this.setState({
- formError: {},
- });
+ const isTwoFactorAuthRequired = Boolean(props.account.requiresTwoFactorAuth);
+ const hasServerError = Boolean(props.account) && !_.isEmpty(props.account.errors);
- Session.signIn(password, '', twoFactorCode, this.props.preferredLocale);
- }
+ // When the 2FA required flag is set, user has already passed/completed the password field
+ const passwordFieldHasError = !isTwoFactorAuthRequired && hasServerError;
+ const twoFactorFieldHasError = isTwoFactorAuthRequired && hasServerError;
- render() {
- const isTwoFactorAuthRequired = Boolean(this.props.account.requiresTwoFactorAuth);
- const hasServerError = Boolean(this.props.account) && !_.isEmpty(this.props.account.errors);
+ return (
+ <>
+
+ onTextInput(text, 'password')}
+ onSubmitEditing={validateAndSubmitForm}
+ blurOnSubmit={false}
+ errorText={formError.password ? props.translate(formError.password) : ''}
+ hasError={passwordFieldHasError}
+ />
+
+
+ {props.translate('passwordForm.forgot')}
+
+
+
- // When the 2FA required flag is set, user has already passed/completed the password field
- const passwordFieldHasError = !isTwoFactorAuthRequired && hasServerError;
- const twoFactorFieldHasError = isTwoFactorAuthRequired && hasServerError;
- return (
- <>
+ {isTwoFactorAuthRequired && (
(this.inputPassword = el)}
- label={this.props.translate('common.password')}
- secureTextEntry
- autoCompleteType={ComponentUtils.PASSWORD_AUTOCOMPLETE_TYPE}
- textContentType="password"
- nativeID="password"
- name="password"
- value={this.state.password}
- onChangeText={(text) => this.onTextInput(text, 'password')}
- onSubmitEditing={this.validateAndSubmitForm}
+ ref={input2FA}
+ label={props.translate('common.twoFactorCode')}
+ value={twoFactorAuthCode}
+ placeholder={props.translate('passwordForm.requiredWhen2FAEnabled')}
+ placeholderTextColor={themeColors.placeholderText}
+ onChangeText={(text) => onTextInput(text, 'twoFactorAuthCode')}
+ onSubmitEditing={validateAndSubmitForm}
+ keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
blurOnSubmit={false}
- errorText={this.state.formError.password ? this.props.translate(this.state.formError.password) : ''}
- hasError={passwordFieldHasError}
+ maxLength={CONST.TFA_CODE_LENGTH}
+ errorText={formError.twoFactorAuthCode ? props.translate(formError.twoFactorAuthCode) : ''}
+ hasError={twoFactorFieldHasError}
/>
-
-
- {this.props.translate('passwordForm.forgot')}
-
-
+ )}
- {isTwoFactorAuthRequired && (
-
- (this.input2FA = el)}
- label={this.props.translate('common.twoFactorCode')}
- value={this.state.twoFactorAuthCode}
- placeholder={this.props.translate('passwordForm.requiredWhen2FAEnabled')}
- placeholderTextColor={themeColors.placeholderText}
- onChangeText={(text) => this.onTextInput(text, 'twoFactorAuthCode')}
- onSubmitEditing={this.validateAndSubmitForm}
- keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD}
- blurOnSubmit={false}
- maxLength={CONST.TFA_CODE_LENGTH}
- errorText={this.state.formError.twoFactorAuthCode ? this.props.translate(this.state.formError.twoFactorAuthCode) : ''}
- hasError={twoFactorFieldHasError}
- />
-
- )}
-
- {hasServerError && }
-
-
-
-
-
-
-
- >
- );
- }
+ {hasServerError && }
+
+
+
+
+
+
+
+
+
+ >
+ );
}
PasswordForm.propTypes = propTypes;
PasswordForm.defaultProps = defaultProps;
+PasswordForm.displayName = 'PasswordForm';
export default compose(
withLocalize,