diff --git a/react-native/ChatApp/components/AuthenticateNavigation.js b/react-native/ChatApp/components/AuthenticateNavigation.js index 67d201b6d94ae83846ec27bc1a1a3eeaaa309627..a00468b74ad464b3cade200e2baa8d62938aaa2c 100644 --- a/react-native/ChatApp/components/AuthenticateNavigation.js +++ b/react-native/ChatApp/components/AuthenticateNavigation.js @@ -1,6 +1,7 @@ import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createStackNavigator } from '@react-navigation/stack'; import FontAwesome5 from 'react-native-vector-icons/FontAwesome5'; import { ActivityIndicator, View } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; @@ -9,8 +10,10 @@ import HomeScreen from './HomeScreen' import DiscussionsScreen from './DiscussionsScreen' import ProfileScreen from './ProfileScreen' import LoginScreen from './LoginScreen' +import SignupScreen from './SignupScreen' const Tab = createBottomTabNavigator(); +const Stack = createStackNavigator(); class AuthenticateNavigation extends React.Component { @@ -45,11 +48,27 @@ class AuthenticateNavigation extends React.Component { }); } + async logoutAuthentication() { + this.setState({isAuthenticated: false}); + try { + await AsyncStorage.removeItem('@token'); + } + catch(exception) { + console.warn(exception) + } + try { + await AsyncStorage.removeItem('@user'); + } + catch(exception) { + console.warn(exception) + } + } + login(username, password) { let status = null; //login to API - fetch('http://localhost:3000/users/login', { + fetch('http://163.172.178.146:3000/users/login', { method: 'POST', headers: { Accept: 'application/json', @@ -60,47 +79,88 @@ class AuthenticateNavigation extends React.Component { password: password, }) }) - .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) { - try { - await AsyncStorage.setItem( - '@token', - json.token - ); - } catch (error) { - //Error saving data - } - try { - const jsonUser = JSON.stringify(json.user) - await AsyncStorage.setItem( - '@user', - jsonUser - ); - } catch (error) { - //Error saving data - } - //user is logged, we update isAuthenticated to true - this.updateAuthentication(); + .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) { + try { + await AsyncStorage.setItem( + '@token', + json.token + ); + } catch (error) { + //Error saving data } - - //Handled error status - else if ("error" in json) { - console.warn(json.error); + try { + const jsonUser = JSON.stringify(json.user) + await AsyncStorage.setItem( + '@user', + jsonUser + ); + } catch (error) { + //Error saving data } + //user is logged, we update isAuthenticated to true + this.updateAuthentication(); + } - //Unhandled error status - else { - console.warn("Unhandled error"); - } + //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 + }); + } + + signup(username, password, confirm) { + let status = null; + + //login to API + fetch('http://163.172.178.146:3000/users', { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + username: username, + password: password, + confirm: confirm }) - .catch(async (error) => { - //Error fetching url - }); + }) + .then(response => { + status = response.status; + return response.json(); + }) + .then(json => { + //OK Status : we store the token & the user in local storage + if (status == 200) { + console.warn("Inscription réussie"); + this.props.navigation.navigate('Signup'); + } + //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 + }); } render() { @@ -111,14 +171,16 @@ class AuthenticateNavigation extends React.Component { </View> ) } - else if (this.state.isAuthenticated) + else if (this.state.isAuthenticated) { return ( <NavigationContainer> <Tab.Navigator initialRouteName="Home" activeColor="#fff" inactiveColor="#ffffff55" - barStyle={{ backgroundColor: '#5352ed' }} + tabBarOptions={{ + activeTintColor: 'dodgerblue' + }} > <Tab.Screen name="Home" @@ -142,7 +204,7 @@ class AuthenticateNavigation extends React.Component { /> <Tab.Screen name="Profile" - component={ProfileScreen} + children={(props) => <ProfileScreen logoutAuthentication={this.logoutAuthentication.bind(this)} />} options={{ tabBarLabel: 'Profil', tabBarIcon: ({ color }) => ( @@ -153,10 +215,26 @@ class AuthenticateNavigation extends React.Component { </Tab.Navigator> </NavigationContainer> ) - else + } + else { return ( - <LoginScreen login={this.login} updateAuthentication={this.updateAuthentication.bind(this)} /> + <NavigationContainer> + <Stack.Navigator + screenOptions={{ + headerShown: false + }}> + <Stack.Screen + name="Login" + children={(props) => <LoginScreen {...props} login={this.login} updateAuthentication={this.updateAuthentication.bind(this)}/>} + /> + <Stack.Screen + name="Signup" + children={(props) => <SignupScreen {...props} signup={this.signup} updateAuthentication={this.updateAuthentication.bind(this)}/>} + /> + </Stack.Navigator> + </NavigationContainer> ) + } } }; diff --git a/react-native/ChatApp/components/HomeScreen.js b/react-native/ChatApp/components/HomeScreen.js index 22cba912a15e7cbf794aee882bbdfc2c114c04da..1c4d6a245992b7d24d22c5ea3666fe360a7b3ff8 100644 --- a/react-native/ChatApp/components/HomeScreen.js +++ b/react-native/ChatApp/components/HomeScreen.js @@ -1,8 +1,8 @@ import React from 'react'; import { View, - Text, } from 'react-native'; +import { Text } from 'react-native-elements'; class HomeScreen extends React.Component { @@ -15,7 +15,7 @@ class HomeScreen extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> - <Text>Home Screen</Text> + <Text h2>Bienvenue !</Text> </View> ) } diff --git a/react-native/ChatApp/components/ListScreen.js b/react-native/ChatApp/components/ListScreen.js index d7e7ff01ea176dfe7d5b25d1e260c7ec95b4c4a3..bbafb27dc889cd14ed0561525c36e02aadc99dce 100644 --- a/react-native/ChatApp/components/ListScreen.js +++ b/react-native/ChatApp/components/ListScreen.js @@ -27,7 +27,7 @@ class ListScreen extends React.Component { const token = await AsyncStorage.getItem('@token'); //if token is stored, user is logged in if (token !== null) { - fetch("http://localhost:3000/rooms", { + fetch("http://163.172.178.146:3000/rooms", { method: 'GET', headers: { Authorization: "Bearer " + token diff --git a/react-native/ChatApp/components/LoginScreen.js b/react-native/ChatApp/components/LoginScreen.js index cc76606b75e97b8da71367d2e20dda603f281247..b3a8df33831686ca62d00dd59af53356e76ecdf9 100644 --- a/react-native/ChatApp/components/LoginScreen.js +++ b/react-native/ChatApp/components/LoginScreen.js @@ -1,9 +1,11 @@ import React from 'react'; import { View, - StyleSheet + StyleSheet, + KeyboardAvoidingView } from 'react-native'; import { Input, Button, Text } from 'react-native-elements'; +import Icon from 'react-native-vector-icons/FontAwesome'; class LoginScreen extends React.Component { @@ -22,47 +24,61 @@ class LoginScreen extends React.Component { this.props.login(this.state.username, this.state.password); } - updateAuthentication() { - this.props.updateAuthentication(); - } - render() { return ( - <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> - <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> - <Text h1>Bonjour !</Text> - </View> - <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> - <Input - placeholder="Pseudonyme" - style={{ fontSize: 16, borderBottomColor: "grey" }} - leftIcon={{ type: 'font-awesome', name: 'user', color: "black" }} - onChangeText={value => this.setState({ username: value })} - placeholderTextColor={"black"} - /> - <Input - placeholder="Mot de passe" - style={{ fontSize: 16, borderBottomColor: "grey" }} - leftIcon={{ type: 'font-awesome', name: 'lock', color: "black" }} - onChangeText={value => this.setState({ password: value })} - secureTextEntry={true} - placeholderTextColor={"black"} - /> - <Button - containerStyle={styles.customButton} - title="Se connecter" - onPress={this.login.bind(this)} - /> - </View> - <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <KeyboardAvoidingView + behavior="height" + style={{ flex: 1, alignItems: 'center', justifyContent: 'center'}} + > + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <Text h1>Connexion</Text> + </View> + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <Input + placeholder="Pseudonyme" + style={{ fontSize: 16, borderBottomColor: "grey" }} + leftIcon={{ type: 'font-awesome', name: 'user', color: "black" }} + onChangeText={value => this.setState({ username: value })} + placeholderTextColor={"black"} + /> + <Input + placeholder="Mot de passe" + style={{ fontSize: 16, borderBottomColor: "grey" }} + leftIcon={{ type: 'font-awesome', name: 'lock', color: "black" }} + onChangeText={value => this.setState({ password: value })} + secureTextEntry={true} + placeholderTextColor={"black"} + /> + <Button + containerStyle={styles.customButton} + title="Se connecter" + onPress={this.login.bind(this)} + buttonStyle={{backgroundColor: 'dodgerblue'}} + titleStyle={{ marginLeft: 5 }} + icon={ + <Icon + name="sign-in" + size={20} + color="white" + /> + } + /> + </View> + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> - <Text - onPress={() => null}> - Pas encore de compte ? S'incrire - </Text> - </View> + <Text> + Pas encore inscrit ? + </Text> + <Button + containerStyle={styles.customButton} + title="S'inscrire" + onPress={() => this.props.navigation.navigate('Signup')} + buttonStyle={{backgroundColor: 'lightgrey'}} + titleStyle={{color: 'black'}} + /> + </View> - </View> + </KeyboardAvoidingView> ) } }; @@ -70,7 +86,7 @@ class LoginScreen extends React.Component { const styles = StyleSheet.create({ customButton: { borderRadius: 1000, - width: '65%', + width: 200, textAlign: 'center', } }) diff --git a/react-native/ChatApp/components/MessagesScreen.js b/react-native/ChatApp/components/MessagesScreen.js index 683c8fa7808775b53bed3b48e4c6eb3ae75dbcb0..aaf7756c9ae163d0d5bc2ef147b8c9e055d5ad89 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://localhost:3000/rooms/" + this.props.route.params.id + "/messages", { + fetch("http://163.172.178.146:3000/rooms/" + this.props.route.params.id + "/messages", { method: 'GET', headers: { Authorization: "Bearer " + token @@ -66,8 +66,8 @@ class MessagesScreen extends React.Component { text: message.body, createdAt: message.date, user: { - _id: message.author, - name: message.author, + _id: message.author._id, + name: message.author.username, avatar: 'https://placeimg.com/140/140/any', }, }, @@ -129,7 +129,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://localhost:3000/messages', { + fetch('http://163.172.178.146:3000/messages', { method: 'POST', headers: { Accept: 'application/json', diff --git a/react-native/ChatApp/components/ProfileScreen.js b/react-native/ChatApp/components/ProfileScreen.js index a483e70f272ea49c71b979095c011e51e03331a2..d926c66bff3332ff082549ef22f27042e4f96c84 100644 --- a/react-native/ChatApp/components/ProfileScreen.js +++ b/react-native/ChatApp/components/ProfileScreen.js @@ -1,8 +1,10 @@ import React from 'react'; import { View, - Text, + StyleSheet, } from 'react-native'; +import { Button, Text } from 'react-native-elements'; +import Icon from 'react-native-vector-icons/FontAwesome'; class ProfileScreen extends React.Component { @@ -15,10 +17,32 @@ class ProfileScreen extends React.Component { render() { return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> - <Text>Profile Screen</Text> + <Button + containerStyle={styles.customButton} + title="Se déconnecter" + onPress={this.props.logoutAuthentication} + buttonStyle={{backgroundColor: 'red'}} + titleStyle={{ marginLeft: 5 }} + icon={ + <Icon + name="sign-out" + size={20} + color="white" + /> + } + /> </View> ) } }; +const styles = StyleSheet.create({ + customButton: { + borderRadius: 1000, + width: 200, + textAlign: 'center', + backgroundColor: 'red' + } +}) + export default ProfileScreen; \ No newline at end of file diff --git a/react-native/ChatApp/components/SignupScreen.js b/react-native/ChatApp/components/SignupScreen.js new file mode 100644 index 0000000000000000000000000000000000000000..960ef6d721a710df14e9b2e216014f876fbd95e9 --- /dev/null +++ b/react-native/ChatApp/components/SignupScreen.js @@ -0,0 +1,107 @@ +import React from 'react'; +import { + View, + StyleSheet, + KeyboardAvoidingView +} from 'react-native'; +import { Input, Button, Text } from 'react-native-elements'; +import Icon from 'react-native-vector-icons/FontAwesome'; + +class SignupScreen extends React.Component { + + constructor(props) { + + super(props); + + this.state = { + username: "", + password: "", + confirm: "" + } + + } + + signup() { + this.props.signup(this.state.username, this.state.password, this.state.confirm); + } + + render() { + return ( + <KeyboardAvoidingView + behavior="height" + style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }} + > + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <Text h1>Inscription</Text> + </View> + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <Input + placeholder="Pseudonyme" + style={{ fontSize: 16, borderBottomColor: "grey" }} + leftIcon={{ type: 'font-awesome', name: 'user', color: "black" }} + onChangeText={value => this.setState({ username: value })} + placeholderTextColor={"black"} + /> + <Input + placeholder="Mot de passe" + style={{ fontSize: 16, borderBottomColor: "grey" }} + leftIcon={{ type: 'font-awesome', name: 'lock', color: "black" }} + onChangeText={value => this.setState({ password: value })} + secureTextEntry={true} + placeholderTextColor={"black"} + /> + <Input + placeholder="Confirmer le mot de passe" + style={{ fontSize: 16, borderBottomColor: "grey" }} + leftIcon={{ type: 'font-awesome', name: 'lock', color: "black" }} + onChangeText={value => this.setState({ confirm: value })} + secureTextEntry={true} + placeholderTextColor={"black"} + /> + <Button + containerStyle={styles.customButton} + title="S'inscrire" + onPress={this.signup.bind(this)} + buttonStyle={{backgroundColor: 'dodgerblue'}} + titleStyle={{ marginLeft: 5 }} + icon={ + <Icon + name="user-plus" + size={20} + color="white" + /> + } + /> + </View> + <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', width: '100%' }}> + <Text> + J'ai déjà un compte + </Text> + <Button + containerStyle={styles.customButton} + title="Se connecter" + onPress={() => this.props.navigation.navigate('Login')} + buttonStyle={{backgroundColor: 'lightgrey'}} + titleStyle={{color: 'black'}} + /> + </View> + + </KeyboardAvoidingView> + ) + } +}; + +const styles = StyleSheet.create({ + customButton: { + borderRadius: 1000, + width: 200, + textAlign: 'center', + }, + linkText: { + color: 'dodgerblue', + textDecorationLine: 'underline' + } +}) + +export default SignupScreen; +