Skip to content

Commit

Permalink
Merge pull request #3190 from anthony-hull/setPassword
Browse files Browse the repository at this point in the history
Set password
  • Loading branch information
thienlnam authored Jun 12, 2021
2 parents c5e6da2 + 66cbd4b commit 05aedfe
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,10 @@ export default {
setPasswordPage: {
passwordCannotBeBlank: 'Password cannot be blank',
enterPassword: 'Enter a password',
confirmNewPassword: 'Confirm the password',
setPassword: 'Set Password',
passwordsDontMatch: 'Passwords must match',
newPasswordPrompt: 'Your password must have at least 8 characters,\n1 capital letter, 1 lowercase letter, 1 number.',
},
bankAccount: {
accountNumber: 'Account Number',
Expand Down
38 changes: 7 additions & 31 deletions src/pages/SetPasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, {Component} from 'react';
import {
SafeAreaView,
Text,
TextInput,
View,
} from 'react-native';
import PropTypes from 'prop-types';
Expand All @@ -14,11 +13,10 @@ import styles from '../styles/styles';
import {setPassword} from '../libs/actions/Session';
import ONYXKEYS from '../ONYXKEYS';
import Button from '../components/Button';
import themeColors from '../styles/themes/default';
import SignInPageLayout from './signin/SignInPageLayout';
import canFocusInputOnScreenFocus from '../libs/canFocusInputOnScreenFocus';
import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
import compose from '../libs/compose';
import NewPasswordForm from './settings/NewPasswordForm';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -63,24 +61,17 @@ class SetPasswordPage extends Component {

this.state = {
password: '',
formError: null,
isFormValid: false,
};
}

/**
* Validate the form and then submit it
*/
validateAndSubmitForm() {
if (!this.state.password.trim()) {
this.setState({
formError: this.props.translate('setPasswordPage.passwordCannotBeBlank'),
});
if (!this.state.isFormValid) {
return;
}

this.setState({
formError: null,
});
setPassword(
this.state.password,
lodashGet(this.props.route, 'params.validateCode', ''),
Expand All @@ -93,20 +84,11 @@ class SetPasswordPage extends Component {
<SafeAreaView style={[styles.signInPage]}>
<SignInPageLayout>
<View style={[styles.mb4]}>
<Text style={[styles.formLabel]}>
{this.props.translate('setPasswordPage.enterPassword')}
</Text>
<TextInput
style={[styles.textInput]}
value={this.state.password}
secureTextEntry
autoCompleteType="password"
textContentType="password"
onChangeText={text => this.setState({password: text})}
<NewPasswordForm
password={this.state.password}
updatePassword={password => this.setState({password})}
updateIsFormValid={isValid => this.setState({isFormValid: isValid})}
onSubmitEditing={this.validateAndSubmitForm}
autoCapitalize="none"
placeholderTextColor={themeColors.placeholderText}
autoFocus={canFocusInputOnScreenFocus()}
/>
</View>
<View>
Expand All @@ -119,12 +101,6 @@ class SetPasswordPage extends Component {
/>
</View>

{this.state.formError && (
<Text style={[styles.formError]}>
{this.state.formError}
</Text>
)}

{!_.isEmpty(this.props.account.error) && (
<Text style={[styles.formError]}>
{this.props.account.error}
Expand Down
138 changes: 138 additions & 0 deletions src/pages/settings/NewPasswordForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React from 'react';
import PropTypes from 'prop-types';
import {TextInput, View} from 'react-native';
import Text from '../../components/Text';
import withLocalize, {
withLocalizePropTypes,
} from '../../components/withLocalize';
import CONST from '../../CONST';
import styles from '../../styles/styles';

const propTypes = {
/** String to control the first password box in the form */
password: PropTypes.string.isRequired,

/** Function to update the first password box in the form */
updatePassword: PropTypes.func.isRequired,

/** Callback function called with boolean value for if the password form is valid */
updateIsFormValid: PropTypes.func.isRequired,

/** Callback function for when form is submitted */
onSubmitEditing: PropTypes.func.isRequired,
...withLocalizePropTypes,
};

class NewPasswordForm extends React.Component {
constructor(props) {
super(props);

this.state = {
confirmNewPassword: '',
passwordHintError: false,
shouldShowPasswordConfirmError: false,
};
}

componentDidUpdate(prevProps, prevState) {
const eitherPasswordChanged = (this.props.password !== prevProps.password)
|| this.state.confirmNewPassword !== prevState.confirmNewPassword;
if (eitherPasswordChanged) {
this.props.updateIsFormValid(this.isValidForm());
}
}

onBlurNewPassword() {
if (this.state.passwordHintError) {
return;
}
if (this.props.password && !this.isValidPassword()) {
this.setState({passwordHintError: true});
}
}

onBlurConfirmPassword() {
if (this.state.shouldShowPasswordConfirmError) {
return;
}
if (this.state.confirmNewPassword && !this.doPasswordsMatch()) {
this.setState({shouldShowPasswordConfirmError: true});
}
}

isValidPassword() {
return this.props.password.match(CONST.PASSWORD_COMPLEXITY_REGEX_STRING);
}

doPasswordsMatch() {
return this.props.password === this.state.confirmNewPassword;
}

isValidForm() {
return this.isValidPassword() && this.doPasswordsMatch();
}

showPasswordMatchError() {
return (
!this.doPasswordsMatch()
&& this.state.shouldShowPasswordConfirmError
&& this.state.confirmNewPassword
);
}

render() {
let passwordHintStyle;
if (this.state.passwordHintError && this.props.password && !this.isValidPassword()) {
passwordHintStyle = styles.formError;
}
if (this.isValidPassword()) {
passwordHintStyle = styles.formSuccess;
}

return (
<>
<View style={styles.mb6}>
<Text style={[styles.mb1, styles.formLabel]}>
{`${this.props.translate('setPasswordPage.enterPassword')}`}
</Text>
<TextInput
secureTextEntry
autoCompleteType="password"
textContentType="password"
style={styles.textInput}
value={this.state.password}
onChangeText={password => this.props.updatePassword(password)}
onBlur={() => this.onBlurNewPassword()}
/>
<Text style={[styles.formHint, styles.mt1, passwordHintStyle]}>
{this.props.translate('setPasswordPage.newPasswordPrompt')}
</Text>
</View>
<View style={styles.mb6}>
<Text style={[styles.mb1, styles.formLabel]}>
{`${this.props.translate('setPasswordPage.confirmNewPassword')}*`}
</Text>
<TextInput
secureTextEntry
autoCompleteType="password"
textContentType="password"
style={styles.textInput}
value={this.state.confirmNewPassword}
onChangeText={confirmNewPassword => this.setState({confirmNewPassword})}
onSubmitEditing={() => this.props.onSubmitEditing()}
onBlur={() => this.onBlurConfirmPassword()}
/>
{this.showPasswordMatchError() && (
<Text style={[styles.formError, styles.mt1]}>
{this.props.translate('setPasswordPage.passwordsDontMatch')}
</Text>
)}
</View>
</>
);
}
}

NewPasswordForm.propTypes = propTypes;

export default withLocalize(NewPasswordForm);

0 comments on commit 05aedfe

Please sign in to comment.