Alameda Dev.
Published in

Alameda Dev.

React Native Chat App Study

This is a chat app study, In here we try to study an implementation of a chat app using Firebase auth and Pusher ChatKit.

Create the base React Native app

import React, { Component } from 'react'
import {
StyleSheet,
KeyboardAvoidingView,
View,
Text,
TextInput,
TouchableOpacity
} from 'react-native'
export default class LoginScreen extends Component {
constructor(props){
super(props)
this.state = {
email: null,
password: null
}
}
updateFields(field, value){
this.setState({[field]: value})
}
onButtonPress(){
// auth with firebase
}
render() {
return (
<KeyboardAvoidingView style={styles.container} behavior="padding" enabled>
<View style={styles.container}>
<Text style={styles.text}>Login Form</Text>
<View>
<Text style={styles.text}>Enter your email</Text>
<TextInput style = {styles.input}
autoCapitalize="none"
onChangeText={(e) => this.updateFields('email', e)}
autoCorrect={false}
keyboardType='email-address'
placeholder='Enter your email'/>
</View>
<View>
<Text style={styles.text}>Enter your password</Text>
<TextInput style = {styles.input}
onChangeText={(e) => this.updateFields('password', e)}
autoCapitalize="none"
autoCorrect={false}
placeholder='Enter your password'/>
</View>
<TouchableOpacity
style={styles.buttonContainer}
onPress={this.onButtonPress}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
text: {
fontSize: 18,
paddingVertical: 10
},
input: {
width: 200,
height: 40,
backgroundColor: 'rgba(225,225,225,0.2)',
borderWidth: 1,
borderColor: 'rgba(225,225,225,0.9)',
marginBottom: 10,
padding: 10
},
buttonContainer: {
backgroundColor: '#2980b6',
paddingVertical: 15,
paddingHorizontal: 15
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontWeight: '700'
}
});

Integrate firebase and add auth login with firebase (IOs Only)

npm install --save react-native-firebase

Follow our integration guide here https://bouncingshield.github.io/React-Native-Firebase-Integration/

Create basic chat screen

import React, { Component } from 'react'
import {
StyleSheet,
View,
Text,
} from 'react-native'
export default class ChatScreen extends Component { render() {
return (
<View style={styles.container}>
<Text>Chat SCreen</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});

Create Basic auth methods

import React, { Component } from 'react'
import {
StyleSheet,
KeyboardAvoidingView,
View,
Text,
TextInput,
TouchableOpacity
} from 'react-native'
import firebase from 'react-native-firebase'; export default class LoginScreen extends Component {
constructor(props){
super(props)
this.state = {
email: '',
password: '',
error: null
}
this.onButtonPress = this.onButtonPress.bind(this)
}
updateFields(field, value){
this.setState({[field]: value})
}
onButtonPress(){
if (this.state.email && this.state.password) {
firebase.auth().signInWithEmailAndPassword(
this.state.email, this.state.password
).then(() => {
this.setState({ isAuthenticated: true });
}).catch((error) => {
this.setState({error: error.message})
});
} else {
this.setState({error: 'Please add the email address and password'})
}
}
render() {
//firebase.auth().signOut()
return (
<KeyboardAvoidingView style={styles.container} behavior="padding" enabled>
<View style={styles.container}>
<Text style={styles.text}>Login Form</Text>
<View>
<Text style={styles.text}>Enter your email</Text>
<TextInput style = {styles.input}
autoCapitalize="none"
onChangeText={(e) => this.updateFields('email', e)}
autoCorrect={false}
keyboardType='email-address'
placeholder='Enter your email'/>
</View>
<View>
<Text style={styles.text}>Enter your password</Text>
<TextInput style = {styles.input}
onChangeText={(e) => this.updateFields('password', e)}
autoCapitalize="none"
autoCorrect={false}
placeholder='Enter your password'/>
</View>
<View>
<Text style={styles.error}>{this.state.error && (this.state.error) }</Text>
</View>
<TouchableOpacity
style={styles.buttonContainer}
onPress={this.onButtonPress}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
text: {
fontSize: 18,
paddingVertical: 10
},
input: {
width: 200,
height: 40,
backgroundColor: 'rgba(225,225,225,0.2)',
borderWidth: 1,
borderColor: 'rgba(225,225,225,0.9)',
marginBottom: 10,
padding: 10
},
buttonContainer: {
backgroundColor: '#2980b6',
paddingVertical: 15,
paddingHorizontal: 15
},
buttonText: {
color: '#fff',
textAlign: 'center',
fontWeight: '700'
},
error: {
color: 'red',
paddingVertical: 15
}
});

Add navigation dependency

npm install react-navigation
npm install --save react-native-gesture-handler

Add navigation config

Follow the guide here https://reactnavigation.org/docs/en/app-containers.html

Show basic list of messages

import React, { Component } from 'react'
import { Dimensions, StyleSheet, View, Text, FlatList } from 'react-native'
const { width, height } = Dimensions.get("window") const DUMMY_DATA = [{
senderId: 'Os',
text: 'Hey, how is it going?'
}, {
senderId: 'Jane',
text: 'Great! How about you?'
}, {
senderId: 'Os',
text: 'Good to hear! I am great as well'
}]
export default class ChatMessageList extends Component {
render() {
return(
<View style={styles.messagesContainer}>
<FlatList
data={DUMMY_DATA}
renderItem={({item, index}) => (
<View key={index} style={styles.message}>
<Text style={styles.messageUsername}>{item.senderId}:</Text>
<View style={styles.messageTextBox}>
<Text style={styles.messageText}>{item.text}</Text>
</View>
</View>
)}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
messagesContainer: {
flex: 1,
height: height - 200,
paddingHorizontal: 10
},
message: {
marginVertical: 15
},
messageUsername: {
fontSize: 16,
color: '#3e5869',
marginBottom: 6
},
messageTextBox: {
backgroundColor: '#5ea3d0',
paddingVertical: 6,
paddingHorizontal: 8,
borderRadius: 10
},
messageText: {
color: '#ffffff',
fontSize: 18,
}
});

Show list of messages in ChatKit test mode

import React, { Component } from 'react'
import { Dimensions, StyleSheet, View, Text, FlatList } from 'react-native'
import { ChatManager, TokenProvider } from '@pusher/chatkit-client'
const { width, height } = Dimensions.get("window") export default class ChatMessageList extends Component {
constructor(props){
super(props)
this.state = {
currentUser: null,
roomId: 'YOUR ROOM ID',
messages: []
}
this.getChatKitUser()
}
getChatKitUser(){
// Config ChatKit
const chatManager = new ChatManager({
instanceLocator: 'YPUR INSTANCE LOCATOR',
userId: 'YOUR USER ID',
tokenProvider: new TokenProvider({ url: 'YOUT TEST TOKEN PROVIDER' })
})
// Connect to Room
chatManager.connect()
.then(currentUser => {
currentUser.subscribeToRoom({ roomId: this.state.roomId })
this.setState({ currentUser: currentUser }, this.getMessages)
})
}
getMessages(){
let { currentUser } = this.state
currentUser.fetchMessages({
roomId: this.state.roomId,
direction: 'newer',
limit: 10,
}).then(messages => {
this.setState({ messages })
console.log(messages)
}).catch(err => {
console.log(`Error fetching messages: ${err}`)
})
}
render() {
return(
<View style={styles.messagesContainer}>
<FlatList
data={this.state.messages}
renderItem={({item, index}) => (
<View key={index} style={styles.message}>
<Text style={styles.messageUsername}>{item.senderId}:</Text>
<View style={styles.messageTextBox}>
<Text style={styles.messageText}>{item.text}</Text>
</View>
</View>
)}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
messagesContainer: {
flex: 1,
height: height - 200,
paddingHorizontal: 10
},
message: {
marginVertical: 15
},
messageUsername: {
fontSize: 16,
color: '#3e5869',
marginBottom: 6
},
messageTextBox: {
backgroundColor: '#5ea3d0',
paddingVertical: 6,
paddingHorizontal: 8,
borderRadius: 10
},
messageText: {
color: '#ffffff',
fontSize: 18,
}
});

Create a server to use

To create a user, we need a server that does the request to chatkit, we can’t do it from the client. I am going to use chatkit-server-ruby and sinatra https://github.com/pusher/chatkit-server-ruby http://sinatrarb.com/

require 'sinatra'
require 'sinatra/contrib'
require "sinatra/reloader" if development?
# Chatkit
require 'chatkit'
chatkit = Chatkit::Client.new({
instance_locator: YOUR_INSTACE_LOCATOR,
key: YOUR_KEY,
})
get '/' do
"hello world"
end
get '/create_user/:user_name' do
begin
response = chatkit.create_user({ id: params['user_name'], name: params['user_name'] })
logger.info response.inspect
return response['body']
rescue => e
logger.info e.inspect
return "There was an error with the user creation"
end
end
get '/get_user/:user_name' do
begin
response = chatkit.get_user({ id: params['user_name'] })
logger.info response.inspect
return response['body']
rescue => e
logger.info e.inspect
return "There was an error with getting the user"
end
end

To run the server

foreman start

Create a new user

getChatKitUser(){
fetch('http://localhost:5000/get_user/'+this.state.userName)
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.name) {
//connect to room
console.log('connect to room after getChatKitUser')
}
}).catch((error)=> {
// create ChatKit user
console.log('create chatkit user')
this.createChatKitUser()
})
}
createChatKitUser(){
fetch('http://localhost:5000/create_user/'+this.state.userName)
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.name) {
//connect to room
console.log('connect to room after createChatKitUser')
}
}).catch((error)=> {
console.log('error', error)
})
}

Connect to a room

connectToRoom(roomId = this.state.roomId) {
console.log('lets connect to a room')
fetch('http://localhost:5000/connect_user_to_room/'+ this.state.userName +'/' + roomId)
.then((response) => response.json())
.then((responseJson) => {
console.log('responseJson', responseJson)
// lets get the messages
}).catch((error)=> {
console.log('error', error)
})
}
get '/connect_user_to_room/:user_id/:room_id' dobegin
response = chatkit.add_users_to_room({
room_id: params[:room_id],
user_ids: [params[:user_id]]
})
logger.info response.inspect
return response[:body].to_json
rescuee
logger.info e.inspect
return "There was an error with adding the user to the room"
end
end

Get messages

getMessages(roomId = this.state.roomId) {
fetch('http://localhost:5000/get_messages/' + roomId)
.then((response) => response.json())
.then((responseJson) => {
this.setState({messages: responseJson.reverse(), ready: true})
}).catch((error)=> {
console.log('getMessages error', error)
})
}
get '/get_messages/:room_id' do
begin
response = chatkit.get_room_messages({
room_id: params[:room_id],
limit: 10,
})
logger.info response.inspect
return response[:body].to_json
rescuee
logger.info e.inspect
return "There was an error with getting the room messages"
end
end

Send messages

onMessageSend(){
console.log('onMessageSend')
let message = this.state.message
fetch('http://localhost:5000/send_message/' + this.state.roomId + '/' + this.state.userName + '/' + message)
.then((response) => response.json())
.then((responseJson) => {
this.getMessages()
this.setState({message: null})
}).catch((error)=> {
console.log('onMessageSend error', error)
})
}

Bouncing Shield is part of Alameda dev Team. If you have any questions, you can contact us at hola@alamedadev.com.
And https://alamedadev.com

--

--

--

We are a small agency 100% Remote. Specialized in Design and Development of Mobile Apps, Web and advanced software with React Ecosystem.

Recommended from Medium

Top 6 reasons to convert website into react native mobile app

Learn Deno: Chat app

Declarative Decorating in AWS Lambdas

Implementing two way Data Binding without using any framework.

JavaScript Booking Calendar

News Reader Web App using React/Redux with Ruby on Rails API

https://t.co/htKB16bXYt

Laravel 8 Authentication using Jetstream Example

Laravel 8 Authentication using Jetstream Example Login Page

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alameda Dev.

Alameda Dev.

¡Hola! We are a team 100% Remote. Specialized Development of Mobile Apps, Web and advanced software with React and ReactNative. www.alamedadev.com

More from Medium

Deep linking React Native — iOS and Android using Branch

branch.io — dashboard

Ads Alert! Integration of Huawei Ads Kit in Application using React Native

Universal Links (App Links) in React Native for iOS & Android

React Native Notes 28: How to prevent go back with React Navigation v6?