Skip to content
Snippets Groups Projects
Commit e95d7ef9 authored by GOEPP THOMAS's avatar GOEPP THOMAS
Browse files

refactor: login and signup

parent 8c8fbe7f
Branches
2 merge requests!132V4.0,!127Feature/132 refacto login and signup
Pipeline #324120 passed with stages
in 15 seconds
......@@ -9,4 +9,10 @@ export interface User {
email: string;
username: string;
stats?: Stats;
}
export enum UserConnectionState {
LOADING = "Loading",
NOT_CONNECTED = "NotConnected",
CONNECTED = "Connected",
}
\ No newline at end of file
import { View, StyleSheet, Image, Modal, TextInput } from "react-native";
import DefaultButton from "../../components/DefaultButton";
import {Image, StyleSheet, Text, View} from "react-native";
import {useTranslation} from "react-i18next";
import { useState } from "react";
import { TextsStyles } from "../../styles/TextsStyles";
import React, {useEffect, useState} from "react";
import ModalJoinQuiz from "../../components/ModalJoinQuiz";
import MenuButton from "../../components/buttons/MenuButton";
import {NavigationProp} from "@react-navigation/native";
import {useQuizService} from "../../services/QuizService";
import HttpError from "../../services/HttpError";
import {useUserService} from "../../services/UserService";
import {UserConnectionState} from "../../models/User";
import LoadingIndicator from "../../components/loading/LoadingIndicator";
import Connection from "../Profil/Connection/Connection";
interface Props {
navigation: NavigationProp<any>;
}
/**
* HomeChild : Enfant de l'écran Home, il contient le menu principal
* @param navigation - navigation
......@@ -20,6 +22,22 @@ interface Props {
export default function MultiplayerChild({navigation}: Props) {
const [modalVisible, setModalVisible] = useState(false);
const {t} = useTranslation();
const [userConnectionState, setUserConnectionState] = useState(UserConnectionState.LOADING);
const { getInformationsUser, logoutUser } = useUserService();
const getUser = async () => {
setUserConnectionState(UserConnectionState.LOADING);
const user = await getInformationsUser();
if(user instanceof HttpError){
setUserConnectionState(UserConnectionState.NOT_CONNECTED);
return;
}
setUserConnectionState(UserConnectionState.CONNECTED);
}
useEffect(() => {
getUser();
}, []);
const handleButtonCommunityPressed = async () => {
navigation.navigate("MultiplayerCommunity");
......@@ -35,15 +53,24 @@ export default function MultiplayerChild({navigation}: Props) {
return (
<View style={styles.containerGlobal}>
<View style={styles.imageContainer}>
<Image source={require('../../assets/TitleApp.png')} style={styles.image} />
</View>
<View style={styles.buttonContainer}>
<MenuButton text={"COMMUNITY"} handleButtonPressed={handleButtonCommunityPressed}/>
<MenuButton text={"PLAY AN ONLINE QUIZ"} handleButtonPressed={handleOnlineQuizPressed}/>
<MenuButton text={"ONGOING QUIZZES"} handleButtonPressed={handleButtonOngoingQuizzesPressed}/>
</View>
<ModalJoinQuiz modalVisible={modalVisible} setModalVisible={setModalVisible} navigation={navigation}/>
{userConnectionState === UserConnectionState.LOADING && (
<LoadingIndicator/>
)}
{userConnectionState === UserConnectionState.CONNECTED && (
<>
<View style={styles.imageContainer}>
<Image source={require('../../assets/TitleApp.png')} style={styles.image} />
</View>
<View style={styles.buttonContainer}>
<MenuButton text={"COMMUNITY"} handleButtonPressed={handleButtonCommunityPressed}/>
<MenuButton text={"PLAY AN ONLINE QUIZ"} handleButtonPressed={handleOnlineQuizPressed}/>
<MenuButton text={"ONGOING QUIZZES"} handleButtonPressed={handleButtonOngoingQuizzesPressed}/>
</View>
</>
)}
{userConnectionState === UserConnectionState.NOT_CONNECTED && (
<Connection title={"Multiplayer"} navigation={navigation}/>
)}
</View>
);
}
......@@ -58,6 +85,13 @@ const styles = StyleSheet.create({
},
image: {
},
title: {
fontSize: 40,
fontWeight: "bold",
color: "#00b3f4",
marginBottom: 10,
alignSelf: "center", // Centre uniquement le titre
},
button: {
borderRadius: 40,
height: '35%',
......
import React from "react";
import {
Modal,
View,
StyleSheet,
TextInput,
TouchableOpacity,
Keyboard,
TouchableWithoutFeedback,
} from "react-native";
import {Keyboard, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View} from "react-native";
import ProfilSelectMode from "../ProfilSelectMode";
import { ProfilSelectModeType } from "../../../models/SelectModeType";
import ProfilModalLogin from "./ProfilModalLogin";
import ProfilModalSignup from "./ProfilModalSignup";
import Icon from "react-native-vector-icons/MaterialIcons";
import React, {useState} from "react";
import {ProfilSelectModeType} from "../../../models/SelectModeType";
import {NavigationProp} from "@react-navigation/native";
import ConnectionLogin from "./ConnectionLogin";
import ConnectionSignup from "./ConnectionSignup";
interface Props {
modalVisible: boolean;
setModalVisible: (visible: boolean) => void;
mode: ProfilSelectModeType;
setMode: (mode: ProfilSelectModeType) => void;
title: string;
navigation: NavigationProp<any>;
}
export default function ProfilModal({
modalVisible,
setModalVisible,
mode,
setMode,
navigation
}: Props) {
const closeModal = () => {
setModalVisible(false);
}
export default function Connection({title, navigation}: Props) {
const [mode, setMode] = useState<ProfilSelectModeType>("login");
return (
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.container}>
<TouchableOpacity
style={styles.closeButton}
onPress={() => setModalVisible(false)} // Ferme la modal
>
<Icon name="close" size={50} color="#000" />
</TouchableOpacity>
<View style={styles.backgroundShadow} />
<View style={styles.containerModal}>
<ProfilSelectMode mode={mode} setMode={setMode} />
{mode === "login" ? (
<ProfilModalLogin navigation={navigation} closeModal={closeModal}/>
) : (
<ProfilModalSignup navigation={navigation} closeModal={closeModal}/>
)}
</View>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<View style={styles.containerModal}>
<ProfilSelectMode mode={mode} setMode={setMode} />
{mode === "login" ? (
<ConnectionLogin navigation={navigation} />
) : (
<ConnectionSignup navigation={navigation} />
)}
</View>
</TouchableWithoutFeedback>
</Modal>
</View>
</TouchableWithoutFeedback>
);
}
......@@ -74,6 +39,13 @@ const styles = StyleSheet.create({
height: "100%",
width: "100%",
},
title: {
fontSize: 40,
fontWeight: "bold",
color: "#00b3f4",
marginBottom: 10,
alignSelf: "center", // Centre uniquement le titre
},
backgroundShadow: {
height: "100%",
width: "100%",
......@@ -97,4 +69,4 @@ const styles = StyleSheet.create({
borderRadius: 10,
margin: '5%',
},
});
});
\ No newline at end of file
......@@ -8,9 +8,8 @@ import BlueButton from "../../../components/buttons/BlueButton";
interface Props {
navigation: NavigationProp<any>;
closeModal: () => void;
}
export default function ProfilModalLogin({navigation, closeModal}: Props) {
export default function ConnectionLogin({navigation}: Props) {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
......@@ -27,7 +26,6 @@ export default function ProfilModalLogin({navigation, closeModal}: Props) {
return;
}
setError(null);
closeModal();
navigation.reset({
routes: [{name: "TabNavigator"}],
});
......@@ -54,6 +52,7 @@ const styles = StyleSheet.create({
justifyContent: 'flex-start',
rowGap: '7%',
marginTop: "3%",
marginBottom: "auto", // Espacement entre le texte d'erreur et les inputs
},
container:{
height: 475,
......@@ -80,7 +79,6 @@ const styles = StyleSheet.create({
errorText: {
color: 'red',
fontSize: 16,
marginBottom: 10, // Espacement entre le texte d'erreur et les inputs
textAlign: 'center', // Centrer le message d'erreur
},
});
......@@ -9,9 +9,8 @@ import BlueButton from "../../../components/buttons/BlueButton";
interface Props {
navigation: NavigationProp<any>;
closeModal: () => void;
}
export default function ProfilModalSignup({navigation, closeModal}: Props) {
export default function ConnectionSignup({navigation}: Props) {
const [email, setEmail] = useState("");
const [username, setUsername] = useState("");
......@@ -25,6 +24,10 @@ export default function ProfilModalSignup({navigation, closeModal}: Props) {
setError("Please fill in all fields");
return;
}
if(password.length < 8){
setError("Password must be at least 8 characters long");
return;
}
if(password !== repeatPassword){
setError("Passwords do not match");
return;
......@@ -35,7 +38,6 @@ export default function ProfilModalSignup({navigation, closeModal}: Props) {
return;
}
setError(null);
closeModal();
navigation.reset({
routes: [{name: "TabNavigator"}],
});
......@@ -62,13 +64,13 @@ const styles = StyleSheet.create({
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
rowGap: '7%',
rowGap: '5%',
marginTop: "3%",
},
container:{
height: 475,
paddingTop: '5%',
isplay: 'flex',
display: 'flex',
justifyContent: 'space-between'
},
textInput: {
......
import { NavigationProp } from "@react-navigation/native";
import { View, StyleSheet, Image, Text, TouchableOpacity } from "react-native";
import ProfilModal from "./Modals/ProfilModal";
import React, { useEffect, useState } from "react";
import ProfilHeaderAccount from "./ProfilHeaderAccount";
import { ProfilSelectModeType } from "../../models/SelectModeType";
import { useUserService } from "../../services/UserService";
import HttpError from "../../services/HttpError";
import Icon from "react-native-vector-icons/MaterialIcons";
import {User} from "../../models/User";
import {User, UserConnectionState} from "../../models/User";
import StatsOfUsers from "../../components/Profil/StatsOfUsers";
import LoadingIndicator from "../../components/loading/LoadingIndicator";
import Connection from "./Connection/Connection";
interface Props {
navigation: NavigationProp<any>;
}
enum UserConnectionState {
LOADING = "Loading",
NOT_CONNECTED = "NotConnected",
CONNECTED = "Connected",
}
export default function ProfilChild({ navigation }: Props) {
const [isLogged, setIsLogged] = useState(false);
......@@ -28,6 +24,7 @@ export default function ProfilChild({ navigation }: Props) {
const [userConnectionState, setUserConnectionState] = useState(UserConnectionState.LOADING);
const { getInformationsUser, logoutUser } = useUserService();
const getUser = async () => {
setUserConnectionState(UserConnectionState.LOADING);
const user = await getInformationsUser();
......@@ -42,7 +39,6 @@ export default function ProfilChild({ navigation }: Props) {
useEffect(() => {
getUser();
}, []);
// Pour s'adapter quand l'état de connexion change
......@@ -55,33 +51,32 @@ export default function ProfilChild({ navigation }: Props) {
if (!(result instanceof HttpError)) {
setUser(undefined); // Réinitialise l'utilisateur après la déconnexion
}
navigation.reset({
routes: [{name: "TabNavigator"}],
});
};
return (
<View style={styles.containerGlobal}>
{userConnectionState === UserConnectionState.LOADING && (
<LoadingIndicator/>
)}
{userConnectionState === UserConnectionState.CONNECTED && (
<>
<View style={styles.containerPlayerInfos}>
<Image source={require('../../assets/TitleApp.png')} style={styles.titleImage} />
<Image source={require('../../assets/ProfilBaseImage.png')} style={styles.profilImage} />
<Text style={styles.pseudoText}>{user ? user.username : "?"}</Text>
</View>
{!user && (
<ProfilHeaderAccount setModalVisible={setModalVisible} setMode={setMode} />
)}
<ProfilModal
modalVisible={modalVisible}
setModalVisible={setModalVisible}
mode={mode}
setMode={setMode}
navigation={navigation}
/>
<StatsOfUsers user={user}/>
{user && (
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Icon name="logout" size={40} color="#FF0000" />
</TouchableOpacity>
)}
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Icon name="logout" size={40} color="#FF0000" />
</TouchableOpacity>
</>
)}
{userConnectionState === UserConnectionState.NOT_CONNECTED && (
<Connection title={"Profil"} navigation={navigation} />
)}
</View>
);
}
......@@ -99,6 +94,13 @@ const styles = StyleSheet.create({
display: "flex",
alignItems: "center",
},
title: {
fontSize: 40,
fontWeight: "bold",
color: "#00b3f4",
marginBottom: 10,
alignSelf: "center", // Centre uniquement le titre
},
titleImage: {
width: "45%",
resizeMode: "contain",
......
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import { ProfilSelectModeType } from "../../models/SelectModeType";
interface Props {
setModalVisible: (visible:boolean) => void;
setMode: (mode: ProfilSelectModeType) => void;
}
export default function ProfilHeaderAccount({ setModalVisible, setMode }: Props) {
const handleAccountPress = (mode:ProfilSelectModeType) => {
setMode(mode);
setModalVisible(true);
};
return (
<View style={styles.containerHeader}>
<TouchableOpacity onPress={() => handleAccountPress('login')}>
<Text style={styles.buttonHeader}>LOGIN</Text>
</TouchableOpacity>
<Text style={styles.textHeader}>{' OR '}</Text>
<TouchableOpacity onPress={() => handleAccountPress('signup')}>
<Text style={styles.buttonHeader}>CREATE AN ACCOUNT</Text>
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
containerHeader: {
backgroundColor: '#D9D9D9',
height: '10%',
width: '100%',
position: 'absolute',
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center'
},
textHeader: {
color: '#000000',
fontSize: 20,
fontWeight: 'bold',
},
buttonHeader: {
textDecorationLine: 'underline',
color: '#000000',
fontSize: 20,
fontWeight: 'bold',
},
});
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment