diff --git a/gamehistoryservice/gamehistory.js b/gamehistoryservice/gamehistory.js
index 2c1a069a..ea9f939b 100644
--- a/gamehistoryservice/gamehistory.js
+++ b/gamehistoryservice/gamehistory.js
@@ -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 {
@@ -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 {
@@ -126,9 +148,9 @@ 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) {
@@ -136,6 +158,49 @@ app.get("/topUsers", async (req, res) => {
}
});
+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}`);
});
diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js
index 8da47664..6822741f 100644
--- a/gatewayservice/gateway-service.js
+++ b/gatewayservice/gateway-service.js
@@ -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'
diff --git a/questiongenerator/game-model.js b/questiongenerator/game-model.js
index 8e97397d..9c30a4b6 100644
--- a/questiongenerator/game-model.js
+++ b/questiongenerator/game-model.js
@@ -1,7 +1,7 @@
const mongoose = require('mongoose');
const gameSchema = new mongoose.Schema({
- userId:{
+ userId: {
type: String,
ref: 'User',
required: true,
@@ -9,12 +9,15 @@ const gameSchema = new mongoose.Schema({
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
\ No newline at end of file
+module.exports = Game;
\ No newline at end of file
diff --git a/webapp/src/components/EndGame.js b/webapp/src/components/EndGame.js
new file mode 100644
index 00000000..959b7625
--- /dev/null
+++ b/webapp/src/components/EndGame.js
@@ -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 (
+
+
+
+
+ Estadísticas de la última partida
+
+
+
+
+ Preguntas correctas: {endGame.totalRightQuestions}
+
+
+
+
+ Preguntas incorrectas: {endGame.totalIncorrectQuestions}
+
+
+
+
+ Ratio de aciertos: {endGame.ratio}
+
+
+
+
+ Tiempo total: {endGame.totalTime}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default EndGame;
\ No newline at end of file
diff --git a/webapp/src/components/Game.js b/webapp/src/components/Game.js
index b4f76bd9..148c7cbe 100644
--- a/webapp/src/components/Game.js
+++ b/webapp/src/components/Game.js
@@ -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();
}
@@ -114,7 +116,7 @@ const Game = () => {
setTimeout(() => {
setAnsweredQuestions(0);
saveGameHistory();
- navigate("/PantallaInicio");
+ navigate("/EndGame");
}, 3000);
}else{
setTimeout(() => {
diff --git a/webapp/src/components/PantallaInicio.js b/webapp/src/components/PantallaInicio.js
index c3c2ad3f..522c9f67 100644
--- a/webapp/src/components/PantallaInicio.js
+++ b/webapp/src/components/PantallaInicio.js
@@ -56,6 +56,7 @@ const PantallaInicio = () => {
)}
+
);
};
diff --git a/webapp/src/components/Ranking.js b/webapp/src/components/Ranking.js
index 86430bc3..b190f0cf 100644
--- a/webapp/src/components/Ranking.js
+++ b/webapp/src/components/Ranking.js
@@ -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';
@@ -28,48 +27,48 @@ const Ranking = () => {
return (
-
- {/* Fila con una columna para el primero */}
-
- {ranking && (
-
-
-
- {ranking.primero.userId} - {ranking.primero.ratio}%
-
- )}
-
- {/* Fila con dos columnas para el segundo y tercero */}
-
-
+ sx={{
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ height: '100vh',
+ width: '100%',
+ }}>
+
+
+ Top 3 Usuarios
+
+
+
{ranking && (
-
-
- {ranking.segundo.userId} - {ranking.segundo.ratio}%
+
+ {ranking.primero}
)}
-
- {ranking && (
-
-
-
- {ranking.tercero.userId} - {ranking.tercero.ratio}%
-
- )}
+
+
+ {ranking && (
+
+
+ {ranking.segundo}
+
+ )}
+
+
+ {ranking && (
+
+
+ {ranking.tercero}
+
+ )}
+
-
-
+
+
);
};
diff --git a/webapp/src/components/fragments/Footer.js b/webapp/src/components/fragments/Footer.js
new file mode 100644
index 00000000..e216ee06
--- /dev/null
+++ b/webapp/src/components/fragments/Footer.js
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Box, Typography } from '@mui/material';
+
+const Footer = () => {
+ return (
+
+ © {new Date().getFullYear()} ASW - WIQ_ES5B
+
+ );
+}
+
+export default Footer;
diff --git a/webapp/src/components/NavigationBar.js b/webapp/src/components/fragments/NavigationBar.js
similarity index 77%
rename from webapp/src/components/NavigationBar.js
rename to webapp/src/components/fragments/NavigationBar.js
index 6b66ed4e..5fd3e8dd 100644
--- a/webapp/src/components/NavigationBar.js
+++ b/webapp/src/components/fragments/NavigationBar.js
@@ -2,7 +2,7 @@
import React, { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { AppBar, Button, Grid } from '@mui/material';
-import { useUser } from './UserContext';
+import { useUser } from '../UserContext';
const NavigationBar = () => {
@@ -47,22 +47,22 @@ const NavigationBar = () => {
{/* Columna izquierda */}
{/* Columna derecha */}
diff --git a/webapp/src/components/NavigationBar.test.js b/webapp/src/components/fragments/NavigationBar.test.js
similarity index 89%
rename from webapp/src/components/NavigationBar.test.js
rename to webapp/src/components/fragments/NavigationBar.test.js
index 6628def5..3145e822 100644
--- a/webapp/src/components/NavigationBar.test.js
+++ b/webapp/src/components/fragments/NavigationBar.test.js
@@ -1,7 +1,7 @@
import React from 'react';
import { render} from '@testing-library/react';
import { MemoryRouter as Router } from "react-router-dom";
-import { UserProvider } from './UserContext';
+import { UserProvider } from '../UserContext';
import NavigationBar from './NavigationBar';
describe('Navigation bar component', () => {
diff --git a/webapp/src/components/images/perroBasado.png b/webapp/src/components/images/perroBasado.png
new file mode 100644
index 00000000..f4caba53
Binary files /dev/null and b/webapp/src/components/images/perroBasado.png differ
diff --git a/webapp/src/components/images/ronnie.gif b/webapp/src/components/images/ronnie.gif
new file mode 100644
index 00000000..18a7b2ea
Binary files /dev/null and b/webapp/src/components/images/ronnie.gif differ
diff --git a/webapp/src/index.js b/webapp/src/index.js
index 49bb1d72..bd086078 100644
--- a/webapp/src/index.js
+++ b/webapp/src/index.js
@@ -2,7 +2,6 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
-import NavigationBar from './components/NavigationBar';
import reportWebVitals from './reportWebVitals';
import { UserProvider } from './components/UserContext';
@@ -18,6 +17,9 @@ import AddUser from './components/AddUser';
import Game from './components/Game';
import Gamehistory from './components/Gamehistory';
import Ranking from './components/Ranking';
+import EndGame from './components/EndGame';
+import Footer from './components/fragments/Footer';
+import NavigationBar from './components/fragments/NavigationBar';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
@@ -34,7 +36,9 @@ root.render(
} />
} />
} />
+ } />
+