diff --git a/gameservice/Dockerfile b/gameservice/Dockerfile index 12ee2849..fddddf76 100644 --- a/gameservice/Dockerfile +++ b/gameservice/Dockerfile @@ -17,4 +17,5 @@ COPY . . EXPOSE 8005 # Define the command to run your app -CMD ["node", "game-service.js"] \ No newline at end of file +CMD ["node", "game-service.js"] + diff --git a/gameservice/game-service.js b/gameservice/game-service.js index 5c9fa0a5..6d06842b 100644 --- a/gameservice/game-service.js +++ b/gameservice/game-service.js @@ -44,7 +44,42 @@ app.post('/addgame', async (req, res) => { } }); -// Lógica para juegos?? +// Ruta para obtener datos de participación del usuario +app.get('/getParticipation/:userId', async (req, res) => { + try { + const userId = req.params.userId; + + // Consulta para obtener los datos de participación del usuario + const participationData = await Game.aggregate([ + { $match: { user: mongoose.Types.ObjectId(userId) } }, + { + $group: { + _id: null, + totalGames: { $sum: 1 }, //$sum -> Returns a sum of numerical values + correctAnswers: { $sum: { $size: { + $filter: { + input: "$answers", as: "answer", cond: "$$answer.isCorrect" } + } } }, + incorrectAnswers: { $sum: { $size: { + $filter: { input: "$answers", as: "answer", cond: { $eq: ["$$answer.isCorrect", false] } } + } } }, + totalTime: { $sum: "$totalTime" }, + }, + }, + ]); + + if (participationData.length === 0) { + // No se encontraron datos para el usuario + res.status(404).json({ error: 'No participation data found for the user.' }); + return; + } + + res.status(200).json(participationData[0]); + } catch (error) { + console.error('Error al obtener datos de participación:', error); + res.status(500).json({ error: 'Internal Server Error' }); + } +}); const server = app.listen(port, () => { console.log(`Games Service listening at http://localhost:${port}`); diff --git a/gameservice/package.json b/gameservice/package.json index d4efa5ca..0c1697ab 100644 --- a/gameservice/package.json +++ b/gameservice/package.json @@ -27,4 +27,4 @@ "mongodb-memory-server": "^9.1.6", "supertest": "^6.3.4" } -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2951e9ab..ec4032e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,66 @@ "requires": true, "packages": { "": { +<<<<<<< HEAD + "dependencies": { + "chart.js": "^4.4.1", + "react-chartjs-2": "^5.2.0" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, + "node_modules/chart.js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", + "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" +======= "devDependencies": { "serve": "^14.2.1" } @@ -983,6 +1043,7 @@ }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" +>>>>>>> origin/Develop } } } diff --git a/package.json b/package.json index 66d13a98..103530b2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,13 @@ { +<<<<<<< HEAD + "dependencies": { + "chart.js": "^4.4.1", + "react-chartjs-2": "^5.2.0" + } +} +======= "devDependencies": { "serve": "^14.2.1" } -} \ No newline at end of file +} +>>>>>>> origin/Develop diff --git a/webapp/src/App.jsx b/webapp/src/App.jsx new file mode 100644 index 00000000..ee71223d --- /dev/null +++ b/webapp/src/App.jsx @@ -0,0 +1,21 @@ +import React, { useState } from 'react'; +import './App.css'; +import { Game } from './components/Game'; +import { Participation } from './components/Participation'; + +function App() { + const [menuState, setMenuState] = useState(0); + + const goTo = (parameter) => { + setMenuState(parameter); + }; + + return ( + <> + {menuState === 0 && goTo(x)} />} + {menuState === 1 && goTo(x)} />} + + ); +} + +export default App; diff --git a/webapp/src/components/Login.js b/webapp/src/components/Login.js index 5810344a..2b84d33e 100644 --- a/webapp/src/components/Login.js +++ b/webapp/src/components/Login.js @@ -10,6 +10,8 @@ const Login = ({ goTo }) => { const [loginSuccess, setLoginSuccess] = useState(false); const [createdAt, setCreatedAt] = useState(''); const [openSnackbar, setOpenSnackbar] = useState(false); + const [timeStart, setTimeStart] = useState(0); + const [timeElapsed, setTimeElapsed] = useState(0); const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000'; @@ -19,16 +21,30 @@ const Login = ({ goTo }) => { // Extract data from the response const { createdAt: userCreatedAt } = response.data; - + + setTimeStart(Date.now()); setCreatedAt(userCreatedAt); setLoginSuccess(true); +<<<<<<< HEAD + + +======= +>>>>>>> origin/Develop setOpenSnackbar(true); } catch (error) { setError(error.response.data.error); } }; + const calculateTime = async () => { + try { + setTimeElapsed((Date.now() - timeStart) / 1000); + } catch (error) { + setError(error.response.data.error); + } + }; + const handleCloseSnackbar = () => { setOpenSnackbar(false); }; @@ -46,6 +62,12 @@ const Login = ({ goTo }) => { Your account was created on {new Date(createdAt).toLocaleDateString()}. + + Han pasado {timeElapsed} segundos. + + ) : (
diff --git a/webapp/src/components/Participation.jsx b/webapp/src/components/Participation.jsx index d8ee64df..a355a393 100644 --- a/webapp/src/components/Participation.jsx +++ b/webapp/src/components/Participation.jsx @@ -1,16 +1,60 @@ -import React from 'react'; -//import Chart from "chart.js/auto"; +import React, { useState, useEffect } from 'react'; +import { Bar } from 'react-chartjs-2'; +import axios from 'axios'; -//const mongoose = require('mongoose'); +export const Participation = ({ userId, goTo }) => { + const [participationData, setParticipationData] = useState(null); -// Número de juegos, preguntas acertadas/falladas, tiempos -// Esquema de preguntas -> question, correct, incorrects[] -// Esquema de Juegos -> usuario, preguntas[], respuestas[], tiempo + useEffect(() => { + // Realizar la solicitud al servidor para obtener los datos de participación + const fetchData = async () => { + try { + const response = await axios.get(`http://localhost:8005/getParticipation/${userId}`); + setParticipationData(response.data); + } catch (error) { + console.error('Error al obtener los datos de participación:', error); + } + }; -export const Participation = () => { - return ( -
-

Participation

-
- ); + fetchData(); + }, [userId]); + + //Gráfica + const data = { + labels: ['Preguntas Acertadas', 'Preguntas Falladas'], + datasets: [ + { + label: 'Número de preguntas', + data: [participationData?.correctAnswers || 0, participationData?.incorrectAnswers || 0], + backgroundColor: ['green', 'red'], + }, + ], + }; + + const options = { + scales: { + y: { + beginAtZero: true, + max: Math.max(participationData?.correctAnswers || 0, participationData?.incorrectAnswers || 0) + 1, + }, + }, }; + + return ( +
+

Participation

+ {participationData ? ( +
+

Número de partidas jugadas: {participationData.totalGames}

+

Preguntas acertadas: {participationData.correctAnswers}

+

Preguntas falladas: {participationData.incorrectAnswers}

+

Tiempo total jugando: {participationData.totalTime} segundos

+ +
+ ) : ( +

Cargando datos de participación...

+ )} + +
+ ); +}; \ No newline at end of file