Skip to content

Commit

Permalink
Acabado final de partida
Browse files Browse the repository at this point in the history
  • Loading branch information
uo289792 committed Apr 9, 2024
1 parent f056a70 commit f8c0b3a
Show file tree
Hide file tree
Showing 13 changed files with 250 additions and 58 deletions.
75 changes: 70 additions & 5 deletions gamehistoryservice/gamehistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ app.get("/gamehistory", async (req, res) => {
totalQuestionsAnswered: gamehistory.totalQuestionsAnswered,
totalRightQuestions: gamehistory.totalRightQuestions,
totalIncorrectQuestions: gamehistory.totalIncorrectQuestions,
ratio: gamehistory.ratio + " %",
totalTime: gamehistory.totalTime + " s"
ratio: gamehistory.ratio + "%",
totalTime: gamehistory.totalTime + "s"
};
res.json(response);
} else {
Expand All @@ -65,6 +65,28 @@ app.get("/gamehistory", async (req, res) => {
}
});

app.get("/endgamestats", async (req, res) => {
try {
const userId = req.query.username;
const gameStats = await getEndGameStats(userId);

// Formatea la respuesta JSON
const response = {
totalRightQuestions: gameStats.totalRightQuestions || 0,
totalIncorrectQuestions: gameStats.totalIncorrectQuestions || 0,
ratio: (gameStats.ratio || 0) + "%",
totalTime: (gameStats.totalTime || 0) + "s"
};

// Envía la respuesta JSON
res.json(response);

} catch (error) {
res.status(400).json({ error: "Error al obtener las estadísticas de la partida: " + error.message });
}
});


async function saveGameHistory(userId) {
try {

Expand Down Expand Up @@ -126,16 +148,59 @@ app.get("/topUsers", async (req, res) => {
const topUsers = await GameHistory.find()
.sort({ ratio: -1 }) // Ordena porcentaje de aciertos de mayor a menor
const response = {
primero: topUsers[0] || null,
segundo: topUsers[1] || null,
tercero: topUsers[2] || null
primero: topUsers[0] ? topUsers[0].userId + " - " + topUsers[0].ratio + "%" : "",
segundo: topUsers[1] ? topUsers[1].userId + " - " + topUsers[1].ratio + "%": "",
tercero: topUsers[2] ? topUsers[2].userId + " - " + topUsers[2].ratio + "%": ""
};
res.json(response);
} catch (error) {
res.status(400).json({ error: "Error al obtener el ranking de usuarios: " + error.message });
}
});

async function getEndGameStats(userId) {
try {
// Busca las partidas del usuario y ordena por fecha descendente para obtener la última partida
const games = await mongoose.connection.collection('games').aggregate([
{
$match: { userId: userId }
},
{
$sort: { createdAt: -1 }
},
{
$lookup: {
from: 'questions',
localField: 'questions',
foreignField: '_id',
as: 'questionsData'
}
},
]).toArray();

// Calcula las estadísticas de la última partida
const lastGame = games[0];
const totalQuestionsAnswered = lastGame.questionsData.length;
const totalRightQuestions = lastGame.questionsData.filter(question => question.correct).length;
const totalIncorrectQuestions = totalQuestionsAnswered - totalRightQuestions;
const totalTime = lastGame.questionsData.reduce((acc, curr) => acc + (curr.time ?? 0), 0);
const ratio = totalQuestionsAnswered === 0 ? 0 : parseInt((totalRightQuestions / totalQuestionsAnswered) * 100);

// Devuelve las estadísticas
return {
totalRightQuestions,
totalIncorrectQuestions,
ratio,
totalTime
};

} catch (error) {
console.error('Error al obtener las estadísticas de la partida:', error);
throw error;
}
}


const server = app.listen(port, () => {
console.log(`Stats Service listening at http://localhost:${port}`);
});
Expand Down
10 changes: 10 additions & 0 deletions gatewayservice/gateway-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ app.get('/topUsers', async (req, res) => {
}
});

app.get('/endgamestats', async (req, res) => {
try {
const URL = gamehistoryUrl + '/endgamestats?username=' + req.query.username;
const response = await axios.get(URL);
res.json(response.data);
} catch (error) {
res.status(error.response.status).json({ error: error.response.data.error });
}
});

// Read the OpenAPI YAML file synchronously
// Hubo que cambiar el path porque los test e2e ahora sólo se ejecutan desde webapp
openapiPath='../gatewayservice/openapi.yaml'
Expand Down
13 changes: 8 additions & 5 deletions questiongenerator/game-model.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
const mongoose = require('mongoose');

const gameSchema = new mongoose.Schema({
userId:{
userId: {
type: String,
ref: 'User',
required: true,
},
questions: [
{
type: mongoose.Schema.Types.ObjectId,
ref:'Question'
ref: 'Question'
}
]

],
createdAt: {
type: Date,
default: Date.now
}
});

const Game = mongoose.model('Game', gameSchema);

module.exports = Game
module.exports = Game;
86 changes: 86 additions & 0 deletions webapp/src/components/EndGame.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useState, useEffect, useCallback } from 'react';
import axios from 'axios';
import { Container, Box, Typography, Grid, Button} from '@mui/material';
import { useUser } from './UserContext';
import { useNavigate } from 'react-router-dom';
import HomeIcon from '@mui/icons-material/Home';
import '../App.css';

const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000';

const EndGame = () => {

const { usernameGlobal } = useUser();
const navigate = useNavigate();
const [endGame, setEndGame] = useState('');
const [error, setError] = useState('');

const getEndGame = useCallback(async () => {
try {
const response = await axios.get(`${apiEndpoint}/endgamestats`,{
params: {
username: usernameGlobal
}
});
setEndGame(response.data);
} catch (error) {
setError(error.response.data.error);
}
}, [usernameGlobal])

function volverInicio() {
navigate("/PantallaInicio");
}

useEffect(() => {
getEndGame();
}, [getEndGame]);

return (
<Container component="main" maxWidth="xl"
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100%',
}}>
<Box border={2} borderColor="black" p={3} borderRadius={8} bgcolor="#9A77B0" width="30%" maxWidth={800} height="auto" maxHeight="600px">
<img src={require('./images/ronnie.gif')} alt="End Game" style={{ width: '100%', marginBottom: '16px', borderRadius: '8px' }} />
<Typography variant="h5" align="center" gutterBottom style={{ color: 'white', fontWeight: 'bold', marginBottom: '16px' }}>
Estadísticas de la última partida
</Typography>
<Grid container spacing={3} justifyContent="center">
<Grid item xs={12} textAlign="center">
<Typography variant="body1" style={{ color: 'white', fontWeight: 'bold' }}>
Preguntas correctas: {endGame.totalRightQuestions}
</Typography>
</Grid>
<Grid item xs={12} textAlign="center">
<Typography variant="body1" style={{ color: 'white', fontWeight: 'bold' }}>
Preguntas incorrectas: {endGame.totalIncorrectQuestions}
</Typography>
</Grid>
<Grid item xs={12} textAlign="center">
<Typography variant="body1" style={{ color: 'white', fontWeight: 'bold' }}>
Ratio de aciertos: {endGame.ratio}
</Typography>
</Grid>
<Grid item xs={12} textAlign="center">
<Typography variant="body1" style={{ color: 'white', fontWeight: 'bold' }}>
Tiempo total: {endGame.totalTime}
</Typography>
</Grid>
</Grid>
<Box mt={3} textAlign="center">
<Button variant="contained" color="primary" align="center" style={{ marginTop: 4, backgroundColor: '#FCF5B8', color: '#413C3C', fontWeight: 'bold'}} onClick={volverInicio}>
<HomeIcon style={{ marginRight: '8px' }} /> Volver al inicio
</Button>
</Box>
</Box>
</Container>
);
};

export default EndGame;
10 changes: 6 additions & 4 deletions webapp/src/components/Game.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ const Game = () => {
if(elapsedTime<=0){
setIsTimeRunning(false);
if (answeredQuestions >= MAX_PREGUNTAS) {
setAnsweredQuestions(0);
saveGameHistory();
navigate("/PantallaInicio");
setTimeout(() => {
setAnsweredQuestions(0);
saveGameHistory();
navigate("/EndGame");
}, 3000);
}else{
getQuestion();
}
Expand Down Expand Up @@ -114,7 +116,7 @@ const Game = () => {
setTimeout(() => {
setAnsweredQuestions(0);
saveGameHistory();
navigate("/PantallaInicio");
navigate("/EndGame");
}, 3000);
}else{
setTimeout(() => {
Expand Down
1 change: 1 addition & 0 deletions webapp/src/components/PantallaInicio.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const PantallaInicio = () => {
)}

</Container>

);
};

Expand Down
71 changes: 35 additions & 36 deletions webapp/src/components/Ranking.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useEffect, useCallback } from 'react';
import axios from 'axios';
import { Container, Box, Typography, Grid} from '@mui/material';
import HorizontalRuleIcon from '@mui/icons-material/HorizontalRule';
import { useUser } from './UserContext';
import '../App.css';

Expand All @@ -28,48 +27,48 @@ const Ranking = () => {

return (
<Container component="main" maxWidth="xl"
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100%',
}}>
<Grid container spacing={1} justifyContent="center">
{/* Fila con una columna para el primero */}
<Grid item xs={12} sm={12} md={4} textAlign="center">
{ranking && (
<Box>
<img src={require('./images/medalla-de-oro.png')} alt="Primero" style={{ width: '50%', maxWidth: '100px', marginBottom: '5px' }} />
<HorizontalRuleIcon style={{ color: 'black' }} />
<Typography variant="h6" sx={{ marginTop: '5px' }}>{ranking.primero.userId} - {ranking.primero.ratio}%</Typography>
</Box>
)}
</Grid>
{/* Fila con dos columnas para el segundo y tercero */}
<Grid item container xs={12} spacing={1} justifyContent="center">
<Grid item xs={12} sm={6} md={4} textAlign="center">
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
width: '100%',
}}>
<Box border={2} borderColor="black" p={3} borderRadius={8} bgcolor="#9A77B0" width="30%" maxWidth={800} height="auto">
<Typography variant="h5" align="center" gutterBottom style={{ color: 'white', fontWeight: 'bold', marginBottom: '16px' }}>
Top 3 Usuarios
</Typography>
<Grid container spacing={6} justifyContent="center">
<Grid item xs={12} md={4} textAlign="center">
{ranking && (
<Box>
<img src={require('./images/medalla-de-plata.png')} alt="Segundo" style={{ width: '50%', maxWidth: '100px', marginBottom: '5px' }} />
<HorizontalRuleIcon style={{ color: 'black' }} />
<Typography variant="h6" sx={{ marginTop: '5px' }}>{ranking.segundo.userId} - {ranking.segundo.ratio}%</Typography>
<img src={require('./images/medalla-de-oro.png')} alt="Primero" style={{ width: '80%', maxWidth: '160px', marginBottom: '8px' }} />
<Typography variant="h6" style={{ fontWeight: 'bold', color: 'white' }}>{ranking.primero}</Typography>
</Box>
)}
</Grid>
<Grid item xs={12} sm={6} md={4} textAlign="center">
{ranking && (
<Box>
<img src={require('./images/medalla-de-bronce.png')} alt="Tercero" style={{ width: '50%', maxWidth: '100px', marginBottom: '5px' }} />
<HorizontalRuleIcon style={{ color: 'black' }} />
<Typography variant="h6" sx={{ marginTop: '5px' }}>{ranking.tercero.userId} - {ranking.tercero.ratio}%</Typography>
</Box>
)}
<Grid item container xs={12} spacing={2} justifyContent="center">
<Grid item xs={12} sm={6} md={4} textAlign="center">
{ranking && (
<Box>
<img src={require('./images/medalla-de-plata.png')} alt="Segundo" style={{ width: '70%', maxWidth: '120px', marginBottom: '6px' }} />
<Typography variant="h6" style={{ fontWeight: 'bold', color: 'white' }}>{ranking.segundo}</Typography>
</Box>
)}
</Grid>
<Grid item xs={12} sm={6} md={4} textAlign="center">
{ranking && (
<Box>
<img src={require('./images/medalla-de-bronce.png')} alt="Tercero" style={{ width: '70%', maxWidth: '120px', marginBottom: '6px' }} />
<Typography variant="h6" style={{ fontWeight: 'bold', color: 'white' }}>{ranking.tercero}</Typography>
</Box>
)}
</Grid>
</Grid>
</Grid>
</Grid>
</Container>
</Box>
</Container>
);
};

Expand Down
22 changes: 22 additions & 0 deletions webapp/src/components/fragments/Footer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { Box, Typography } from '@mui/material';

const Footer = () => {
return (
<Box
component="footer"
py={4}
px={8}
mt={8}
sx={{
backgroundColor: '#9A77B0',
color: 'black',
textAlign: 'center'
}}
>
<Typography variant="body1" fontWeight="bold">&copy; {new Date().getFullYear()} ASW - WIQ_ES5B</Typography>
</Box>
);
}

export default Footer;
Loading

0 comments on commit f8c0b3a

Please sign in to comment.