Chat com React Native e Firebase
Tags: reactnative, chat, firebase, login
Published: 2019-12-28 01:54:45


Antes de mais nada, iremos usar partes de dois tutoriais que já disponibilizei.
1) Siga o tutorial do link abaixo a partir da parte que contém os prints da tela do Android Studio. Esse passo requer que você já tenha seu projeto criado e rodando. 
[Login com Google usando React Native](https://dev.to/mensonones/react-native-google-login-1b18)
2) Siga todo o tutorial do link abaixo. No final vou disponibilizar as modificações feitas no arquivo deste tutorial, mas é importante seguir o passo a passo.
[Login com LinkedIn usando React Native](https://dev.to/mensonones/login-com-linkedin-usando-react-native-288n)

Acesse o console do firebase da sua conta, abra seu projeto criado especialmente para este tutorial. No menu lateral, acesse **Database**, em seu **Cloud Firestore** crie uma coleção chamada **groupChat**. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/uc07js7cws1scwukscot.png)

Outra coisa importante para essa parte do firebase é que você adicione um app **android** e outro app **web** ao seu projeto. A imagem abaixo mostra onde fica essa opção.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/npen06buwvtyusldr0b7.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/opbdmjiaz7o3mta5zz1c.png)

Ao selecionar **android**, irá aparecer uma outra página para que você possa preencher os dados necessários, onde a chave **SHA1** obtida **no passo 1** será preenchida. Ao final é disponibilizado um arquivos chamado **google-services.json**  **que você precisa salvar na pasta app que fica dentro da pasta android de seu projeto.**  A imagem abaixo mostra como é a página em questão.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zuk7jpb1nfbt141pu5id.png)

Ao selecionar **web**, irá abrir uma página para que você preencha alguns dados e o mais importante nessa parte é copiar os dados que serão disponibilizados pelo firebase ao final. Copie e salve os dados disponibilizados. A imagem abaixo mostra como é a página. 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ds3pc2nilezv4002c2yh.png)

Em seu projeto, crie um arquivo chamado **firebaseSDK.js** e dentro dele você vai colocar os dados obtidos no passo anterior. Abaixo um exemplo do arquivo:

```javascript
import firebase from  '@react-native-firebase/app';

const config = {

apiKey:  '*****',

authDomain:  '*****',

databaseURL:  '*****',

projectId:  '*****',

storageBucket:  '******',

messagingSenderId:  '*****',

appId:  '******',

};

let Firebase;

if (!firebase.apps.length) {

Firebase = firebase.initializeApp(config);

}

export  default Firebase;
```

Iremos precisar de duas dependências para a parte do Firebase em nosso projeto. A instalação e configuração de cada uma é mostrada nos links que irei disponibilizar abaixo:
1) [https://invertase.io/oss/react-native-firebase/quick-start/existing-project](https://invertase.io/oss/react-native-firebase/quick-start/existing-project)
2) [https://invertase.io/oss/react-native-firebase/v6/firestore/quick-start](https://invertase.io/oss/react-native-firebase/v6/firestore/quick-start)

**Observação:** No passo 1 acima, há uma configuração para android e iOS, recomendo que dê uma olhada para que tudo ocorra bem. Caso use apenas android, como é no meu caso, siga apenas a parte de configuração para android. 

Neste tutorial também é usado outra dependência, ela será útil para a navegação usada no tutorial. Navegue até a raiz do seu projeto pelo terminal e digite o comando abaixo:
```sh
$ yarn add react-navigation
```

Para a parte do chat iremos usar uma lib bastante famosa para esta finalidade. A lib se chama **Gifted Chat** e para adicionar a mesma em seu projeto, acesse a raiz do seu projeto pelo terminal e digite o comando abaixo:

```sh
$ yarn add react-native-gifted-chat
```
Agora irei disponibilizar o código dos arquivos referentes ao **Login e Chat** em si. **Abaixo o código de Login com LinkedIn com algumas alterações para este tutorial**. Neste tutorial o chamei de **Main**.

**Main.js**
```javascript
import React, {useState, useEffect} from  'react';

import {StyleSheet, View, Text, Image} from  'react-native';

import LinkedInModal from  'react-native-linkedin';

import axios from  'axios';

const styles = StyleSheet.create({

container: {

flex:  1,

backgroundColor:  '#fff',

justifyContent:  'center',

alignItems:  'center',

},

});

export  default  function  Main({navigation}) {

const [token, setToken] =  useState('');

const [info, setInfo] =  useState();

const [loading, setLoading] =  useState(true);

  
const instance = axios.create({

baseURL:  'https://api.linkedin.com/v2',

headers: {

Authorization:  'Bearer  '  + token,

},

});

async  function  getInfo() {

await instance

.get(

'/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))',

)

.then(response => {

setInfo(response.data);

setLoading(false);

navigation.navigate('Chat', {

userChat: response.data,

});

})

.catch(error =>  console.log(error));

}

useEffect(() => {

getInfo();

}, [token]);

const renderData = info && (

<>

<Text>{info.firstName.localized.pt_BR}</Text>

<Text>{info.lastName.localized.pt_BR}</Text>

<Image

source={{

uri:

info.profilePicture['displayImage~'].elements[3]['identifiers'][0][

'identifier'

],

}}

style={{

width:  200,

height:  200,

left:  'auto',

right:  'auto',

justifyContent:  'center',

}}

/>

</>

);

return (

<View  style={styles.container}>

<LinkedInModal

clientID="******"

clientSecret="*****"

redirectUri="https://api.linkedin.com/v2/me"

onSuccess={token =>  setToken(token.access_token)}

onError={error =>  console.log(error)}

areaTouchText={{top:  20, bottom:  20, left:  150, right:  150}}

/>

{loading && <Text>{'Loading...'}</Text>}

{renderData}

</View>
);

}

Main.navigationOptions = {

title:  'Main',

};
```
Agora o código do **Chat.js**

```javascript
import React, {useState, useEffect} from  'react';

import {View, Text} from  'react-native';

import firestore from  '@react-native-firebase/firestore';

import {GiftedChat, Bubble} from  'react-native-gifted-chat';

function  Chat(props) {

const [user, setUser] =  useState(props.navigation.getParam('userChat'));

const [messages, setMessages] =  useState([]);

useEffect(() => {

console.log(user);

const db =  firestore();

db.collection('groupChat')

.orderBy('createdAt', 'desc')

.onSnapshot(function(doc) {

let receivedMessages = [];

doc.docs.map(doc => {

receivedMessages.push({

_id: doc.id,

...doc.data(),

});

});

setMessages(GiftedChat.append(messages, receivedMessages));

});

}, [user]);

  

function  onSend([messages]) {

firestore()

.collection('groupChat')

.add(messages);

}

function  renderBubble(props) {

return (

<View>

<Text  style={{left:  90}}>{props.currentMessage.user.name}</Text>

<Bubble

{...props}

/>

</View>

);

}

return (

<GiftedChat

dateFormat={'DD-MM-YYYY'}

timeFormat={'h:mm'}

renderBubble={renderBubble}

messages={messages}

onSend={messages =>  onSend(messages)}

user={{

id: user.id,

name: user.firstName.localized.pt_BR,

}}

/>

);

}

Chat.navigationOptions = {

title:  'Chat',

};

export  default Chat;
```

E por último o código de rotas

**routes.js**

```javascript
import {createAppContainer, createSwitchNavigator} from  'react-navigation';

import Main from  './Main';
import Chat from  './Chat';

const Routes =  createAppContainer(
createSwitchNavigator({
Main: Main,
Chat: Chat,
}),
);

export  default Routes;
```

O Chat em questão funciona como uma sala única para várias pessoas. Abaixo segue imagens do app em funcionamento e como deve ficar:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/3f1j8lqwbd857m4jbb61.jpg)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/5ltgvdkksn72rfbsp2gr.jpg)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/noqkiuaop6ohyrrbtzos.jpg)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0axd1cbf5idm6h4773in.jpg)

É isto! Esse é bem mais trabalhoso, mas creio que deu para passar +/- como é e espero que consigam seguir o tutorial e funcione direitinho :) se surgir dúvidas é só comentar. Até a próxima :)