Skip to content

Commit

Permalink
Merge pull request #123 from Arquisoft/UO287747-Develop
Browse files Browse the repository at this point in the history
Uo287747 develop to develop
  • Loading branch information
UO287687 authored Mar 30, 2024
2 parents b62cf3e + 8c10744 commit 55f94c1
Show file tree
Hide file tree
Showing 23 changed files with 845 additions and 254 deletions.
21 changes: 0 additions & 21 deletions webapp/src/App.jsx

This file was deleted.

33 changes: 33 additions & 0 deletions webapp/src/SessionContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { createContext, useState, useEffect } from 'react';

export const SessionContext = createContext();

export const SessionProvider = ({ children }) => {
const [sessionData, setSessionData] = useState(() => {
const storedSessionData = localStorage.getItem('sessionData');
return storedSessionData ? JSON.parse(storedSessionData) : null;
});

const saveSessionData = (data) => {
setSessionData(data);
localStorage.setItem('sessionData', JSON.stringify(data));
};

const clearSessionData = () => {
setSessionData(null);
localStorage.removeItem('sessionData');
};

useEffect(() => {
const storedSessionData = localStorage.getItem('sessionData');
if (storedSessionData) {
setSessionData(JSON.parse(storedSessionData));
}
}, []);

return (
<SessionContext.Provider value={{ sessionData, saveSessionData, clearSessionData }}>
{children}
</SessionContext.Provider>
);
};
Binary file added webapp/src/assets/defaultImgProfile.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webapp/src/assets/sonidoOFF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webapp/src/assets/sonidoON.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added webapp/src/audio/correct.mp3
Binary file not shown.
Binary file added webapp/src/audio/incorrect.mp3
Binary file not shown.
165 changes: 3 additions & 162 deletions webapp/src/components/Game.jsx
Original file line number Diff line number Diff line change
@@ -1,165 +1,6 @@
import { Card, List, ListItem, ListItemButton, ListItemText, Typography } from '@mui/material'

import React from 'react'
import { useState, useEffect } from 'react'
import { PostGame } from './PostGame'

const N_QUESTIONS = 10
const MAX_TIME = 600;

const gatewayUrl=process.env.REACT_APP_API_ENDPOINT||"http://localhost:8000"

const Question = ({ goTo, setGameFinished }) => {

const [question, setQuestion] = useState('');
const [options, setOptions] = useState([]);

const [selectedOption, setSelectedOption] = useState(null);
const [selectedIndex, setSelectedIndex] = useState();
const [isSelected, setIsSelected] = useState(false);

const [correct, setCorrect] = useState('');
const [numberCorrect, setNumberCorrect] = useState(0);
const [nQuestion, setNQuestion] = useState(0);

const [segundos, setSegundos] = useState(MAX_TIME);
useEffect(() => {

const intervalId = setInterval(() => {
setSegundos(segundos => {
if (segundos === 1) { clearInterval(intervalId); finish() }
return segundos - 1;
});
}, 1000);

return () => clearInterval(intervalId);
// eslint-disable-next-line
}, []);

const formatTiempo = (segundos) => {
const minutos = Math.floor((segundos % 3600) / 60);
const segs = segundos % 60;
return `${minutos < 10 ? '0' : ''}${minutos}:${segs < 10 ? '0' : ''}${segs}`;
};

const fetchQuestion = async () => {

try {
const response = await fetch(`${gatewayUrl}/api/questions/create`, {
method: 'GET'
});
const data = await response.json();

setQuestion(data.question);
setCorrect(data.correct);
setOptions(shuffleOptions([data.correct, ...data.incorrects]));

setSelectedOption(null);
setIsSelected(false);
setNQuestion((prevNQuestion) => prevNQuestion + 1);
handleGameFinish();
} catch (error) {
console.error('Error fetching question:', error);
}
};


const getBackgroundColor = (option, index) => {

if (selectedOption == null) return 'transparent';

if (!isCorrect(option) && index === selectedIndex) return 'red';

if (isCorrect(option)) return 'green';
};

// @SONAR_STOP@
// sonarignore:start
const shuffleOptions = (options) => {
//NOSONAR
return options.sort(() => Math.random() - 0.5); //NOSONAR
//NOSONAR
};
// sonarignore:end
// @SONAR_START@

const handleSubmit = (option, index) => {

if (isSelected) return;

setSelectedOption(option);
setSelectedIndex(index);
setIsSelected(true);

if (isCorrect(option)) {
setNumberCorrect(numberCorrect+1);
}
};

const isCorrect = (option) => {

return option === correct;
};

const handleGameFinish = () => {

if (nQuestion === N_QUESTIONS) { finish() }
if (segundos === 1) { setSegundos(0); finish() }
}

const finish = () => {
// Almacenar datos
localStorage.setItem("pAcertadas", numberCorrect);
localStorage.setItem("pFalladas", N_QUESTIONS - numberCorrect);
localStorage.setItem("tiempoUsado", MAX_TIME - segundos);
localStorage.setItem("tiempoRestante", segundos)

setGameFinished(true);
goTo(1);
}

useEffect(() => {
fetchQuestion();
// eslint-disable-next-line
}, []);

return(

<main className='preguntas'>
<div>
<div className='questionTime'>
<Typography sx={{ display:'inline-block', textAlign:'left'}} >Question: {nQuestion}</Typography>
<Typography sx={{ display:'inline-block', textAlign:'right'}}>Time: {formatTiempo(segundos)}</Typography>
</div>
<Card variant='outlined' sx={{ bgcolor: '#222', p: 2, textAlign: 'left' }}>

<Typography variant='h4' paddingBottom={"20px"}>
{question}
</Typography>

<List sx={{ bgcolor: '#333'}} disablePadding>
{options.map((option, index) => (
<ListItem onClick={ () => handleSubmit(option, index) } key={index} sx={{ bgcolor: getBackgroundColor(option, index)}}>
<ListItemButton>
<ListItemText sx={{textAlign: 'center'}}>
{option}
</ListItemText>
</ListItemButton>
</ListItem>
))}
</List>
</Card>
{ isSelected ? (

<ListItemButton onClick={ () => fetchQuestion() } sx={{ justifyContent: 'center' , marginTop: 2}} >
Next
</ListItemButton>
) : (null)
}
</div>
</main>
)
}
import React, { useState, useEffect } from 'react';
import { PostGame } from './PostGame';
import Question from './Question';

export const Game = () => {
const [gameState, setGameState] = useState(0);
Expand Down
10 changes: 7 additions & 3 deletions webapp/src/components/Login.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// src/components/Login.js
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import axios from 'axios';
import { Container, Typography, TextField, Button, Snackbar } from '@mui/material';
import { SessionContext } from '../SessionContext';

const Login = ({ goTo }) => {

const { saveSessionData } = useContext(SessionContext);

const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
Expand All @@ -20,12 +24,12 @@ const Login = ({ goTo }) => {
const response = await axios.post(`${apiEndpoint}/login`, { username, password });

// Extract data from the response
const { createdAt: userCreatedAt } = response.data;
const { createdAt: userCreatedAt, username: loggedInUsername } = response.data;

setTimeStart(Date.now());
setCreatedAt(userCreatedAt);
setLoginSuccess(true);

saveSessionData({ username: loggedInUsername, createdAt: userCreatedAt });
setOpenSnackbar(true);
} catch (error) {
setError(error.response.data.error);
Expand Down
42 changes: 16 additions & 26 deletions webapp/src/components/Nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ import Tooltip from '@mui/material/Tooltip';
import MenuItem from '@mui/material/MenuItem';
import AdbIcon from '@mui/icons-material/Adb';

import { useContext } from 'react';
import { SessionContext } from '../SessionContext';
import profileImage from '../assets/defaultImgProfile.jpg';

function Nav({ goTo }) {

const { sessionData } = useContext(SessionContext);
const username = sessionData ? sessionData.username : 'noUser';

const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);

Expand Down Expand Up @@ -53,17 +61,16 @@ function Nav({ goTo }) {
noWrap
component="a"
href="#app-bar-with-responsive-menu"
onClick={() => goToMenuClic()}
sx={{
mr: 2,
display: { xs: 'none', md: 'flex' },
fontFamily: 'roboto',
fontWeight: 700,
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none',
textDecoration: 'none'
}}
>
React Quiz
ASW WIQ
</Typography>

<Box sx={{ flexGrow: 1, display: { xs: 'flex', md: 'none' } }}>
Expand Down Expand Up @@ -101,38 +108,21 @@ function Nav({ goTo }) {
</MenuItem>
</Menu>
</Box>
<AdbIcon sx={{ display: { xs: 'flex', md: 'none' }, mr: 1 }} />
<Typography
variant="h5"
noWrap
component="a"
href="#app-bar-with-responsive-menu"
sx={{
mr: 2,
display: { xs: 'flex', md: 'none' },
flexGrow: 1,
fontFamily: 'roboto',
fontWeight: 'bold',
letterSpacing: '.3rem',
color: 'inherit',
textDecoration: 'none',
}}
>
React Quiz
</Typography>

<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
<Button
onClick={() => goToMenuClic()}
sx={{ my: 2, color: 'white', display: 'block' }}
sx={{ my: 2, color: 'white', display: 'block' }} className='navButton'
>
Menu
</Button>
</Box>

<Box sx={{ flexGrow: 0 }}>
<Box sx={{ flexGrow: 0, flexDirection: 'row', display:'flex', alignItems: 'center', fontWeight: 'bold'}}>
<Typography sx={{ marginRight: 2, fontFamily: 'Roboto Slab'}} >{username}</Typography>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar alt="Remy Sharp" src="/static/images/avatar/2.jpg" />
<Avatar alt="Remy Sharp" src={profileImage}/>
</IconButton>
</Tooltip>
<Menu
Expand Down
3 changes: 2 additions & 1 deletion webapp/src/components/Participation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const Participation = ({ userId, goTo }) => {
};

return (
<main>
<div>
<h1>Participation</h1>
{participationData ? (
Expand All @@ -54,7 +55,7 @@ export const Participation = ({ userId, goTo }) => {
) : (
<p>Cargando datos de participación...</p>
)}
<button onClick={() => goTo(0)}>Menú</button>
</div>
</main>
);
};
Loading

0 comments on commit 55f94c1

Please sign in to comment.