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
8 changes: 8 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ export default {
newPassword: 'Your password must have at least 8 characters, 1 capital letter, 1 lowercase letter, and 1 number.',
},
},
confirmationScreen: {
passwordUpdated: 'Password updated!',
allSet: 'You’re all set, keep your new password safe.',
set2FAPartOne: 'Set up',
set2FAPartTwo: 'two-factor authentication',
set2FAPartThree: 'for additional account security.',
gotIt: 'Got it',
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Enter your username to get paid back via PayPal.',
payPalMe: 'PayPal.me/',
Expand Down
8 changes: 8 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,14 @@ export default {
newPassword: 'Su contraseña debe tener al menos 8 caracteres, 1 letra mayúscula, 1 letra minúscula y 1 número.',
},
},
confirmationScreen: {
passwordUpdated: 'Contraseña actualizada!',
allSet: 'Todo está listo, guarda tu contraseña en un lugar seguro.',
set2FAPartOne: 'Configura',
set2FAPartTwo: 'autenticación de dos factores',
set2FAPartThree: 'para obtener seguridad adicional.',
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
94 changes: 94 additions & 0 deletions src/pages/settings/ConfirmationScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import {Image, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
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 * as Link from '../../libs/actions/Link';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import Navigation from '../../libs/Navigation/Navigation';

const propTypes = {
/* Onyx Props */

/** Holds information about the users account that is logging in */
account: PropTypes.shape({
/** Whether or not two factor authentication is enabled */
requiresTwoFactorAuth: PropTypes.bool,
}),

...withLocalizePropTypes,
};

const defaultProps = {
account: {},
};

const ConfirmationScreen = props => (
<>
<View style={[styles.flex1, styles.p5, styles.justifyContentCenter]}>
<View style={[styles.alignItemsCenter, styles.mb10]}>
<Image
source={confettiPop}
style={styles.confettiIcon}
/>
<Text
style={[
styles.textStrong,
styles.textLarge,
styles.mb2,
]}
>
{props.translate('confirmationScreen.passwordUpdated')}
</Text>
<Text style={styles.textAlignCenter}>
<Text style={styles.textAlignCenter}>
{props.translate('confirmationScreen.allSet')}
</Text>
{!props.requiresTwoFactorAuth && (
<>
<Text>
{' '}
{props.translate('confirmationScreen.set2FAPartOne')}
</Text>
<Text
style={styles.link}
onPress={() => Link.openExternalLink('')}
>
{' '}
{props.translate('confirmationScreen.set2FAPartTwo')}
{' '}
</Text>
<Text>{props.translate('confirmationScreen.set2FAPartThree')}</Text>
</>
)}
</Text>
</View>
</View>
<FixedFooter>
<Button
success
text={props.translate('confirmationScreen.gotIt')}
style={styles.mt6}
pressOnEnter
onPress={() => Navigation.goBack()}
/>
</FixedFooter>
</>
);

ConfirmationScreen.propTypes = propTypes;
ConfirmationScreen.defaultProps = defaultProps;
ConfirmationScreen.displayName = 'ConfirmationScreen';

export default compose(
withLocalize,
withOnyx({
account: {key: ONYXKEYS.ACCOUNT},
}),
)(ConfirmationScreen);
140 changes: 72 additions & 68 deletions src/pages/settings/PasswordPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ 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 +19,7 @@ import KeyboardAvoidingView from '../../components/KeyboardAvoidingView';
import FixedFooter from '../../components/FixedFooter';
import TextInput from '../../components/TextInput';
import * as Session from '../../libs/actions/Session';
import ConfirmationScreen from './ConfirmationScreen';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -152,77 +152,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)
? (
<ConfirmationScreen />
) : (
<>
<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
4 changes: 4 additions & 0 deletions src/styles/utilities/spacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ export default {
marginBottom: 32,
},

mb10: {
marginBottom: 40,
},

mbn1: {
marginBottom: -4,
},
Expand Down