From 50612ed5ee7ed1d5c5eccac67618fdaa794277fb Mon Sep 17 00:00:00 2001
From: COURTES Guillaume <guillaumecourtes88@gmail.com>
Date: Sat, 19 Jun 2021 18:24:25 +0200
Subject: [PATCH] add menu on item long press; add update discussion pages; fix
 api changes; add menu & multiselect packages;

---
 react-native/ChatApp/App.js                   |   5 +-
 .../components/AddUsersDiscussionScreen.js    | 195 ++++++++++++++++++
 .../components/AuthenticateNavigation.js      | 134 +++++++++++-
 .../components/CreateDiscussionScreen.js      |   2 +-
 .../ChatApp/components/DiscussionsScreen.js   |  97 ++++++++-
 react-native/ChatApp/components/ListScreen.js |  61 +++++-
 .../ChatApp/components/MessagesScreen.js      |   4 +-
 .../components/UpdateDiscussionScreen.js      | 109 ++++++++++
 react-native/ChatApp/package-lock.json        |  10 +
 react-native/ChatApp/package.json             |   2 +
 10 files changed, 597 insertions(+), 22 deletions(-)
 create mode 100644 react-native/ChatApp/components/AddUsersDiscussionScreen.js
 create mode 100644 react-native/ChatApp/components/UpdateDiscussionScreen.js

diff --git a/react-native/ChatApp/App.js b/react-native/ChatApp/App.js
index 87bba2081..7455f7890 100644
--- a/react-native/ChatApp/App.js
+++ b/react-native/ChatApp/App.js
@@ -1,9 +1,12 @@
 import React from 'react';
 import AuthenticateNavigation from './components/AuthenticateNavigation'
+import { MenuProvider } from 'react-native-popup-menu';
 
 export default function App() {
   
   return (
-    <AuthenticateNavigation />
+    <MenuProvider>
+      <AuthenticateNavigation />
+    </MenuProvider>
   );
 }
diff --git a/react-native/ChatApp/components/AddUsersDiscussionScreen.js b/react-native/ChatApp/components/AddUsersDiscussionScreen.js
new file mode 100644
index 000000000..c079d6cec
--- /dev/null
+++ b/react-native/ChatApp/components/AddUsersDiscussionScreen.js
@@ -0,0 +1,195 @@
+import React from 'react';
+import {
+  View,
+  StyleSheet,
+  KeyboardAvoidingView,
+  ActivityIndicator,
+  Dimensions
+} from 'react-native';
+import { Input, Button, Text } from 'react-native-elements';
+import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import Icon from 'react-native-vector-icons/MaterialIcons';
+import SectionedMultiSelect from 'react-native-sectioned-multi-select';
+
+const windowHeight = Dimensions.get('window').height;
+
+class AddUsersDiscussionScreen extends React.Component {
+
+  constructor(props) {
+
+    super(props);
+
+    this.state = {
+      users: [],
+      selectedUsers: [],
+      user: null,
+      isLoading: true
+    }
+
+  }
+
+  async getUsers() {
+
+    let defaultUsers = this.props.route.params.item.users.map(
+      user => user._id
+    );
+    defaultUsers = [...new Set(defaultUsers)];
+    this.setState({selectedUsers: defaultUsers});
+
+    let status = null;
+
+    //get users from API
+    try {
+      const token = await AsyncStorage.getItem('@token');
+      //if token is stored, user is logged in
+      if (token !== null) {
+        fetch("http://163.172.178.146:3000/users", {
+          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({ users: json });
+            console.log(this.state.users);
+          }
+
+          //Unauthorized status : token has expired, we force user to login to continue
+          else if (status == 401) {
+            this.props.logoutAuthentication();
+          }
+
+          //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.logoutAuthentication();
+      }
+    } catch (error) {
+      //Error fetching data
+    }
+  }
+
+  async componentDidMount() {
+    //get user from asyncStorage
+    try {
+      const user = await AsyncStorage.getItem('@user');
+      if (user !== null) {
+        await this.setState({ user: JSON.parse(user) });
+      }
+      else {
+        this.props.logoutAuthentication();
+      }
+    } catch (error) {
+      console.warn(error);
+    }
+
+    await this.getUsers();
+
+    this.setState({ isLoading: false });
+
+  }
+
+  updateDiscussion() {
+    this.props.updateDiscussion(this.props.route.params.item._id, this.props.route.params.item.name, this.props.route.params.item.description, this.state.selectedUsers);
+  }
+
+  onSelectedItemsChange = (selectedUsers) => {
+    this.setState({ selectedUsers });
+  };
+
+  render() {
+    if (this.state.isLoading)
+      return (
+        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
+          <ActivityIndicator size="large" />
+        </View>
+      )
+    else
+      return (
+        <View style={{flex: 1, justifyContent: 'center'}}>
+          <View style={{flex: 3, alignItems: 'center', justifyContent: 'center'}}>
+          <FontAwesome5 name={'users'} solid color={'lightgrey'} size={150} />
+          <SectionedMultiSelect
+            items={this.state.users}
+            selectedItems={this.state.selectedUsers}
+            IconRenderer={Icon}
+            uniqueKey="_id"
+            displayKey="username"
+            primary='dodgerblue'
+            itemFontFamily={{
+              fontFamily: Platform.OS === 'android' ? 'normal' : 'Avenir',
+              fontWeight: '200'
+            }}
+            confirmFontFamily={{
+              fontFamily: Platform.OS === 'android' ? 'normal' : 'Avenir',
+              fontWeight: '200'
+            }}
+            confirmText="Confirmer"
+            showDropDowns={true}
+            onSelectedItemsChange={this.onSelectedItemsChange}
+            renderSelectText={() => "Utilisateurs"}
+            searchPlaceholderText="Rechercher"
+            noResultsComponent={
+              <View
+                style={{ marginTop: 20, alignItems: 'center', justifyContent: 'center' }}>
+                <Text>Aucun résultat trouvé</Text>
+              </View>
+            }
+            noItemsComponent={
+              <View
+                style={{ marginTop: 20, alignItems: 'center', justifyContent: 'center' }}>
+                <Text>Aucun éléments trouvé</Text>
+              </View>
+            }
+            styles={{ button: { backgroundColor: "dodgerblue" }, searchBar: {backgroundColor: 'white'}, selectToggle: {backgroundColor: 'white', padding: 10, margin: 5, maxWidth: 250, alignSelf: 'center'} }}
+          />
+          </View>
+          <View style={{flex:1,alignItems: 'center', justifyContent: 'center', width: '100%' }}>
+            <Button
+              containerStyle={styles.customButton}
+              title="Enregistrer"
+              onPress={this.updateDiscussion.bind(this)}
+              buttonStyle={{backgroundColor: 'dodgerblue'}}
+              titleStyle={{ marginLeft: 5 }}
+              icon={
+                <FontAwesome5 name={'user-plus'} solid color={'white'} size={20} />
+              }
+            />
+          </View>
+        </View>
+      )
+  }
+};
+
+const styles = StyleSheet.create({
+  customButton: {
+    borderRadius: 1000,
+    width: 200,
+    textAlign: 'center',
+    backgroundColor: 'red'
+  }
+})
+
+export default AddUsersDiscussionScreen;
\ No newline at end of file
diff --git a/react-native/ChatApp/components/AuthenticateNavigation.js b/react-native/ChatApp/components/AuthenticateNavigation.js
index 1f902a413..fd7df274e 100644
--- a/react-native/ChatApp/components/AuthenticateNavigation.js
+++ b/react-native/ChatApp/components/AuthenticateNavigation.js
@@ -49,7 +49,6 @@ class AuthenticateNavigation extends React.Component {
   }
 
   async logoutAuthentication() {
-    this.setState({isAuthenticated: false});
     try {
       await AsyncStorage.removeItem('@token');
     }
@@ -62,6 +61,7 @@ class AuthenticateNavigation extends React.Component {
     catch(exception) {
       console.warn(exception)
     }
+    this.setState({isAuthenticated: false});
   }
 
   login(username, password) {
@@ -220,6 +220,128 @@ class AuthenticateNavigation extends React.Component {
     }
   }
 
+  async updateDiscussion(id, name, description, users, format = false) {
+    let status = null;
+
+    if (format) {
+      users = users.map(
+        user => user._id
+      );
+    }
+
+    //post room from API
+    try {
+      const token = await AsyncStorage.getItem('@token');
+      //if token is stored, user is logged in
+      if (token !== null) {
+        fetch('http://163.172.178.146:3000/rooms/' + id, {
+          method: 'PUT',
+          headers: {
+            Accept: 'application/json',
+            'Content-Type': 'application/json',
+            Authorization: "Bearer " + token
+          },
+          body: JSON.stringify({
+            name: name,
+            description: description,
+            users: users
+          })
+        })
+        .then(response => {
+          status = response.status;
+          return response.json();
+        })
+        .then(async (json) => {
+          //OK Status : we store the token & the user in local storage
+          if (status == 200) {
+            console.warn("Discussion mise à jour");
+          }
+
+          //Unauthorized status : token has expired, we force user to login to continue
+          else if (status == 401) {
+            this.props.logoutAuthentication();
+          }
+
+          //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.logoutAuthentication();
+      }
+    } catch (error) {
+      //Error fetching data
+    }
+  }
+
+  async deleteDiscussion(id, user) {
+    let status = null;
+
+    //post room from API
+    try {
+      const token = await AsyncStorage.getItem('@token');
+      //if token is stored, user is logged in
+      if (token !== null) {
+        fetch('http://163.172.178.146:3000/rooms/' + id, {
+          method: 'DELETE',
+          headers: {
+            Accept: 'application/json',
+            'Content-Type': 'application/json',
+            Authorization: "Bearer " + token
+          },
+          body: JSON.stringify({
+            user: user
+          })
+        })
+        .then(response => {
+          status = response.status;
+          return response.json();
+        })
+        .then(async (json) => {
+          //OK Status : we store the token & the user in local storage
+          if (status == 200) {
+            console.warn("Discussion supprimée");
+          }
+
+          //Unauthorized status : token has expired, we force user to login to continue
+          else if (status == 401) {
+            this.props.logoutAuthentication();
+          }
+
+          //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.logoutAuthentication();
+      }
+    } catch (error) {
+      //Error fetching data
+    }
+  }
+
   render() {
     if (this.state.isLoading) {
       return (
@@ -261,7 +383,15 @@ class AuthenticateNavigation extends React.Component {
             />
             <Tab.Screen
               name="Discussions"
-              children={(props) => <DiscussionsScreen {...props} addDiscussion={this.addDiscussion.bind(this)} logoutAuthentication={this.logoutAuthentication.bind(this)} />}
+              children={(props) =>
+                <DiscussionsScreen
+                  {...props}
+                  addDiscussion={this.addDiscussion.bind(this)}
+                  updateDiscussion={this.updateDiscussion.bind(this)}
+                  deleteDiscussion={this.deleteDiscussion.bind(this)}
+                  logoutAuthentication={this.logoutAuthentication.bind(this)}
+                />
+              }
               options={{
                 tabBarLabel: 'Discussions',
                 tabBarIcon: ({ color }) => (
diff --git a/react-native/ChatApp/components/CreateDiscussionScreen.js b/react-native/ChatApp/components/CreateDiscussionScreen.js
index 176b262a9..7f29c3614 100644
--- a/react-native/ChatApp/components/CreateDiscussionScreen.js
+++ b/react-native/ChatApp/components/CreateDiscussionScreen.js
@@ -62,7 +62,7 @@ class CreateDiscussionScreen extends React.Component {
           style={{flex:1, alignItems: 'center', justifyContent: 'center' }}
         >
           
-          <FontAwesome5 name={'users'} solid color={'lightgrey'} size={150} />
+          <FontAwesome5 name={'comment'} solid color={'lightgrey'} size={150} />
           <View style={{alignItems: 'center', justifyContent: 'center', width: '100%' }}>
             <Input
               placeholder="Nom"
diff --git a/react-native/ChatApp/components/DiscussionsScreen.js b/react-native/ChatApp/components/DiscussionsScreen.js
index f60dab8d5..1b871e44e 100644
--- a/react-native/ChatApp/components/DiscussionsScreen.js
+++ b/react-native/ChatApp/components/DiscussionsScreen.js
@@ -1,10 +1,23 @@
 import React from 'react';
-import { Icon, Button } from 'react-native-elements';
+import {
+  View,
+  FlatList
+} from 'react-native';
+import { Icon, Button, Text } from 'react-native-elements';
 import { createStackNavigator } from '@react-navigation/stack';
 
 import ListScreen from './ListScreen'
 import MessagesScreen from './MessagesScreen'
 import CreateDiscussionScreen from './CreateDiscussionScreen'
+import UpdateDiscussionScreen from './UpdateDiscussionScreen'
+import AddUsersDiscussionScreen from './AddUsersDiscussionScreen'
+import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
+import {
+  Menu,
+  MenuOptions,
+  MenuOption,
+  MenuTrigger
+} from 'react-native-popup-menu';
 
 const Stack = createStackNavigator();
 
@@ -16,16 +29,30 @@ class DiscussionsScreen extends React.Component {
 
   }
 
+  openMenu = (id) => {
+    this["user-list" + id].open();
+  };
+
+ renderItem = ({ item }) => (
+    <Text style={{fontSize: 15, margin: 5, marginLeft: 15}}><FontAwesome5 name={'user-alt'} solid color={'lightgrey'} size={15} /> {item.username}</Text>
+  );
+
   render() {
     return (
       <Stack.Navigator initialRouteName="List">
         <Stack.Screen
           name="List"
-          children={(props) => <ListScreen {...props} logoutAuthentication={this.props.logoutAuthentication}/>}
+          children={(props) =>
+            <ListScreen
+              {...props}
+              deleteDiscussion={this.props.deleteDiscussion}
+              logoutAuthentication={this.props.logoutAuthentication}
+            />
+          }
           options={{
             title: "Discussions", headerRight: () => (
               <Button
-                icon={<Icon solid name='plus' type='font-awesome-5' />}
+                icon={<Icon solid name='plus' type='font-awesome-5' size={20} />}
                 onPress={() => this.props.navigation.navigate('CreateDiscussion')}
                 type="clear"
                 containerStyle={{margin: 5}}
@@ -35,15 +62,73 @@ class DiscussionsScreen extends React.Component {
         />
         <Stack.Screen
           name="CreateDiscussion"
-          children={(props) => <CreateDiscussionScreen {...props} addDiscussion={this.props.addDiscussion} logoutAuthentication={this.props.logoutAuthentication}/>}
+          children={(props) =>
+            <CreateDiscussionScreen
+              {...props}
+              addDiscussion={this.props.addDiscussion}
+              logoutAuthentication={this.props.logoutAuthentication}
+            />
+          }
           options={{
             title: "Nouvelle discussion"
           }}
         />
+        <Stack.Screen
+          name="UpdateDiscussion"
+          children={(props) =>
+            <UpdateDiscussionScreen
+              {...props}
+              updateDiscussion={this.props.updateDiscussion}
+              logoutAuthentication={this.props.logoutAuthentication}
+            />
+          }
+          options={({ route }) => ({ title: 'Modifier ' + route.params.item.name })}
+        />
+        <Stack.Screen
+          name="AddUsersDiscussion"
+          children={(props) =>
+            <AddUsersDiscussionScreen
+              {...props}
+              updateDiscussion={this.props.updateDiscussion}
+              logoutAuthentication={this.props.logoutAuthentication}
+            />
+          }
+          options={({ route }) => ({ title: 'Gérer les utilisateurs' })}
+        />
         <Stack.Screen
           name="Messages"
-          children={(props) => <MessagesScreen {...props} logoutAuthentication={this.props.logoutAuthentication}/>}
-          options={({ route }) => ({ title: route.params.title })}
+          children={(props) =>
+            <MessagesScreen
+              {...props}
+              logoutAuthentication={this.props.logoutAuthentication}
+            />
+          }
+          options={
+            ({ route }) => ({
+              title: route.params.item.name, headerRight: () => (
+                <View>
+                  <Button
+                    icon={<Icon solid name='user-friends' type='font-awesome-5' size={20} />}
+                    onPress={() => this.openMenu(route.params.item._id)}
+                    type="clear"
+                    containerStyle={{margin: 5}}
+                  />
+                  <Menu ref={c => (this["user-list" + route.params.item._id] = c)}>
+                    <MenuTrigger />
+                    <MenuOptions customStyles={{optionWrapper: { padding: 10 }}}>
+                      <MenuOption>
+                      <FlatList
+                        data={route.params.item.users}
+                        renderItem={this.renderItem}
+                        keyExtractor={item => item._id}
+                      />
+                      </MenuOption>
+                    </MenuOptions>
+                  </Menu>
+                </View>
+              ),
+            })
+          }
         />
       </Stack.Navigator>
     )
diff --git a/react-native/ChatApp/components/ListScreen.js b/react-native/ChatApp/components/ListScreen.js
index 9415a6088..ebbd4b66f 100644
--- a/react-native/ChatApp/components/ListScreen.js
+++ b/react-native/ChatApp/components/ListScreen.js
@@ -1,11 +1,17 @@
 import React from 'react';
 import {
   View,
-  FlatList
+  FlatList,
+  Alert
 } from 'react-native';
 import { ListItem, Icon, Text } from 'react-native-elements';
 import AsyncStorage from '@react-native-async-storage/async-storage';
-
+import {
+  Menu,
+  MenuOptions,
+  MenuOption,
+  MenuTrigger
+} from 'react-native-popup-menu';
 class ListScreen extends React.Component {
 
   constructor(props) {
@@ -88,6 +94,15 @@ class ListScreen extends React.Component {
 
   keyExtractor = (item, index) => index.toString();
 
+  openMenu = (id) => {
+    this["menu" + id].open();
+  };
+
+  deleteDiscussion(id) {
+    this.props.deleteDiscussion(id, this.state.user);
+    this.getRooms();
+  }
+
   render() {
     if (this.state.list.length > 0)
       return (
@@ -96,14 +111,40 @@ class ListScreen extends React.Component {
             keyExtractor={this.keyExtractor}
             data={this.state.list}
             renderItem={({ item }) => (
-              <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.name}</ListItem.Title>
-                  <ListItem.Subtitle>{item.description}</ListItem.Subtitle>
-                </ListItem.Content>
-                <ListItem.Chevron />
-              </ListItem>
+            <ListItem bottomDivider onLongPress={() => this.openMenu(item._id)} onPress={() => this.props.navigation.navigate('Messages', { item: item })}>
+              <Icon solid name='comment' type='font-awesome-5' />
+              <ListItem.Content>
+                <ListItem.Title>{item.name}</ListItem.Title>
+                <ListItem.Subtitle>{item.description}</ListItem.Subtitle>
+              </ListItem.Content>
+              <ListItem.Chevron />
+              <Menu ref={c => (this["menu" + item._id] = c)}>
+                <MenuTrigger />
+                <MenuOptions customStyles={{optionWrapper: { padding: 10 }}}>
+                  <MenuOption onSelect={() => this.props.navigation.navigate('UpdateDiscussion', { item: item })}>
+                    <Text style={{ fontSize: 15 }}><Icon solid name='edit' type='font-awesome-5' size={13} style={{marginRight: 5}}/>Modifier</Text>
+                  </MenuOption>
+                  <MenuOption onSelect={() => this.props.navigation.navigate('AddUsersDiscussion', { item: item })}>
+                    <Text style={{ fontSize: 15 }}><Icon solid name='user-cog' type='font-awesome-5' size={13} style={{marginRight: 5}}/>Gérer les utilisateurs</Text>
+                  </MenuOption>
+                  <MenuOption onSelect={() => 
+                    Alert.alert(
+                      "",
+                      "Voulez vous vraiment supprimer cette discussion ?",
+                      [
+                        {
+                          text: "Annuler",
+                          style: 'cancel'
+                        },
+                        { text: "Supprimer", style: 'destructive', onPress: () => this.deleteDiscussion(item._id) }
+                      ]
+                    )
+                  }>
+                    <Text style={{ color: 'red', fontSize: 15 }}><Icon solid name='trash-alt' type='font-awesome-5' color={'red'} size={13} style={{marginRight: 5}}/>Supprimer</Text>
+                  </MenuOption>
+                </MenuOptions>
+              </Menu>
+            </ListItem>
             )}
           />
         </View>
diff --git a/react-native/ChatApp/components/MessagesScreen.js b/react-native/ChatApp/components/MessagesScreen.js
index ccba3d04e..4d4f8bd5e 100644
--- a/react-native/ChatApp/components/MessagesScreen.js
+++ b/react-native/ChatApp/components/MessagesScreen.js
@@ -43,7 +43,7 @@ class MessagesScreen extends React.Component {
       const token = await AsyncStorage.getItem('@token');
       //if token is stored, user is logged in
       if (token !== null) {
-        fetch("http://163.172.178.146:3000/rooms/" + this.props.route.params.id + "/messages", {
+        fetch("http://163.172.178.146:3000/rooms/" + this.props.route.params.item._id + "/messages", {
           method: 'GET',
           headers: {
             Authorization: "Bearer " + token
@@ -138,7 +138,7 @@ class MessagesScreen extends React.Component {
           },
           body: JSON.stringify({
             body: messages[0].text,
-            roomId: this.props.route.params.id,
+            roomId: this.props.route.params.item._id,
           })
         })
           .then(response => {
diff --git a/react-native/ChatApp/components/UpdateDiscussionScreen.js b/react-native/ChatApp/components/UpdateDiscussionScreen.js
new file mode 100644
index 000000000..ba15dde69
--- /dev/null
+++ b/react-native/ChatApp/components/UpdateDiscussionScreen.js
@@ -0,0 +1,109 @@
+import React from 'react';
+import {
+  View,
+  StyleSheet,
+  KeyboardAvoidingView,
+  ActivityIndicator,
+  Dimensions
+} from 'react-native';
+import { Input, Button } from 'react-native-elements';
+import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+
+const windowHeight = Dimensions.get('window').height;
+
+class UpdateDiscussionScreen extends React.Component {
+
+  constructor(props) {
+
+    super(props);
+
+    this.state = {
+      name: this.props.route.params.item.name,
+      description: this.props.route.params.item.description,
+      users: this.props.route.params.item.users,
+      user: null,
+      isLoading: true
+    }
+
+  }
+
+  async componentDidMount() {
+    //get user from asyncStorage
+    try {
+      const user = await AsyncStorage.getItem('@user');
+      if (user !== null) {
+        await this.setState({ user: JSON.parse(user) });
+      }
+      else {
+        this.props.logoutAuthentication();
+      }
+    } catch (error) {
+      console.warn(error);
+    }
+
+    this.setState({ isLoading: false });
+
+    console.log(this.state.users);
+  }
+
+  updateDiscussion() {
+    this.props.updateDiscussion(this.props.route.params.item._id, this.state.name, this.state.description, this.state.users, this.state.user, true);
+  }
+
+  render() {
+    if (this.state.isLoading)
+      return (
+        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
+          <ActivityIndicator size="large" />
+        </View>
+      )
+    else
+      return (
+        <KeyboardAvoidingView
+          behavior="height"
+          style={{flex:1, alignItems: 'center', justifyContent: 'center' }}
+        >
+          
+          <FontAwesome5 name={'comment'} solid color={'lightgrey'} size={150} />
+          <View style={{alignItems: 'center', justifyContent: 'center', width: '100%' }}>
+            <Input
+              placeholder="Nom"
+              style={{ fontSize: 16, borderBottomColor: "grey" }}
+              onChangeText={value => this.setState({ name: value })}
+              placeholderTextColor={"black"}
+              defaultValue={this.state.name}
+            />
+            <Input
+              placeholder="Description"
+              style={{ fontSize: 16, borderBottomColor: "grey" }}
+              onChangeText={value => this.setState({ description: value })}
+              placeholderTextColor={"black"}
+              defaultValue={this.state.description}
+            />
+            <Button
+              containerStyle={styles.customButton}
+              title="Enregistrer"
+              onPress={this.updateDiscussion.bind(this)}
+              buttonStyle={{backgroundColor: 'dodgerblue'}}
+              titleStyle={{ marginLeft: 5 }}
+              icon={
+                <FontAwesome5 name={'edit'} solid color={'white'} size={20} />
+              }
+            />
+          </View>
+        </KeyboardAvoidingView>
+      )
+  }
+};
+
+const styles = StyleSheet.create({
+  customButton: {
+    borderRadius: 1000,
+    width: 200,
+    textAlign: 'center',
+    backgroundColor: 'red'
+  }
+})
+
+export default UpdateDiscussionScreen;
\ No newline at end of file
diff --git a/react-native/ChatApp/package-lock.json b/react-native/ChatApp/package-lock.json
index fd492981d..2c3446db3 100644
--- a/react-native/ChatApp/package-lock.json
+++ b/react-native/ChatApp/package-lock.json
@@ -8515,6 +8515,11 @@
         "prop-types": "^15.7.x"
       }
     },
+    "react-native-popup-menu": {
+      "version": "0.15.11",
+      "resolved": "https://registry.npmjs.org/react-native-popup-menu/-/react-native-popup-menu-0.15.11.tgz",
+      "integrity": "sha512-f5q2GoDN99bkA24wHiwasaErcdQEgyqYZ8IYuZPOrZNFr66E4rg6f4LElSVBA3EZJTSq5OddVeaOcU340bSTEg=="
+    },
     "react-native-ratings": {
       "version": "7.3.0",
       "resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-7.3.0.tgz",
@@ -8542,6 +8547,11 @@
       "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.16.1.tgz",
       "integrity": "sha512-WZ7m0sBDVaHbBnlHxwQnUlI6KNfQKHq+Unfw+VBuAlnSXvT+aw6Bb/K2bUlHzBgvrPjwY3Spc7ZERFuTwRLLwg=="
     },
+    "react-native-sectioned-multi-select": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/react-native-sectioned-multi-select/-/react-native-sectioned-multi-select-0.8.1.tgz",
+      "integrity": "sha512-iH/5PHBo64yFhKzjd+6sCG0aEvgDnUwpn3I7R0ohcGo/+gJdw47mYmJMTwJTmR9JqBFXHx+2bkQi4ij2ghfqRQ=="
+    },
     "react-native-size-matters": {
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
diff --git a/react-native/ChatApp/package.json b/react-native/ChatApp/package.json
index 9593289a5..c101bd961 100644
--- a/react-native/ChatApp/package.json
+++ b/react-native/ChatApp/package.json
@@ -22,9 +22,11 @@
     "react-native-gesture-handler": "^1.9.0",
     "react-native-gifted-chat": "^0.16.3",
     "react-native-paper": "^4.6.0",
+    "react-native-popup-menu": "^0.15.11",
     "react-native-reanimated": "^1.13.2",
     "react-native-safe-area-context": "^3.1.9",
     "react-native-screens": "^2.16.1",
+    "react-native-sectioned-multi-select": "^0.8.1",
     "react-native-vector-icons": "^7.1.0"
   },
   "devDependencies": {
-- 
GitLab