Skip to content

Commit

Permalink
game1 functionality added
Browse files Browse the repository at this point in the history
  • Loading branch information
angelalvaigle committed Nov 10, 2024
1 parent a0936fe commit 9e5f6e4
Show file tree
Hide file tree
Showing 13 changed files with 479 additions and 14 deletions.
4 changes: 4 additions & 0 deletions questionservice/question-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ const questionSchema = new mongoose.Schema({
type: String,
required: true,
},
name: {
type: String,
required: true,
},
path: {
type: String,
required: true,
Expand Down
9 changes: 5 additions & 4 deletions questionservice/question-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ app.post('/addquestion', async (req, res) => {
try {
const newQuestion = new Question({
type: req.body.type,
name: req.body.name,
path: req.body.path,
right: req.body.right,
// wrong1: req.body.wrong1,
// wrong2: req.body.wrong2,
// wrong3: req.body.wrong3,
wrong1: req.body.wrong1,
wrong2: req.body.wrong2,
wrong3: req.body.wrong3,
});
await newQuestion.save();
res.json(newQuestion);
Expand All @@ -34,7 +35,7 @@ app.post('/addquestion', async (req, res) => {

app.get('/questions', async (req, res) => {
try {
const questions = await Question.find(); // Fetch all questions
const questions = await Question.aggregate([{ $sample: { size: 5 } }]);
res.json(questions);
} catch (error) {
res.status(500).json({ error: error.message });
Expand Down
15 changes: 15 additions & 0 deletions webapp/src/assets/wrappers/InfoContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import styled from 'styled-components';

const Wrapper = styled.div`
background: var(--background-secondary-color);
border-radius: var(--border-radius);
margin: 0.5rem auto;
padding: 1.5rem;
min-width: 175px;
box-shadow: var(--shadow-2);
h5 {
align-self: flex-start; /* Alinea el texto a la izquierda */
}
`;

export default Wrapper;
18 changes: 18 additions & 0 deletions webapp/src/assets/wrappers/Play.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import styled from 'styled-components';

const Wrapper = styled.div`
display: flex; /* Usamos flexbox */
flex-direction: row
align-items: center; /* Alinea los elementos verticalmente en el centro */
justify-content: flex-start; /* Alinea los elementos en el inicio (izquierda) */
border-radius: var(--border-radius);
margin: 0.5rem auto;
padding: 1rem;
max-width: 1200px;
h5 {
align-self: flex-start; /* Alinea el texto a la izquierda */
}
`;

export default Wrapper;
67 changes: 67 additions & 0 deletions webapp/src/assets/wrappers/QuestionContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import styled from 'styled-components';

const Wrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
background: var(--background-secondary-color);
border-radius: var(--border-radius);
margin: 0.5rem auto;
padding: 1rem;
max-width: 700px;
box-shadow: var(--shadow-2);
h3,
h5 {
align-self: flex-start; /* Alinea el texto a la izquierda */
margin: 0 0 1.5rem 0; /* Margen inferior para separar el texto de la imagen */
}
p {
align-self: flex-start; /* Alinea el texto a la izquierda */
margin: 1.5rem 0 0 0; /* Margen superior para separar el texto de los botones */
}
.image {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 0 1.5rem 0; /* Margen inferior para separar la imagen de los botones*/
}
img {
width: auto; // Mantiene el ratio
max-width: 80%;
height: auto; // Ajusta al alto del contenedor
max-height: 500px;
object-fit: contain; // Asegura que la imagen no se recorte ni se distorsione
}
.buttons-container {
display: grid;
grid-template-columns: 1fr 1fr; /* Dos columnas de igual ancho */
grid-template-rows: 1fr 1fr; /* Dos filas de igual altura */
gap: 1rem;
}
.btn {
padding: 1rem;
font-size: 1rem;
cursor: pointer;
border: none;
border-radius: 4px;
&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
}
.btn.correct {
background-color: green;
color: white;
}
.btn.incorrect {
background-color: red;
color: white;
}
.result {
font-size: 1.25rem;
font-weight: bold;
}
`;

export default Wrapper;
61 changes: 52 additions & 9 deletions webapp/src/components/AddQuestionContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,25 @@ const AddQuestionContainer = () => {
const [openSnackbar, setOpenSnackbar] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);

const addQuestion = async ({ type, path, right }) => {
const addQuestion = async ({
type,
name,
path,
right,
wrong1,
wrong2,
wrong3,
}) => {
try {
await axios.post(`${apiEndpoint}/addquestion`, { type, path, right });
await axios.post(`${apiEndpoint}/addquestion`, {
type,
name,
path,
right,
wrong1,
wrong2,
wrong3,
});
setOpenSnackbar(true);
} catch (error) {
console.log(error);
Expand All @@ -31,19 +47,46 @@ const AddQuestionContainer = () => {
const query = await queryDispatcher.query(artworksQuery);
// handle results
const bindings = query.results.bindings;
// Crear un array para almacenar todas las posibles opciones de creadores
const allCreators = bindings.map((result) => result.creatorLabel.value);
for (const result of bindings) {
// Accedemos a cada propiedad
const workLabel = result.workLabel.value; // Título de la obra
const creator = result.creatorLabel.value; // Nombre del creador
const imageUrl = result.image.value; // URL de la imagen
const sitelinks = result.sitelinks.value; // Número de sitelinks
const name = result.workLabel.value; // Título de la obra
const path = result.image.value; // URL de la imagen
const right = result.creatorLabel.value; // Nombre del creador

// Filtrar creadores para obtener solo los que sean diferentes a la respuesta correcta
const incorrectCreators = allCreators.filter(
(creator) => creator !== right
);

// Seleccionar tres opciones incorrectas de manera aleatoria
const wrongCreators = [];
while (wrongCreators.length < 3) {
const randomCreator =
incorrectCreators[
Math.floor(Math.random() * incorrectCreators.length)
];

// Agregar solo si no está ya en la lista de opciones incorrectas
if (
!wrongCreators.includes(randomCreator) &&
!randomCreator.startsWith('http')
) {
wrongCreators.push(randomCreator);
}
}

// Muestra los resultados en la consola
if (!workLabel.startsWith('http') && !creator.startsWith('http')) {
if (!name.startsWith('http') && !right.startsWith('http')) {
await addQuestion({
type: 'artwork',
path: workLabel,
right: creator,
name: name,
path: path,
right: right,
wrong1: wrongCreators[0],
wrong2: wrongCreators[1],
wrong3: wrongCreators[2],
});
}
}
Expand Down
14 changes: 14 additions & 0 deletions webapp/src/components/GameOverContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import Wrapper from '../assets/wrappers/InfoContainer';

const GameOverContainer = ({ score }) => {
return (
<Wrapper>
<div className="score">
<h1>Game Over</h1>
</div>
</Wrapper>
);
};

export default GameOverContainer;
123 changes: 123 additions & 0 deletions webapp/src/components/QuestionContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React, { useState, useEffect } from 'react';
import Wrapper from '../assets/wrappers/QuestionContainer';

const QuestionContainer = ({
shuffledAnswers,
name,
path,
right,
updateScore,
isActive,
onCorrectAnswer,
loadNextQuestion,
}) => {
// Estado para manejar las respuestas seleccionadas
const [selectedAnswer, setSelectedAnswer] = useState(null);
const [incorrectAnswers, setIncorrectAnswers] = useState([]);
const [showResult, setShowResult] = useState(false);

// Efecto para reiniciar los estados cuando se carga una nueva pregunta
useEffect(() => {
// Restablecemos el estado al cargar una nueva pregunta
setSelectedAnswer(null);
setIncorrectAnswers([]);
setShowResult(false);
}, [right, name, path]);

// Efecto para seleccionar la respuesta correcta automáticamente cuando el tiempo se agota
useEffect(() => {
if (!isActive && selectedAnswer === null) {
setSelectedAnswer(right); // Seleccionamos la respuesta correcta
setShowResult(true);
}
}, [isActive, selectedAnswer, right]);

// Función para manejar el clic en las respuestas
const handleAnswerClick = (answer) => {
if (answer === right) {
// Si la respuesta es correcta, la seleccionamos y deshabilitamos todos los botones
setSelectedAnswer(answer);
onCorrectAnswer(); // Detenemos el temporizador
setShowResult(true);
} else {
// Sumar 100 puntos por cada respuesta incorrecta seleccionada
updateScore();
setIncorrectAnswers((prev) => {
const newIncorrectAnswers = [...prev, answer];
// Si ya se han seleccionado 3 respuestas incorrectas, selecciona la correcta por descarte
if (newIncorrectAnswers.length === 3) {
setSelectedAnswer(right);
onCorrectAnswer(); // Detenemos el temporizador
setShowResult(true);
}
return newIncorrectAnswers;
});
}
};

useEffect(() => {
if (showResult) {
const timer = setTimeout(() => {
loadNextQuestion(); // Cargar la siguiente pregunta después del retraso
}, 2000); // Esperar 2 segundos antes de cargar la siguiente pregunta

return () => clearTimeout(timer); // Limpiar el temporizador cuando se desmonte o cambie el resultado
}
}, [showResult]); //, loadNextQuestion]);

return (
<Wrapper>
{/* Título de la obra */}
<h3>{`¿Quién creó la obra "${name}"?`}</h3>
{/* Imagen de la obra */}
<div className="image">
<img src={path} alt={name} />
</div>
<div>
<h5>Descarta las respuestas incorrectas</h5>
</div>
{/* Renderizar botones con las respuestas */}
<div className="buttons-container">
{shuffledAnswers.map((answer, index) => (
<button
className={`btn ${
selectedAnswer === right
? answer === right && incorrectAnswers.length === 3 // Marca la respuesta correcta cuando se selecciona
? 'correct'
: 'disabled' // Deshabilita las demás cuando la correcta es seleccionada
: incorrectAnswers.includes(answer) // Marca las respuestas incorrectas una a una
? 'incorrect'
: ''
}`}
key={index}
onClick={() => handleAnswerClick(answer)}
disabled={
selectedAnswer !== null ||
incorrectAnswers.includes(answer) ||
!isActive // Deshabilita
}
>
{answer}
</button>
))}
</div>

{/* Mostrar el resultado después de seleccionar */}
{selectedAnswer && (
<div>
{incorrectAnswers.length === 3 ? (
<p style={{ color: 'green' }}>
¡Correcto! {right} es el creador de "{name}".
</p>
) : (
<p style={{ color: 'red' }}>
{right} es el creador de "{name}".
</p>
)}
</div>
)}
</Wrapper>
);
};

export default QuestionContainer;
14 changes: 14 additions & 0 deletions webapp/src/components/ScoreContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import Wrapper from '../assets/wrappers/InfoContainer';

const ScoreContainer = ({ score }) => {
return (
<Wrapper>
<div className="score">
<h5>Score: {score}</h5>
</div>
</Wrapper>
);
};

export default ScoreContainer;
12 changes: 12 additions & 0 deletions webapp/src/components/TimerContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import Wrapper from '../assets/wrappers/InfoContainer';

const TimerContainer = ({ seconds }) => {
return (
<Wrapper>
<h5>Time: {seconds}</h5>
</Wrapper>
);
};

export default TimerContainer;
Loading

0 comments on commit 9e5f6e4

Please sign in to comment.