|
@@ -1,18 +1,54 @@
|
|
|
-import React from 'react'
|
|
|
+import * as React from 'react';
|
|
|
import { store } from '../redux';
|
|
|
import { useState } from "react";
|
|
|
-import { Link, Redirect } from "react-router-dom";
|
|
|
+import { useHistory, useLocation } from "react-router-dom";
|
|
|
import { actionFullLogin } from "../redux/action";
|
|
|
|
|
|
-import { Paper, Box, Typography, Button, Stack, OutlinedInput, IconButton, InputLabel, InputAdornment, FormControl } from "@mui/material";
|
|
|
+import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Paper, Box, Typography, Button, Stack, OutlinedInput, IconButton, InputLabel, InputAdornment, FormControl, TextField, Slide } from "@mui/material";
|
|
|
|
|
|
import { Visibility, VisibilityOff } from '@mui/icons-material';
|
|
|
|
|
|
-// поля логин/пароль/кнопка входа
|
|
|
-const LoginForm = ({ onLogin }) => {
|
|
|
+// появление модального окна
|
|
|
+const Transition = React.forwardRef(function Transition(props, ref) {
|
|
|
+ return <Slide direction="up" ref={ref} {...props} />;
|
|
|
+})
|
|
|
+
|
|
|
+
|
|
|
+// поля ввода и кнопки
|
|
|
+function LoginForm() {
|
|
|
+ let location = useLocation();
|
|
|
+
|
|
|
+ const history = useHistory();
|
|
|
+
|
|
|
+ // модальное окно
|
|
|
+ const [open, setOpen] = useState(false);
|
|
|
+ const handleOpen = () => {
|
|
|
+ setOpen(true);
|
|
|
+ }
|
|
|
+ const handleClose = () => {
|
|
|
+ setOpen(false);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
// отслеживаем введение данных в полях логин/пароль
|
|
|
- const [login, setLogin] = useState('')
|
|
|
- const [pass, setPass] = useState('')
|
|
|
+ const [data, setData] = useState({ login: '', pass: '', confirmPass: '' })
|
|
|
+ console.log('data: ', data)
|
|
|
+
|
|
|
+
|
|
|
+ // проверка пароля на заданные параметры
|
|
|
+ // регулярка, какие символы должны входить
|
|
|
+ const pattern = /(?=.*[0-9])(?=.*[!@#$%^&*])(?=.*[a-z])(?=.*[A-Z])/g
|
|
|
+
|
|
|
+ // минимальная длинна пароля
|
|
|
+ const passLength = 8;
|
|
|
+
|
|
|
+ let isValidate, isCorrect;
|
|
|
+
|
|
|
+ ((data.pass.length < passLength) || !(pattern.test(data.pass))) && (isValidate = true);
|
|
|
+ (data.pass != data.confirmPass) && (isCorrect = true);
|
|
|
+
|
|
|
+ const validation = (data.login == '') || (data.pass == '')
|
|
|
+
|
|
|
|
|
|
// включаем,выклюаем отображение пароля
|
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
@@ -21,144 +57,203 @@ const LoginForm = ({ onLogin }) => {
|
|
|
event.preventDefault();
|
|
|
};
|
|
|
|
|
|
+ // включаем,выклюаем отображение подтверждения пароля
|
|
|
+ const [showPasswordConfirm, setShowPasswordConfirm] = useState(false);
|
|
|
+ const handleClickShowPasswordConfirm = () => setShowPasswordConfirm((show) => !show);
|
|
|
+ const handleMouseDownPasswordConfirm = (event) => {
|
|
|
+ event.preventDefault();
|
|
|
+ };
|
|
|
+
|
|
|
+ async function fullLogin() {
|
|
|
+ const answer = await store.dispatch(actionFullLogin(data.login, data.pass))
|
|
|
+
|
|
|
+ if (answer == null) {
|
|
|
+ handleOpen()
|
|
|
+ }
|
|
|
|
|
|
+ if (store.getState()?.auth?.token) {
|
|
|
+ history.push('/')
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return (
|
|
|
<Box sx={{ width: '100%' }}>
|
|
|
- <Stack spacing={2}>
|
|
|
- <FormControl variant="outlined">
|
|
|
- <InputLabel htmlFor="outlined-adornment-password">Имя пользователя</InputLabel>
|
|
|
- <OutlinedInput
|
|
|
- id="login"
|
|
|
- label="Имя пользователя"
|
|
|
- type="text"
|
|
|
- size="small"
|
|
|
- value={login}
|
|
|
- onChange={e => setLogin(e.target.value)}
|
|
|
+ <form>
|
|
|
+ <Stack spacing={2}>
|
|
|
+ <TextField
|
|
|
+ fullWidth
|
|
|
+ variant='outlined'
|
|
|
+ id='login'
|
|
|
+ label='Логин'
|
|
|
+ size='normal'
|
|
|
+ value={data.login}
|
|
|
+ onChange={e => setData({ ...data, login: e.target.value })}
|
|
|
/>
|
|
|
- </FormControl>
|
|
|
-
|
|
|
- <FormControl variant="outlined">
|
|
|
- <InputLabel htmlFor="outlined-adornment-password">Пароль</InputLabel>
|
|
|
- <OutlinedInput
|
|
|
- id="password"
|
|
|
- label="Пароль"
|
|
|
- size="small"
|
|
|
- type={showPassword ? 'text' : 'password'}
|
|
|
- value={pass}
|
|
|
- onChange={e => setPass(e.target.value)}
|
|
|
-
|
|
|
- endAdornment={
|
|
|
- <InputAdornment position="end">
|
|
|
- <IconButton
|
|
|
- aria-label="toggle password visibility"
|
|
|
- onClick={handleClickShowPassword}
|
|
|
- onMouseDown={handleMouseDownPassword}
|
|
|
- edge="end"
|
|
|
- >
|
|
|
- {showPassword ? <VisibilityOff /> : <Visibility />}
|
|
|
- </IconButton>
|
|
|
- </InputAdornment>
|
|
|
- }
|
|
|
- />
|
|
|
- </FormControl>
|
|
|
|
|
|
- <Button
|
|
|
- variant="contained"
|
|
|
- disabled={((login == '') || (pass == '')) || false}
|
|
|
- onClick={() => onLogin(login, pass)}
|
|
|
+ <FormControl variant="outlined">
|
|
|
+ <InputLabel htmlFor="outlined-adornment-password">Пароль</InputLabel>
|
|
|
+ <OutlinedInput
|
|
|
+ error={isValidate}
|
|
|
+ fullWidth
|
|
|
+ id="password"
|
|
|
+ label="Пароль"
|
|
|
+ size="normal"
|
|
|
+ type={showPassword ? 'text' : 'password'}
|
|
|
+ value={data.pass}
|
|
|
+ onChange={e => setData({ ...data, pass: e.target.value })}
|
|
|
+
|
|
|
+ endAdornment={
|
|
|
+ <InputAdornment position="end">
|
|
|
+ <IconButton
|
|
|
+ aria-label="visibility"
|
|
|
+ onClick={handleClickShowPassword}
|
|
|
+ onMouseDown={handleMouseDownPassword}
|
|
|
+ edge="end"
|
|
|
+ >
|
|
|
+ {showPassword ? <VisibilityOff /> : <Visibility />}
|
|
|
+ </IconButton>
|
|
|
+ </InputAdornment>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+
|
|
|
+ {(location.pathname === '/registration') && <FormControl variant="outlined">
|
|
|
+ <InputLabel htmlFor="outlined-adornment-password">Подтвердите пароль</InputLabel>
|
|
|
+ <OutlinedInput
|
|
|
+ error={isCorrect}
|
|
|
+ fullWidth
|
|
|
+ id="confirmPassword"
|
|
|
+ label="Подтвердите пароль"
|
|
|
+ size="normal"
|
|
|
+ type={showPasswordConfirm ? 'text' : 'password'}
|
|
|
+ value={data.confirmPass}
|
|
|
+ onChange={e => setData({ ...data, confirmPass: e.target.value })}
|
|
|
+
|
|
|
+ endAdornment={
|
|
|
+ <InputAdornment position="end">
|
|
|
+ <IconButton
|
|
|
+ aria-label="visibility"
|
|
|
+ onClick={handleClickShowPasswordConfirm}
|
|
|
+ onMouseDown={handleMouseDownPasswordConfirm}
|
|
|
+ edge="end"
|
|
|
+ >
|
|
|
+ {showPasswordConfirm ? <VisibilityOff /> : <Visibility />}
|
|
|
+ </IconButton>
|
|
|
+ </InputAdornment>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </FormControl>}
|
|
|
+
|
|
|
+ <Button
|
|
|
+ size="large"
|
|
|
+ variant="contained"
|
|
|
+ disabled={location.pathname === '/' ?
|
|
|
+ (validation || false) :
|
|
|
+ (validation || isCorrect) || false}
|
|
|
+ onClick={fullLogin}
|
|
|
+ >
|
|
|
+ {location.pathname === '/' ? 'Войти' : 'Регистрация'}
|
|
|
+ </Button>
|
|
|
+ </Stack>
|
|
|
+ </form>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <Dialog
|
|
|
+ open={open}
|
|
|
+ onClose={handleClose}
|
|
|
+ TransitionComponent={Transition}
|
|
|
+ // keepMounted // всегда держит компонент смонтированным в DOM
|
|
|
>
|
|
|
- Войти
|
|
|
- </Button>
|
|
|
- </Stack>
|
|
|
+ <DialogTitle>Что-то пошло не так!</DialogTitle>
|
|
|
+ <DialogContent>
|
|
|
+ <DialogContentText>
|
|
|
+ Вы ввели неправильный логин или пароль. Повторите попытку.
|
|
|
+ </DialogContentText>
|
|
|
+ </DialogContent>
|
|
|
+ <DialogActions>
|
|
|
+ <Button onClick={handleClose}>Ок</Button>
|
|
|
+ </DialogActions>
|
|
|
+ </Dialog>
|
|
|
+ </div>
|
|
|
</Box>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
-class Authorization extends React.Component {
|
|
|
|
|
|
- state = {
|
|
|
- redirectToReferrer: false
|
|
|
- }
|
|
|
- login = () => {
|
|
|
- this.setState(() => ({
|
|
|
- redirectToReferrer: true
|
|
|
- }))
|
|
|
- }
|
|
|
- render() {
|
|
|
- const { from } = this.props.location.state || { from: { pathname: '/' } }
|
|
|
- const { redirectToReferrer } = this.state
|
|
|
+function RegistrationLink() {
|
|
|
+ const history = useHistory()
|
|
|
|
|
|
- if (redirectToReferrer === true) {
|
|
|
- return <Redirect to={from} />
|
|
|
- }
|
|
|
+ function goToRegistration() {
|
|
|
+ history.push('/registration')
|
|
|
+ }
|
|
|
|
|
|
- return (
|
|
|
- <Box sx={{
|
|
|
+ return (
|
|
|
+ <Typography
|
|
|
+ variant="subtitle1"
|
|
|
+ sx={{
|
|
|
display: 'grid',
|
|
|
- height: '80vh',
|
|
|
+ alignSelf: 'end',
|
|
|
justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
- }}>
|
|
|
- <Paper elevation={3}
|
|
|
+ cursor: 'pointer'
|
|
|
+ }}
|
|
|
+ onClick={goToRegistration}
|
|
|
+ >
|
|
|
+ Зарегистрироваться
|
|
|
+ </Typography>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function AuthReg() {
|
|
|
+
|
|
|
+ let location = useLocation();
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Box sx={{
|
|
|
+ display: 'grid',
|
|
|
+ height: '80vh',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+
|
|
|
+ <Paper elevation={3}
|
|
|
+ sx={{
|
|
|
+ padding: '5px',
|
|
|
+ width: '400px',
|
|
|
+ height: '500px',
|
|
|
+ display: 'grid',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignItems: 'center'
|
|
|
+ }}>
|
|
|
+ <Typography
|
|
|
+ variant="h4"
|
|
|
+ noWrap
|
|
|
sx={{
|
|
|
- padding: '5px',
|
|
|
- width: '400px',
|
|
|
- height: '500px',
|
|
|
display: 'grid',
|
|
|
- justifyContent: 'center',
|
|
|
- alignItems: 'center'
|
|
|
+ fontFamily: 'monospace',
|
|
|
+ fontWeight: 700,
|
|
|
+ letterSpacing: '.3rem',
|
|
|
+ color: 'inherit',
|
|
|
+ textDecoration: 'none',
|
|
|
+ flexGrow: '1',
|
|
|
+ marginTop: '20px',
|
|
|
+ justifyContent: 'center'
|
|
|
+ }} >
|
|
|
+ Hipstagram
|
|
|
+ </Typography>
|
|
|
+
|
|
|
+ <Box
|
|
|
+ sx={{
|
|
|
+ display: 'grid',
|
|
|
+ alignSelf: 'start'
|
|
|
}}>
|
|
|
- <Typography
|
|
|
- variant="h4"
|
|
|
- noWrap
|
|
|
- sx={{
|
|
|
- display: 'grid',
|
|
|
- fontFamily: 'monospace',
|
|
|
- fontWeight: 700,
|
|
|
- letterSpacing: '.3rem',
|
|
|
- color: 'inherit',
|
|
|
- textDecoration: 'none',
|
|
|
- flexGrow: '1',
|
|
|
- marginTop: '20px',
|
|
|
- justifyContent: 'center'
|
|
|
- }} >
|
|
|
- Hipstagram
|
|
|
- </Typography>
|
|
|
-
|
|
|
- <Box
|
|
|
- sx={{
|
|
|
- display: 'grid',
|
|
|
- alignSelf: 'start'
|
|
|
- }}>
|
|
|
- <LoginForm
|
|
|
- onLogin={async (login, pass) => {
|
|
|
- await store.dispatch(actionFullLogin(login, pass))
|
|
|
-
|
|
|
- this.login()
|
|
|
- }}
|
|
|
+ <LoginForm />
|
|
|
+ </Box>
|
|
|
|
|
|
- />
|
|
|
- </Box>
|
|
|
-
|
|
|
- <Typography
|
|
|
- variant="subtitle1"
|
|
|
- sx={{
|
|
|
- display: 'grid',
|
|
|
- alignSelf: 'end',
|
|
|
- justifyContent: 'center',
|
|
|
- }}>
|
|
|
- <Link
|
|
|
- color="inherit"
|
|
|
- to='/registration'
|
|
|
- >
|
|
|
- Зарегистрироваться
|
|
|
- </Link>
|
|
|
- </Typography>
|
|
|
- </Paper>
|
|
|
- </Box >
|
|
|
- )
|
|
|
- }
|
|
|
+ {(location.pathname === '/') && <RegistrationLink />}
|
|
|
+ </Paper>
|
|
|
+ </Box >
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
-export default Authorization
|
|
|
+export default AuthReg
|