From ef9210fab07b544cdb6e4aba7de3dd26647892d5 Mon Sep 17 00:00:00 2001 From: Omar Date: Thu, 27 Dec 2018 00:01:02 -0800 Subject: [PATCH] Forgot Password --- App.js | 12 +- src/config/apiEndpoints.js | 6 +- src/config/errors.js | 2 +- src/config/router.js | 10 +- src/locales/translations/en.json | 4 +- src/screens/auth/ForgotPasswordScreen.js | 196 ++++++++++++++++++ src/screens/{boarding => auth}/LoginScreen.js | 22 +- .../{boarding => onboaring}/WelcomeScreen.js | 0 src/utils/errorHandler.js | 6 +- 9 files changed, 233 insertions(+), 25 deletions(-) create mode 100644 src/screens/auth/ForgotPasswordScreen.js rename src/screens/{boarding => auth}/LoginScreen.js (92%) rename src/screens/{boarding => onboaring}/WelcomeScreen.js (100%) diff --git a/App.js b/App.js index 9c36aa0..f183f49 100644 --- a/App.js +++ b/App.js @@ -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 ; + return ( + + + + + ); } -}; +} + diff --git a/src/config/apiEndpoints.js b/src/config/apiEndpoints.js index 452c751..4812389 100644 --- a/src/config/apiEndpoints.js +++ b/src/config/apiEndpoints.js @@ -3,7 +3,11 @@ const endpoints = { login: { method: 'POST', url: `${baseurl}/auth/signin` + }, + passwordReset: { + method: 'POST', + url: `${baseurl}/auth/passwordReset` } }; -export default endpoints; \ No newline at end of file +export default endpoints; diff --git a/src/config/errors.js b/src/config/errors.js index e93cf13..fd32e0c 100644 --- a/src/config/errors.js +++ b/src/config/errors.js @@ -14,4 +14,4 @@ const errors = { MISSING_BODY_ATTRIBUTES: 'request/missing-body-attributes' }; -export default errors; \ No newline at end of file +export default errors; diff --git a/src/config/router.js b/src/config/router.js index 509d507..de1685f 100644 --- a/src/config/router.js +++ b/src/config/router.js @@ -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; \ No newline at end of file +export default AppNavigator; diff --git a/src/locales/translations/en.json b/src/locales/translations/en.json index 3a9b6af..9f09039 100644 --- a/src/locales/translations/en.json +++ b/src/locales/translations/en.json @@ -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": { diff --git a/src/screens/auth/ForgotPasswordScreen.js b/src/screens/auth/ForgotPasswordScreen.js new file mode 100644 index 0000000..fa0174c --- /dev/null +++ b/src/screens/auth/ForgotPasswordScreen.js @@ -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 ( + + + + {/* LOGO */} + + + + + {/* HEADER */} + + Forgot your password? + Enter your email address below and we'll get you back on track + + + {/* TEXT INPUTS */} + + + + this.setState({ email })} + placeholder={strings('common.contactFields.email_or_tagferid_placeholder')} + autoCorrect={false} + autoCapitalize='none' + inputStyle={styles.inputTextStyle} + /> + + + {/* BUTTONS */} + + this.props.navigation.navigate('login')} style={styles.backButtonStyle} > + Back to Login + + +