1
votes

I am a newbie in react-native and react-redux. I am working on a react native project in which i wanted to implement authentication and authorization. For some miliseconds, i wanted to show splashscreen, if user is not logged in then redirect to login page else redirect to dashboard page. If user logged out, then navigate to login screen. i am using react-native 0.62, react-navigation 5.x and redux 7.2. i have created one stacknavigator for login screen, forgot password screen, otp screen and reset password screen. and one drawernavigator for drawer which contains dashboard screen, lms screen, my profile screen and logout. i have implemented the api using redux-thunk. i am not able to redirect to dashboard. Currently, i have checked the condition using static value with UseStatic. i don't know whether it is correct or not. i have remember me checkbox in the login screen. so if the user check that checkbox then the necxt the user wont need to enter the credentials until user logs out. I exhausted as i am not getting what is redux and asyncStorage and how to use it

App.js file
import 'react-native-gesture-handler';
enableScreens();
import React, { useState, useEffect } from 'react';
import { enableScreens } from 'react-native-screens';
import { StatusBar } from 'react-native';
import { Provider, connect } from 'react-redux';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

import store from '../store/store';
import SplashScreen from '../screens/splashScreen';
import MainStack  from '../routes/MainStack';
import MainNavigator  from '../routes/MainNavigator';


const RootStack = createStackNavigator();

const App = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [auth, setAuth] = useState(false);

  useEffect(() => {
    setTimeout(async () => {
      setIsLoading(!isLoading);
      setAuth(false);  
    }, 2000)
  }, []);



  return (
    <Provider store={store}>
      <NavigationContainer>
        <StatusBar backgroundColor={isLoading ? '#000000' : '#F3F3F3'} />
                {isLoading ?
          
            <SplashScreen/>:
            auth ?
            <MainNavigator/>
           
              :
              <MainStack />
             
      </NavigationContainer>
    </Provider>
  );
  //}
}


export default App;

MainStack.js File

export default ({navigation}) => {
  return (
    <Stack.Navigator initialRouteName="Login" screenOptions={{
      headerShown: false
    }}>
      <Stack.Screen name="Login" component={Login}/>
      <Stack.Screen name="ForgotPassword" component={ForgetPassword}/>
      <Stack.Screen name="VerifyOTP" component={VerifyOTP} />
      <Stack.Screen name="ResetPassword" component={ResetPassword} />      
    </Stack.Navigator>
  );
};

MainNavigator.js
const DashboardStackScreen = ({ navigation }) => {
  return (
    <DashboardStack.Navigator screenOptions={{
      headerTitle: 'Good Morning, John',
      header: props => <GradientHeader {...props} />,
     
      headerLeft: () => (
        <TouchableOpacity onPress={navigation.openDrawer} style={{padding: 20}}>
          <Image source={require('../assets/images/menu_bar.png')} style={{width:18, height:12}}/>
        </TouchableOpacity>
      ),
      headerTransparent: true,
      headerStyle: {
        backgroundColor:  'transparent' 
      },
      headerTintColor: '#fff',    
      headerTitleStyle: { fontFamily: 'OpenSans-SemiBold', fontSize: 20},
    }}>
      <DashboardStack.Screen name="Dashboard" component={Dashboard} />
    </DashboardStack.Navigator>
  );
}

export default({navigation}) =>{
  return (
    <Drawer.Navigator initialRouteName="Dashboard" drawerContent={(props) => <DrawerContent {...props} />} hideStatusBar={false} focused={true} labelStyle={{ fontSize: 14, fontFamily: 'OpenSans-SemiBold' }} drawerContentOptions={{ activeBackgroundColor: "#F1F1F1", activeTintColor: "#000000", inactiveTintColor: "#818181",itemStyle: { marginLeft:0, paddingHorizontal: 10,width:'100%',  borderRadius: 0}}} 
    
   >
      <Drawer.Screen name="Dashboard" component={DashboardStackScreen} options={{
        drawerIcon: ({ focused, size }) => (
          <Image source={require('../assets/images/dashboard.png')} style={{ height: 17.78, width: 16}}  resizeMode="contain"/>
        ),
      }}
      
      />
      <Drawer.Screen name="My Profile" component={MyProfileStackScreen} options={{
        drawerIcon: ({ focused, size }) => (
          <Image source={require('../assets/images/profile.png')} style={{ height: 16, width: 16 }}  resizeMode="contain"/>
        ),
      }} />
     
      <Drawer.Screen name="LMS" component={LmsStackScreen} options={{
        drawerIcon: ({ focused, size }) => (
          <Image source={require('../assets/images/lms.png')} style={{ height: 14.46, width: 16 }}  resizeMode="contain"/>
        ),
      }} />
      <Drawer.Screen name="Change Password" component={ChangePasswordStackScreen} options={{
        drawerIcon: ({ focused, size }) => (
          <Image source={require('../assets/images/key.png')} style={{ height: 8.73, width: 16 }}  resizeMode="contain"/>
        ),
      }} />
    </Drawer.Navigator>
  );
};

Login.js 
import React from 'react';
import { connect } from 'react-redux';
import LinearGradient from 'react-native-linear-gradient';
import { ScrollView, KeyboardAvoidingView, View, Text, Image, TextInput, TouchableOpacity, SafeAreaView, Keyboard, TouchableWithoutFeedback } from 'react-native';
import Toast from 'react-native-simple-toast';
/* import CheckBox from '@react-native-community/checkbox'; */
/* import CheckBox from 'react-native-check-box'; */
import Checkbox from 'react-native-custom-checkbox';

import styles from '../utility/styles';
import { thunk_login_creator } from '../actions/login';

class Login extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      color: "#ffffff",
      isSelected: false,
      isPasswordHidden: true,
      employeeId: '',
      employeeIdError: '',
      password: '',
      passwordError: ''
    }
  }

  handleValidation(type) {
    let obj = this.state;
    switch (type) {
      case 'employeeId':
        obj.employeeIdError = this.state.employeeId.trim() == "" ? "Employee ID is required" : "";
        break;
      case 'password':
        obj.passwordError = this.state.password.trim() == "" ? "Password is required" : ""
        break;
      default:
        break;
    }
    this.setState({ obj });
  }

  handleChange(type, text) {
    if (type == 'employeeId') {
      this.setState({ employeeId: text.trim() }, () => {
        this.handleValidation(type);
      });
    } else {
      this.setState({ password: text.trim() }, () => {
        this.handleValidation(type);
      });
    }
  }

  handlePasswordToggle = () => {
    console.log('handlePasswordToggle called');
    this.setState({ isPasswordHidden: !this.state.isPasswordHidden })
  }

  handleRememberMe = () => {
    console.log('handleRememberMe called');
    this.setState({ isSelected: !this.state.isSelected }, () => {
      if (this.state.isSelected == true) {
        this.setState({ color: "red" });
      } else {
        this.setState({ color: "black" });
      }
      console.log('remember me--->', this.state.isSelected);
    })
  }

  handleLogin = () => {
    console.log('handleLogin called')
    this.props.dispatch(thunk_login_creator({ 'empId': this.state.employeeId, 'password': this.state.password, 'isRemembered': this.state.isSelected },/* ()=>{
      if (this.props.data.login.loading) {
        Toast.show('Loading...');
      } else if (this.props.data.login.error) {
        Toast.show('Invalid Credentials');
      } else {
        this.setState({
          employeeId: '',
          employeeIdError: '',
          password: '',
          passwordError: ''
        }, () => {
           this.props.navigation.navigate('Dashboard') 
        })
      }
    } */));
     if (this.props.data.login.loading) {
      Toast.show('Loading...');
    } else if (this.props.data.login.error != '') {
      Toast.show(this.props.data.login.error);
    } else {
      this.setState({
        isSelected: false,
        employeeId: '',
        employeeIdError: '',
        password: '',
        passwordError: ''
      }, () => {
        //this.props.navigation.navigate('Dashboard')
      })
    } 
  }

  render() {
    return (

      <SafeAreaView style={styles.baseContainer}>

        <KeyboardAvoidingView behaviour="padding" style={styles.baseContainer} >
          <TouchableWithoutFeedback style={styles.baseContainer} onPress={Keyboard.dismiss}>

            <View style={styles.baseContainer} >
              <View style={styles.ovalContainer}>
                <View style={styles.oval1} />
                <View style={styles.oval2} />
                <View style={styles.logoContainer}>
                  <Image source={require('../assets/images/MJB_Logo.png')} style={styles.logo} />
                </View>
              </View>
              <View style={styles.formContainer}>
                <View style={styles.loginTextContainer}>
                  <Text style={styles.loginText}>Login</Text>
                </View>
                <View style={styles.loginFormContainer}>
                  <View>
                    <Text style={styles.labelText}>Employee ID</Text>
                    <TextInput style={styles.inputField} value={this.state.employeeId} placeholder="" onBlur={() => this.handleValidation('employeeId')} keyboardType="email-address" returnKeyType="next" autoCorrect={false} onSubmitEditing={() => this.refs.txtPassword.focus()} onChangeText={(text) => this.handleChange('employeeId', text)} />
                    <Text style={styles.errorText} >{this.state.employeeIdError}</Text>
                  </View>
                  <View>
                    <Text style={styles.labelText}>Password</Text>
                    <View>
                      <TextInput style={styles.inputField} value={this.state.password} onBlur={() => this.handleValidation('password')}
                        placeholder="" returnKeyType="go" secureTextEntry={this.state.isPasswordHidden} autoCorrect={false} ref={"txtPassword"} onChangeText={(text) => this.handleChange('password', text)} />
                      <TouchableWithoutFeedback onPress={this.handlePasswordToggle} style={styles.eyeIconContainer}>
                        <Image source={this.state.isPasswordHidden
                          ? require('../assets/images/eye_on.png')
                          : require('../assets/images/eye_off.png')} style={styles.eyeIcon} resizeMode="contain" />
                      </TouchableWithoutFeedback>
                    </View>
                    <Text style={styles.errorText} >{this.state.passwordError}</Text>
                  </View>
                  {/* 
                  <View style={styles.rememberMeContainer}>
                      <CheckBox 
                        value={this.state.isSelected}
                        onValueChange={this.handleRememberMe}
                        style={styles.checkbox}
                        tintColors={{ true: '#6CCFF6', false: '#CED4DA' }}
                        onFillColor="#6CCFF6"
                        onTintColor="#6CCFF6"
                      />
                      <Text style={styles.rememberMeText}>Remember Me</Text>
                    </View>
                  */}

                  <View style={styles.rememberMeContainer}>
                    {/*  <CheckBox 
                        isChecked={this.state.isSelected}
                        onClick={this.handleRememberMe}
                       style={styles.checkbox}
                        checkBoxColor="#CED4DA"
                        checkedCheckBoxColor="#6CCFF6"
                       
                      /> */}
                    <Checkbox
                      checked={this.state.isSelected}
                      style={{/* backgroundColor: (this.state.isSelected ? 'green':'black'), */ color: '#000000', borderRadius: 3, borderColor: '#CED4DA', borderWidth: 1 }}
                      size={25}
                      onChange={this.handleRememberMe} />
                    <Text style={styles.rememberMeText}>Remember Me</Text>
                  </View>

                  <TouchableOpacity disabled={this.state.employeeId == '' || this.state.password == '' ? true : false} onPress={this.handleLogin} >
                    <LinearGradient start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} colors={['#6CCFF6', '#596AB2']} style={styles.linearGradient}>
                      <Text style={styles.buttonText}>
                        Login
                      </Text>
                    </LinearGradient>
                  </TouchableOpacity>
                  <View style={styles.forgetPasswordTextContainer} >
                    <Text style={styles.forgetText}>Forgot password? <Text style={styles.resetText} onPress={() =>
                      this.props.navigation.navigate('ForgotPassword')
                    }> Reset</Text></Text>
                  </View>
                </View>
                {/* <View style={styles.forgetPasswordTextContainer}>
                  <Text style={styles.forgetText}>Forgot password? <Text style={styles.resetText} onPress={() =>
                    this.props.navigation.navigate('ForgotPassword')
                  }> Reset</Text></Text>
                </View> */}
              </View>
            </View>

          </TouchableWithoutFeedback >
        </KeyboardAvoidingView>

      </SafeAreaView>

    )
  }
};

const mapStateToProps = state => {
  console.log('login state===>', state)
  return {
    data: state
  };
};
export default connect(mapStateToProps)(Login);


Any help is appreciated. 
1

1 Answers

0
votes

Do you use a token to log in to a user? Usually, I use asyncStorage for storing the token in my app. In your login function, you can set a user to redux state and set your token to asyncStorage. When mounting the app.js you can check if the token is there while your splash screen is showing. If the token is there you can get the user and set your redux state, but if not it would go back to the login page, after the splash screen.

So in total when starting the app, your splash screen would check if there is a token in the asyncStorage and if there is a logged-in user in your redux state. if any of those are not exist, you would ask the user to login again. Or if you have the token, you can try to get the user again.