From 9978c78d800e47bc3b4da9e9d878768a3114862c Mon Sep 17 00:00:00 2001 From: Angel Gabriel Manzano Contreras Date: Wed, 29 May 2024 16:11:01 -0600 Subject: [PATCH 1/4] Iniciar page almost ready + Stats page WIP --- docs/Memorama.postman_collection[1].json | 254 ++++++++++++++++++ frontend/src/app/iniciar/page.jsx | 29 +- frontend/src/app/stats/page.jsx | 10 +- frontend/src/components/host/GameForm.jsx | 24 +- .../src/libs/helpers/host/useGameInfoLogic.js | 78 ++++++ .../src/libs/helpers/host/useSubRoomLogic.js | 10 + frontend/src/services/GetAlumnosPartida.js | 9 +- frontend/src/services/GetAlumnosSubpartida.js | 2 +- frontend/src/services/crearPartida.js | 4 +- 9 files changed, 391 insertions(+), 29 deletions(-) create mode 100644 docs/Memorama.postman_collection[1].json create mode 100644 frontend/src/libs/helpers/host/useGameInfoLogic.js create mode 100644 frontend/src/libs/helpers/host/useSubRoomLogic.js diff --git a/docs/Memorama.postman_collection[1].json b/docs/Memorama.postman_collection[1].json new file mode 100644 index 0000000..4d8c244 --- /dev/null +++ b/docs/Memorama.postman_collection[1].json @@ -0,0 +1,254 @@ +{ + "info": { + "_postman_id": "2083381c-545f-49b5-859b-46b1336c927a", + "name": "Memorama", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "29780256" + }, + "item": [ + { + "name": "crear partida", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"nombre profesor\" : \"Surisadai\",\r\n \"nombre juego\" : \"TPSI 8A\",\r\n \"cartas\" : {\r\n \"0\" : {\r\n \"question\" : \"a\",\r\n \"answer\" : \"a\"\r\n },\r\n \"1\" : {\r\n \"question\" : \"b\",\r\n \"answer\" : \"b\"\r\n },\r\n \"3\" : {\r\n \"question\" : \"c\",\r\n \"answer\" : \"c\"\r\n },\r\n \"4\" : {\r\n \"question\" : \"d\",\r\n \"answer\" : \"d\"\r\n }\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://127.0.0.1:8000/api/crearPartida/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "crearPartida", + "" + ] + } + }, + "response": [] + }, + { + "name": "unirse", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "partidaID", + "value": "1", + "type": "text" + }, + { + "key": "nombre alumno", + "value": "milo", + "type": "text" + } + ] + }, + "url": { + "raw": "http://127.0.0.1:8000/api/unirse/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "unirse", + "" + ] + } + }, + "response": [] + }, + { + "name": "cartas subpartida", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://127.0.0.1:8000/api/cartas/subpartida/:subpartida/?alumno=1", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "cartas", + "subpartida", + ":subpartida", + "" + ], + "query": [ + { + "key": "alumno", + "value": "1" + } + ], + "variable": [ + { + "key": "subpartida", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "alumnos subpartida", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://127.0.0.1:8000/api/subpartida/alumnos/:subpartida/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "subpartida", + "alumnos", + ":subpartida", + "" + ], + "variable": [ + { + "key": "subpartida", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "cartas partida", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://127.0.0.1:8000/api/partida/:partida/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "partida", + ":partida", + "" + ], + "variable": [ + { + "key": "partida", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "voltear cartas", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"alumnoID\": 1,\r\n \"carta1ID\": 1,\r\n \"carta2ID\": 3\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://127.0.0.1:8000/api/subpartida/:subpartida/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "subpartida", + ":subpartida", + "" + ], + "variable": [ + { + "key": "subpartida", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "update score", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://127.0.0.1:8000/api/updateScore/:alumno/", + "protocol": "http", + "host": [ + "127", + "0", + "0", + "1" + ], + "port": "8000", + "path": [ + "api", + "updateScore", + ":alumno", + "" + ], + "variable": [ + { + "key": "alumno", + "value": "1" + } + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/frontend/src/app/iniciar/page.jsx b/frontend/src/app/iniciar/page.jsx index bbf3c58..6dc2bcf 100644 --- a/frontend/src/app/iniciar/page.jsx +++ b/frontend/src/app/iniciar/page.jsx @@ -1,22 +1,21 @@ -import HostHeader from "@/components/host/HostHeader" -import MainButton from "@/components/MainButton" -import styles from '@/styles/pages/Iniciar.module.css' +'use client'; +import useGameInfoLogic from "@/libs/helpers/host/useGameInfoLogic"; -import { DummyGame, DummySubroom } from "@/libs/Dummy" - -/* - * Dummy Data - */ -const GameInfo = DummyGame -const { players : a } = DummySubroom -const players = [ ...a, ...a] +import styles from '@/styles/pages/Iniciar.module.css'; +import HostHeader from "@/components/host/HostHeader"; +import MainButton from "@/components/MainButton"; export default function page() { + const { gameInfo, players, startGame } = useGameInfoLogic(); + return (
- - + + @@ -27,6 +26,10 @@ export default function page() {
{ players.map( ( player, key ) =>

{player.name}

) }
+ { + gameInfo.playersOnline == 0 && +

No hay jugadores en lĂ­nea

+ } diff --git a/frontend/src/app/stats/page.jsx b/frontend/src/app/stats/page.jsx index ccab465..5e3f529 100644 --- a/frontend/src/app/stats/page.jsx +++ b/frontend/src/app/stats/page.jsx @@ -1,13 +1,18 @@ "use client" +import useGameInfoLogic from "@/libs/helpers/host/useGameInfoLogic" +import useSubRoomLogic from "@/libs/helpers/host/useSubRoomLogic" + import style from "@/styles/pages/stats.module.css" import MainButton from "@/components/MainButton" import SubroomStat from "@/components/host/SubroomStat" import HostHeader from "@/components/host/HostHeader" -import { DummyGame, DummySubroom } from "@/libs/Dummy"; +import { DummySubroom } from "@/libs/Dummy"; const Page = () => { + const { queryParams, gameInfo, players } = useGameInfoLogic(); + const { Nothing_You_Could_Do } = useSubRoomLogic(); /* * I'm working with dummy data for now * This will be replaced with the real-time connection to the server @@ -19,13 +24,12 @@ const Page = () => { * - Number of players * - Teacher name */ - const GameInfo = DummyGame const Subrooms = [DummySubroom, DummySubroom] return (
- + diff --git a/frontend/src/components/host/GameForm.jsx b/frontend/src/components/host/GameForm.jsx index 847c0e8..76f49e3 100644 --- a/frontend/src/components/host/GameForm.jsx +++ b/frontend/src/components/host/GameForm.jsx @@ -36,23 +36,33 @@ const GameForm = () => { setCards(updatedCards); }; - const startGame = (userName, gameName, cards) => { + const startGame = async (userName, gameName, cards) => { let cardsObject = {} for (let i = 0; i < cards.length; i++) { cardsObject[i] = cards[i]; } - console.log(cardsObject) - console.log(cards) - - console.log("Exporting Game Data:", userName, gameName, cardsObject); - let res = CreateGame({ + let res = await CreateGame({ "nombre profesor": userName, "nombre juego": gameName, cartas: cardsObject, }); - // router.push("/iniciar"); + if (!res) { + alert("Error al crear la partida"); + return; + } + + if ( res ) { + console.log(res);//{profesorID: 9, partidaID: 9} + + const query = new URLSearchParams({ + profesorID: res.profesorID.toString(), + partidaID: res.partidaID.toString(), + }).toString(); + + router.push(`/iniciar?${query}`); + } }; const exportGameData = () => { diff --git a/frontend/src/libs/helpers/host/useGameInfoLogic.js b/frontend/src/libs/helpers/host/useGameInfoLogic.js new file mode 100644 index 0000000..c89e7cc --- /dev/null +++ b/frontend/src/libs/helpers/host/useGameInfoLogic.js @@ -0,0 +1,78 @@ +import { useSearchParams, useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { getStudentsGame } from "@/services/GetAlumnosPartida"; + +export default function useGameInfoLogic() { + const searchParams = useSearchParams(); + const router = useRouter(); + + const [ queryParams, setQueryParams] = useState({ profesorID: 0, partidaID: 0 }); + const [ gameInfo, setGameInfo ] = useState({ gameName : '', gameID : 0, teacherName : '', playersOnline : 0 }); + const [ players, setPlayers ] = useState([]); + + const startGame = () => { + const query = new URLSearchParams( queryParams ).toString(); + + router.push(`/stats?${query}`); + } + + /* + * Get the query params + */ + useEffect(() => { + const profesorID = searchParams.get("profesorID"); + const partidaID = searchParams.get("partidaID"); + + if (profesorID && partidaID) { + setQueryParams({ + profesorID: parseInt( profesorID ), + partidaID: parseInt( partidaID ) + }); + } + }, [ searchParams ]); + + /* + * Set the gameID + */ + useEffect(() => { + setGameInfo({ ...gameInfo, gameID: parseInt( queryParams.partidaID ) }); + }, [ queryParams ]); + + /* + * Get online players + */ + useEffect(() => { + const getGameInfo = async () => { + const gameStudents = await getStudentsGame( queryParams.partidaID ); + + if ( gameStudents ) setPlayers( gameStudents ); + else console.log('Error fetching students'); + } + + if ( queryParams.partidaID ) { + getGameInfo(); + + const intervalId = setInterval(() => { + getGameInfo(); + }, 3000); // Fetch every 3 seconds + + return () => clearInterval(intervalId); // Clear interval on unmount + } + + }, [ queryParams ]); + + /* + * Update the players online count + */ + useEffect(() => { + setGameInfo({ ...gameInfo, playersOnline: players.length }); + }, [ players ]); + + return { + queryParams, + gameInfo, + players, + startGame + } +} diff --git a/frontend/src/libs/helpers/host/useSubRoomLogic.js b/frontend/src/libs/helpers/host/useSubRoomLogic.js new file mode 100644 index 0000000..2aefc2c --- /dev/null +++ b/frontend/src/libs/helpers/host/useSubRoomLogic.js @@ -0,0 +1,10 @@ + +export default function useSubRoomLogic() { + // as the players come along with the subrooms + // we'll receive the players here and + // sort them into the subrooms + + return { + Nothing_You_Could_Do + } +} diff --git a/frontend/src/services/GetAlumnosPartida.js b/frontend/src/services/GetAlumnosPartida.js index 08ebdd8..c332e43 100644 --- a/frontend/src/services/GetAlumnosPartida.js +++ b/frontend/src/services/GetAlumnosPartida.js @@ -1,16 +1,17 @@ -export const getStudentsSubGame = async (partidaID) => { +export const getStudentsGame = async (partidaID) => { const res = await fetch( `http://127.0.0.1:8000/api/partida/alumnos/${partidaID}/`, { method: "GET", headers: { "Content-Type": "application/json" }, - body: {}, } ); if (!res.ok) { - console.log(res); - throw new Error(res); + console.log(res) + // In case of error, return undefined + // This will be handled in the component + return undefined; } return res.json(); diff --git a/frontend/src/services/GetAlumnosSubpartida.js b/frontend/src/services/GetAlumnosSubpartida.js index 6354a22..1bda6ee 100644 --- a/frontend/src/services/GetAlumnosSubpartida.js +++ b/frontend/src/services/GetAlumnosSubpartida.js @@ -1,4 +1,4 @@ -export const getStudentsGame = async (subpartidaID) => { +export const getStudentsSubGame = async (subpartidaID) => { const res = await fetch( `http://127.0.0.1:8000/api/subpartida/alumnos/${subpartidaID}/`, { diff --git a/frontend/src/services/crearPartida.js b/frontend/src/services/crearPartida.js index 75c1217..b1a5a92 100644 --- a/frontend/src/services/crearPartida.js +++ b/frontend/src/services/crearPartida.js @@ -7,7 +7,9 @@ export const CreateGame = async (data) => { if (!res.ok) { console.log(res) - throw new Error(res); + // In case of error, return undefined + // This will be handled in the component + return undefined; } return res.json(); From 5b454646d4eacbf771acdbb8096616e035cfe5f9 Mon Sep 17 00:00:00 2001 From: Angel Gabriel Manzano Contreras Date: Fri, 31 May 2024 15:02:09 -0600 Subject: [PATCH 2/4] Iniciar page almost ready, missing cta func, Stats page the same --- frontend/src/app/iniciar/page.jsx | 2 +- frontend/src/app/stats/page.jsx | 11 +-- frontend/src/components/Inicio.jsx | 10 ++- frontend/src/components/host/SubroomStat.jsx | 8 +- .../src/libs/helpers/host/useGameInfoLogic.js | 52 ++++++++++-- .../src/libs/helpers/host/useSubRoomLogic.js | 83 ++++++++++++++++++- frontend/src/services/GetAlumnosPartida.js | 4 +- frontend/src/services/SETTINGS.js | 5 ++ frontend/src/services/crearPartida.js | 4 +- frontend/src/services/getPatida.js | 18 ++++ 10 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 frontend/src/services/SETTINGS.js create mode 100644 frontend/src/services/getPatida.js diff --git a/frontend/src/app/iniciar/page.jsx b/frontend/src/app/iniciar/page.jsx index 6dc2bcf..d36a074 100644 --- a/frontend/src/app/iniciar/page.jsx +++ b/frontend/src/app/iniciar/page.jsx @@ -24,7 +24,7 @@ export default function page() {

Jugadores en linea

- { players.map( ( player, key ) =>

{player.name}

) } + { players.map( ( player, key ) =>

{player.nombre}

) }
{ gameInfo.playersOnline == 0 && diff --git a/frontend/src/app/stats/page.jsx b/frontend/src/app/stats/page.jsx index 5e3f529..c24f2b8 100644 --- a/frontend/src/app/stats/page.jsx +++ b/frontend/src/app/stats/page.jsx @@ -8,11 +8,9 @@ import MainButton from "@/components/MainButton" import SubroomStat from "@/components/host/SubroomStat" import HostHeader from "@/components/host/HostHeader" -import { DummySubroom } from "@/libs/Dummy"; - const Page = () => { - const { queryParams, gameInfo, players } = useGameInfoLogic(); - const { Nothing_You_Could_Do } = useSubRoomLogic(); + const { gameInfo, players } = useGameInfoLogic(); + const { subrooms } = useSubRoomLogic( players ); /* * I'm working with dummy data for now * This will be replaced with the real-time connection to the server @@ -24,7 +22,6 @@ const Page = () => { * - Number of players * - Teacher name */ - const Subrooms = [DummySubroom, DummySubroom] return (
@@ -42,8 +39,8 @@ const Page = () => { - {Subrooms.map(subroom => ( - + { Object.keys( subrooms ).map(subroom => ( + ))} diff --git a/frontend/src/components/Inicio.jsx b/frontend/src/components/Inicio.jsx index f1accdf..e0207f6 100644 --- a/frontend/src/components/Inicio.jsx +++ b/frontend/src/components/Inicio.jsx @@ -22,7 +22,15 @@ export default function Inicio() { partidaID: gameCode, "nombre alumno": name, }); - console.log(res) + + if ( !res ) { + alert("Error al unirse al juego"); + } + + if (res) { + console.log("res", res); + redirect(`/espera/?gameCode=${ gameCode.toString() }`); + } }; return ( diff --git a/frontend/src/components/host/SubroomStat.jsx b/frontend/src/components/host/SubroomStat.jsx index f2a3e67..18ee37e 100644 --- a/frontend/src/components/host/SubroomStat.jsx +++ b/frontend/src/components/host/SubroomStat.jsx @@ -3,7 +3,7 @@ import SubroomPlayer from '@/components/host/SubroomPlayer' export default function SubroomStat( { subroomID, score, position, players = [] } ) { - const MaxSubRoomScore = Math.max(...players.map( player => player.score ), 0) + const MaxPlayersScore = Math.max(...players.map( player => player.score ), 0) return ( @@ -19,9 +19,9 @@ export default function SubroomStat( { subroomID, score, position, players = [] {players.map( (player, key) => ( ))} diff --git a/frontend/src/libs/helpers/host/useGameInfoLogic.js b/frontend/src/libs/helpers/host/useGameInfoLogic.js index c89e7cc..1f362c5 100644 --- a/frontend/src/libs/helpers/host/useGameInfoLogic.js +++ b/frontend/src/libs/helpers/host/useGameInfoLogic.js @@ -2,6 +2,7 @@ import { useSearchParams, useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { getStudentsGame } from "@/services/GetAlumnosPartida"; +import { getPartida } from "@/services/getPatida"; export default function useGameInfoLogic() { const searchParams = useSearchParams(); @@ -24,11 +25,13 @@ export default function useGameInfoLogic() { const profesorID = searchParams.get("profesorID"); const partidaID = searchParams.get("partidaID"); - if (profesorID && partidaID) { - setQueryParams({ - profesorID: parseInt( profesorID ), - partidaID: parseInt( partidaID ) - }); + if ( profesorID && partidaID ) { + if ( parseInt( profesorID ) != queryParams.profesorID && parseInt( partidaID ) != queryParams.partidaID ) { + setQueryParams({ + profesorID: parseInt( profesorID ), + partidaID: parseInt( partidaID ) + }); + } } }, [ searchParams ]); @@ -40,21 +43,52 @@ export default function useGameInfoLogic() { }, [ queryParams ]); /* - * Get online players + * Get the game info */ useEffect(() => { const getGameInfo = async () => { + const game = await getPartida( queryParams.partidaID ); + + if ( game ) { + setGameInfo({ + gameName: game.nombre, + gameID: queryParams.partidaID, + teacherName: game.profesorID// This should be the teacher name + }); + } + else { + console.log(` + Error fetching game Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } + + ${ game } + `); + } + } + + if ( queryParams.partidaID ) getGameInfo(); + }, [ queryParams ]); + + /* + * Get online players + */ + useEffect(() => { + const getOnlinePlayers = async () => { const gameStudents = await getStudentsGame( queryParams.partidaID ); if ( gameStudents ) setPlayers( gameStudents ); - else console.log('Error fetching students'); + else console.log( + `Error fetching game students Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } + + ${ gameStudents } + ` + ); } if ( queryParams.partidaID ) { - getGameInfo(); + getOnlinePlayers(); const intervalId = setInterval(() => { - getGameInfo(); + getOnlinePlayers(); }, 3000); // Fetch every 3 seconds return () => clearInterval(intervalId); // Clear interval on unmount diff --git a/frontend/src/libs/helpers/host/useSubRoomLogic.js b/frontend/src/libs/helpers/host/useSubRoomLogic.js index 2aefc2c..6c8effd 100644 --- a/frontend/src/libs/helpers/host/useSubRoomLogic.js +++ b/frontend/src/libs/helpers/host/useSubRoomLogic.js @@ -1,10 +1,89 @@ +import { useEffect, useState } from "react" -export default function useSubRoomLogic() { +export default function useSubRoomLogic( inputPlayers ) { // as the players come along with the subrooms // we'll receive the players here and // sort them into the subrooms + const [ players, setPlayers ] = useState( inputPlayers ); + const [ subrooms, setSubrooms ] = useState({}); + + useEffect(() => { + if ( inputPlayers.length != players.length ) { + // update the subrooms + const sortedPlayers = sortPlayers( inputPlayers, subrooms ); + + // if there are new players, update the subrooms + if ( sortedPlayers ) { + setSubrooms( sortedPlayers ); + setPlayers( inputPlayers ); + } + } + }, [ inputPlayers ]); + + useEffect(() => { + // calculate the score of the subrooms + // and update the subrooms + const updatedSubrooms = calculateSubroomScore( subrooms ); + setSubrooms( updatedSubrooms ); + }, [ players ]); return { - Nothing_You_Could_Do + subrooms } } + +const sortPlayers = ( players, currentSubrooms ) => { + let subrooms = { ...currentSubrooms }; + + /* + * get the new players by comparing the players with the subrooms + * if the player is not in any subroom, add it to a new subroom + */ + const newPlayers = players.filter(player => + !Object.values(subrooms).some(subroom => { + /* + * check if the player is in the subroom + * It'd be nice if we could use a player ID + * So we could compare the players solo by ID + */ + return subroom.players.some( subroomPlayer => ( + subroomPlayer.nombre == player.nombre + && subroomPlayer.subpartidaID == player.subpartidaID + && subroomPlayer.puntaje == player.puntaje + ) + ); + } + ) + ); + + newPlayers.forEach( newPlayer => { + const subroomID = newPlayer.subpartidaID; + + // if the subroom doesn't exist, create it + if (!subrooms[ subroomID ]) { + subrooms[ subroomID ] = { players: [], subroomID, score: 0, position: 0 }; + } + + // add the player to the subroom + subrooms[ subroomID ].players.push( newPlayer ); + }); + + if ( newPlayers.length > 0 ) { + return subrooms; + } +} + +const calculateSubroomScore = ( subrooms ) => { + let updatedSubrooms = { ...subrooms }; + + Object.keys( updatedSubrooms ).forEach( subroomID => { + const subroom = updatedSubrooms[ subroomID ]; + /* + * Calculate the score of the subroom by adding the score of each player + */ + const score = subroom.players.reduce( (acc, player) => acc + player.puntaje, 0 ); + updatedSubrooms[ subroomID ].score = score; + }); + + return updatedSubrooms; +} \ No newline at end of file diff --git a/frontend/src/services/GetAlumnosPartida.js b/frontend/src/services/GetAlumnosPartida.js index c332e43..25839c6 100644 --- a/frontend/src/services/GetAlumnosPartida.js +++ b/frontend/src/services/GetAlumnosPartida.js @@ -1,6 +1,8 @@ +import { SERVER_URL } from "./SETTINGS"; + export const getStudentsGame = async (partidaID) => { const res = await fetch( - `http://127.0.0.1:8000/api/partida/alumnos/${partidaID}/`, + `${ SERVER_URL }/api/partida/alumnos/${partidaID}/`, { method: "GET", headers: { "Content-Type": "application/json" }, diff --git a/frontend/src/services/SETTINGS.js b/frontend/src/services/SETTINGS.js new file mode 100644 index 0000000..5277a51 --- /dev/null +++ b/frontend/src/services/SETTINGS.js @@ -0,0 +1,5 @@ +export const SERVER_PROTOCOL = 'http' +export const SERVER_PORT = '8000' +export const SERVER_IP = '127.0.0.1' + +export const SERVER_URL = `${SERVER_PROTOCOL}://${SERVER_IP}:${SERVER_PORT}` \ No newline at end of file diff --git a/frontend/src/services/crearPartida.js b/frontend/src/services/crearPartida.js index c9ebe6d..d7e932f 100644 --- a/frontend/src/services/crearPartida.js +++ b/frontend/src/services/crearPartida.js @@ -1,5 +1,7 @@ +import { SERVER_URL } from "./SETTINGS"; + export const CreateGame = async (data) => { - const res = await fetch("http://127.0.0.1:8000/api/crear/", { + const res = await fetch(`${ SERVER_URL }/api/crear/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), diff --git a/frontend/src/services/getPatida.js b/frontend/src/services/getPatida.js new file mode 100644 index 0000000..c8d97ab --- /dev/null +++ b/frontend/src/services/getPatida.js @@ -0,0 +1,18 @@ +import { SERVER_URL } from "./SETTINGS"; + +export const getPartida = async ( idPartida ) => { + const res = await fetch(`${ SERVER_URL }/api/partida/${ idPartida }`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + if (!res.ok) { + console.log(res) + // In case of error, return undefined + // This will be handled in the component + return undefined; + } + + return res.json(); + }; + \ No newline at end of file From 1225763ea8664f3a6fa43c5da894a9c52e132b08 Mon Sep 17 00:00:00 2001 From: Angel Gabriel Manzano Contreras Date: Sat, 1 Jun 2024 13:28:19 -0600 Subject: [PATCH 3/4] Code aesthetics --- frontend/src/app/stats/page.jsx | 11 ------ .../src/libs/helpers/host/useGameInfoLogic.js | 39 ++++++++++--------- .../src/libs/helpers/host/useSubRoomLogic.js | 4 -- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/frontend/src/app/stats/page.jsx b/frontend/src/app/stats/page.jsx index c24f2b8..6c3f26e 100644 --- a/frontend/src/app/stats/page.jsx +++ b/frontend/src/app/stats/page.jsx @@ -11,17 +11,6 @@ import HostHeader from "@/components/host/HostHeader" const Page = () => { const { gameInfo, players } = useGameInfoLogic(); const { subrooms } = useSubRoomLogic( players ); - /* - * I'm working with dummy data for now - * This will be replaced with the real-time connection to the server - * - * We have to get the Subrooms from the server and then map them to the SubroomStat component - * The game info probably from cookies - * - Name of the game - * - Game ID - * - Number of players - * - Teacher name - */ return (
diff --git a/frontend/src/libs/helpers/host/useGameInfoLogic.js b/frontend/src/libs/helpers/host/useGameInfoLogic.js index 1f362c5..af708ee 100644 --- a/frontend/src/libs/helpers/host/useGameInfoLogic.js +++ b/frontend/src/libs/helpers/host/useGameInfoLogic.js @@ -25,14 +25,15 @@ export default function useGameInfoLogic() { const profesorID = searchParams.get("profesorID"); const partidaID = searchParams.get("partidaID"); - if ( profesorID && partidaID ) { - if ( parseInt( profesorID ) != queryParams.profesorID && parseInt( partidaID ) != queryParams.partidaID ) { - setQueryParams({ - profesorID: parseInt( profesorID ), - partidaID: parseInt( partidaID ) - }); - } + if ( !profesorID || !partidaID ) return; + + if ( parseInt( profesorID ) != queryParams.profesorID || parseInt( partidaID ) != queryParams.partidaID ) { + setQueryParams({ + profesorID: parseInt( profesorID ), + partidaID: parseInt( partidaID ) + }); } + }, [ searchParams ]); /* @@ -57,11 +58,7 @@ export default function useGameInfoLogic() { }); } else { - console.log(` - Error fetching game Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } - - ${ game } - `); + ERROR_MESSAGE_HANDLER( 'getting game info', game ); } } @@ -76,12 +73,7 @@ export default function useGameInfoLogic() { const gameStudents = await getStudentsGame( queryParams.partidaID ); if ( gameStudents ) setPlayers( gameStudents ); - else console.log( - `Error fetching game students Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } - - ${ gameStudents } - ` - ); + else ERROR_MESSAGE_HANDLER( 'No se encontraron alumnos', gameStudents ); } if ( queryParams.partidaID ) { @@ -110,3 +102,14 @@ export default function useGameInfoLogic() { startGame } } + +const ERROR_MESSAGE = ( action, err ) => ` +Error while ${ action }: +Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } + +${ err } +`; + +const ERROR_MESSAGE_HANDLER = ( err ) => { + console.log( ERROR_MESSAGE( err ) ); +} \ No newline at end of file diff --git a/frontend/src/libs/helpers/host/useSubRoomLogic.js b/frontend/src/libs/helpers/host/useSubRoomLogic.js index 6c8effd..ec32728 100644 --- a/frontend/src/libs/helpers/host/useSubRoomLogic.js +++ b/frontend/src/libs/helpers/host/useSubRoomLogic.js @@ -1,15 +1,11 @@ import { useEffect, useState } from "react" export default function useSubRoomLogic( inputPlayers ) { - // as the players come along with the subrooms - // we'll receive the players here and - // sort them into the subrooms const [ players, setPlayers ] = useState( inputPlayers ); const [ subrooms, setSubrooms ] = useState({}); useEffect(() => { if ( inputPlayers.length != players.length ) { - // update the subrooms const sortedPlayers = sortPlayers( inputPlayers, subrooms ); // if there are new players, update the subrooms From cfe7a12113fe7ce0b3dff1c9d3d30432e0e80b1b Mon Sep 17 00:00:00 2001 From: Angel Gabriel Manzano Contreras Date: Thu, 13 Jun 2024 14:26:49 -0600 Subject: [PATCH 4/4] Added functionality to stats and iniciar pages --- frontend/src/app/iniciar/page.jsx | 15 ++- frontend/src/app/stats/page.jsx | 6 +- .../{useGameInfoLogic.js => useGameInfo.js} | 96 +++++++++++++++++-- frontend/src/services/updatePartida.js | 21 ++++ 4 files changed, 124 insertions(+), 14 deletions(-) rename frontend/src/libs/helpers/host/{useGameInfoLogic.js => useGameInfo.js} (50%) create mode 100644 frontend/src/services/updatePartida.js diff --git a/frontend/src/app/iniciar/page.jsx b/frontend/src/app/iniciar/page.jsx index d36a074..ea50d8f 100644 --- a/frontend/src/app/iniciar/page.jsx +++ b/frontend/src/app/iniciar/page.jsx @@ -1,22 +1,27 @@ 'use client'; -import useGameInfoLogic from "@/libs/helpers/host/useGameInfoLogic"; +import useGameInfo from "@/libs/helpers/host/useGameInfo"; import styles from '@/styles/pages/Iniciar.module.css'; import HostHeader from "@/components/host/HostHeader"; import MainButton from "@/components/MainButton"; export default function page() { - const { gameInfo, players, startGame } = useGameInfoLogic(); + const { gameInfo, players, statusOptions, cancelGame } = useGameInfo(); return (
+ + cancelGame( gameInfo.gameID ) } /> -
diff --git a/frontend/src/app/stats/page.jsx b/frontend/src/app/stats/page.jsx index 6c3f26e..f9877cc 100644 --- a/frontend/src/app/stats/page.jsx +++ b/frontend/src/app/stats/page.jsx @@ -1,6 +1,6 @@ "use client" -import useGameInfoLogic from "@/libs/helpers/host/useGameInfoLogic" +import useGameInfo from "@/libs/helpers/host/useGameInfo" import useSubRoomLogic from "@/libs/helpers/host/useSubRoomLogic" import style from "@/styles/pages/stats.module.css" @@ -9,14 +9,14 @@ import SubroomStat from "@/components/host/SubroomStat" import HostHeader from "@/components/host/HostHeader" const Page = () => { - const { gameInfo, players } = useGameInfoLogic(); + const { gameInfo, players, statusOptions } = useGameInfo(); const { subrooms } = useSubRoomLogic( players ); return (
- + diff --git a/frontend/src/libs/helpers/host/useGameInfoLogic.js b/frontend/src/libs/helpers/host/useGameInfo.js similarity index 50% rename from frontend/src/libs/helpers/host/useGameInfoLogic.js rename to frontend/src/libs/helpers/host/useGameInfo.js index af708ee..a813d15 100644 --- a/frontend/src/libs/helpers/host/useGameInfoLogic.js +++ b/frontend/src/libs/helpers/host/useGameInfo.js @@ -3,21 +3,95 @@ import { useEffect, useState } from "react"; import { getStudentsGame } from "@/services/GetAlumnosPartida"; import { getPartida } from "@/services/getPatida"; +import { updatePartida } from "@/services/updatePartida"; -export default function useGameInfoLogic() { +export default function useGameInfo() { const searchParams = useSearchParams(); const router = useRouter(); const [ queryParams, setQueryParams] = useState({ profesorID: 0, partidaID: 0 }); - const [ gameInfo, setGameInfo ] = useState({ gameName : '', gameID : 0, teacherName : '', playersOnline : 0 }); + const [ gameInfo, setGameInfo ] = useState({ gameName : '', gameID : 0, teacherName : '', playersOnline : 0, estado : 'Iniciando' }); const [ players, setPlayers ] = useState([]); + const [ statusOptions, setStatusOptions ] = useState({}); - const startGame = () => { + const startGame = async ( queryParams ) => { const query = new URLSearchParams( queryParams ).toString(); + const res = await updatePartida( queryParams.partidaID, { estado: 'en-progreso' } ); + if ( !res ) { + ERROR_MESSAGE_HANDLER( 'starting game', res ); + return; + } + router.push(`/stats?${query}`); } + const endGame = async ( queryParams ) => { + const query = new URLSearchParams( queryParams ).toString(); + const res = await updatePartida( queryParams.partidaID , { estado: 'finalizado' } ); + + if ( !res ) { + ERROR_MESSAGE_HANDLER( 'ending game', res ); + return; + } + + router.push(`/iniciar?${query}`); + } + + const cancelGame = async ( id ) => { + const res = await updatePartida( id, { estado: 'cancelado' } ); + + if ( !res ) { + ERROR_MESSAGE_HANDLER( 'canceling game', res ); + return; + } + + router.push(`/`); + } + + const statusHandler = () => { + /** + * I pass the queryParams to the startGame and endGame functions + * because the functions aren't reading the last value of the queryParams + * they read { profesorID: 0, partidaID: 0 } instead of the current value + */ + const currentStatus = gameInfo.estado; + + switch ( currentStatus ) { + case 'Iniciando': + setStatusOptions({ + estado: currentStatus, + action: () => startGame( queryParams ), + cta : 'Iniciar juego' + }); + break; + + case 'en-progreso': + setStatusOptions({ + estado: currentStatus, + action: () => endGame( queryParams ), + cta : 'Finalizar juego' + }); + break; + + case 'finalizado': + setStatusOptions({ + estado: currentStatus, + action: () => startGame( queryParams ), + cta : 'Jugar de nuevo' + }); + break; + + default: + setStatusOptions({ + estado: 'Iniciando', + action: () => startGame( queryParams ), + cta : 'Iniciar juego' + }); + break; + } + }; + /* * Get the query params */ @@ -25,8 +99,10 @@ export default function useGameInfoLogic() { const profesorID = searchParams.get("profesorID"); const partidaID = searchParams.get("partidaID"); + // if there's no profesorID or partidaID, return if ( !profesorID || !partidaID ) return; + // if one of the values is different from the current queryParams, update it if ( parseInt( profesorID ) != queryParams.profesorID || parseInt( partidaID ) != queryParams.partidaID ) { setQueryParams({ profesorID: parseInt( profesorID ), @@ -54,7 +130,8 @@ export default function useGameInfoLogic() { setGameInfo({ gameName: game.nombre, gameID: queryParams.partidaID, - teacherName: game.profesorID// This should be the teacher name + teacherName: game.profesorID,// This should be the teacher name + estado: game.estado }); } else { @@ -95,17 +172,24 @@ export default function useGameInfoLogic() { setGameInfo({ ...gameInfo, playersOnline: players.length }); }, [ players ]); + /* + * Update the status options + */ + useEffect(() => { + statusHandler(); + }, [ gameInfo.estado, queryParams ]); + return { queryParams, gameInfo, players, - startGame + statusOptions, + cancelGame } } const ERROR_MESSAGE = ( action, err ) => ` Error while ${ action }: -Query params: Partida ${ queryParams.partidaID } Profesor ${ queryParams.profesorID } ${ err } `; diff --git a/frontend/src/services/updatePartida.js b/frontend/src/services/updatePartida.js new file mode 100644 index 0000000..7f6b557 --- /dev/null +++ b/frontend/src/services/updatePartida.js @@ -0,0 +1,21 @@ +import { SERVER_URL } from "./SETTINGS"; + +export const updatePartida = async (partidaID, data) => { + const res = await fetch( + `${ SERVER_URL }/api/update/partida/${partidaID}/`, + { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data) + } + ); + + if (!res.ok) { + console.log(res) + // In case of error, return undefined + // This will be handled in the component + return undefined; + } + + return res.json(); +} \ No newline at end of file