Fitur Authentication React Native

Fitur Authentication React Native

Apa jadinya apabila informasi yang bersifat pribadi dapat diakses secara publik yang bukan merupakan pemilik informasi tersebut? Maka dalam kondisi seperti ini, fitur authentication akan sangat dibutuhkan untuk menangani masalah permission untuk user yang akan menggunakan aplikasi kita. Melanjutkan case sebelumnya, membuat aplikasi chatting react native (baca: Jadi, silahkan baca artikel sebelumnya. Apabila kamu sudah tahu cara kerja dari React Native, maka kamu dapat langsung mendownload source codenya saja yang sudah saya lampirkan pada artikel sebelumnya), kita akan menambahkan fitur authentication sebelum user dapat melakukan chatting pada aplikasi whatsapp clone.

Baca Juga: Membuat Aplikasi Chatting React Native

Tahap Persiapan

Sebelum kita membuat fitur authentication menggunakan React Native, maka langkah pertama yang harus dilakukan adalah mengaktifkan service authentication di Firebase. Masih menggunakan project Firebase sebelumnya, lakukan beberapa hal berikut:

  1. Pada menu di sisi kiri, pilih Authentication

  2. Kemudian pilih tab SIGN-IN METHOD

  3. Kemudian Enable pada bagian Email/Password

Setelah kebutuhan terakait service Firebase telah diaktifkan, maka tiba saatnya untuk berinteraksi dengan React Native. Authentication, selalu berkaitan dengan Login & Sing Up, dua hal yang saling terkait satu sama lainnya. Maka pada kesempatan kali ini kita akan membuat keduanya agar dapat digunakan sebagaimana mestinya.

Login & Sign Up Screen

Sebelum beranjak pada topik sub heading diatas, kita akan mengatur route terlebih dahulu yang akan bertindak sebagai navigasi dalam aplikasi yang akan kita bangun. Oleh karena itu, buka file src/config/routes.js kemudian modifikasi menjadi seperti berikut:

import React from 'react';
import Login from '../screens/Login';
import Signup from '../screens/Signup';
import Home from '../screens/Home';
import ChatScreen from '../screens/ChatScreen';
​
const routes = {
    login: { screen: Login },
    signup: { screen: Signup },
    home: { screen: Home },
    chat: { screen: ChatScreen }
}
​
export default routes;

Cara kerja dari code diatas masih sama, yakni mengatur navigasi untuk berpindah antar screen. Perlu diperhatikan, kita meng-import dua screen tambahan (baca: Login dan Singup), maka buat file tersebut satu persatu. Pertama, buat file Login.js di dalam folder screens kemudian ketikkan code berikut:

import React from 'react'; 
import { login } from '../services/api';
import { View, StyleSheet, Image, ScrollView, TextInput, Button, Text, TouchableOpacity } from 'react-native';
import SplashScreen from '../components/SplashScreen';
import { NavigationActions } from 'react-navigation';
​
export default class Login extends React.Component {

 
    render() {
        return(
            <View style={styles.container}>
                <Image
                    style={[ styles.logo ]}
                    source={require('../assets/img/whatsapplogo.png')} />
                <ScrollView style={styles.container}>
                    <TextInput
                        ref={(textInput) => this._user = textInput }
                        style={styles.inputField}
                        value={this.state.text}
                        onChangeText={(user) => this.setState({user})}
                        onSubmitEditing={(event) => this._password.focus()}
                        onFocus={ () => this.clearValidationErrors() }
                        editable={true}
                        maxLength={40}
                        multiline={false}
                        placeholder="Masukkan Email"
                    />
                    <TextInput
                        ref={(textInput) => this._password = textInput }
                        style={styles.inputField}
                        value={this.state.text}
                        onChangeText={(password) => this.setState({password})}
                        onSubmitEditing={(event) => this.submit()}
                        editable={true}
                        secureTextEntry={true}
                        maxLength={40}
                        multiline={false}
                        placeholder="Masukkan Password"
                    />
                    { this.state.error &&
                        <View style={styles.validationErrors}>
                            <Text style={styles.error}>{this.state.error}
                            </Text>
                        </View>
                    }
                    <View style={styles.buttonStyle}>
                    { this.state.loading ? 
                    <SplashScreen /> :
                    <Button
                        onPress={() => this.submit()} 
                        title="Masuk" />
                    }
                    </View>
                    <View style={styles.redirectLink}>
                        <Text>Tidak punya akun? </Text>
                        <TouchableOpacity onPress={() =>
                        this.props.navigation.navigate('signup')}>
                        <Text style={styles.link}>Daftar</Text>
                        </TouchableOpacity>
                    </View>
                    <View style={styles.copyright}>
                    <Text style={{fontSize: 18, color: '#19B5FE'}}>https://daengweb.id</Text>
                    </View>
                </ScrollView>
            </View>
        );
    }
}
​
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white'
  },
  logo: {
    width: '100%',
    height: 200
  },
  inputField: {
    marginTop: 20,
    alignSelf: 'center',
    height: 55,
    width: '80%',
    backgroundColor: '#FAFAFA',
    borderWidth: 1,
    paddingHorizontal: 10,
    borderRadius: 10,
    borderColor: "#CACACA"
  },
  redirectLink: {
    marginTop: 20,
    flex: 1,
    flexDirection: 'row',
    alignSelf: 'center'
  },
  link: {
    color: 'blue'
  },
  validationErrors: {
    flexDirection: 'row',
    justifyContent: 'center',
  },
  error: {
    marginTop: 10,
    textAlign: 'center',
    color: 'red'
  },
  buttonStyle: {
    marginTop: 15,
    flex: 1
  },
  copyright: {
    marginTop: 15,
    flex: 1,
    alignSelf: 'center'
  }
})

Penjelasan: Pada layer pertama akan me-load gambar menggunakan Image component dari directory src/assets/img/whatsapplogo.png yang dapat kamu download di Github. Pada layer kedua, kita memiliki dua buah TextInput component yang diapit oleh ScrollView component agar pada device yang tidak dapat me-load component secara penuh dapat di-scroll. Adapun properti yang mengikuti TextInput masih sama seperti sebelumnya, yang membedakan hanya pada bagian TextInput untuk password terdapat prop secureTextEntry yang berfungsi untuk mengatur apakah text pada input field akan ditampilkan atau tidak.

Pada layer selanjutnya yang terletak dibawah input field, terdapat bagian yang akan menampilkan errors yang diperoleh dari Firebase:

{ this.state.error &&
    <View style={styles.validationErrors}>
        <Text style={styles.error}>{this.state.error}
        </Text>
    </View>
}

Kita juga memiliki sebuah Buttonyang menggunkan event onpress, dimana ketika tombol tersebut ditekan maka akan memicu submit function. Sedangkan untuk function submit akan kita tambahkan nanti sebab memiliki penjelasan tersendiri agar tidak kebingungan. Kemudian di layer terakhir, kita memiliki memiliki tombol untuk berpindah ke Sign Up screen.

Masih di dalam file Login.js, tambahkan code berikut yang merupakan function submit:

async submit(){
  try {
     const response = await login(this.state.user, this.state.password);
     if (response) {
      this.setState({loading: true})
      setTimeout(() => {
        this.clearAndNavigate('home')
      }, 1000);
     }
  } catch ({ message }) {
     this.setState({
       error: message
     })
  }
}

Penjelasan: Kita menggunakan method login yang didapatkan dari service/api.js dengan mengirimkan parameter state user dan password. Apabila response bernilai true, maka state loading akan diset ke true, kemudian dalam waktu satu menit kedepan akan mengirimkan parameter home ke clearAndNavigate function. Apabila authentication gagal, maka state error akan diset dengan value message (baca: message ini berisi pesan error yang didapatkan dari Firebase).

Buat function berikutnya yang bernama clearAndNavigate:

clearAndNavigate(screen) {
    this.setState({
        user: '',
        password: ''
    })
    Keyboard.dismiss();
    this.isAuthenticated = true;
    this.props.navigation.dispatch(
        NavigationActions.reset({
            index: 0,
            actions: [
                NavigationActions.navigate({ routeName: 'home' })
            ]
        })
    );
}

Penjelasan: Function ini berfungsi untuk membersihkan state username dan password menggunakan setState. Kemudian, kita menutup keyboard dan menentukan nilai dari state isAuthenticated menjadi true, kemudian kita me-replace navigation screen dengan home screen. Kondisi yang diharapkan adalah dimana user tidak diizinkan untuk kembali ke Login atau SignUp screen, jadi kita menggunakan teknik dispatch navigation actions untuk mengimplementasikannya.

Ada yang ketinggalan, pada TextInput username, kita mengatur prop onFocus dengan memanggil method clearValidationErrors, maka tambahkan function berikut yang berfungsi untuk menghapus error:

clearValidationErrors(){
  this.setState({
     error: false
  })
}

Karena kita membutuhkan beberapa state, diantaranya: username, password, error, isAuthenticated, loading. Maka kita tetapkan nilai defaultnya terlebih dahulu, tambahkan code berikut:

state = {
  user: '',
  password: '',
  error: false,
  isAuthenticated: false,
  loading: false
}

Pada screen ini, kita tidak membutuhkan sebuah header, maka navigationOptions akan diset null:

static navigationOptions = {
  header: null
}

Baca Juga: React Native Navigation

Authentication Logic

Izinkan saya untuk beranjak ke tahap authentication logic terlebih dahulu, sedangkan untuk SignUp screen kita skip dulu dan akan dilanjutkan kemudian. Jika kita perhatikan, pada Login.js terdapat code untuk meng-import SplashScreen, maka buat file SplashScreen.js di dalam folder src/components kemudian masukkan code berikut:

import React from 'react';
import { View, ActivityIndicator } from 'react-native';
​
export default function SplashScreen(){
  return (
    <View style={{ flex: 1, justifyContent: 'center'}}>
      <ActivityIndicator
        animating={true}
        style={[styles.centering, {height: 80}]}
        size="large"
      />
    </View>
  )
}
​
const styles = {
  centering: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 8
  }
}

Tak ada yang perlu dijelaskan dari code di atas, karena hanya sebuah component biasa yang di dalamnya terdapat ActivityIndicator yang akan memicu efek loading. Langkah berikutnya adalah dengan membuat service API, buka file api.js yang terdapat di dalam folder src/services, kemudian modifikasi menjadi seperti ini:

import { setListener, pushData, initialize, signup, login } from './firebase';
export const initApi = () => initialize();
​
export const getMessages = (updaterFn) => setListener('messages', updaterFn);
export const postMessage = (message) => {
    if (Boolean(message)) {
        pushData('messages', {
            incoming: false,
            message
        })
    }
}
​
export {
    login,
    signup
}

Pada file firebase.js, tambahkan function login dan signup berikut:

export const login = (email, pass) =>
    firebase.auth()
    .signInWithEmailAndPassword(email, pass)
​
export const signup = (email, pass) =>
    firebase.auth().createUserWithEmailAndPassword(email, pass);

Penjelasan: Masing-masing dari function diatas menerima value email dan password, dimana akan dikirimkan ke Firebase untuk melakukan otentikasi baik berupa login maupun signup.

Sampai pada tahap ini fitur login telah selesai dan siap digunakan, adapun tampilannya tampak seperti dibawah ini

Karena kita belum memiliki user, maka buat file Signup.js di dalam folder src/screens, kemudian masukkan code berikut:

import React from 'react';
import { signup } from '../services/api';
import { View, StyleSheet, Image, ScrollView, TextInput, Button, Text, Keyboard, TouchableOpacity } from 'react-native';
import { NavigationActions } from 'react-navigation';
​
export default class Login extends React.Component {
    static navigationOptions = {
        header: null
    }
​
    state = {
        user: '',
        password: '',
        isAuthenticated: false
    }
​
    async submit() {
        try {
            const response = await signup(this.state.user, this.state.password)
            this._user.clear();
            this._password.clear();
            Keyboard.dismiss();
            this.isAuthenticated = true;
            this.props.navigation.dispatch(
                NavigationActions.reset({
                    index: 0,
                    actions: [
                        NavigationActions.navigate({ routeName: 'home' })
                    ]
                })
            );
        } catch ({ message }) {
            this.setState({
                error: message
            })
        }
    }
    render() {
        return (
            <View
                style={styles.container}>
                <Image
                    style={[ styles.logo ]}
                    source={require('../assets/img/whatsapplogo.png')} />
                <ScrollView style={styles.container}>
                    <TextInput
                        ref={(textInput) =>this._user = textInput }
                        style={styles.inputField}
                        value={this.state.text}
                        onChangeText={(user) => this.setState({user})}
                        onSubmitEditing={(event) => this._password.focus()}
                        editable={true}
                        maxLength={40}
                        multiline={false}
                        placeholder="Masukkan Email"
                    />
                    <TextInput
                        ref={(textInput) =>this._password = textInput }
                        style={styles.inputField}
                        value={this.state.text}
                        onChangeText={(password) => this.setState({password})}
                        onSubmitEditing={(event) => this.submit()}
                        editable={true}
                        secureTextEntry={true}
                        maxLength={40}
                        multiline={false}
                        placeholder="Masukkan Password"
                    />
                    { this.state.error &&
                        <View style={styles.validationErrors}>
                            <Text style={styles.error}>{this.state.error}</Text>
                        </View>
                    }
                    <View style={styles.buttonStyle}>
                        <Button
                            onPress={() => this.submit()} 
                            title="Daftar" />
                    </View>
                    <View style={styles.redirectLink}>
                        <Text>Sudah punya akun? </Text>
                        <TouchableOpacity onPress={() =>
                        this.props.navigation.navigate('login')}>
                        <Text style={styles.link}>Masuk</Text>
                        </TouchableOpacity>
                    </View>
                    <View style={styles.copyright}>
                        <Text style={{fontSize: 18, color: '#19B5FE'}}>https://daengweb.id</Text>
                    </View>
                </ScrollView>
            </View>
        );
    }
}
​
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white'
  },
  logo: {
    width: '100%',
    height: 200
  },
  inputField: {
    marginTop: 20,
    alignSelf: 'center',
    height: 55,
    width: '80%',
    backgroundColor: '#FAFAFA',
    borderWidth: 1,
    paddingHorizontal: 10,
    borderRadius: 10,
    borderColor: "#CACACA"
  },
  redirectLink: {
    flex: 1,
    flexDirection: 'row',
    alignSelf: 'center'
  },
  link: {
    color: 'blue'
  },
  validationErrors: {
    flexDirection: 'row',
    justifyContent: 'center',
  },
  error: {
    marginTop: 10,
    textAlign: 'center',
    color: 'red'
  },
  buttonStyle: {
    marginTop: 15,
    flex: 1
  },
  copyright: {
    marginTop: 15,
    flex: 1,
    alignSelf: 'center'
  }
})

Tak ada yang perlu dijelaskan dari code diatas, karena hampir mirip dengan Login.js. Adapun tampilannya tampak seperti ini:

Kesimpulan

Membuat fitur authentication diatas telah mengajari kita banyak hal bagaimana bekerja dengan React Native, sebuah case yang sederhana yang bisa mengasah logika kita untuk mengerti alur dari sebuah fitur yang diinginkan. Maka kunci dari belajar pemrograman adalah Repeat. Ohya, code lengkapnya dapat kamu download di Github. Semoga bermanfaat.

Category:
Share:

Comments