From b55af52e944eed55a3cec6ca9116a2269c4e5824 Mon Sep 17 00:00:00 2001 From: Omar Date: Thu, 27 Dec 2018 20:18:25 -0800 Subject: [PATCH] Signup Screen One --- src/config/apiEndpoints.js | 4 + src/config/router.js | 4 +- src/locales/translations/en.json | 5 +- src/screens/auth/ForgotPasswordScreen.js | 33 +-- src/screens/auth/LoginScreen.js | 23 +-- src/screens/auth/SignScreenOne.js | 245 +++++++++++++++++++++++ src/utils/aux.js | 8 + src/utils/errorHandler.js | 15 ++ src/utils/fetch.js | 2 +- 9 files changed, 288 insertions(+), 51 deletions(-) create mode 100644 src/screens/auth/SignScreenOne.js create mode 100644 src/utils/aux.js diff --git a/src/config/apiEndpoints.js b/src/config/apiEndpoints.js index 4812389..2d466f5 100644 --- a/src/config/apiEndpoints.js +++ b/src/config/apiEndpoints.js @@ -7,6 +7,10 @@ const endpoints = { passwordReset: { method: 'POST', url: `${baseurl}/auth/passwordReset` + }, + emailExists: { + method: 'GET', + url: `${baseurl}/auth/email/:email/exists` } }; diff --git a/src/config/router.js b/src/config/router.js index de1685f..2f14166 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/onboaring/WelcomeScreen'; import LoginScreen from '../screens/auth/LoginScreen'; +import SignupScreenOne from '../screens/auth/SignScreenOne'; import ForgotPasswordScreen from '../screens/auth/ForgotPasswordScreen'; const StackNavigator = createStackNavigator({ welcome: WelcomeScreen, login: LoginScreen, - forgotPassword: ForgotPasswordScreen + forgotPassword: ForgotPasswordScreen, + signupOne: SignupScreenOne }); const AppNavigator = createAppContainer(StackNavigator); diff --git a/src/locales/translations/en.json b/src/locales/translations/en.json index 9f09039..061bb36 100644 --- a/src/locales/translations/en.json +++ b/src/locales/translations/en.json @@ -25,7 +25,8 @@ "share": "Share Now", "skip": "Skip", "uploadImage": "Upload Image", - "takePhoto": "Take Photo" + "takePhoto": "Take Photo", + "saveAndContinue": "Save and Continue" }, "contactFields": { "about_labelText": "About", @@ -559,7 +560,7 @@ "title": "Verify SMS Code" }, "signUp": { - "minPassword": "Must be at least 8 characters.", + "minPassword": "6+ characters", "password": "Password", "password2": "Confirm Password", "title": "Sign Up", diff --git a/src/screens/auth/ForgotPasswordScreen.js b/src/screens/auth/ForgotPasswordScreen.js index fa0174c..8f7201f 100644 --- a/src/screens/auth/ForgotPasswordScreen.js +++ b/src/screens/auth/ForgotPasswordScreen.js @@ -6,7 +6,8 @@ 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 { showAuthErrorMessage } from '../../utils/errorHandler'; +import { isEmail } from '../../utils/aux'; import endpoints from '../../config/apiEndpoints'; import colors from '../../config/colors.json'; @@ -32,41 +33,17 @@ export default class ForgotPasswordScreen extends React.Component { 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); + showAuthErrorMessage(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 + showAuthErrorMessage(error); }); } @@ -127,7 +104,7 @@ export default class ForgotPasswordScreen extends React.Component { onPress={this.onRequestResetPress.bind(this)} title={strings('settings.forgotPasswordScreen.submitButton')} buttonStyle={styles.buttonStyle} - disabled={this.isNotEmail()} + disabled={!isEmail(this.state.email)} loading={this.state.loading} fontSize={20} /> diff --git a/src/screens/auth/LoginScreen.js b/src/screens/auth/LoginScreen.js index 2ba98e0..3b0d484 100644 --- a/src/screens/auth/LoginScreen.js +++ b/src/screens/auth/LoginScreen.js @@ -1,12 +1,11 @@ import React from 'react'; import { Image, KeyboardAvoidingView, Platform, Dimensions, View, Text, Keyboard, TouchableWithoutFeedback } from 'react-native'; import { Button, FormInput } from 'react-native-elements'; -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 { getErrorDescription } from '../../utils/errorHandler'; +import { showAuthErrorMessage } from '../../utils/errorHandler'; import endpoints from '../../config/apiEndpoints'; import colors from '../../config/colors.json'; @@ -38,14 +37,14 @@ export default class LoginScreen extends React.Component { fetchAuth(endpoints.login, body).then(res => { if (res.error) { this.setState({ loading: false, password: '' }); - this.showErrorMessage(res.error); + showAuthErrorMessage(res.error); } else { this.setState({ loading: false }); console.log(res.sessionId); } }).catch(error => { this.setState({ loading: false, password: '' }); - this.showErrorMessage(error); + showAuthErrorMessage(error); }); } @@ -69,20 +68,6 @@ export default class LoginScreen extends React.Component { return this.state.id.length < 1 || this.state.password.length < 6; } - /** - * 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: 3000 - }); - } - renderContent() { return ( @@ -140,7 +125,7 @@ export default class LoginScreen extends React.Component { this.props.navigation.navigate('signup1')} + onPress={() => this.props.navigation.navigate('signupOne')} disabled={this.state.loading} /> diff --git a/src/screens/auth/SignScreenOne.js b/src/screens/auth/SignScreenOne.js new file mode 100644 index 0000000..c961485 --- /dev/null +++ b/src/screens/auth/SignScreenOne.js @@ -0,0 +1,245 @@ +import React, { Component } from 'react'; +import { Dimensions, Image, KeyboardAvoidingView, Platform, Text, View, ScrollView, Keyboard } from 'react-native'; +import { Button, FormInput } from 'react-native-elements'; + +import { FormLabel, Spacer } from '../../components/common'; +import { strings } from '../../locales/i18n'; +import { fetchAuth } from '../../utils/fetch'; +import { showAuthErrorMessage } from '../../utils/errorHandler'; +import { isEmail, isEmpty } from '../../utils/aux'; + +import logo from '../../../assets/logo-round.png'; +import colors from '../../config/colors.json'; +import endpoints from '../../config/apiEndpoints'; +import errors from '../../config/errors'; + +export default class SignupScreenOne extends Component { + static navigationOptions = { + header: null + } + + constructor(props) { + super(props); + this.state = { + firstName: '', + lastName: '', + email: '', + password: '', + loading: false + }; + } + /** + * Handles the button press by sending the request, based on the response received either navigates the user + * to SignupScreenTwo or displays an error message. + */ + onSaveButtonPress() { + Keyboard.dismiss(); + this.setState({ loading: true }); + + const endpoint = this.addParamsToEndpoint(endpoints.emailExists, this.state.email); + + fetchAuth(endpoint).then(res => { + this.toggleLoadingSpinner(); + + if (res.error) { + showAuthErrorMessage(res.error); + } else if (res.result === true) { + this.setState({ email: '' }); + showAuthErrorMessage(errors.AUTH_EMAIL_ALREADY_EXISTS); + } else { + console.log(res.result); + } + }).catch(error => { + this.toggleLoadingSpinner(); + showAuthErrorMessage(error); + }); + } + + /** + * Replaces the default express `:email` parameter with the actual value. + * @param {Object} endpoint takes an endpoint object @see config/endpoints + * @param {String} email + */ + addParamsToEndpoint(endpoint, email) { + const endpointWithParams = { ...endpoint }; + endpointWithParams.url = endpoint.url.replace(':email', email); + return endpointWithParams; + } + + /** + * Boolen function that says if the button is disabled based on if the fields are empty. + */ + isButtonDisabled() { + const { firstName, lastName, email, password } = this.state; + return isEmpty(firstName) || isEmpty(lastName) || !isEmail(email) || password.length < 6; + } + + /** + * Utility function that toggles the state of the loading variable, true to false and false to true. + */ + toggleLoadingSpinner() { + this.setState({ loading: !this.state.loading }); + } + + renderContent() { + return ( + + + {/* LOGO */} + + + + + {/* HEADER */} + + Signup + + + {/* TEXT INPUTS */} + + + + this.setState({ firstName })} + placeholder={strings('common.contactFields.firstName_placeholder')} + autoCorrect={false} + autoCapitalize='words' + inputStyle={styles.inputTextStyle} + /> + + + + this.setState({ lastName })} + placeholder={strings('common.contactFields.lastName_placeholder')} + autoCorrect={false} + autoCapitalize='words' + inputStyle={styles.inputTextStyle} + /> + + + + this.setState({ email })} + placeholder={strings('common.contactFields.email_or_tagferid_placeholder')} + autoCorrect={false} + autoCapitalize='none' + inputStyle={styles.inputTextStyle} + /> + + + + this.setState({ password })} + placeholder={strings('userCreateFlow.signUp.minPassword')} + autoCorrect={false} + autoCapitalize='none' + inputStyle={styles.inputTextStyle} + /> + + + + + {strings('userCreateFlow.termsLeft')} + + this.props.navigation.navigate('termsAndConditions')}> + {strings('userCreateFlow.termsRight')} + + + + + +