Build Login and Signup Component for Your App

Learn how to add Login and Signup functionality to your custom React Native and Django app with Crowdbotics.

What is the Login and Signup component and how much does it cost?

A screen that allows the user to create a new account for the application and login with their email and password. It usually takes between 6.3 and 7.7 hours and costs $525 to add Login and Signup to an application.

How does the Login and Signup component work?

This feature is used to allow end users to register themselves with the application using their email address and password and then login with those credentials. It contains text input fields and a checkbox to capture a user's credentials and their consent. Each input field includes placeholder text and a custom icon. A background screen with custom screen colors is used for branding.

What is the Login and Signup component used for?

Here are some common Login and Signup user stories in a custom app build:

As a new user, I would like to enter my full name, email address, and password. As a new user, I would like to register with my credentials with the app by pressing a button. As an app user, I would like to login with my credentials with the app by pressing a button. As a returning user, I should be able to navigate back to the sign in screen. As a new user, my consent should be asked using a checkbox that I have read all terms and conditions of the application and I agree to them.

Login and Signup component README file

Basic Login Signup Screen

The Basic Login Signup Screen is a React Native-based screen that allows the user to login or signup.

Installation

After you have added the screen module into your project, you will need to configure a few items by modifying the project files in the github repository. Please note to replace ####### with the numeric sequence for your screen (found in folder name under /src/features), and also that the @BluePrint tags for ImportInsertion and NavigationInsertion will be removed in future so placement is with other imports and inside the AppNavigator above other screens.

STEP 1: Add dependency library to the project.

/PROJECT_ROOT_DIRECTORY/package.json:

ADD Dependency after Line 16 (dependencies opening line ""dependencies": { ")

 "native-base": "^2.13.15",

STEP 2: Add screen into your project screen navigation.

/src/mainNavigator.js: ADD immediately below in the section labeled //@BlueprintImportInsertion:

import BasicLoginSignup#######Navigator from '../features/BasicLoginSignup#######/navigator';

ADD immediately below in the section inside AppNavigator definition labeled //@BlueprintNavigationInsertion section:

BasicLoginSignup: { screen: BasicLoginSignup#######Navigator },

STEP 3: Add reducers to store.

/src/store/index.js ADD after Line 4 (sagas import):

import authRootSaga from './auth/sagas';
import authReducer from './auth/reducers';

Locate the store creation with createStore, ADD comma at end of customReducer and ADD below the following code authReducer: authReducer.

This is how your createStore should look like after modifications:

const store = createStore(
 combineReducers({
   apiReducer: apiReducer,
   customReducer: customReducer,
   authReducer: authReducer
 }),
 composeEnhancers(applyMiddleware(...middlewares))
);

Near the end, before the export { store } line, register the new sagas sagaMiddleware like this:

sagaMiddleware.run(authRootSaga);

STEP 4: Change Login screen destination to your desired screen (likely Home screen).

Open the screens/constants.js file and edit the HOME_SCREEN_NAME value with desired destination screen (likely Home Screen). For example, if my home screen is called HomeScreen1234535, then I should change as follows: export const HOME_SCREEN_NAME = 'HomeScreen1234535'. If you desire, you can also update your logo image URL (be mindful that the size of the image should match the original ones for ideal results).

STEP 5: Modify backend

If your app's back-end does not have SENDGRID environmental variables available, Make changes to project backend files (in /backend/YOUR_PROJECT folder):

MODIFY: /backend/YOUR_PROJECT_NAME/settings.py version in your project backend folder

ADD above AWS S3 Config lines:

EMAIL_HOST = env.str("EMAIL_HOST", "smtp.sendgrid.net")
EMAIL_HOST_USER = env.str("SENDGRID_USERNAME", "")
EMAIL_HOST_PASSWORD = env.str("SENDGRID_PASSWORD", "")

If this code already exists, you can just skip this step.

STEP 6: Setup SendGrid account and keep reference to username and password.

Reference website Sendgrid

STEP 7: Configure Environment Variables.

Using the Crowdbotics Dashboard, navigate to "Settings" and select the tab "Environment Variables", here you will add the following variables:

SENDGRID_USERNAME
SENDGRID_PASSWORD

STEP 8: Update api url (optional)

If you have renamed your app through the Crowdbotics platform, you might need to change the reference url of your deployed app that is used to execute the api requests. To find out if you need to update, go to the file src/config/app.js and locate the emailAuthAPIEndPoint. If the value is your app's back-end url, then you do not need to change anything. If your current back-end url is different that what is shown there, update accordingly.

For example, after renaming my app from loginapp to personalapp, the code needs to be changed from:

export const appConfig = {
 // todo add library to handle env variables
 emailAuthAPIEndPoint: "https://loginapp-123.botics.co",
 ...

to

export const appConfig = {
 // todo add library to handle env variables
 emailAuthAPIEndPoint: "https://personalapp-123.botics.co",
 ...

Note for developer: you can access the user token through the authReducer state (i.e. state.authReducer.token and user auth information like e-mail at state.authReducer.user)

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate.

License

MIT

This component does not yet have a README file. However, another Crowdbotics user may have created this component and shared it as a free community component.

Browse our community components for the Login and Signup component.

Full Login and Signup component code


import React, {Component} from 'react';
import {
  View,
  ImageBackground,
  Image,
  Text,
  KeyboardAvoidingView,
  TouchableOpacity,
  TextInput,
  ActivityIndicator,
  ScrollView,
  Alert,
} from 'react-native';
import {
  HOME_SCREEN_NAME,
  BACKGROUND_URL,
  emailValidationRegex,
  LOGO_URL,
} from './constants.js';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import {Tab, Tabs} from 'native-base';
import {styles, buttonStyles, textInputStyles, Color} from './styles';
import {connect} from 'react-redux';
import {apiLoginRequest, apiSignupRequest} from '../../../store/auth/actions';
import {
  API_LOGIN_FAILED,
  API_SIGNUP_FAILED,
} from '../../../store/auth/constants';

Tab.prototype.requestAnimationFrame = () => {};
Tabs.prototype.requestAnimationFrame = () => {};

const TextInputField = props => (
  <View>
    <Text style={[textInputStyles.label, props.labelStyle]}>{props.label}</Text>
    <TextInput
      autoCapitalize="none"
      style={[textInputStyles.textInput, props.textInputStyle]}
      placeholderTextColor={Color.steel}
      underlineColorAndroid={'transparent'}
      {...props}
    />
    {!!props.error && <Text style={textInputStyles.error}>{props.error}</Text>}
  </View>
);

const Button = props => (
  <TouchableOpacity onPress={props.onPress} disabled={props.loading}>
    <View style={[buttonStyles.viewStyle, props.viewStyle]}>
      {props.loading ? (
        <ActivityIndicator
          color={props.loadingColor ? props.loadingColor : Color.white}
          style={props.loadingStyle}
        />
      ) : (
        <Text style={[buttonStyles.textStyle, props.textStyle]}>
          {props.title}
        </Text>
      )}
    </View>
  </TouchableOpacity>
);

class SignUpComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      email: '',
      password: '',
      confirmPassword: '',
      emailError: '',
      passwordError: '',
      confirmPasswordError: '',
      requestError: '',
    }
  }

  componentDidUpdate(prevProps) {
    const {requestError, user, success} = this.props;
    if (prevProps.isLoading && requestError?.type === API_SIGNUP_FAILED) {
      const error =
        requestError.code == 400
          ? 'This email is already registered or password is too weak.'
          : requestError.message;

      Alert.alert('Error', error);
      this.setState({
        requestError: error,
      });
    }
    if (prevProps.isLoading && success && user !== {}) {
      Alert.alert(
        'Signup Success',
        'Registration Successful. A confirmation will be sent to your e-mail address.',
      );
    }
  }

  onSignupPress = async () => {
    const {email, password, confirmPassword} = this.state;
    if (emailValidationRegex.test(email)) {
      if (password != '') {
        if (password == confirmPassword) {
          this.props.signup(email, password);
        } else {
          this.setState({
            confirmPasswordError: 'Confirm password and password do not match',
          });
        }
      } else {
        this.setState({passwordError: 'Please enter a valid password'});
      }
    } else {
      this.setState({emailError: 'Please enter a valid email address'});
    }
  };

  render() {
    const {
      email,
      password,
      emailError,
      passwordError,
      confirmPassword,
      confirmPasswordError,
    } = this.state;
    return (
      <KeyboardAvoidingView>
        <View style={{marginVertical: 20, marginHorizontal: 15}}>
          <TextInputField
            keyboardType="email-address"
            label="Email address"
            placeholder="Email address"
            onChangeText={email => this.setState({email})}
            value={email}
            error={emailError}
          />
          <TextInputField
            label="Password"
            placeholder="Password"
            secureTextEntry={true}
            onChangeText={password => this.setState({password})}
            value={password}
            error={passwordError}
          />
          <TextInputField
            label="Confirm Password"
            placeholder="Confirm Password"
            secureTextEntry={true}
            onChangeText={confirmPassword => this.setState({confirmPassword})}
            value={confirmPassword}
            error={confirmPasswordError}
          />
        </View>
        <Button
          title="Sign Up"
          loading={this.props.isLoading}
          onPress={this.onSignupPress}
        />
        {!!this.state.requestError && (
          <Text style={textInputStyles.error}>
            {this.state.requestError.message}
          </Text>
        )}
      </KeyboardAvoidingView>
    );
  }
}

class SignInComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      email: '',
      password: '',
      emailError: '',
      passwordError: '',
      authLoading: false,
      fbLoading: false,
    };
  }

  componentDidUpdate(prevProps) {
    const {requestError, token} = this.props;
    if (prevProps.isLoading && requestError?.type === API_LOGIN_FAILED) {
      Alert.alert('Login Error', requestError.message);
    }
    if (token) {
      this.props.navigation.navigate(HOME_SCREEN_NAME);
    }
  }

  onSigninPress = () => {
    const {email, password} = this.state;
    if (emailValidationRegex.test(email)) {
      if (password != '') {
        this.props.login(email, password);
        this.setState({authLoading: false});
      } else {
        this.setState({passwordError: 'Please enter a valid password'});
      }
    } else {
      this.setState({emailError: 'Please enter a valid email address'});
    }
  };
  render() {
    const {email, password, emailError, passwordError} = this.state;
    return (
      <KeyboardAvoidingView>
        <View style={{marginVertical: 20, marginHorizontal: 15}}>
          <TextInputField
            keyboardType="email-address"
            label="Email address"
            placeholder="Email address"
            onChangeText={email => this.setState({email})}
            value={email}
            error={emailError}
          />
          <TextInputField
            label="Password"
            placeholder="Password"
            secureTextEntry={true}
            onChangeText={password => this.setState({password})}
            value={password}
            error={passwordError}
          />
        </View>
        <Button
          title="Login"
          loading={this.props.isLoading}
          onPress={this.onSigninPress}
        />
        <View
          style={{
            justifyContent: 'center',
            alignItems: 'center',
            marginTop: 10,
          }}>
          <TouchableOpacity
            activeOpacity={0.7}
            onPress={() => {
              this.props.navigation.navigate('PasswordRecover');
            }}>
            <Text>Forgot your password?</Text>
          </TouchableOpacity>
        </View>
      </KeyboardAvoidingView>
    );
  }
}

export class Blank extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <ScrollView style={[styles.container]}>
        <KeyboardAwareScrollView contentContainerStyle={{flex: 1}}>
          <View style={[styles.container]}>
            <View style={{flex: 1}}>
              <View style={styles.imageContainer}>
                <ImageBackground
                  source={{
                    uri: BACKGROUND_URL,
                  }}
                  style={{
                    flex: 1,
                    justifyContent: 'center',
                    resizeMode: 'cover',
                  }}>
                  <Image
                    source={{
                      uri: LOGO_URL,
                    }}
                    style={{
                      width: 155,
                      height: 155,
                      alignSelf: 'center',
                      resizeMode: 'contain',
                    }}
                  />
                </ImageBackground>
              </View>
            </View>
            <View style={[styles.cardView]}>
              <View style={{marginBottom: 20}}>
                <Tabs
                  tabBarUnderlineStyle={styles.tabBarUnderlineStyle}
                  tabContainerStyle={styles.tabContainerStyle}>
                  <Tab
                    heading="Sign In"
                    activeTabStyle={styles.activeTabStyle}
                    tabStyle={styles.tabStyle}
                    activeTextStyle={styles.activeTextStyle}
                    textStyle={styles.textStyle}>
                    <SignInComponent {...this.props} />
                  </Tab>
                  <Tab
                    heading="Sign Up"
                    activeTabStyle={styles.activeTabStyle}
                    tabStyle={styles.tabStyle}
                    activeTextStyle={styles.activeTextStyle}
                    textStyle={styles.textStyle}>
                    <SignUpComponent {...this.props} />
                  </Tab>
                </Tabs>
              </View>
            </View>
          </View>
        </KeyboardAwareScrollView>
      </ScrollView>
    );
  }
}

function mapStateToProps(state) {
  return {
    token: state.authReducer.token,
    requestError: state.authReducer.error,
    isLoading: state.authReducer.isLoading,
    user: state.authReducer.user,
    success: state.authReducer.success,
  };
}

const mapDispatchToProps = dispatch => {
  return {
    login: (email, password) =>
      dispatch(apiLoginRequest({username: email, password})),
    signup: (email, password) => dispatch(apiSignupRequest({email, password})),
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Blank);

This component is not yet available as a verified component in the Crowdbotics platform. However, another Crowdbotics user may have created it and shared it as a free community component.

Browse our community components for the Login and Signup component.

Recommended components for you

All component categories

Add this feature to your project

Snap Login and Signup into your app along with our full library of prebuilt components.

Import layouts directly from Figma and visually build backend data models.

Two-way GitHub sync and automated deployments to Heroku will have your app up and running in minutes.

Add Login and Signup to My App

Build with more components from Crowdbotics

Crowdbotics can build your custom app with Login and Signup functionality and hundreds of other components.

Go from specs to code 4X faster than conventional development.

Our expert PMs and developers are standing by to provide a detailed quote and build timeline.

Start Building