Affichage dynamique de la navbar et des pages + Connexion/Déconnexion OK

pull/81/head
Baptiste MARCEL 2 years ago
parent c9a405a554
commit a49cc06aa3

@ -3,6 +3,7 @@ import React from 'react';
import { useState } from 'react'; import { useState } from 'react';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { GameProvider } from './Contexts/GameContext'; import { GameProvider } from './Contexts/GameContext';
import { AuthProvider } from './Contexts/AuthContext';
/* Page */ /* Page */
import Home from './Pages/Home'; import Home from './Pages/Home';
@ -63,9 +64,10 @@ function App() {
// <img src={logo} className="App-logo" alt="logo" /> // <img src={logo} className="App-logo" alt="logo" />
// </header> // </header>
// </div> // </div>
<AuthProvider>
<GameProvider> <GameProvider>
{/*@ts-ignore*/}
{/*@ts-ignore*/}
<IntlProvider locale={locale} messages={messages[locale]}> <IntlProvider locale={locale} messages={messages[locale]}>
<ThemeProvider> <ThemeProvider>
<BrowserRouter> <BrowserRouter>
@ -85,7 +87,7 @@ function App() {
</ThemeProvider> </ThemeProvider>
</IntlProvider> </IntlProvider>
</GameProvider> </GameProvider>
</AuthProvider>
); );
} }

@ -1,4 +1,4 @@
import React from 'react'; import React, {useEffect, useState} from 'react';
/* Naviagtion */ /* Naviagtion */
import { Navbar, Container, Nav, NavDropdown } from 'react-bootstrap'; import { Navbar, Container, Nav, NavDropdown } from 'react-bootstrap';
@ -7,7 +7,7 @@ import { Navbar, Container, Nav, NavDropdown } from 'react-bootstrap';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
/* Icon */ /* Icon */
import { BiLogInCircle } from 'react-icons/bi'; import { BiDoorOpen, BiLogInCircle } from 'react-icons/bi';
import { BsFillPersonPlusFill } from 'react-icons/bs'; import { BsFillPersonPlusFill } from 'react-icons/bs';
import { HiLanguage } from 'react-icons/hi2'; import { HiLanguage } from 'react-icons/hi2';
@ -17,16 +17,22 @@ import logo from '../res/img/logo2_preview_rev_1.png';
/* Components */ /* Components */
import ReactCountryFlag from "react-country-flag" import ReactCountryFlag from "react-country-flag"
/* Services */
import SessionService from '../services/SessionService';
import AuthService from '../services/AuthService';
/* Style */ /* Style */
import './NavBar.css'; import './NavBar.css';
/* Style */ /* Style */
import { useTheme } from '../Style/ThemeContext'; import { useTheme } from '../Style/ThemeContext';
import { useAuth } from '../Contexts/AuthContext';
// @ts-ignore // @ts-ignore
function AppNavbar({changeLocale}) { function AppNavbar({changeLocale}) {
const theme = useTheme(); const theme = useTheme();
const {isLoggedIn, logout} = useAuth();
return ( return (
<Navbar expand="lg" className="custom-navbar" style={{ backgroundColor: theme.colors.primary }}> <Navbar expand="lg" className="custom-navbar" style={{ backgroundColor: theme.colors.primary }}>
<Container> <Container>
@ -45,14 +51,26 @@ function AppNavbar({changeLocale}) {
</Nav> </Nav>
<div className='leftdiv'> <div className='leftdiv'>
<Nav className="ml-auto navbar-title-dd"> <Nav className="ml-auto navbar-title-dd">
<Nav.Link href="login" className='navbar-title-dd' style={{ backgroundColor: theme.colors.secondary }}> {/* Affichage dynamique selon état de connexion */}
<BiLogInCircle/> {isLoggedIn ? (
<FormattedMessage id="log_in"/> <Nav.Link href="/play" onClick={logout} className='navbar-title-dd' style={{ backgroundColor: theme.colors.secondary }}>
</Nav.Link> <BiDoorOpen />
<Nav.Link href="signup" className='navbar-title-dd' style={{ backgroundColor: theme.colors.secondary }}> <FormattedMessage id="log_out" />
<BsFillPersonPlusFill/> </Nav.Link>
<FormattedMessage id="sign_up"/> )
</Nav.Link> : (
<>
<Nav.Link href="/login" className='navbar-title-dd' style={{ backgroundColor: theme.colors.secondary }}>
<BiLogInCircle />
<FormattedMessage id="log_in" />
</Nav.Link>
<Nav.Link href="/signup" className='navbar-title-dd' style={{ backgroundColor: theme.colors.secondary }}>
<BsFillPersonPlusFill />
<FormattedMessage id="sign_up" />
</Nav.Link>
</>
)
}
</Nav> </Nav>
<Nav className="me-auto"> <Nav className="me-auto">
<NavDropdown <NavDropdown

@ -21,9 +21,13 @@ import Col from 'react-bootstrap/Col';
/* Component */ /* Component */
import ButtonImgNav from './ButtonImgNav'; import ButtonImgNav from './ButtonImgNav';
/* Types */
import { PlayerProps } from '../types/Player';
//@ts-ignore //@ts-ignore
function ScoreBoard({Player = null}) { const ScoreBoard: React.FC<{ Player: PlayerProps }> = ({ Player }) => {
const theme=useTheme(); const theme=useTheme();
return ( return (
// <div className='LeaderBoardiv'> // <div className='LeaderBoardiv'>
<div className='LeaderBoardiv'> <div className='LeaderBoardiv'>
@ -31,9 +35,36 @@ function ScoreBoard({Player = null}) {
defaultActiveKey="profile" defaultActiveKey="profile"
id="ScoreBoard" id="ScoreBoard"
className="mb-3"> className="mb-3">
<Tab eventKey="perso" title="Vos Stats" disabled = { !Player.pseudo.startsWith("Guest_") ? false : true}>
<Tab eventKey="perso" title="Vos Stats" disabled> <Container fluid>
Tab content for Contact <Row>Stats en solo :</Row>
<Row>
<Col sm={10}>Partie Jouées :</Col>
<Col className='leftRow'>{Player !== null ? Player.soloStats.nbGames : "0"}</Col>
</Row>
<Row>
<Col sm={10}>Best-Score :</Col>
<Col className='leftRow'>{Player !== null ? Player.soloStats.bestScore : "0"}</Col>
</Row>
<Row>
<Col sm={10}>Moyenne d'essai :</Col>
<Col className='leftRow'>{Player !== null ? Player.soloStats.avgNbTry : "0"}</Col>
</Row>
<hr/>
<Row>Stats en ligne :</Row>
<Row>
<Col sm={10}>Partie jouée :</Col>
<Col className='leftRow'>{Player !== null ? Player.onlineStats.nbGames : "0"}</Col>
</Row>
<Row>
<Col sm={10}>Nombre de victoire :</Col>
<Col className='leftRow'>{Player !== null ? Player.onlineStats.nbWins : "0"}</Col>
</Row>
<Row>
<Col sm={10}>Ratio P/V :</Col>
<Col className='leftRow'>{Player !== null ? Player.onlineStats.ratio : "0"}</Col>
</Row>
</Container>
</Tab> </Tab>
<Tab eventKey="daily" title="Daily" <Tab eventKey="daily" title="Daily"
style={{display:"flex", flexDirection:'column', alignItems:'center'}}> style={{display:"flex", flexDirection:'column', alignItems:'center'}}>

@ -0,0 +1,45 @@
// AuthContext.js
import React, { createContext, useContext, useState, ReactNode } from 'react';
import AuthService from '../services/AuthService';
interface AuthContextProps {
isLoggedIn: boolean;
login: () => void;
logout: () => void;
}
const AuthContext = createContext<AuthContextProps | undefined>(undefined);
const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
const login = () => {
setIsLoggedIn(true);
};
const logout = async() => {
try {
await AuthService.logout();
setIsLoggedIn(false);
}
catch (error) {
console.log(error);
};
};
return (
<AuthContext.Provider value={{ isLoggedIn, login, logout }}>
{children}
</AuthContext.Provider>
);
};
const useAuth = (): AuthContextProps => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
export { AuthProvider, useAuth };

@ -1,4 +1,6 @@
import React from 'react'; import React, {useEffect} from 'react';
import { useAuth } from '../Contexts/AuthContext';
import SessionService from '../services/SessionService';
import './Home.css'; import './Home.css';
import '../App.css'; import '../App.css';
import { useTheme } from '../Style/ThemeContext'; import { useTheme } from '../Style/ThemeContext';
@ -9,6 +11,25 @@ import ButtonImgNav from '../Components/ButtonImgNav';
function Home() { function Home() {
const theme=useTheme(); const theme=useTheme();
const {isLoggedIn, login} = useAuth();
useEffect(() => {
// Verifie la connexion
const verifSession = async () => {
try {
const sessionData = await SessionService.getSession();
if (sessionData.user) {
login();
}
}
catch (error) {
console.log(error);
};
}
verifSession();
}, []);
return ( return (
<div className="home-container"> <div className="home-container">

@ -1,11 +1,13 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { AiOutlineSend } from 'react-icons/ai'; import { AiOutlineSend } from 'react-icons/ai';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuth } from '../Contexts/AuthContext';
import AuthService from '../services/AuthService'; import AuthService from '../services/AuthService';
import '../Style/Global.css'; import '../Style/Global.css';
const SignIn = () => { const SignIn = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const { login } = useAuth();
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [showConfirmation, setShowConfirmation] = useState(false); const [showConfirmation, setShowConfirmation] = useState(false);
@ -32,6 +34,7 @@ const SignIn = () => {
setShowConfirmation(true); setShowConfirmation(true);
setTimeout(() => { setTimeout(() => {
login();
navigate('/play'); // 3 secondes avant de rediriger vers la page de connexion navigate('/play'); // 3 secondes avant de rediriger vers la page de connexion
}, 3000); }, 3000);
} }

@ -1,12 +1,12 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
/* Context */
import { useAuth } from '../Contexts/AuthContext';
/* Style */ /* Style */
import './Play.css'; import './Play.css';
import { useTheme } from '../Style/ThemeContext'; import { useTheme } from '../Style/ThemeContext';
/* Nav */
import { Link } from 'react-router-dom';
/* Component */ /* Component */
import ButtonImgNav from "../Components/ButtonImgNav" import ButtonImgNav from "../Components/ButtonImgNav"
import SessionService from "../services/SessionService"; import SessionService from "../services/SessionService";
@ -15,43 +15,66 @@ import SessionService from "../services/SessionService";
import Person from '../res/img/Person.png'; import Person from '../res/img/Person.png';
/* Icon */ /* Icon */
import trophy from '../res/icon/trophy.png';
import param from '../res/icon/param.png';
import share from '../res/icon/share.png';
import { socket } from '../SocketConfig'; import { socket } from '../SocketConfig';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import GameCreator from '../model/GameCreator'; import GameCreator from '../model/GameCreator';
import { useGame } from '../Contexts/GameContext'; import { useGame } from '../Contexts/GameContext';
import ScoreBoard from '../Components/ScoreBoard'; import ScoreBoard from '../Components/ScoreBoard';
import { set } from 'lodash';
/* Types */
import { PlayerProps } from '../types/Player';
function Play() { function Play() {
const theme=useTheme() const theme=useTheme()
const [username, setUsername] = useState(''); const {isLoggedIn, login} = useAuth();
const [nbSoloGames, setNbSoloGames] = useState(0); const [player, setPlayer] = useState<PlayerProps | null>(null);
const [soloBestScore, setSoloBestScore] = useState(0);
const [soloAverageTry, setSoloAverageTry] = useState(0);
useEffect(() => { useEffect(() => {
const fetchUserInformation = async () => { const fetchUserInformation = async () => {
try { try {
const sessionData = await SessionService.getSession(); const sessionData = await SessionService.getSession();
console.log(sessionData); // Vérifie si il y a une session
// Vérifie si il y a une session if (sessionData.user) {
if (sessionData.user) { // Il y a une session on récupère les infos du joueur
setUsername(sessionData.user.pseudo); const updatedPlayer: PlayerProps = {
setNbSoloGames(sessionData.user.soloStats.nbGames); pseudo: sessionData.user.pseudo,
setSoloBestScore(sessionData.user.soloStats.bestScore); profilePicture: sessionData.user.profilePicture,
setSoloAverageTry(sessionData.user.soloStats.averageTry); soloStats: {
} else { nbGames: sessionData.user.soloStats.nbGames,
// Pas de session on génère un guest random bestScore: sessionData.user.soloStats.bestScore,
setUsername(`Guest ${Math.floor(Math.random() * 100000)}`); avgNbTry: sessionData.user.soloStats.avgNbTry,
},
onlineStats: {
nbGames: sessionData.user.onlineStats.nbGames,
nbWins: sessionData.user.onlineStats.nbWins,
ratio: sessionData.user.onlineStats.ratio,
},
};
login();
setPlayer(updatedPlayer);
} else {
// Pas de session on génère un guest random
const guestPlayer: PlayerProps = {
pseudo: 'Guest_' + Math.floor(Math.random() * 1000000),
profilePicture: '',
soloStats: {
nbGames: 0,
bestScore: 0,
avgNbTry: 0,
},
onlineStats: {
nbGames: 0,
nbWins: 0,
ratio: 0,
},
};
setPlayer(guestPlayer);
}
} catch (error) {
console.error(error);
} }
} catch (error) {
console.error(error);
}
}; };
fetchUserInformation(); fetchUserInformation();
@ -113,7 +136,7 @@ function Play() {
<div className="MidContainer"> <div className="MidContainer">
<div> <div>
<h2> <h2>
{username} {player && player.pseudo}
</h2> </h2>
<img src={Person} <img src={Person}
height='300' height='300'
@ -129,7 +152,7 @@ function Play() {
</div> </div>
</div> </div>
<div className='rightContainer'> <div className='rightContainer'>
<ScoreBoard/> {player && (<ScoreBoard Player={player}/>)}
</div> </div>
</div> </div>
); );

@ -21,6 +21,7 @@
"log_in":" Log in ", "log_in":" Log in ",
"sign_up":" Sign up ", "sign_up":" Sign up ",
"log_out":" Log out ",
"join" : "Join", "join" : "Join",
"create_room" : "Create room", "create_room" : "Create room",

@ -21,6 +21,7 @@
"log_in":" Se connecter ", "log_in":" Se connecter ",
"sign_up":" S'inscrire ", "sign_up":" S'inscrire ",
"log_out":" Se déconnecter ",
"join" : "Rejoindre", "join" : "Rejoindre",

@ -87,16 +87,16 @@ class AuthController {
} }
} }
static getSession(req, res) { static async logout(req, res) {
console.log(req.session); // Détruire la session pour déconnecter l'utilisateur
// Vérifier si l'utilisateur est connecté req.session.destroy((err) => {
if (req.session.user) { if (err) {
// Envoyer une réponse réussie console.error(err);
res.status(200).json({ message: 'Utilisateur connecté', user: req.session.user }); res.status(500).json({ error: 'Erreur lors de la déconnexion.' });
} else { } else {
// Envoyer une réponse d'erreur res.status(200).json({ message: 'Déconnexion réussie' });
res.status(401).json({ error: 'Utilisateur non connecté' }); }
} });
} }
} }

@ -6,6 +6,7 @@ const SessionController = require('../controllers/SessionController');
// Routes pour l'authentification // Routes pour l'authentification
router.post('/auth/signup', AuthController.signUp); router.post('/auth/signup', AuthController.signUp);
router.post('/auth/signin', AuthController.signIn); router.post('/auth/signin', AuthController.signIn);
router.delete('/auth/logout', AuthController.logout)
// Routes pour les sessions // Routes pour les sessions
router.get('/session', SessionController.getUserInformation); router.get('/session', SessionController.getUserInformation);

@ -58,6 +58,29 @@ class AuthService{
throw error; throw error;
} }
} }
static async logout() {
try {
const response = await fetch('http://localhost:3003/auth/logout', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
});
if (response.ok) {
const result = await response.json();
return result;
} else {
const errorResponse = await response.json();
throw new Error(errorResponse.error);
}
} catch (error) {
console.error(error);
throw error;
}
}
} }
export default AuthService; export default AuthService;

@ -0,0 +1,18 @@
export interface PlayerSoloStats {
nbGames: number;
bestScore: number;
avgNbTry: number;
};
export interface PlayerOnlineStats {
nbGames: number;
nbWins: number;
ratio: number;
};
export interface PlayerProps {
profilePicture: string;
pseudo: string;
soloStats: PlayerSoloStats;
onlineStats: PlayerOnlineStats;
};
Loading…
Cancel
Save