Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

show confirmation screen on password change #8493

Merged
merged 12 commits into from
Apr 29, 2022
5 changes: 5 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ export default {
newPassword: 'Your password must have at least 8 characters, 1 capital letter, 1 lowercase letter, and 1 number.',
},
},
passwordConfirmationScreen: {
passwordUpdated: 'Password updated!',
allSet: 'You’re all set. Keep your new password safe.',
gotIt: 'Got it',
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Enter your username to get paid back via PayPal.',
payPalMe: 'PayPal.me/',
Expand Down
5 changes: 5 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ export default {
newPassword: 'Su contraseña debe tener al menos 8 caracteres, 1 letra mayúscula, 1 letra minúscula y 1 número.',
},
},
passwordConfirmationScreen: {
passwordUpdated: 'Contraseña actualizada!',
allSet: 'Todo está listo. Guarda tu contraseña en un lugar seguro.',
gotIt: 'Ok, entendido',
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Escribe tu nombre de usuario para que otros puedan pagarte a través de PayPal.',
payPalMe: 'PayPal.me/',
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ function changePasswordAndNavigate(oldPassword, password) {
return;
}

Navigation.goBack();
const success = lodashGet(response, 'message', 'Password changed successfully.');
Onyx.merge(ONYXKEYS.ACCOUNT, {success});
})
.finally(() => {
Onyx.merge(ONYXKEYS.ACCOUNT, {loading: false});
Expand Down
50 changes: 50 additions & 0 deletions src/pages/settings/PasswordConfirmationScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import {Image, View} from 'react-native';
import Text from '../../components/Text';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import styles from '../../styles/styles';
import confettiPop from '../../../assets/images/confetti-pop.gif';
import Button from '../../components/Button';
import FixedFooter from '../../components/FixedFooter';
import Navigation from '../../libs/Navigation/Navigation';

const propTypes = {
...withLocalizePropTypes,
};

const PasswordConfirmationScreen = props => (
<>
<View style={[styles.screenCenteredContainer, styles.alignItemsCenter]}>
<Image
source={confettiPop}
style={styles.confettiIcon}
/>
<Text
style={[
styles.textStrong,
styles.textLarge,
styles.mb2,
]}
>
{props.translate('passwordConfirmationScreen.passwordUpdated')}
</Text>
<Text style={styles.textAlignCenter}>
{props.translate('passwordConfirmationScreen.allSet')}
</Text>
</View>
<FixedFooter>
<Button
success
text={props.translate('passwordConfirmationScreen.gotIt')}
style={styles.mt6}
pressOnEnter
onPress={() => Navigation.goBack()}
/>
</FixedFooter>
</>
);

PasswordConfirmationScreen.propTypes = propTypes;
PasswordConfirmationScreen.displayName = 'PasswordConfirmationScreen';

export default withLocalize(PasswordConfirmationScreen);
141 changes: 72 additions & 69 deletions src/pages/settings/PasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import {View, ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import _ from 'underscore';

import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import Navigation from '../../libs/Navigation/Navigation';
import ROUTES from '../../ROUTES';
import ScreenWrapper from '../../components/ScreenWrapper';
import Text from '../../components/Text';
import styles from '../../styles/styles';
Expand All @@ -20,6 +18,7 @@ import KeyboardAvoidingView from '../../components/KeyboardAvoidingView';
import FixedFooter from '../../components/FixedFooter';
import TextInput from '../../components/TextInput';
import * as Session from '../../libs/actions/Session';
import PasswordConfirmationScreen from './PasswordConfirmationScreen';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -152,77 +151,81 @@ class PasswordPage extends Component {
<HeaderWithCloseButton
title={this.props.translate('passwordPage.changePassword')}
shouldShowBackButton
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_SECURITY)}
onBackButtonPress={() => Navigation.goBack()}
onCloseButtonPress={() => Navigation.dismissModal(true)}
/>
<ScrollView
style={styles.flex1}
contentContainerStyle={styles.p5}

// Allow the user to click show password while password input is focused.
// eslint-disable-next-line react/jsx-props-no-multi-spaces
keyboardShouldPersistTaps="always"
>
<Text style={[styles.mb6]}>
{this.props.translate('passwordPage.changingYourPasswordPrompt')}
</Text>
<View style={styles.mb6}>
<TextInput
label={`${this.props.translate('passwordPage.currentPassword')}*`}
ref={el => this.currentPasswordInputRef = el}
secureTextEntry
autoCompleteType="password"
textContentType="password"
value={this.state.currentPassword}
onChangeText={text => this.clearErrorAndSetValue('currentPassword', text)}
returnKeyType="done"
hasError={this.state.errors.currentPassword}
errorText={this.getErrorText('currentPassword')}
onSubmitEditing={this.submit}
/>
</View>
<View style={styles.mb6}>
<TextInput
label={`${this.props.translate('passwordPage.newPassword')}*`}
secureTextEntry
autoCompleteType="password"
textContentType="password"
value={this.state.newPassword}
hasError={this.state.errors.newPassword || this.state.errors.newPasswordSameAsOld}
errorText={this.state.errors.newPasswordSameAsOld
? this.getErrorText('newPasswordSameAsOld')
: this.getErrorText('newPassword')}
onChangeText={text => this.clearErrorAndSetValue('newPassword', text, ['newPasswordSameAsOld'])}
onSubmitEditing={this.submit}
/>
{

shouldShowNewPasswordPrompt && (
<Text
style={[
styles.textLabelSupporting,
styles.mt1,
]}
{!_.isEmpty(this.props.account.success)
? (
<PasswordConfirmationScreen />
) : (
<>
<ScrollView
style={styles.flex1}
contentContainerStyle={styles.p5}

// Allow the user to click show password while password input is focused.
// eslint-disable-next-line react/jsx-props-no-multi-spaces
keyboardShouldPersistTaps="always"
>
{this.props.translate('passwordPage.newPasswordPrompt')}
</Text>
)
}
</View>
{_.every(this.state.errors, error => !error) && !_.isEmpty(this.props.account.error) && (
<Text style={styles.formError}>
{this.props.account.error}
</Text>
<Text style={[styles.mb6]}>
{this.props.translate('passwordPage.changingYourPasswordPrompt')}
</Text>
<View style={styles.mb6}>
<TextInput
label={`${this.props.translate('passwordPage.currentPassword')}*`}
ref={el => this.currentPasswordInputRef = el}
secureTextEntry
autoCompleteType="password"
textContentType="password"
value={this.state.currentPassword}
onChangeText={text => this.clearErrorAndSetValue('currentPassword', text)}
returnKeyType="done"
hasError={this.state.errors.currentPassword}
errorText={this.getErrorText('currentPassword')}
onSubmitEditing={this.submit}
/>
</View>
<View style={styles.mb6}>
<TextInput
label={`${this.props.translate('passwordPage.newPassword')}*`}
secureTextEntry
autoCompleteType="password"
textContentType="password"
value={this.state.newPassword}
hasError={this.state.errors.newPassword || this.state.errors.newPasswordSameAsOld}
errorText={this.state.errors.newPasswordSameAsOld
? this.getErrorText('newPasswordSameAsOld')
: this.getErrorText('newPassword')}
onChangeText={text => this.clearErrorAndSetValue('newPassword', text, ['newPasswordSameAsOld'])}
onSubmitEditing={this.submit}
/>
{shouldShowNewPasswordPrompt && (
<Text
style={[
styles.textLabelSupporting,
styles.mt1,
]}
>
{this.props.translate('passwordPage.newPasswordPrompt')}
</Text>
)}
</View>
{_.every(this.state.errors, error => !error) && !_.isEmpty(this.props.account.error) && (
<Text style={styles.formError}>
{this.props.account.error}
</Text>
)}
</ScrollView>
<FixedFooter style={[styles.flexGrow0]}>
<Button
success
isLoading={this.props.account.loading}
text={this.props.translate('common.save')}
onPress={this.submit}
/>
</FixedFooter>
</>
)}
</ScrollView>
<FixedFooter style={[styles.flexGrow0]}>
<Button
success
isLoading={this.props.account.loading}
text={this.props.translate('common.save')}
onPress={this.submit}
/>
</FixedFooter>
</KeyboardAvoidingView>
</ScreenWrapper>
);
Expand Down
7 changes: 7 additions & 0 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -2512,6 +2512,13 @@ const styles = {
userSelectText: {
userSelect: 'text',
},

screenCenteredContainer: {
flex: 1,
justifyContent: 'center',
marginBottom: 40,
padding: 16,
},
};

export default styles;