Refactor Login and add responsive layout
This commit is contained in:
parent
d9bb329cf7
commit
c1bde64266
6 changed files with 212 additions and 122 deletions
17
src/hooks/useLayoutType.js
Normal file
17
src/hooks/useLayoutType.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { useMediaQuery } from '@mui/material';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export default function useLayoutType() {
|
||||||
|
const [layoutType, setLayoutType] = useState('desktop');
|
||||||
|
const isMediaQueryRuleActive = useMediaQuery('(max-width:800px)');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isMediaQueryRuleActive) {
|
||||||
|
setLayoutType('mobile');
|
||||||
|
} else {
|
||||||
|
setLayoutType('desktop');
|
||||||
|
}
|
||||||
|
}, [isMediaQueryRuleActive]);
|
||||||
|
|
||||||
|
return layoutType;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ body {
|
||||||
font-family: 'Fira Code', monospace;
|
font-family: 'Fira Code', monospace;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
import { Fragment, useState } from 'react';
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Link,
|
|
||||||
Paper,
|
|
||||||
Stack,
|
|
||||||
TextField,
|
|
||||||
} from '@mui/material';
|
|
||||||
import { useAuthState } from '../context/auth';
|
|
||||||
|
|
||||||
import LoadingIndicator from '../components/LoadingIndicator';
|
|
||||||
import SnackbarIndicator from '../components/SnackbarIndicator';
|
|
||||||
|
|
||||||
import logoImage from '../assets/if-salas-logo.svg';
|
|
||||||
|
|
||||||
function Login() {
|
|
||||||
const { login, isPending, isError, error } = useAuthState();
|
|
||||||
const [email, setEmail] = useState('');
|
|
||||||
const [password, setPassword] = useState('');
|
|
||||||
|
|
||||||
const isSubmitable = email.length !== 0 && password.length !== 0;
|
|
||||||
|
|
||||||
const onTryLogin = () => {
|
|
||||||
isSubmitable && login(email, password);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<Paper sx={paper} elevation={4} variant="elevation">
|
|
||||||
<Box sx={boxLogo}>
|
|
||||||
<Container>
|
|
||||||
<img src={logoImage} width="100" alt="Logotipo" />
|
|
||||||
<p>A plataforma de ensino de código aberto.</p>
|
|
||||||
</Container>
|
|
||||||
</Box>
|
|
||||||
<Box sx={boxForm}>
|
|
||||||
<h1>Login</h1>
|
|
||||||
<p>Bem-vindo de volta. Faça o login digitando os dados abaixo.</p>
|
|
||||||
<Stack spacing={4} sx={stack} component="form">
|
|
||||||
<TextField
|
|
||||||
id="email"
|
|
||||||
label="E-mail"
|
|
||||||
variant="standard"
|
|
||||||
type="email"
|
|
||||||
value={email}
|
|
||||||
onChange={e => setEmail(e.target.value)}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
id="password"
|
|
||||||
label="Senha"
|
|
||||||
variant="standard"
|
|
||||||
type="password"
|
|
||||||
value={password}
|
|
||||||
onChange={e => setPassword(e.target.value)}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
disabled={!isSubmitable}
|
|
||||||
onClick={onTryLogin}
|
|
||||||
variant="contained"
|
|
||||||
>
|
|
||||||
Entrar
|
|
||||||
</Button>
|
|
||||||
<Link href="#">Esqueci minha senha</Link>
|
|
||||||
<Link href="#">Cadastre-se</Link>
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
</Paper>
|
|
||||||
<LoadingIndicator isLoading={isPending} />
|
|
||||||
<SnackbarIndicator
|
|
||||||
isOpen={isError}
|
|
||||||
severity="error"
|
|
||||||
message={error && error.message}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const paper = {
|
|
||||||
width: '950px',
|
|
||||||
height: '500px',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
color: 'white',
|
|
||||||
textAlign: 'center',
|
|
||||||
};
|
|
||||||
|
|
||||||
const baseBox = {
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
};
|
|
||||||
|
|
||||||
const boxLogo = {
|
|
||||||
...baseBox,
|
|
||||||
backgroundColor: 'secondary.main',
|
|
||||||
};
|
|
||||||
|
|
||||||
const boxForm = {
|
|
||||||
...baseBox,
|
|
||||||
'> h1, p ': {
|
|
||||||
paddingLeft: '70px',
|
|
||||||
paddingRight: '70px',
|
|
||||||
textAlign: 'initial',
|
|
||||||
},
|
|
||||||
'> h1': {
|
|
||||||
color: 'primary.black',
|
|
||||||
margin: 0,
|
|
||||||
},
|
|
||||||
'> p': {
|
|
||||||
color: 'primary.lightGray',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const stack = {
|
|
||||||
padding: '0 70px',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Login;
|
|
88
src/screens/Login/View.js
Normal file
88
src/screens/Login/View.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import { Fragment } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Link,
|
||||||
|
Paper,
|
||||||
|
Stack,
|
||||||
|
TextField,
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
import SnackbarIndicator from '../../components/SnackbarIndicator';
|
||||||
|
import LoadingIndicator from '../../components/LoadingIndicator';
|
||||||
|
|
||||||
|
import logoImage from '../../assets/if-salas-logo.svg';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
function View({
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
onChangeEmail,
|
||||||
|
onChangePassword,
|
||||||
|
isSubmitable,
|
||||||
|
onTryLogin,
|
||||||
|
isPending,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
layoutType,
|
||||||
|
}) {
|
||||||
|
const { paper, boxLogo, boxForm } = styles[layoutType];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Paper sx={paper} elevation={4} variant="elevation">
|
||||||
|
<Box sx={boxLogo}>
|
||||||
|
<Container>
|
||||||
|
<img
|
||||||
|
src={logoImage}
|
||||||
|
width={layoutType === 'desktop' ? '100' : '70'}
|
||||||
|
alt="Logotipo"
|
||||||
|
/>
|
||||||
|
<p>A plataforma de ensino de código aberto.</p>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
<Box sx={boxForm}>
|
||||||
|
<h1>Login</h1>
|
||||||
|
<p>Bem-vindo de volta. Faça o login digitando os dados abaixo.</p>
|
||||||
|
<Stack spacing={4} component="form">
|
||||||
|
<TextField
|
||||||
|
id="email"
|
||||||
|
label="E-mail"
|
||||||
|
variant="standard"
|
||||||
|
type="email"
|
||||||
|
value={email}
|
||||||
|
onChange={e => onChangeEmail(e.target.value)}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="password"
|
||||||
|
label="Senha"
|
||||||
|
variant="standard"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={e => onChangePassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
disabled={!isSubmitable}
|
||||||
|
onClick={onTryLogin}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Entrar
|
||||||
|
</Button>
|
||||||
|
<Link href="#">Esqueci minha senha</Link>
|
||||||
|
<Link href="#">Cadastre-se</Link>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
<LoadingIndicator isLoading={isPending} />
|
||||||
|
<SnackbarIndicator
|
||||||
|
isOpen={isError}
|
||||||
|
severity="error"
|
||||||
|
message={error && error.message}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default View;
|
35
src/screens/Login/index.js
Normal file
35
src/screens/Login/index.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useAuthState } from '../../context/auth';
|
||||||
|
import useLayoutType from '../../hooks/useLayoutType';
|
||||||
|
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
function Login() {
|
||||||
|
const { login, isPending, isError, error } = useAuthState();
|
||||||
|
const layoutType = useLayoutType();
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
|
||||||
|
const isSubmitable = email.length !== 0 && password.length !== 0;
|
||||||
|
|
||||||
|
const onTryLogin = () => {
|
||||||
|
isSubmitable && login(email, password);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
email={email}
|
||||||
|
password={password}
|
||||||
|
onChangeEmail={setEmail}
|
||||||
|
onChangePassword={setPassword}
|
||||||
|
isSubmitable={isSubmitable}
|
||||||
|
onTryLogin={onTryLogin}
|
||||||
|
isPending={isPending}
|
||||||
|
isError={isError}
|
||||||
|
error={error}
|
||||||
|
layoutType={layoutType}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login;
|
71
src/screens/Login/styles.js
Normal file
71
src/screens/Login/styles.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
const desktopPaper = {
|
||||||
|
width: '950px',
|
||||||
|
height: '500px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
color: 'white',
|
||||||
|
textAlign: 'center',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobilePaper = {
|
||||||
|
...desktopPaper,
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: '700px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
marginRight: '10px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseBox = {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '0 70px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktopBoxLogo = {
|
||||||
|
...baseBox,
|
||||||
|
backgroundColor: 'secondary.main',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobileBoxLogo = {
|
||||||
|
...desktopBoxLogo,
|
||||||
|
height: '45%',
|
||||||
|
padding: '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktopBoxForm = {
|
||||||
|
...baseBox,
|
||||||
|
'> h1, p ': {
|
||||||
|
textAlign: 'initial',
|
||||||
|
},
|
||||||
|
'> h1': {
|
||||||
|
color: 'primary.black',
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
'> p': {
|
||||||
|
color: 'primary.lightGray',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobileBoxForm = {
|
||||||
|
...desktopBoxForm,
|
||||||
|
padding: '0 15px',
|
||||||
|
width: 'fit-content',
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktop = {
|
||||||
|
paper: desktopPaper,
|
||||||
|
boxLogo: desktopBoxLogo,
|
||||||
|
boxForm: desktopBoxForm,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobile = {
|
||||||
|
paper: mobilePaper,
|
||||||
|
boxLogo: mobileBoxLogo,
|
||||||
|
boxForm: mobileBoxForm,
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = { desktop, mobile };
|
||||||
|
export default styles;
|
Loading…
Reference in a new issue