Add initial desktop register screen
This commit is contained in:
parent
7ef0b98c8e
commit
5085c05623
6 changed files with 354 additions and 3 deletions
|
@ -2,6 +2,7 @@ import { Container } from '@mui/material';
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
import { Navigate, Route, Routes } from 'react-router-dom';
|
||||||
|
|
||||||
import Login from '../screens/Login';
|
import Login from '../screens/Login';
|
||||||
|
import Register from '../screens/Register';
|
||||||
import UnauthenticatedHome from '../screens/UnauthenticatedHome';
|
import UnauthenticatedHome from '../screens/UnauthenticatedHome';
|
||||||
|
|
||||||
function UnauthenticatedApp() {
|
function UnauthenticatedApp() {
|
||||||
|
@ -10,6 +11,7 @@ function UnauthenticatedApp() {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<UnauthenticatedHome />} />
|
<Route path="/" element={<UnauthenticatedHome />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
<Route path="/register" element={<Register />} />
|
||||||
<Route path="*" element={<Navigate to="/" />} />
|
<Route path="*" element={<Navigate to="/" />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { createContext, useContext, useEffect, useState } from 'react';
|
import { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { getUser } from '../services/user-service';
|
import { getUser, registerUser } from '../services/user-service';
|
||||||
|
|
||||||
const AuthContext = createContext();
|
const AuthContext = createContext();
|
||||||
|
|
||||||
|
@ -20,6 +20,20 @@ function AuthProvider(props) {
|
||||||
bootstrapUser();
|
bootstrapUser();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const register = data => {
|
||||||
|
setState({ ...state, status: 'pending' });
|
||||||
|
let shouldFail =
|
||||||
|
data.email !== 'leo@gmail.com' && data.password !== '#leo1234';
|
||||||
|
|
||||||
|
return registerUser(data, shouldFail).then(data => {
|
||||||
|
if (shouldFail) {
|
||||||
|
return setState({ status: 'error', user: null, error: data });
|
||||||
|
} else {
|
||||||
|
return setState({ status: 'success', user: data, error: null });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const login = (email, password) => {
|
const login = (email, password) => {
|
||||||
setState({ ...state, status: 'pending' });
|
setState({ ...state, status: 'pending' });
|
||||||
let shouldFail = email !== 'leo@gmail.com' && password !== '#leo1234';
|
let shouldFail = email !== 'leo@gmail.com' && password !== '#leo1234';
|
||||||
|
@ -38,11 +52,16 @@ function AuthProvider(props) {
|
||||||
window.localStorage.clear();
|
window.localStorage.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
return <AuthContext.Provider value={{ state, login, logout }} {...props} />;
|
return (
|
||||||
|
<AuthContext.Provider
|
||||||
|
value={{ state, register, login, logout }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useAuthState() {
|
function useAuthState() {
|
||||||
const { state, login, logout } = useContext(AuthContext);
|
const { state, register, login, logout } = useContext(AuthContext);
|
||||||
const isPending = state.status === 'pending';
|
const isPending = state.status === 'pending';
|
||||||
const isError = state.status === 'error';
|
const isError = state.status === 'error';
|
||||||
const isSuccess = state.status === 'success';
|
const isSuccess = state.status === 'success';
|
||||||
|
@ -55,6 +74,7 @@ function useAuthState() {
|
||||||
isError,
|
isError,
|
||||||
isSuccess,
|
isSuccess,
|
||||||
isAuthenticated,
|
isAuthenticated,
|
||||||
|
register,
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
};
|
};
|
||||||
|
|
179
src/screens/Register/View.js
Normal file
179
src/screens/Register/View.js
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
import { Fragment } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Link,
|
||||||
|
MenuItem,
|
||||||
|
Paper,
|
||||||
|
Select,
|
||||||
|
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';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
function View({
|
||||||
|
isPending,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
layoutType,
|
||||||
|
data,
|
||||||
|
onChangeInput,
|
||||||
|
onTryRegister,
|
||||||
|
}) {
|
||||||
|
const { paper, boxLogo, boxForm, logoContainer } = styles[layoutType];
|
||||||
|
const currentYear = dayjs().year();
|
||||||
|
console.log(currentYear);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Paper sx={paper} elevation={4} variant="elevation">
|
||||||
|
<Box sx={boxForm}>
|
||||||
|
<h1>Criar conta</h1>
|
||||||
|
<p>Crie sua conta digitando os dados abaixo.</p>
|
||||||
|
<Stack spacing={4} component="form">
|
||||||
|
<TextField
|
||||||
|
id="firstName"
|
||||||
|
name="firstName"
|
||||||
|
label="Primeiro nome"
|
||||||
|
variant="standard"
|
||||||
|
type="text"
|
||||||
|
value={data.firstName}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="lastName"
|
||||||
|
name="lastName"
|
||||||
|
label="Sobrenome"
|
||||||
|
variant="standard"
|
||||||
|
type="text"
|
||||||
|
value={data.lastName}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="ra"
|
||||||
|
name="ra"
|
||||||
|
label="RA (Registro Acadêmico)"
|
||||||
|
variant="standard"
|
||||||
|
type="text"
|
||||||
|
value={data.ra}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
/>
|
||||||
|
<FormControl sx={{ textAlign: 'start' }} fullWidth>
|
||||||
|
<InputLabel variant="standard" id="course">
|
||||||
|
Curso
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
variant="standard"
|
||||||
|
labelId="course"
|
||||||
|
id="course"
|
||||||
|
name="course"
|
||||||
|
value={data.course}
|
||||||
|
label="Curso"
|
||||||
|
onChange={onChangeInput}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>
|
||||||
|
Bacharelado em Sistemas de Informação
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={1}>
|
||||||
|
Tecnologia em Processos Gerenciais
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={2}>Tecnologia em Logística</MenuItem>
|
||||||
|
<MenuItem value={3}>
|
||||||
|
Engenharia de Controle e Automação
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem value={4}>Bacharelado em Administração</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl sx={{ textAlign: 'start' }} fullWidth>
|
||||||
|
<InputLabel variant="standard" id="course">
|
||||||
|
Ano da turma
|
||||||
|
</InputLabel>
|
||||||
|
<Select
|
||||||
|
variant="standard"
|
||||||
|
labelId="year"
|
||||||
|
id="year"
|
||||||
|
name="year"
|
||||||
|
value={data.year}
|
||||||
|
label="Ano da turma"
|
||||||
|
onChange={onChangeInput}
|
||||||
|
>
|
||||||
|
<MenuItem value={0}>{currentYear}</MenuItem>
|
||||||
|
<MenuItem value={1}>{currentYear - 1}</MenuItem>
|
||||||
|
<MenuItem value={2}>{currentYear - 2}</MenuItem>
|
||||||
|
<MenuItem value={3}>{currentYear - 3}</MenuItem>
|
||||||
|
<MenuItem value={4}>{currentYear - 4}</MenuItem>
|
||||||
|
<MenuItem value={5}>{currentYear - 5}</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
{/* TODO: Add field mask */}
|
||||||
|
<TextField
|
||||||
|
id="phone"
|
||||||
|
name="phone"
|
||||||
|
label="Telefone"
|
||||||
|
variant="standard"
|
||||||
|
type="phone"
|
||||||
|
value={data.phone}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
label="E-mail"
|
||||||
|
variant="standard"
|
||||||
|
type="email"
|
||||||
|
value={data.email}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
label="Senha"
|
||||||
|
variant="standard"
|
||||||
|
type="password"
|
||||||
|
value={data.password}
|
||||||
|
onChange={onChangeInput}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
// disabled={!isSubmitable}
|
||||||
|
onClick={onTryRegister}
|
||||||
|
variant="contained"
|
||||||
|
>
|
||||||
|
Entrar
|
||||||
|
</Button>
|
||||||
|
<Link href="#">Esqueci minha senha</Link>
|
||||||
|
<Link href="#">Cadastre-se</Link>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
<Box sx={boxLogo}>
|
||||||
|
<Container sx={logoContainer}>
|
||||||
|
<img
|
||||||
|
src={logoImage}
|
||||||
|
width={layoutType === 'desktop' ? '130' : '70'}
|
||||||
|
alt="Logotipo"
|
||||||
|
/>
|
||||||
|
<p>A plataforma de ensino de código aberto.</p>
|
||||||
|
</Container>
|
||||||
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
<LoadingIndicator isLoading={isPending} />
|
||||||
|
<SnackbarIndicator
|
||||||
|
isOpen={isError}
|
||||||
|
severity="error"
|
||||||
|
message={error && error.message}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default View;
|
49
src/screens/Register/index.js
Normal file
49
src/screens/Register/index.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { Button } from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useAuthState } from '../../context/auth';
|
||||||
|
import { useDocumentTitle } from '../../hooks/useDocumentTitle';
|
||||||
|
import useLayoutType from '../../hooks/useLayoutType';
|
||||||
|
|
||||||
|
import View from './View';
|
||||||
|
|
||||||
|
function Register() {
|
||||||
|
useDocumentTitle('Entrar');
|
||||||
|
const { register, isPending, isError, error } = useAuthState();
|
||||||
|
const layoutType = useLayoutType();
|
||||||
|
const [data, setData] = useState({
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
ra: '',
|
||||||
|
course: 0,
|
||||||
|
year: 0,
|
||||||
|
phone: '',
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
termsAgreed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onTryRegister = () => {
|
||||||
|
register(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeInput = e => {
|
||||||
|
const name = e.target.name;
|
||||||
|
const value = e.target.value;
|
||||||
|
|
||||||
|
setData(prev => ({ ...prev, [name]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
isPending={isPending}
|
||||||
|
isError={isError}
|
||||||
|
error={error}
|
||||||
|
layoutType={layoutType}
|
||||||
|
data={data}
|
||||||
|
onChangeInput={onChangeInput}
|
||||||
|
onTryRegister={onTryRegister}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Register;
|
89
src/screens/Register/styles.js
Normal file
89
src/screens/Register/styles.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// ========== Desktop ==========
|
||||||
|
const desktopPaper = {
|
||||||
|
width: '1500px',
|
||||||
|
height: '70%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
color: 'white',
|
||||||
|
textAlign: 'center',
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseBox = {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '0 70px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktopBoxLogo = {
|
||||||
|
...baseBox,
|
||||||
|
backgroundColor: 'secondary.main',
|
||||||
|
};
|
||||||
|
|
||||||
|
const desktopBoxForm = {
|
||||||
|
...baseBox,
|
||||||
|
'> h1, p ': {
|
||||||
|
textAlign: 'initial',
|
||||||
|
},
|
||||||
|
'> h1': {
|
||||||
|
color: 'primary.black',
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
'> p': {
|
||||||
|
color: 'primary.lightGray',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const logoContainerDesktop = {};
|
||||||
|
|
||||||
|
const desktop = {
|
||||||
|
paper: desktopPaper,
|
||||||
|
boxLogo: desktopBoxLogo,
|
||||||
|
boxForm: desktopBoxForm,
|
||||||
|
logoContainer: logoContainerDesktop,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== Mobile ==========
|
||||||
|
const mobilePaper = {
|
||||||
|
...desktopPaper,
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: '700px',
|
||||||
|
marginLeft: '10px',
|
||||||
|
marginRight: '10px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobileBoxLogo = {
|
||||||
|
...desktopBoxLogo,
|
||||||
|
height: '50%',
|
||||||
|
padding: '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobileBoxForm = {
|
||||||
|
...desktopBoxForm,
|
||||||
|
padding: '0 15px',
|
||||||
|
width: 'fit-content',
|
||||||
|
};
|
||||||
|
|
||||||
|
const logoContainerMobile = {
|
||||||
|
padding: '20px 16px',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mobile = {
|
||||||
|
paper: mobilePaper,
|
||||||
|
boxLogo: mobileBoxLogo,
|
||||||
|
boxForm: mobileBoxForm,
|
||||||
|
logoContainer: logoContainerMobile,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========== Unset ==========
|
||||||
|
const unset = {
|
||||||
|
paper: null,
|
||||||
|
boxLogo: null,
|
||||||
|
boxForm: null,
|
||||||
|
logoContainer: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = { desktop, mobile, unset };
|
||||||
|
export default styles;
|
|
@ -86,6 +86,17 @@ const getUser = shouldFail =>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const registerUser = (data, shouldFail) =>
|
||||||
|
sleep(3000).then(() => {
|
||||||
|
if (shouldFail) {
|
||||||
|
return authFailure;
|
||||||
|
} else {
|
||||||
|
console.log(data);
|
||||||
|
window.localStorage.setItem('$USER', JSON.stringify(data));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getClassrooms,
|
getClassrooms,
|
||||||
getClassroomById,
|
getClassroomById,
|
||||||
|
@ -96,4 +107,5 @@ export {
|
||||||
getPeopleByClassId,
|
getPeopleByClassId,
|
||||||
getFaq,
|
getFaq,
|
||||||
getUser,
|
getUser,
|
||||||
|
registerUser,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue