diff --git a/react-native/ChatApp/components/DiscussionsScreen.js b/react-native/ChatApp/components/DiscussionsScreen.js index e825df475653c0a13a48c445d3f08b499050e1ee..42d4ff0e68eca9e6545224bb2014ff5cb97d7b75 100644 --- a/react-native/ChatApp/components/DiscussionsScreen.js +++ b/react-native/ChatApp/components/DiscussionsScreen.js @@ -18,14 +18,24 @@ class DiscussionsScreen extends React.Component { render() { return ( <Stack.Navigator initialRouteName="List"> - <Stack.Screen name="List" component={ListScreen} options={{ title: "Discussions", headerRight: () => ( - <Button - icon={<Icon solid name='plus' type='font-awesome-5'/>} - onPress={() => alert('Nouvelle discussion')} - type="clear" + <Stack.Screen + name="List" + children={(props) => <ListScreen {...props} updateAuthentication={this.props.updateAuthentication}/>} + options={{ + title: "Discussions", headerRight: () => ( + <Button + icon={<Icon solid name='plus' type='font-awesome-5' />} + onPress={() => alert('Nouvelle discussion')} + type="clear" + /> + ), + }} + /> + <Stack.Screen + name="Messages" + children={(props) => <MessagesScreen {...props} updateAuthentication={this.props.updateAuthentication}/>} + options={({ route }) => ({ title: route.params.title })} /> - ), }}/> - <Stack.Screen name="Messages" component={MessagesScreen} options={({ route }) => ({ title: route.params.title })}/> </Stack.Navigator> ) } diff --git a/react-native/ChatApp/components/ListScreen.js b/react-native/ChatApp/components/ListScreen.js index ef61298c982fa97a52d97611b6a35b73972c9b5f..4645b43322d05bf39426b78f7ae56d4b66c166db 100644 --- a/react-native/ChatApp/components/ListScreen.js +++ b/react-native/ChatApp/components/ListScreen.js @@ -4,89 +4,7 @@ import { FlatList } from 'react-native'; import { ListItem, Icon } from 'react-native-elements'; - -const currentUser = { - name: "Guillaume", - id: 1 -} - -const list = [ - { - id: 1, - title: 'Conversation 1', - messages: [ - { - author: { - name: "Brian", - id: 2 - }, - id: 7, - date: "2021-01-24T20:25:37.705Z", - message: "Yo !" - }, - { - author: { - name: "Guillaume", - id: 1 - }, - id: 1, - date: "2021-01-25T20:25:38.705Z", - message: "Yo !" - }, - { - author: { - name: "Brian", - id: 2 - }, - id: 2, - date: "2021-01-25T20:25:38.705Z", - message: "Salut !" - }, - { - author: { - name: "Julien", - id: 3 - }, - id: 3, - date: "2021-01-25T20:25:38.705Z", - message: "Bonsoir !" - }, - { - author: { - name: "Elise", - id: 4 - }, - id: 4, - date: "2021-01-25T20:25:38.705Z", - message: "Bonjour !" - } - ] - }, - { - id: 2, - title: 'Conversation 2', - messages: [ - { - author: { - name: "Guillaume", - id: 1 - }, - id: 5, - date: "2021-01-25T20:25:38.705Z", - message: "Salut toi !" - }, - { - author: { - name: "Brian", - id: 2 - }, - id: 6, - date: "2021-01-25T20:25:38.705Z", - message: "Salutations monsieur" - } - ] - } -] +import { AsyncStorage } from 'react-native'; class ListScreen extends React.Component { @@ -94,6 +12,64 @@ class ListScreen extends React.Component { super(props); + this.state = { + list: [] + } + + } + + async componentDidMount() { + let status = null; + + //get rooms from API + try { + const token = await AsyncStorage.getItem('@token'); + //if token is stored, user is logged in + if (token !== null) { + fetch("http://localhost:3000/rooms", { + method: 'GET', + headers: { + Authorization: "Bearer " + token + } + }) + .then(response => { + status = response.status; + return response.json(); + }) + .then(async (json) => { + + //OK Status : we store the rooms list in list state + if (status == 200) { + this.setState({ list: json }); + } + + //Unauthorized status : token has expired, we force user to login to continue + else if (status == 401) { + this.props.updateAuthentication(); + } + + //Handled error status + else if ("error" in json) { + console.warn(json.error); + } + + //Unhandled error status + else { + console.warn("Unhandled error"); + } + + }) + .catch(async (error) => { + //Error fetching url + }); + } + //token is not stored, user is not logged in + else { + this.props.updateAuthentication(); + } + } catch (error) { + //Error fetching data + } } keyExtractor = (item, index) => index.toString(); @@ -103,13 +79,13 @@ class ListScreen extends React.Component { <View style={{ flex: 1 }}> <FlatList keyExtractor={this.keyExtractor} - data={list} + data={this.state.list} renderItem={({ item }) => ( - <ListItem bottomDivider onPress={() => this.props.navigation.navigate('Messages', { title: item.title, messages: item.messages, currentUser: currentUser })}> + <ListItem bottomDivider onPress={() => this.props.navigation.navigate('Messages', { title: item.name, id: item._id })}> <Icon solid name='comment' type='font-awesome-5' /> <ListItem.Content> - <ListItem.Title>{item.title}</ListItem.Title> - <ListItem.Subtitle>{item.subtitle}</ListItem.Subtitle> + <ListItem.Title>{item.name}</ListItem.Title> + <ListItem.Subtitle>{item.description}</ListItem.Subtitle> </ListItem.Content> <ListItem.Chevron /> </ListItem> diff --git a/react-native/ChatApp/components/MessagesScreen.js b/react-native/ChatApp/components/MessagesScreen.js index 973eb57dc64c46f7aab14530050f7c7116fef158..b71dac0a2818a4590c3a7c90199a4c79b430f4c3 100644 --- a/react-native/ChatApp/components/MessagesScreen.js +++ b/react-native/ChatApp/components/MessagesScreen.js @@ -1,6 +1,7 @@ -import React, { useState, useCallback, useEffect } from 'react'; -import { View, Text, StyleSheet } from 'react-native'; +import React from 'react'; +import { View, Text, StyleSheet, ActivityIndicator } from 'react-native'; import { GiftedChat, utils, Bubble } from 'react-native-gifted-chat'; +import { AsyncStorage } from 'react-native'; const { isSameUser, isSameDay } = utils @@ -13,37 +14,163 @@ class MessagesScreen extends React.Component { super(props); this.state = { - messages: [] + messages: [], + user: null, + isLoading: true } - + this.onSend = this.onSend.bind(this); } - componentDidMount() { - let messages = []; - this.props.route.params.messages.forEach(message => { - messages.push( - { - _id: message.id, - text: message.message, - createdAt: message.date, - user: { - _id: message.author.id, - name: message.author.name, - avatar: 'https://placeimg.com/140/140/any', - }, - }, - ); - }); - this.setState({ messages: messages }); + async componentDidMount() { + + let status = null; + + //get user from asyncStorage + try { + const user = await AsyncStorage.getItem('@user'); + if (user !== null) { + await this.setState({ user: JSON.parse(user) }); + } + else { + this.props.updateAuthentication(); + } + } catch (error) { + console.warn(error); + } + + //get messages from API + try { + const token = await AsyncStorage.getItem('@token'); + //if token is stored, user is logged in + if (token !== null) { + fetch("http://localhost:3000/rooms/" + this.props.route.params.id + "/messages", { + method: 'GET', + headers: { + Authorization: "Bearer " + token + } + }) + .then(response => { + status = response.status; + return response.json(); + }) + .then(async (json) => { + + //OK Status : we update message state with room messages from API + if (status == 200) { + let messages = []; + + json.forEach(message => { + messages.push( + { + _id: message._id, + text: message.body, + createdAt: message.date, + user: { + _id: message.author, + name: message.author, + avatar: 'https://placeimg.com/140/140/any', + }, + }, + ); + }); + + this.setState({ messages: messages }); + } + + //Unauthorized status : token has expired, we force user to login to continue + else if (status == 401) { + this.props.updateAuthentication(); + } + + //Handled error status + else if ("error" in json) { + console.warn(json.error); + } + + //Unhandled error status + else { + console.warn("Unhandled error"); + } + + }) + .catch(async (error) => { + //Error fetching url + }); + } + //token is not stored, user is not logged in + else { + this.props.updateAuthentication(); + } + } catch (error) { + //Error fetching data + } + + this.setState({ isLoading: false }) } - onSend(messages = []) { - this.setState((previousState) => { - return { - messages: GiftedChat.append(previousState.messages, messages), - }; - }); + async onSend(messages = []) { + let status = null; + + //post message in room with API + try { + const token = await AsyncStorage.getItem('@token'); + //if token is stored, user is logged in + if (token !== null) { + fetch('http://localhost:3000/messages', { + method: 'POST', + headers: { + Accept: 'application/json', + Authorization: "Bearer " + token, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + body: messages[0].text, + roomId: this.props.route.params.id, + }) + }) + .then(response => { + status = response.status; + return response.json(); + }) + .then(async (json) => { + + //OK Status : we update messages state with the message we post + if (status == 200) { + this.setState((previousState) => { + return { + messages: GiftedChat.append(previousState.messages, messages), + }; + }); + } + + //Unauthorized status : token has expired, we force user to login to continue + else if (status == 401) { + this.props.updateAuthentication(); + } + + //Handled error status + else if ("error" in json) { + console.warn(json.error); + } + + //Unhandled error status + else { + console.warn("Unhandled error"); + } + + }) + .catch(async (error) => { + //Error fetching url + }); + } + //token is not stored, user is not logged in + else { + this.props.updateAuthentication(); + } + } catch (error) { + //Error fetching data + } } renderBubble(props) { @@ -77,17 +204,24 @@ class MessagesScreen extends React.Component { } render() { - return ( - <GiftedChat - renderBubble={this.renderBubble} - messages={this.state.messages} - onSend={this.onSend} - user={{ - _id: this.props.route.params.currentUser.id, - }} - locale={'fr'} - /> - ) + if (this.state.isLoading) + return ( + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> + <ActivityIndicator size="large" /> + </View> + ) + else + return ( + <GiftedChat + renderBubble={this.renderBubble} + messages={this.state.messages} + onSend={this.onSend} + user={{ + _id: this.state.user.id, + }} + locale={'fr'} + /> + ) } };