Forgot Password

This commit is contained in:
Omar 2018-12-27 00:01:02 -08:00
parent 82b8e0699e
commit ef9210fab0
9 changed files with 233 additions and 25 deletions

12
App.js
View File

@ -1,9 +1,17 @@
import React from 'react';
import { View } from 'react-native';
import FlashMessage from 'react-native-flash-message';
import AppNavigator from './src/config/router';
export default class App extends React.Component {
render() {
return <AppNavigator />;
return (
<View style={{ flex: 1 }}>
<AppNavigator />
<FlashMessage position="top" />
</View>
);
}
};
}

View File

@ -3,7 +3,11 @@ const endpoints = {
login: {
method: 'POST',
url: `${baseurl}/auth/signin`
},
passwordReset: {
method: 'POST',
url: `${baseurl}/auth/passwordReset`
}
};
export default endpoints;
export default endpoints;

View File

@ -14,4 +14,4 @@ const errors = {
MISSING_BODY_ATTRIBUTES: 'request/missing-body-attributes'
};
export default errors;
export default errors;

View File

@ -1,12 +1,14 @@
import { createStackNavigator, createAppContainer } from 'react-navigation';
import WelcomeScreen from '../screens/boarding/WelcomeScreen';
import LoginScreen from '../screens/boarding/LoginScreen';
import WelcomeScreen from '../screens/onboaring/WelcomeScreen';
import LoginScreen from '../screens/auth/LoginScreen';
import ForgotPasswordScreen from '../screens/auth/ForgotPasswordScreen';
const StackNavigator = createStackNavigator({
welcome: WelcomeScreen,
login: LoginScreen
login: LoginScreen,
forgotPassword: ForgotPasswordScreen
});
const AppNavigator = createAppContainer(StackNavigator);
export default AppNavigator;
export default AppNavigator;

View File

@ -45,7 +45,7 @@
"education_educationSummary_placeholder": "Education Summary",
"education_fieldOfStudy_placeholder": "Field Of Study",
"education_school_placeholder": "College/University",
"email_labelText": "Email",
"email_labelText": "Email Address",
"email_or_tagferid_label": "EMAIL OR TAGFERID",
"email_or_tagferid_placeholder": "username@tagfer.com",
"email_placeholder": "Email Address",
@ -449,7 +449,7 @@
"title": "Fingerprint Settings"
},
"forgotPasswordScreen": {
"submitButton": "Request Reset Email",
"submitButton": "Request Reset Link",
"title": "Forgot Password"
},
"investment": {

View File

@ -0,0 +1,196 @@
import React from 'react';
import { Dimensions, Image, TouchableWithoutFeedback, Text, View, Keyboard, KeyboardAvoidingView, Platform } from 'react-native';
import { Button, FormInput } from 'react-native-elements';
import { showMessage } from 'react-native-flash-message';
import { FormLabel, Spacer } from '../../components/common';
import { fetchAuth } from '../../utils/fetch';
import { strings } from '../../locales/i18n';
import { getErrorDescription } from '../../utils/errorHandler';
import endpoints from '../../config/apiEndpoints';
import colors from '../../config/colors.json';
import logo from '../../../assets/logo-round.png';
export default class ForgotPasswordScreen extends React.Component {
static navigationOptions = {
header: null
}
constructor(props) {
super(props);
this.state = {
email: '',
loading: false
};
}
/**
* Send an API request and display error/sucess message
*/
onRequestResetPress() {
Keyboard.dismiss();
this.setState({ loading: true });
const body = { email: this.state.email };
console.log(body);
fetchAuth(endpoints.passwordReset, body).then(res => {
this.setState({ loading: false });
console.log(res);
if (res.error) {
this.showErrorMessage(res.error);
} else {
this.showSuccessMessage();
}
}).catch(error => {
this.setState({ loading: false });
this.showErrorMessage(error);
});
}
/**
* Simple regex to check if the input is an email.
*/
isNotEmail() {
const regex = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/;
return !regex.test(this.state.email);
}
/**
* Display a flash message at the top of the screen.
* @param {String} error one of the error codes in {@see config.error.js}
*/
showErrorMessage(error) {
showMessage({
message: 'Authentication Error',
description: getErrorDescription(error),
type: 'danger',
icon: 'auto',
duration: 4000
});
}
/**
* Displays a success message
*/
showSuccessMessage() {
showMessage({
message: 'Password reset link sent',
description: 'Please check your email.',
type: 'success',
icon: 'auto',
autoHide: false,
onPress: () => this.props.navigation.navigate('login')
});
}
renderContent() {
return (
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
<View style={{ flex: 1 }}>
{/* LOGO */}
<View style={styles.logoContainerStyle}>
<Image source={logo} />
</View>
{/* HEADER */}
<View>
<Text style={styles.headerStyle} >Forgot your password?</Text>
<Text style={styles.instructions}>Enter your email address below and we'll get you back on track</Text>
</View>
{/* TEXT INPUTS */}
<View style={{ flex: 3 }}>
<Spacer />
<FormLabel
required
labelText={strings('common.contactFields.email_labelText').toUpperCase()}
textStyle={styles.labelStyle}
/>
<FormInput
onChangeText={email => this.setState({ email })}
placeholder={strings('common.contactFields.email_or_tagferid_placeholder')}
autoCorrect={false}
autoCapitalize='none'
inputStyle={styles.inputTextStyle}
/>
</View>
{/* BUTTONS */}
<View>
<Text onPress={() => this.props.navigation.navigate('login')} style={styles.backButtonStyle} >
Back to Login
</Text>
<Button
onPress={this.onRequestResetPress.bind(this)}
title={strings('settings.forgotPasswordScreen.submitButton')}
buttonStyle={styles.buttonStyle}
disabled={this.isNotEmail()}
loading={this.state.loading}
fontSize={20}
/>
</View>
</View>
</TouchableWithoutFeedback>
);
}
render() {
if (Platform.OS === 'android') {
return this.renderContent();
}
return (
<KeyboardAvoidingView style={{ flex: 1 }} behavior="padding" >
{this.renderContent()}
</KeyboardAvoidingView>
);
}
}
const SCREEN_WIDTH = Dimensions.get('window').width;
const styles = {
logoContainerStyle: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
marginTop: 50,
marginBottom: 40
},
logoStyle: {
width: '100%',
height: '100%'
},
headerStyle: {
color: colors.headerBlue,
fontWeight: 'bold',
marginLeft: 20,
fontSize: 24
},
instructions: {
color: colors.grey,
fontSize: 18,
marginLeft: 20,
marginRight: 20
},
buttonStyle: {
width: SCREEN_WIDTH * 0.9,
marginTop: 15,
marginBottom: 30,
borderRadius: 5,
backgroundColor: colors.buttonBlue
},
backButtonStyle: {
marginLeft: 20,
fontSize: 18,
color: colors.grey
},
labelStyle: {
color: colors.labelBlue
},
inputTextStyle: {
color: colors.black
}
};

View File

@ -1,12 +1,12 @@
import React from 'react';
import { Image, KeyboardAvoidingView, Platform, Dimensions, View, Text, Keyboard, TouchableWithoutFeedback } from 'react-native';
import { Button, FormInput } from 'react-native-elements';
import FlashMessage, { showMessage } from 'react-native-flash-message';
import { showMessage } from 'react-native-flash-message';
import { FormLabel, Spacer, TextButton } from '../../components/common';
import { strings } from '../../locales/i18n';
import { fetchAuth } from '../../utils/fetch';
import { getErrorMessage } from '../../utils/errorHandler';
import { getErrorDescription } from '../../utils/errorHandler';
import endpoints from '../../config/apiEndpoints';
import colors from '../../config/colors.json';
@ -31,19 +31,20 @@ export default class LoginScreen extends React.Component {
* and displays the error if needed.
*/
onLoginPress() {
Keyboard.dismiss();
this.setState({ loading: true });
const body = this.getLoginRequestBody();
fetchAuth(endpoints.login, body).then(res => {
if (res.error) {
this.setState({ loading: false });
this.setState({ loading: false, password: '' });
this.showErrorMessage(res.error);
} else {
this.setState({ loading: false });
console.log(res.sessionId);
}
}).catch(error => {
this.setState({ loading: false });
this.setState({ loading: false, password: '' });
this.showErrorMessage(error);
});
}
@ -75,9 +76,10 @@ export default class LoginScreen extends React.Component {
showErrorMessage(error) {
showMessage({
message: 'Authentication Error',
description: getErrorMessage(error),
description: getErrorDescription(error),
type: 'danger',
icon: 'auto'
icon: 'auto',
duration: 3000
});
}
@ -118,6 +120,7 @@ export default class LoginScreen extends React.Component {
/>
<FormInput
secureTextEntry
value={this.state.password}
onChangeText={password => this.setState({ password })}
placeholder={strings('userLoginScreen.password_placeholder')}
autoCorrect={false}
@ -152,8 +155,6 @@ export default class LoginScreen extends React.Component {
disabled={this.isButtonDiabled()}
fontSize={20}
/>
<FlashMessage position="top" />
</View>
</TouchableWithoutFeedback>
);
@ -165,10 +166,7 @@ export default class LoginScreen extends React.Component {
}
return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior="padding"
>
<KeyboardAvoidingView style={{ flex: 1 }} behavior="padding" >
{this.renderContent()}
</KeyboardAvoidingView>
);

View File

@ -1,10 +1,10 @@
import errors from '../config/errors';
export function getErrorMessage(error) {
export function getErrorDescription(error) {
switch (error) {
case errors.AUTH_INVALID_EMAIL: return 'Invalid email format used.';
case errors.AUTH_INVALID_PHONE_NUMBER: return 'Invalid phone number format is used.';
case errors.AUTH_USER_NOT_FOUND: return 'Identifier used does not exist.';
case errors.AUTH_USER_NOT_FOUND: return 'User is not recognized.';
case errors.AUTH_WRONG_PASSWORD: return 'Wrong password.';
case errors.AUTH_UID_ALREADY_EXISTS: return 'TagferID already exists.';
case errors.AUTH_EMAIL_ALREADY_EXISTS: return 'Email already exists.';
@ -17,4 +17,4 @@ export function getErrorMessage(error) {
case errors.MISSING_BODY_ATTRIBUTES: return 'Invalid request. Please try again.';
default: return 'Oops, an error occured! Please try again.';
}
}
}