- );
- }
-
- return <>>;
-};
-
-export default ParticlesComponent;
\ No newline at end of file
diff --git a/webapp/src/data/__questions.json b/webapp/src/data/__questions.json
deleted file mode 100644
index 876324f0..00000000
--- a/webapp/src/data/__questions.json
+++ /dev/null
@@ -1,20 +0,0 @@
-[
- {
- "question": "¿Cuál es la capital de Francia?",
- "options": ["Berlín", "París", "Londres", "Madrid"],
- "correctAnswer": "París",
- "category": "Geografía"
- },
- {
- "question": "¿En qué año comenzó la Segunda Guerra Mundial?",
- "options": ["1935", "1938", "1939", "1942"],
- "correctAnswer": "1939",
- "category": "Historia"
- },
- {
- "question": "¿Cuál es el elemento más abundante en la corteza terrestre?",
- "options": ["Hierro", "Oxígeno", "Aluminio", "Silicio"],
- "correctAnswer": "Oxígeno",
- "category": "Ciencia"
- }
-]
\ No newline at end of file
diff --git a/webapp/src/data/gameInfo.json b/webapp/src/data/gameInfo.json
index d00df85f..27a8397e 100644
--- a/webapp/src/data/gameInfo.json
+++ b/webapp/src/data/gameInfo.json
@@ -2,27 +2,39 @@
{
"nombre": "WISE MEN STACK",
"descripcion":
- "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they win €20; otherwise, they move on to the next question (as the correct answer would be the other option). If the time runs out before the question is fully asked and both possible answers are provided, the contestant may still answer it; however, if the statement hasn't been completed (or the options weren't provided), they cannot answer.",
- "foto": "../gameImg/foto0.png"
+ "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they move on to the next question.",
+ "foto": "../instructions/foto0.png",
+ "card":"The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds.",
+ "cardFoto": "../homePage/foto0.png"
},
{
"nombre": "WARM QUESTION",
"descripcion": "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly.",
- "foto": "../gameImg/foto1.jpg"
+ "foto": "../instructions/foto1.jpg",
+ "card":"It consists of ten topics of varied themes.",
+ "cardFoto": "../homePage/foto1.jpg"
},
{
"nombre": "DISCOVERING CITIES",
"descripcion": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test..",
- "foto": "../gameImg/foto2.png"
+ "foto": "../instructions/foto2.png",
+ "card":"The contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world.",
+ "cardFoto": "../homePage/foto2.png"
},
{
"nombre": "THE CHALLENGE",
"descripcion": "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes.",
- "foto": "../gameImg/foto3.jpg"
+ "foto": "../instructions/foto3.jpg",
+ "card":"The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking.",
+ "cardFoto": "../homePage/foto3.jpg"
+
},
{
- "nombre": "ONLINE MODE",
- "descripcion": "Create a room for other player to join and play 1vs1",
- "foto": "../gameImg/foto3.jpg"
+ "nombre": "MULTIPLAYER MODE",
+ "descripcion": "Create a room and share the room code with other players to play. It also has a room chat.",
+ "foto": "../instructions/online-photo.jpg",
+ "card":"Create a room and share the room code with other players to play. It also has a room chat.",
+ "cardFoto": "../homePage/online-photo.jpg"
+
}
]
\ No newline at end of file
diff --git a/webapp/src/data/icons.js b/webapp/src/data/icons.js
new file mode 100644
index 00000000..386ae2d9
--- /dev/null
+++ b/webapp/src/data/icons.js
@@ -0,0 +1,29 @@
+const getHugo = () => {
+ return "/hugoIcon.jpg";
+}
+
+const getAlberto = () => {
+ return "bertinIcon.jpg";
+ }
+
+const getWiffo = () => {
+return "wiffoIcon.jpg";
+}
+
+const getAndina = () => {
+return "and1naIcon.jpg";
+}
+
+const getSamu = () => {
+return "samuIcon.jpg";
+}
+
+const getBarrero = () => {
+return "barreroIcon.jpg";
+}
+
+const getMaite = () => {
+return "teresaIcon.jpg";
+}
+
+export { getHugo, getAlberto, getWiffo, getAndina, getSamu, getBarrero, getMaite };
\ No newline at end of file
diff --git a/webapp/src/index.css b/webapp/src/index.css
index 5bcaa367..d0d08a2c 100644
--- a/webapp/src/index.css
+++ b/webapp/src/index.css
@@ -1,5 +1,4 @@
body {
- background-image: url('../public/hurta2.jpg');
background-size: cover;
background-repeat: no-repeat;
margin: 0;
diff --git a/webapp/src/index.js b/webapp/src/index.js
index afcccc27..6172bbd1 100644
--- a/webapp/src/index.js
+++ b/webapp/src/index.js
@@ -5,6 +5,8 @@ import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from 'react-router-dom';
import { SessionProvider } from './SessionContext';
+import './localize/i18n';
+
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
diff --git a/webapp/src/localize/en.json b/webapp/src/localize/en.json
new file mode 100644
index 00000000..1522c944
--- /dev/null
+++ b/webapp/src/localize/en.json
@@ -0,0 +1,160 @@
+{
+ "Home": "PLAY",
+ "WIQ": {
+ "w": "WIKIDATA",
+ "i": "INFINITE",
+ "q": "QUEST"
+ },
+
+ "NavBar":{
+ "play": "Play",
+ "statistics": "Statistics",
+ "instructions": "Instructions",
+ "groups": "Groups",
+ "languages": {
+ "en": "English",
+ "es": "Spanish",
+ "fr": "French"
+ }
+ },
+
+ "Footer": {
+ "api_questions": "QUESTIONS API DOC",
+ "api_users": "USERS API DOC"
+ },
+
+ "Games": {
+ "wise_men": {
+ "name": "Wise Men Stack",
+ "desc": "The player chooses a topic from five available options and must answer a battery of questions related to it within 60 seconds. For each question, the host provides two options. If the contestant guesses correctly, they win €20; otherwise, they move on to the next question (as the correct answer would be the other option). If the time runs out before the question is fully asked and both possible answers are provided, the contestant may still answer it; however, if the statement hasn't been completed (or the options weren't provided), they cannot answer."
+ },
+ "warm_quest": {
+ "name": "Warm Question",
+ "desc": "It consists of ten topics of varied themes. For each correct answer, €100 is earned, and €10 are lost if the contestant passes, does not respond, or answers incorrectly."
+ },
+ "discover": {
+ "name": "Discovering Cities",
+ "desc": "In the 'Discovering Cities' game mode, the contestant will face a challenge where they will be repeatedly asked questions referring to different cities around the world. To successfully overcome the challenge, the contestant must answer as many questions as possible correctly throughout the test.."
+ },
+ "challenge": {
+ "name": "Challenge",
+ "desc": "The 'Challenge' game mode is the quintessential game mode, as it allows you to customize the match to your liking. This game mode is tailored for those who wish to practice certain game formats before engaging in our various other game modes."
+ },
+ "multiplayer": {
+ "name": "Multiplayer",
+ "desc": "Create a room for other player to join and play 1vs1"
+ }
+
+ },
+
+ "Game": {
+ "win_msg": "Great Job!",
+ "lose_msg": "Game Over",
+ "correct": "Correct Answers",
+ "incorrect": "Incorrect Answers",
+ "money": "Final points",
+ "time": "Game Time (sec)",
+ "pause": "Pause",
+ "play": "Play",
+ "round": "Question ",
+ "start": "Start game"
+ },
+
+ "Wise_Men": {
+ "instructions": "Choose a category:",
+ "category":"Categories: ",
+ "geography": "Geography",
+ "political":"Political",
+ "sports":"Sports"
+ },
+
+ "Login": {
+ "title": "Log In",
+ "username": "Username",
+ "password": "Password",
+ "button": "Log in",
+ "register_link": "Don't have an account? Register here."
+ },
+
+ "Register": {
+ "title": "Log In",
+ "username": "Username",
+ "password": "Password",
+ "name": "Name",
+ "surname": "Surname",
+ "button": "Sign up",
+ "login_link": "Already have an account? Login here."
+ },
+
+ "Groups": {
+ "title": "GROUPS",
+ "create": "Create",
+ "list": "List",
+ "create_button": "Create",
+ "name": "Name",
+ "see_members": "See Members",
+ "joined": "JOINED",
+ "join": "JOIN IT!",
+ "filled": "FILLED",
+ "Details": {
+ "creator": "Creator",
+ "date": "Created in",
+ "members": "Members"
+ }
+ },
+
+ "Statistics": {
+ "title": "STATISTICS",
+ "table": {
+ "money": "Total Points",
+ "questions_corr": "Correctly Answered Questions",
+ "questions_incorr": "Incorrectly Answered Questions",
+ "questions_pass": "Passed Questions",
+ "played_games": "Games Played",
+ "total_time": "Total Time Played",
+ "cities_corr": "Correctly Answered Cities",
+ "cities_incorr": "Incorrectly Answered Cities"
+ }
+ },
+
+ "Multiplayer": {
+ "Room": {
+ "code": "Room Code",
+ "participants": "Participants",
+ "start": "Start game",
+ "create": "Create room",
+ "join": "Join room",
+ "send": "Send",
+ "chat_title": "Chat of the room",
+ "chat_input_label": "Type your message"
+ },
+ "Game": {
+ "waiting_players_end": "Waiting for players end...",
+ "waiting": "Waiting for winner info...",
+ "winner_1": "Player winner of the game",
+ "winner_2": "with",
+ "winner_3": "correct answers in",
+ "winner_4": "seconds"
+ }
+ },
+
+ "NotFound": {
+ "title": "Page not found",
+ "button_msg": "Return to home page"
+ },
+
+ "Profile": {
+
+ "name":"Name:",
+ "surname": "Surname:",
+ "created_in":"Created in:",
+ "choose_your_avatar":"Choose your avatar:",
+ "confirm_changes":"Confirm change"
+
+ },
+ "Ranking":{
+
+ "users":"Users",
+ "groups": "Groups"
+ }
+}
\ No newline at end of file
diff --git a/webapp/src/localize/es.json b/webapp/src/localize/es.json
new file mode 100644
index 00000000..8a7d97b3
--- /dev/null
+++ b/webapp/src/localize/es.json
@@ -0,0 +1,159 @@
+{
+ "Home": "JUGAR",
+ "WIQ": {
+ "w": "WIKIDATOS",
+ "i": "INFINITO",
+ "q": "QUESTIONARIO"
+ },
+
+ "NavBar":{
+ "play": "Jugar",
+ "statistics": "Estadísticas",
+ "instructions": "Instrucciones",
+ "groups": "Grupos",
+ "languages": {
+ "en": "Inglés",
+ "es": "Español",
+ "fr": "Francés"
+ }
+ },
+
+ "Footer": {
+ "api_questions": "DOCUMENTACIÓN DE LA API DE PREGUNTAS",
+ "api_users": "DOCUMENTACIÓN DE LA API DE USUARIOS"
+ },
+
+ "Games": {
+ "wise_men": {
+ "name": "Hombres Sabiondos",
+ "desc": "El jugador elige un tema entre cinco opciones disponibles y debe responder una batería de preguntas relacionadas con él en un plazo de 60 segundos. Para cada pregunta, el presentador proporciona dos opciones. Si el concursante acierta, gana €20; de lo contrario, pasa a la siguiente pregunta (ya que la respuesta correcta sería la otra opción). Si el tiempo se agota antes de que se formule por completo la pregunta y se proporcionen ambas posibles respuestas, el concursante aún puede responderla; sin embargo, si la afirmación no se ha completado (o las opciones no se proporcionaron), no pueden responder."
+ },
+ "warm_quest": {
+ "name": "Pregunta Calentorra",
+ "desc": "Consta de diez temas de diferentes temáticas. Por cada respuesta correcta, se ganan €100, y se pierden €10 si el concursante pasa, no responde o responde incorrectamente."
+ },
+ "discover": {
+ "name": "Descubriendo Ciudades",
+ "desc": "En el modo de juego 'Descubriendo Ciudades', el concursante enfrentará un desafío donde se le harán preguntas repetidas referentes a diferentes ciudades de todo el mundo. Para superar con éxito el desafío, el concursante debe responder tantas preguntas como sea posible correctamente a lo largo de la prueba."
+ },
+ "challenge": {
+ "name": "Desafío",
+ "desc": "El modo de juego 'Desafío' es el modo de juego por excelencia, ya que te permite personalizar el enfrentamiento a tu gusto. Este modo de juego está diseñado para aquellos que deseen practicar ciertos formatos de juego antes de participar en nuestros diversos otros modos de juego."
+ },
+ "multiplayer": {
+ "name": "Multijugador",
+ "desc": "Crea una sala para que otros jugadores se unan y jueguen 1 contra 1."
+ }
+ },
+
+ "Game": {
+ "win_msg": "¡Buen trabajo!",
+ "lose_msg": "Fin del juego",
+ "correct": "Respuestas correctas",
+ "incorrect": "Respuestas incorrectas",
+ "money": "Puntos finales",
+ "time": "Tiempo de juego (seg)",
+ "pause": "Pausa",
+ "play": "Jugar",
+ "round": "Pregunta ",
+ "start": "Empezar juego"
+ },
+
+ "Wise_Men": {
+ "instructions": "Elige una categoría:",
+ "category":"Categorías: ",
+ "geography": "Geografía",
+ "political":"Política",
+ "sports":"Deporte"
+ },
+
+ "Login": {
+ "title": "Iniciar sesión",
+ "username": "Nombre de usuario",
+ "password": "Contraseña",
+ "button": "Iniciar sesión",
+ "register_link": "¿No tienes una cuenta? Regístrate aquí."
+ },
+
+ "Register": {
+ "title": "Registro",
+ "username": "Nombre de usuario",
+ "password": "Contraseña",
+ "name": "Nombre",
+ "surname": "Apellido",
+ "button": "Registrarse",
+ "login_link": "¿Ya tienes una cuenta? Inicia sesión aquí."
+ },
+
+ "Groups": {
+ "title": "GRUPOS",
+ "create": "Crear",
+ "list": "Lista",
+ "create_button": "Crear",
+ "name": "Nombre",
+ "see_members": "Ver Miembros",
+ "joined": "UNIDO",
+ "join": "¡ÚNETE!",
+ "filled": "LLENO",
+ "Details": {
+ "creator": "Creador",
+ "date": "Creado en",
+ "members": "Miembros"
+ }
+ },
+
+ "Statistics": {
+ "title": "ESTADÍSTICAS",
+ "table": {
+ "money": "Puntos Ganado",
+ "questions_corr": "Preguntas Respondidas Correctamente",
+ "questions_incorr": "Preguntas Respondidas Incorrectamente",
+ "questions_pass": "Preguntas Pasadas",
+ "played_games": "Juegos Jugados",
+ "total_time": "Tiempo Total Jugado",
+ "cities_corr": "Ciudades Respondidas Correctamente",
+ "cities_incorr": "Ciudades Respondidas Incorrectamente"
+ }
+ },
+
+ "Multiplayer": {
+ "Room": {
+ "code": "Código de Sala",
+ "participants": "Participantes",
+ "start": "Comenzar juego",
+ "create": "Crear sala",
+ "join": "Unirse a sala",
+ "send": "Enviar",
+ "chat_title": "Chat de la sala",
+ "chat_input_label": "Escribe tu mensaje"
+ },
+ "Game": {
+ "waiting_players_end": "Esperando a que terminen los demás jugadores...",
+ "waiting": "Esperando información del ganador...",
+ "winner_1": "Jugador ganador del juego",
+ "winner_2": "con",
+ "winner_3": "respuestas correctas en",
+ "winner_4": "segundos"
+ }
+ },
+
+ "NotFound": {
+ "title": "Página no encontrada",
+ "button_msg": "Volver a la página de inicio"
+ },
+
+ "Profile": {
+
+ "name":"Nombre:",
+ "surname": "Apellido:",
+ "created_in":"Fecha de registro:",
+ "choose_your_avatar":"Escoge tu avatar:",
+ "confirm_changes":"Confirmar cambio"
+
+ },
+ "Ranking":{
+
+ "users":"Usuarios",
+ "groups": "Grupos"
+ }
+}
\ No newline at end of file
diff --git a/webapp/src/localize/fr.json b/webapp/src/localize/fr.json
new file mode 100644
index 00000000..ab101a07
--- /dev/null
+++ b/webapp/src/localize/fr.json
@@ -0,0 +1,158 @@
+{
+ "Home": "JOUER",
+ "WIQ": {
+ "w": "WIKIDATA",
+ "i": "INFINITE",
+ "q": "QUEST"
+ },
+
+ "NavBar":{
+ "play": "Jouer",
+ "statistics": "Statistiques",
+ "instructions": "Instructions",
+ "groups": "Groupes",
+ "languages": {
+ "en": "Anglais",
+ "es": "Espagnol",
+ "fr": "Français"
+ }
+ },
+
+ "Footer": {
+ "api_questions": "QUESTIONS API DOC",
+ "api_users": "USERS API DOC"
+ },
+
+ "Games": {
+ "wise_men": {
+ "name": "Pile de Sages",
+ "desc": "Le joueur choisit un sujet parmi cinq options disponibles et doit répondre à une batterie de questions qui y sont liées dans un délai de 60 secondes. Pour chaque question, l'hôte fournit deux options. Si le participant devine correctement, il gagne 20 € ; sinon, il passe à la question suivante (car la bonne réponse serait l'autre option). Si le temps s'écoule avant que la question ne soit entièrement posée et que les deux réponses possibles soient fournies, le participant peut toujours y répondre ; cependant, si l'énoncé n'a pas été complété (ou si les options n'ont pas été fournies), il ne peut pas répondre."
+ },
+ "warm_quest": {
+ "name": "Question Chaleureuse",
+ "desc": "Il se compose de dix sujets de thèmes variés. Pour chaque réponse correcte, 100 € sont gagnés, et 10 € sont perdus si le participant passe, ne répond pas ou répond incorrectement."
+ },
+ "discover": {
+ "name": "Découverte des Villes",
+ "desc": "Dans le mode de jeu 'Découverte des Villes', le participant sera confronté à un défi où il lui sera posé à plusieurs reprises des questions se référant à différentes villes du monde entier. Pour surmonter avec succès le défi, le participant doit répondre correctement à autant de questions que possible tout au long du test."
+ },
+ "challenge": {
+ "name": "Défi",
+ "desc": "Le mode de jeu 'Défi' est le mode de jeu par excellence, car il vous permet de personnaliser le match à votre guise. Ce mode de jeu est adapté à ceux qui souhaitent s'entraîner à certains formats de jeu avant de s'engager dans nos divers autres modes de jeu."
+ },
+ "multiplayer": {
+ "name": "Multijoueur",
+ "desc": "Créez une salle pour que d'autres joueurs se joignent et jouent en 1 contre 1."
+ }
+
+ },
+
+ "Game": {
+ "win_msg": "Excellent travail !",
+ "lose_msg": "Partie terminée",
+ "correct": "Réponses Correctes",
+ "incorrect": "Réponses Incorrectes",
+ "money": "Points Finaux",
+ "time": "Temps de Jeu (sec)",
+ "pause": "Pause",
+ "play": "Jouer",
+ "round": "Question ",
+ "start": "Commencer à jouer"
+ },
+
+ "Wise_Men": {
+ "instructions": "Choisissez une catégorie:",
+ "category":"Catégories: ",
+ "geography": "Geographie",
+ "political":"Politique",
+ "sports":"Sport"
+ },
+
+
+ "Login": {
+ "title": "Connexion",
+ "username": "Nom d'utilisateur",
+ "password": "Mot de passe",
+ "button": "Se connecter",
+ "register_link": "Vous n'avez pas de compte ? Inscrivez-vous ici."
+ },
+
+ "Register": {
+ "title": "Inscription",
+ "username": "Nom d'utilisateur",
+ "password": "Mot de passe",
+ "name": "Prénom",
+ "surname": "Nom de famille",
+ "button": "S'inscrire",
+ "login_link": "Vous avez déjà un compte ? Connectez-vous ici."
+ },
+
+ "Groups": {
+ "title": "GROUPES",
+ "create": "Créer",
+ "list": "Liste",
+ "create_button": "Créer",
+ "name": "Nom",
+ "see_members": "Voir les Membres",
+ "joined": "REJOINT",
+ "join": "REJOINDRE !",
+ "filled": "REMPLI",
+ "Details": {
+ "creator": "Créateur",
+ "date": "Créé en",
+ "members": "Membres"
+ }
+ },
+
+ "Statistics": {
+ "title": "STATISTIQUES",
+ "table": {
+ "money": "Points gagnés",
+ "questions_corr": "Questions Correctement Répondues",
+ "questions_incorr": "Questions Incorrectement Répondues",
+ "questions_pass": "Questions Passées",
+ "played_games": "Parties Jouées",
+ "total_time": "Temps Total Joué",
+ "cities_corr": "Villes Répondus Correctement",
+ "cities_incorr": "Villes Répondus Incorrectement"
+ }
+ },
+
+ "Multiplayer": {
+ "Room": {
+ "code": "Code de la Salle",
+ "participants": "Participants",
+ "start": "Démarrer le jeu",
+ "create": "Créer une salle",
+ "join": "Rejoindre une salle",
+ "send": "Envoyer",
+ "chat_title": "Discussion de la salle",
+ "chat_input_label": "Tape ton message"
+ },
+ "Game": {
+ "waiting_players_end": "En attendant que tous les joueurs finissent...",
+ "waiting": "En attente des informations du gagnant...",
+ "winner_1": "Joueur gagnant de la partie",
+ "winner_2": "avec",
+ "winner_3": "réponses correctes en",
+ "winner_4": "secondes"
+ }
+ },
+
+ "NotFound": {
+ "title": "Page non trouvée",
+ "button_msg": "Retour à la page d'accueil"
+ },
+ "Profile": {
+ "name":"Nom :",
+ "surname": "Nom de famille :",
+ "created_in":"Créé à :",
+ "choose_your_avatar":"Choisissez votre avatar :",
+ "confirm_changes":"Confirmer les changements"
+ },
+ "Ranking": {
+ "users": "Utilisateurs",
+ "groups": "Groupes"
+ }
+
+}
diff --git a/webapp/src/localize/i18n.js b/webapp/src/localize/i18n.js
new file mode 100644
index 00000000..8135a7ef
--- /dev/null
+++ b/webapp/src/localize/i18n.js
@@ -0,0 +1,36 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import es_translation from "./es.json";
+import en_translation from "./en.json";
+import fr_translation from "./fr.json";
+
+// the translations
+// (tip move them in a JSON file and import them,
+// or even better, manage them separated from your code: https://react.i18next.com/guides/multiple-translation-files)
+const resources = {
+ en: {
+ translation: en_translation
+ },
+ es: {
+ translation: es_translation
+ },
+ fr: {
+ translation: fr_translation
+ }
+};
+
+i18n
+ .use(initReactI18next) // passes i18n down to react-i18next
+ .init({
+ resources,
+ lng: "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
+ // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
+ // if you're using a language detector, do not define the lng option
+
+ interpolation: {
+ escapeValue: false // react already safes from xss
+ },
+ fallbackLng: "en"
+});
+
+export default i18n;
\ No newline at end of file
diff --git a/webapp/src/pages/DiscoveringCitiesGame.js b/webapp/src/pages/DiscoveringCitiesGame.js
new file mode 100644
index 00000000..3d50053e
--- /dev/null
+++ b/webapp/src/pages/DiscoveringCitiesGame.js
@@ -0,0 +1,389 @@
+import * as React from 'react';
+import axios from 'axios';
+import { Container, Button, CssBaseline, Grid, Typography, CircularProgress, Card, CardContent } from '@mui/material';
+import { PlayArrow, Pause } from '@mui/icons-material';
+import CheckIcon from '@mui/icons-material/Check';
+import ClearIcon from '@mui/icons-material/Clear';
+import { useNavigate } from 'react-router-dom';
+import { SessionContext } from '../SessionContext';
+import { useContext } from 'react';
+import Confetti from 'react-confetti';
+import { CountdownCircleTimer } from "react-countdown-circle-timer";
+import { useTranslation } from 'react-i18next';
+import i18n from '../localize/i18n';
+
+const apiEndpoint = process.env.REACT_APP_API_ENDPOINT || 'http://localhost:8000';
+
+const DiscovertingCitiesGame = () => {
+ const navigate = useNavigate();
+ const MAX_ROUNDS = 5;
+ const SUCCESS_SOUND_ROUTE = "/sounds/success_sound.mp3";
+ const FAILURE_SOUND_ROUTE = "/sounds/wrong_sound.mp3";
+
+ //sesion information
+ const {username} = useContext(SessionContext);
+
+ // Traductions
+ const { t } = useTranslation();
+
+ // state initialization
+ const [round, setRound] = React.useState(1);
+ const [questionData, setQuestionData] = React.useState(null);
+ const [buttonStates, setButtonStates] = React.useState([]);
+ const [answered, setAnswered] = React.useState(false);
+ const [shouldRedirect, setShouldRedirect] = React.useState(false);
+ const [totalScore, setTotalScore] = React.useState(0);
+ const [correctlyAnsweredQuestions, setCorrectlyAnsweredQuestions] = React.useState(0);
+ const [incorrectlyAnsweredQuestions, setIncorrectlyAnsweredQuestions] = React.useState(0);
+ const [totalTimePlayed, setTotalTimePlayed] = React.useState(0);
+ const [timerRunning, setTimerRunning] = React.useState(true); // indicate if the timer is working
+ const [showConfetti, setShowConfetti] = React.useState(false); //indicates if the confetti must appear
+ const [questionCountdownKey, setQuestionCountdownKey] = React.useState(15); //key to update question timer
+ const [questionCountdownRunning, setQuestionCountdownRunning] = React.useState(false); //property to start and stop question timer
+ const [userResponses, setUserResponses] = React.useState([]);
+ const [language, setCurrentLanguage] = React.useState(i18n.language);
+
+ const [questionHistorial, setQuestionHistorial] = React.useState(Array(MAX_ROUNDS).fill(null));
+
+ React.useEffect(() => {
+ let timer;
+ if (timerRunning) {
+ timer = setInterval(() => {
+ setTotalTimePlayed((prevTotalTime) => prevTotalTime + 1);
+ }, 1000);
+ }
+
+ return () => clearInterval(timer);
+ }, [timerRunning]);
+
+ // hook to initiating new rounds if the current number of rounds is less than or equal to 3
+ React.useEffect(() => {
+ if (round <= MAX_ROUNDS) {
+ startNewRound();
+ setQuestionCountdownRunning(true);
+ setQuestionCountdownKey(questionCountdownKey => questionCountdownKey + 1); //code to reset countdown timer
+ } else {
+ setTimerRunning(false);
+ setShouldRedirect(true);
+ setQuestionCountdownRunning(false);
+ updateStatistics();
+ updateQuestionsRecord();
+ }
+ // eslint-disable-next-line
+ }, [round]);
+
+ // stablish if the confetti must show or not
+ React.useEffect(() => {
+ if (correctlyAnsweredQuestions > incorrectlyAnsweredQuestions) {
+ setShowConfetti(true);
+ } else {
+ setShowConfetti(false);
+ }
+ }, [correctlyAnsweredQuestions, incorrectlyAnsweredQuestions]);
+
+
+ // gets a random question from the database and initializes button states to null
+ const startNewRound = async () => {
+ setAnswered(false);
+ // It works deploying using git repo from machine with: axios.get(`http://20.80.235.188:8000/questions`)
+ // Updates current language
+ setCurrentLanguage(i18n.language);
+ axios.get(`${apiEndpoint}/questions/${language}/Cities`)
+ .then(quest => {
+ // every new round it gets a new question from db
+ setQuestionData(quest.data[0]);
+ setButtonStates(new Array(quest.data[0].options.length).fill(null));
+ }).catch(error => {
+ console.error(error);
+ });
+ };
+
+ const updateStatistics = async() => {
+ try {
+ await axios.post(`${apiEndpoint}/statistics`, {
+ username:username,
+ the_callenge_earned_money:0,
+ the_callenge_correctly_answered_questions:0,
+ the_callenge_incorrectly_answered_questions:0,
+ the_callenge_total_time_played:0,
+ the_callenge_games_played:0,
+ wise_men_stack_earned_money: 0,
+ wise_men_stack_correctly_answered_questions: 0,
+ wise_men_stack_incorrectly_answered_questions: 0,
+ wise_men_stack_games_played: 0,
+ warm_question_earned_money: 0,
+ warm_question_correctly_answered_questions: 0,
+ warm_question_incorrectly_answered_questions: 0,
+ warm_question_passed_questions: 0,
+ warm_question_games_played: 0,
+ discovering_cities_earned_money: totalScore,
+ discovering_cities_correctly_answered_questions: correctlyAnsweredQuestions,
+ discovering_cities_incorrectly_answered_questions: incorrectlyAnsweredQuestions,
+ discovering_cities_games_played: 1,
+ online_earned_money: 0,
+ online_correctly_answered_questions: 0,
+ online_incorrectly_answered_questions: 0,
+ online_total_time_played: 0,
+ online_games_played: 0,
+ });
+ } catch (error) {
+ console.error("Error:", error);
+ };
+ }
+
+ const updateQuestionsRecord = async() => {
+ try {
+ await axios.post(`${apiEndpoint}/user/questionsRecord`, {
+ questions: userResponses,
+ username: username,
+ gameMode: "DiscoveringCities"
+ });
+ } catch (error) {
+ console.error("Error:", error);
+ };
+ }
+
+ // this function is called when a user selects a response.
+ const selectResponse = async (index, response) => {
+ setAnswered(true);
+ const newButtonStates = [...buttonStates];
+
+ setQuestionCountdownRunning(false);
+
+ //check answer
+ if (response === questionData.correctAnswer) {
+ const userResponse = {
+ question: questionData.question,
+ response: response,
+ options: questionData.options,
+ correctAnswer: questionData.correctAnswer
+ };
+ setUserResponses(prevResponses => [...prevResponses, userResponse]);
+
+ newButtonStates[index] = "success"
+ const sucessSound = new Audio(SUCCESS_SOUND_ROUTE);
+ sucessSound.volume = 0.40;
+ sucessSound.play();
+ setCorrectlyAnsweredQuestions(correctlyAnsweredQuestions + 1);
+ setTotalScore(totalScore + 20);
+
+ const newQuestionHistorial = [...questionHistorial];
+ newQuestionHistorial[round-1] = true;
+ setQuestionHistorial(newQuestionHistorial);
+ } else {
+ const userResponse = {
+ question: questionData.question,
+ response: response,
+ options: questionData.options,
+ correctAnswer: questionData.correctAnswer
+ };
+ setUserResponses(prevResponses => [...prevResponses, userResponse]);
+ newButtonStates[index] = "failure";
+ const failureSound = new Audio(FAILURE_SOUND_ROUTE);
+ failureSound.volume = 0.40;
+ failureSound.play();
+ for (let i = 0; i < questionData.options.length; i++) {
+ if (questionData.options[i] === questionData.correctAnswer) {
+ newButtonStates[i] = "success";
+ }
+ }
+ setIncorrectlyAnsweredQuestions(incorrectlyAnsweredQuestions + 1);
+
+ const newQuestionHistorial = [...questionHistorial];
+ newQuestionHistorial[round-1] = false;
+ setQuestionHistorial(newQuestionHistorial);
+ }
+
+ setButtonStates(newButtonStates);
+
+ setTimeout(async() => {
+ setRound(round + 1);
+ setButtonStates([]);
+ setCurrentLanguage(i18n.language);
+
+ }, 4000);
+ };
+
+ const questionHistorialBar = () => {
+ return questionHistorial.map((isCorrect, index) => (
+
+ {index + 1}
+
+ ));
+ };
+
+ const togglePause = () => {
+ setTimerRunning(!timerRunning);
+ setQuestionCountdownRunning(!timerRunning);
+ if (timerRunning) {
+ // Si el juego estaba en marcha y se pausa, deshabilitar los botones
+ setButtonStates(new Array(questionData.options.length).fill(true));
+ } else {
+ // Si el juego estaba pausado y se reanuda, habilitar los botones
+ setButtonStates(new Array(questionData.options.length).fill(null));
+ }
+ }
+
+
+ // circular loading
+ if (!questionData) {
+ return (
+
+
+
+
+ );
+ }
+
+ // redirect to / if game over
+if (shouldRedirect) {
+ // Redirect after 3 seconds
+ setTimeout(() => {
+ navigate('/homepage');
+ }, 4000);
+
+
+ return (
+
+
+ incorrectlyAnsweredQuestions ? 'green' : 'red',
+ fontSize: '4rem', // Tamaño de fuente
+ marginTop: '20px', // Espaciado superior
+ marginBottom: '50px', // Espaciado inferior
+ }}
+ >
+ {correctlyAnsweredQuestions > incorrectlyAnsweredQuestions ? t("Game.win_msg") : t("Game.lose_msg") }
+
+