Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved responsiveness #115

Merged
merged 16 commits into from
Apr 29, 2024
Merged
5 changes: 2 additions & 3 deletions webapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ function App() {
const { i18n } = useTranslation();

React.useEffect(() => {
localStorage.setItem("lang", navigator.language);
i18n.changeLanguage(navigator.language);
localStorage.setItem("lang", navigator.language.slice(0, 2));
i18n.changeLanguage(navigator.language.slice(0, 2));
}, [i18n]);


return (
<BrowserRouter>
Expand Down
16 changes: 9 additions & 7 deletions webapp/src/common/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const NavBar: React.FC<{}> = () =>
const [anchorEl, setAnchorEl] = useState<null | HTMLElement | SVGSVGElement>(null);
const [open, setOpen] = useState<boolean>(false);
const [chevronRotated, setChevronRotated] = useState<boolean>(true);
const [checked, setChecked] = useState<boolean>(navigator.language==="es-ES");

const handleClick = (event: React.MouseEvent<HTMLButtonElement> | React.MouseEvent<SVGSVGElement>) => {
setAnchorEl(event.currentTarget);
Expand All @@ -31,15 +30,13 @@ const NavBar: React.FC<{}> = () =>

const handleSwitch = () => {
const language = localStorage.getItem("lang");
if(language === "es" || language === null){
if(language === "es"){
localStorage.setItem("lang", "en");
i18n.changeLanguage("en");
setChecked(false);
}
else{
localStorage.setItem("lang", "es");
i18n.changeLanguage("es");
setChecked(true)
}
};

Expand Down Expand Up @@ -67,8 +64,7 @@ const NavBar: React.FC<{}> = () =>
<AppBar className="nav-appBar" sx={
{
display: 'flex',
flexDirection: 'row',
flexWrap: 'nowrap',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'flex-start',
width: '100%',
Expand All @@ -80,6 +76,7 @@ const NavBar: React.FC<{}> = () =>
<Container sx={{ maxWidth: '100% !important' }}>
<Grid
container
flexWrap={'nowrap'}
direction="row"
alignItems="center"
justifyContent="space-between"
Expand Down Expand Up @@ -168,7 +165,12 @@ const NavBar: React.FC<{}> = () =>
src={process.env.PUBLIC_URL + '/british-flag.png'}
alt='British flag'
/>
<Switch checked={checked} onChange={handleSwitch} />
{localStorage.getItem("lang") === 'en' && (
<Switch checked={false} onChange={handleSwitch} />
)}
{localStorage.getItem("lang") === 'es' && (
<Switch checked={true} onChange={handleSwitch} />
)}
<img
className='flag'
src={process.env.PUBLIC_URL + '/spanish-flag.png'}
Expand Down
8 changes: 7 additions & 1 deletion webapp/src/common/nav.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.navbar {
width:100%;
height: 50px;
display: flex;
align-items: center;
}
Expand All @@ -20,6 +19,13 @@
}

.logo{
word-wrap: break-word;
white-space: pre-wrap;
word-break: break-word;
overflow: hidden;
display: flex;
flex-wrap: nowrap;
height: 42px;
font-weight: 500;
font-size: xx-large;
margin-right: 15px !important;
Expand Down
1 change: 1 addition & 0 deletions webapp/src/components/group/Group.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
}

.modal {
width: 400px;
background-color: white;
padding: 20px;
border-radius: 8px;
Expand Down
29 changes: 15 additions & 14 deletions webapp/src/components/group/GroupCreationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,43 +54,44 @@ export const CreationModal: FC<ActionProps> = ({nowHasGroup, setError, toggleCre
</button>
</div>
<Grid >
<Grid container padding={2} >
<Grid container padding={2} sx={{ display: 'flex', width: '400px' , justifyContent: 'space-evenly', alignItems: 'center' }}>
<Grid item xs={5} ><p>{t('create_group_group_name')}</p></Grid>
<Grid item xs={5} ><TextField
<Grid item xs={6} ><TextField
margin="normal"
label="Group name"
label={t('create_group_group_name_label')}
value={groupName}
onChange={(e) => setGroupName(e.target.value)}
/></Grid>
</Grid>
<Grid container padding={2} >
<Grid container padding={2} sx={{ display: 'flex', width: '400px', justifyContent: 'space-evenly', alignItems: 'center' }}>
<Grid item xs={5} ><p>{t('create_group_public_group')}</p></Grid>
<Grid item xs={5} ><RadioGroup
<Grid item xs={5}><RadioGroup
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="yes"
name="radio-buttons-group"
sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-evenly', alignItems: 'center' }}
onChange={(e) => setPublic(e.target.value === "yes")}
>
<FormControlLabel value="yes" control={<Radio />} label="Yes" />
<FormControlLabel value="no" control={<Radio />} label="No" />
<FormControlLabel value="yes" control={<Radio />} label={t('create_group_yes')} />
<FormControlLabel value="no" control={<Radio />} label={t('create_group_no')} />
</RadioGroup></Grid>
</Grid>
<Grid container padding={2} >
<Grid item xs={5} ><p>{t('create_group_max_members')}</p></Grid>
<Grid item xs={5} ><input type="number" step={1} value={maxMembers} onChange={handleChange} max={200} min={2} /></Grid>
<Grid container padding={2} sx={{ display: 'flex', width: '400px', justifyContent: 'space-evenly', alignItems: 'center' }}>
<Grid item xs={6} ><p>{t('create_group_max_members')}</p></Grid>
<Grid item xs={1} ><input style={{ width: '25px' }} type="number" step={1} value={maxMembers} onChange={handleChange} max={200} min={2} /></Grid>
</Grid>
<Grid container padding={2} >
<Grid container padding={2} sx={{ display: 'flex', width: '400px', justifyContent: 'space-evenly', alignItems: 'center' }}>
<Grid item xs={5} ><p>{t('create_group_description')}</p></Grid>
<Grid item xs={5} ><TextField
<Grid item xs={7} ><TextField
margin="normal"
multiline
label="Description"
label={t('create_group_description_label')}
value={description}
onChange={(e) => setDescription(e.target.value)}
/></Grid>
</Grid>
<Grid container padding={2} >
<Grid item xs={6} ><Button onClick={createGroup}>{t('create_group_button')}</Button></Grid>
<Grid item xs={6} ><Button variant="contained" onClick={createGroup} sx={{ width: '140px' }}>{t('create_group_button')}</Button></Grid>
</Grid>
</Grid>
</div>
Expand Down
18 changes: 9 additions & 9 deletions webapp/src/components/group/GroupTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,18 @@ export const GroupTable = (props: TableProps) => {
<Container>
{loading ? <CircularProgress /> : (
<Container>
<Grid container padding={2} >
<Grid item xs={3} >
<h1 data-testid="group-name" style={{margin:'1em'}}>{groupName}</h1>
<Grid container padding={2} sx={{ display: 'flex', justifyContent: 'space-evenly', alignItems: 'center' }} >
<Grid item xs={3} sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<h1 data-testid="group-name">{groupName}</h1>
</Grid>
<Grid item xs={3} >
<h1 data-testid="total-points" style={{margin:'1em'}}>{total}{t('group_table_points')}</h1>
<Grid item xs={3} sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<h1 data-testid="total-points">{total}{t('group_table_points')}</h1>
</Grid>
<Grid item xs={3} >
<h1 data-testid="number-members" style={{margin:'1em'}}>{numberMembers}{t('group_table_members')}</h1>
<Grid item xs={3} sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<h1 data-testid="number-members">{numberMembers}{t('group_table_members')}</h1>
</Grid>
<Grid item xs={3} >
<Button data-testid="leave-button" style={{maxWidth: '250px', maxHeight: '50px', minWidth: '250px', minHeight: '50px', float: 'right', margin:'1em'}} variant="contained" onClick={leaveGroup} >{t('group_table_leave')}</Button>
<Grid item xs={3} sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
<Button data-testid="leave-button" style={{ width: '200px' }} variant="contained" onClick={leaveGroup} >{t('group_table_leave')}</Button>
</Grid>
</Grid>
<TableContainer>
Expand Down
2 changes: 1 addition & 1 deletion webapp/src/components/group/NoGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const NoGroup = (props: ActionProps) =>
</Grid>
</Grid>
))}
<Stack direction="row" padding={1}>
<Stack direction="row">
<Button variant="contained" onClick={toggleJoinModal} data-testid="close-join-modal-button">{t('no_group_close')}</Button>
</Stack>
</Grid>
Expand Down
15 changes: 13 additions & 2 deletions webapp/src/components/init/Init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@ const Init = (props:ActionProps) =>{

return (
<Stack direction="column">
<Button onClick={() => handleViewChange(false)} size='large' data-testid="register">
<Button
variant="contained"
onClick={() => handleViewChange(false)}
size='large'
data-testid="register"
sx={{ marginBottom: '5px' }}
>
{t('register')}
</Button>
<Button onClick={() => handleViewChange(true)} size='large' data-testid="login" sx={{ marginBottom: 2 }}>
<Button
variant="contained"
onClick={() => handleViewChange(true)}
size='large'
data-testid="login"
sx={{ marginBottom: '50px' }}>
{t('login')}
</Button>
<GLoginButton />
Expand Down
64 changes: 33 additions & 31 deletions webapp/src/components/login/Login.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Login component', () => {
mockAxios.reset();
});

it('should login user successfully', async () => {
it('should handle error when logging in user', async () => {
render(
<MemoryRouter>
<Login goBack={() => {}} />
Expand All @@ -24,13 +24,8 @@ describe('Login component', () => {
const passwordInput = screen.getByLabelText(/Password/i);
const loginButton = screen.getByRole('button', { name: /login/i });

// Mock the axios.post request to simulate a successful response
mockAxios.onPost('http://localhost:8000/login').reply(200, {
username: 'testUser',
totalScore: 100,
nWins: 5,
uuid: '123456789'
});
// Mock the axios.post request to simulate an error response
mockAxios.onPost('http://localhost:8000/login').reply(500, { error: 'Internal Server Error' });

// Simulate user input
fireEvent.change(usernameInput, { target: { value: 'testUser' } });
Expand All @@ -39,22 +34,22 @@ describe('Login component', () => {
// Trigger the login button click
fireEvent.click(loginButton);

// Wait for the Snackbar to be open
// Wait for the error Snackbar to be open
await waitFor(() => {
expect(screen.getByTestId("login-successfull-snackbar")).toBeInTheDocument();
expect(screen.getByTestId('login-error-snackbar')).toBeInTheDocument();
});

// Verify local storage is set correctly
expect(localStorage.getItem('username')).toBe('testUser');
expect(localStorage.getItem('score')).toBe('100');
expect(localStorage.getItem('nWins')).toBe('5');
expect(localStorage.getItem('uuid')).toBe('123456789');
expect(localStorage.getItem('isAuthenticated')).toBe('true');
expect(localStorage.getItem('userUUID')).toBe('123456789');
expect(localStorage.getItem('lang')).toBe('en');
// Verify local storage is not set when there's an error
expect(localStorage.getItem('username')).toBeNull();
expect(localStorage.getItem('score')).toBeNull();
expect(localStorage.getItem('nWins')).toBeNull();
expect(localStorage.getItem('uuid')).toBeNull();
expect(localStorage.getItem('isAuthenticated')).toBeNull();
expect(localStorage.getItem('userUUID')).toBeNull();
expect(localStorage.getItem('lang')).toBeNull();
});

it('should handle error when logging in user', async () => {
it('should login user successfully', async () => {
render(
<MemoryRouter>
<Login goBack={() => {}} />
Expand All @@ -65,8 +60,13 @@ describe('Login component', () => {
const passwordInput = screen.getByLabelText(/Password/i);
const loginButton = screen.getByRole('button', { name: /login/i });

// Mock the axios.post request to simulate an error response
mockAxios.onPost('http://localhost:8000/login').reply(500, { error: 'Internal Server Error' });
// Mock the axios.post request to simulate a successful response
mockAxios.onPost('http://localhost:8000/login').reply(200, {
username: 'testUser',
totalScore: 100,
nWins: 5,
uuid: '123456789'
});

// Simulate user input
fireEvent.change(usernameInput, { target: { value: 'testUser' } });
Expand All @@ -75,18 +75,20 @@ describe('Login component', () => {
// Trigger the login button click
fireEvent.click(loginButton);

// Wait for the error Snackbar to be open
// Wait for the Snackbar to be open
await waitFor(() => {
expect(screen.getByTestId('login-error-snackbar')).toBeInTheDocument();
expect(screen.getByTestId("login-successfull-snackbar")).toBeInTheDocument();
});

// Verify local storage is not set when there's an error
expect(localStorage.getItem('username')).toBeNull();
expect(localStorage.getItem('score')).toBeNull();
expect(localStorage.getItem('nWins')).toBeNull();
expect(localStorage.getItem('uuid')).toBeNull();
expect(localStorage.getItem('isAuthenticated')).toBeNull();
expect(localStorage.getItem('userUUID')).toBeNull();
expect(localStorage.getItem('lang')).toBeNull();
// Verify local storage is set correctly
expect(localStorage.getItem('username')).toBe('testUser');
expect(localStorage.getItem('score')).toBe('100');
expect(localStorage.getItem('nWins')).toBe('5');
expect(localStorage.getItem('uuid')).toBe('123456789');
expect(localStorage.getItem('isAuthenticated')).toBe('true');
expect(localStorage.getItem('userUUID')).toBe('123456789');
expect(localStorage.getItem('lang')).toBe('en');
});


});
11 changes: 6 additions & 5 deletions webapp/src/components/login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const Login = (props: ActionProps) => {
async function loginUser () {

try {
localStorage.clear();
const user = await axios.post(`${apiEndpoint}/login`, { username, password });
console.log(user.data);

localStorage.setItem("username", user.data.username);
localStorage.setItem("score", user.data.totalScore);
Expand All @@ -38,7 +38,7 @@ const Login = (props: ActionProps) => {
localStorage.setItem("isAuthenticated", JSON.stringify(true));
// Extract data from the response
localStorage.setItem('userUUID', user.data.uuid);
localStorage.setItem('lang','en')
localStorage.setItem("lang", navigator.language.slice(0, 2));

setOpenSnackbar(true);
navigate("/game")
Expand Down Expand Up @@ -78,12 +78,13 @@ const Login = (props: ActionProps) => {
value={password}
onChange={(e) => setPassword(e.target.value)}
onKeyDown={handleKeyPress}
sx={{ marginBottom: '30px' }}
/>
<Stack direction="column">
<Button color="primary" onClick={loginUser}>
<Stack direction="column" spacing={0.5}>
<Button variant='contained' color="primary" onClick={loginUser}>
{t('login')}
</Button>
<Button color="primary" onClick={handleReturnButtonClick}>
<Button variant='contained' color="primary" onClick={handleReturnButtonClick}>
{t('return')}
</Button>
</Stack>
Expand Down
9 changes: 4 additions & 5 deletions webapp/src/components/register/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const Register = (props:ActionProps) => {
// checkear que el username no exista (tiene que ser unico)
await axios.post(`${apiEndpoint}/adduser`, { username, password });
setOpenSnackbar(true);
localStorage.clear();
const user = await axios.post(`${apiEndpoint}/login`, { username, password });

console.log(user.data);
Expand All @@ -36,7 +35,6 @@ const Register = (props:ActionProps) => {
localStorage.setItem("isAuthenticated", JSON.stringify(true));
// Extract data from the response
localStorage.setItem('userUUID', user.data.uuid);
localStorage.setItem('lang','en')

setOpenSnackbar(true);
navigate("/game")
Expand Down Expand Up @@ -88,12 +86,13 @@ const Register = (props:ActionProps) => {
value={password}
onChange={(e) => setPassword(e.target.value)}
onKeyDown={handleKeyPress}
sx={{ marginBottom: '30px' }}
/>
<Stack direction="column">
<Button color="primary" onClick={addUser}>
<Stack direction="column" spacing={0.5}>
<Button variant='contained' color="primary" onClick={addUser}>
{t('register')}
</Button>
<Button color="primary" onClick={handleReturnButtonClick}>
<Button variant='contained' color="primary" onClick={handleReturnButtonClick}>
{t('return')}
</Button>
</Stack>
Expand Down
Loading