Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
P
planner-team-one
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
21
Issues
21
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Евгений Положенцев
planner-team-one
Commits
236adc86
Commit
236adc86
authored
Nov 02, 2022
by
Ibadullina Inabat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Реализована возможность зарегистрироваться и залогиниться на главной странице
parent
bdf3f7b2
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
822 additions
and
43 deletions
+822
-43
App.js
planner-front/src/App.js
+50
-21
App.test.js
planner-front/src/App.test.js
+0
-8
axiosPlanner.js
planner-front/src/axiosPlanner.js
+8
-0
AnonymousMenu.js
...front/src/components/Menus/AnonymousMenu/AnonymousMenu.js
+23
-0
UserMenu.js
planner-front/src/components/Menus/UserMenu/UserMenu.js
+54
-0
AppToolbar.js
planner-front/src/components/UI/AppToolbar/AppToolbar.js
+39
-0
FileInput.js
planner-front/src/components/UI/Form/FileInput/FileInput.js
+63
-0
FormElement.js
...r-front/src/components/UI/Form/FormElement/FormElement.js
+51
-0
HasAccess.js
planner-front/src/components/UI/HasAccess/HasAccess.js
+8
-0
Loader.js
planner-front/src/components/UI/Loader/Loader.js
+8
-0
UserForm.js
planner-front/src/components/UserForm/UserForm.js
+47
-0
UserRegistrationForm.js
...ner-front/src/components/UserForm/UserRegistrationForm.js
+69
-0
constants.js
planner-front/src/constants.js
+2
-0
ForgottenPassword.js
...ont/src/containers/ForgottenPassword/ForgottenPassword.js
+73
-0
Login.js
planner-front/src/containers/Login/Login.js
+73
-0
Register.js
planner-front/src/containers/Register/Register.js
+94
-0
index.js
planner-front/src/index.js
+37
-13
logo.svg
planner-front/src/logo.svg
+0
-1
actionTypes.js
planner-front/src/store/actionTypes.js
+9
-0
commonActions.js
planner-front/src/store/actions/commonActions.js
+6
-0
usersActions.js
planner-front/src/store/actions/usersActions.js
+79
-0
usersReducer.js
planner-front/src/store/reducers/usersReducer.js
+29
-0
No files found.
planner-front/src/App.js
View file @
236adc86
import
logo
from
'./logo.svg'
;
import
'./App.css'
;
import
{
Routes
,
Route
,
Outlet
,
Navigate
}
from
"react-router-dom"
;
import
AppToolbar
from
"./components/UI/AppToolbar/AppToolbar"
;
import
{
Container
}
from
"@mui/material"
;
import
{
useSelector
}
from
"react-redux"
;
import
Register
from
"./containers/Register/Register"
;
import
Login
from
"./containers/Login/Login"
;
function
App
()
{
return
(
<
div
className
=
"App"
>
<
header
className
=
"App-header"
>
<
img
src
=
{
logo
}
className
=
"App-logo"
alt
=
"logo"
/>
<
p
>
Edit
<
code
>
src
/
App
.
js
<
/code> and save to reload
.
<
/p
>
<
a
className
=
"App-link"
href
=
"https://reactjs.org"
target
=
"_blank"
rel
=
"noopener noreferrer"
>
Learn
React
<
/a
>
<
/header
>
<
/div
>
);
const
ProtectedRoute
=
({
isAllowed
,
roles
,
redirectUrl
,
children
})
=>
{
const
user
=
useSelector
(
state
=>
state
.
users
?.
user
);
if
(
!
isAllowed
&&
!
roles
?.
includes
(
user
?.
role
))
{
return
<
Navigate
to
=
{
redirectUrl
}
/
>
}
return
children
||
<
Outlet
/>
}
const
App
=
()
=>
{
const
user
=
useSelector
(
state
=>
state
.
users
.
user
);
return
(
<>
<
Routes
>
<
Route
element
=
{
<>
<
AppToolbar
/>
<
main
>
<
Container
>
<
Outlet
/>
<
/Container
>
<
/main
>
<
/>}
>
{
/* <Route path={"/admin"} element={
<ProtectedRoute roles={["admin"]} redirectUrl={"/"}>
<AdminPanel/>
</ProtectedRoute>
} /> */
}
<
Route
path
=
{
"/"
}
element
=
{
<
div
>
Задачи
на
неделю
<
/div>} /
>
<
Route
path
=
{
"/sign-up"
}
element
=
{
<
ProtectedRoute
isAllowed
=
{
!
user
}
redirectUrl
=
{
"/"
}
>
<
Register
/>
<
/ProtectedRoute
>
}
/
>
<
Route
path
=
{
"/sign-in"
}
element
=
{
<
ProtectedRoute
isAllowed
=
{
!
user
}
redirectUrl
=
{
"/"
}
>
<
Login
/>
<
/ProtectedRoute
>
}
/
>
<
/Route
>
<
/Routes
>
<
/
>
)};
export
default
App
;
planner-front/src/App.test.js
deleted
100644 → 0
View file @
bdf3f7b2
import
{
render
,
screen
}
from
'@testing-library/react'
;
import
App
from
'./App'
;
test
(
'renders learn react link'
,
()
=>
{
render
(
<
App
/>
);
const
linkElement
=
screen
.
getByText
(
/learn react/i
);
expect
(
linkElement
).
toBeInTheDocument
();
});
planner-front/src/axiosPlanner.js
0 → 100644
View file @
236adc86
import
axios
from
"axios"
;
import
{
apiUrl
}
from
"./constants"
;
const
instance
=
axios
.
create
({
baseURL
:
apiUrl
});
export
default
instance
;
planner-front/src/components/Menus/AnonymousMenu/AnonymousMenu.js
0 → 100644
View file @
236adc86
import
{
Button
}
from
"@mui/material"
;
import
{
NavLink
}
from
"react-router-dom"
;
const
AnonymousMenu
=
()
=>
{
return
<>
<
Button
component
=
{
NavLink
}
to
=
"/sign-up"
color
=
"inherit"
>
Sign
Up
<
/Button
>
<
Button
component
=
{
NavLink
}
to
=
"/sign-in"
color
=
"inherit"
>
Sign
In
<
/Button>
<
/
>
};
export
default
AnonymousMenu
;
\ No newline at end of file
planner-front/src/components/Menus/UserMenu/UserMenu.js
0 → 100644
View file @
236adc86
import
{
Button
,
Menu
,
MenuItem
}
from
"@mui/material"
;
import
{
useState
}
from
"react"
;
import
{
useDispatch
}
from
"react-redux"
;
import
{
NavLink
,
useNavigate
}
from
"react-router-dom"
;
import
{
logoutUser
}
from
"../../../store/actions/usersActions"
;
import
HasAccess
from
"../../UI/HasAccess/HasAccess"
;
const
UserMenu
=
({
user
})
=>
{
const
dispatch
=
useDispatch
();
const
navigate
=
useNavigate
()
const
[
anchorEl
,
setAnchorEl
]
=
useState
(
null
);
const
open
=
Boolean
(
anchorEl
);
const
handleClick
=
(
event
)
=>
{
setAnchorEl
(
event
.
currentTarget
);
};
const
handleClose
=
()
=>
{
setAnchorEl
(
null
);
};
const
logout
=
()
=>
{
dispatch
(
logoutUser
(
navigate
));
handleClose
()
}
return
<>
<
Button
color
=
"inherit"
onClick
=
{
handleClick
}
>
Hello
,
{
user
?.
displayName
}
<
/Button
>
{
/* <HasAccess roles={["admin"]}>
<Button
component={NavLink}
color="inherit"
to="/admin"
>
Admin panel
</Button>
</HasAccess> */
}
<
Menu
anchorEl
=
{
anchorEl
}
open
=
{
open
}
onClose
=
{
handleClose
}
>
<
MenuItem
onClick
=
{
handleClose
}
>
Profile
<
/MenuItem
>
<
MenuItem
onClick
=
{
handleClose
}
>
My
account
<
/MenuItem
>
<
MenuItem
onClick
=
{
logout
}
>
Logout
<
/MenuItem
>
<
/Menu
>
<
/
>
};
export
default
UserMenu
;
\ No newline at end of file
planner-front/src/components/UI/AppToolbar/AppToolbar.js
0 → 100644
View file @
236adc86
import
{
AppBar
,
Box
,
Toolbar
,
IconButton
,
Typography
}
from
"@mui/material"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
MenuIcon
from
'@mui/icons-material/Menu'
;
import
HasAccess
from
"../HasAccess/HasAccess"
;
import
{
useSelector
}
from
"react-redux"
;
import
AnonymousMenu
from
"../../Menus/AnonymousMenu/AnonymousMenu"
;
import
UserMenu
from
"../../Menus/UserMenu/UserMenu"
;
const
AppToolbar
=
()
=>
{
const
user
=
useSelector
(
state
=>
state
.
users
.
user
);
return
<
Box
sx
=
{{
flexGrow
:
1
,
mb
:
"40px"
}}
>
<
AppBar
position
=
"static"
>
<
Toolbar
>
<
IconButton
size
=
"large"
edge
=
"start"
color
=
"inherit"
aria
-
label
=
"menu"
sx
=
{{
mr
:
2
}}
component
=
{
NavLink
}
to
=
"/"
>
<
MenuIcon
/>
<
/IconButton
>
<
Typography
variant
=
"h6"
component
=
"div"
sx
=
{{
flexGrow
:
1
}}
>
Planner
<
/Typography
>
<
HasAccess
allowed
=
{
!!
user
}
>
<
UserMenu
user
=
{
user
}
/
>
<
/HasAccess>
<
HasAccess
allowed
=
{
!
user
}
>
<
AnonymousMenu
/>
<
/HasAccess
>
<
/Toolbar
>
<
/AppBar
>
<
/Box
>
};
export
default
AppToolbar
;
planner-front/src/components/UI/Form/FileInput/FileInput.js
0 → 100644
View file @
236adc86
// import {useRef, useState} from "react";
// import {Button, Grid, TextField} from "@mui/material";
// const FileInput = ({onChange, name, label}) => {
// const [filename, setFilename] = useState("");
// const inputRef = useRef();
// const activateInput = () => {
// inputRef.current.click();
// };
// const onFileChange = (e) => {
// const file = e.target.files[0];
// if (file) {
// setFilename(file.name);
// } else {
// setFilename("");
// }
// onChange(e);
// };
// return (
// <>
// <input
// type="file"
// name={name}
// ref={inputRef}
// style={{display: "none"}}
// onChange={onFileChange}
// accept="image/png, image/jpeg"
// />
// <Grid
// container
// direction="row"
// spacing={2}
// alignItems="center"
// >
// <Grid item xs>
// <TextField
// variant="standard"
// disabled
// fullWidth
// label={label}
// value={filename}
// onClick={activateInput}
// />
// </Grid>
// <Grid item>
// <Button
// variant="contained"
// onClick={activateInput}
// >
// Browse
// </Button>
// </Grid>
// </Grid>
// </>
// );
// };
// export default FileInput;
planner-front/src/components/UI/Form/FormElement/FormElement.js
0 → 100644
View file @
236adc86
import
{
Grid
,
TextField
,
MenuItem
}
from
"@mui/material"
;
import
PropTypes
from
"prop-types"
;
import
FileInput
from
"../FileInput/FileInput"
;
const
FormElement
=
({
name
,
label
,
state
,
error
,
onChange
,
select
,
options
,
multiline
,
rows
,
type
=
"'text"
})
=>
{
let
inputChildren
=
null
if
(
select
)
{
inputChildren
=
options
.
map
(
option
=>
{
return
<
MenuItem
key
=
{
option
.
_id
}
value
=
{
option
.
_id
}
>
{
option
.
name
}
<
/MenuItem
>
})
}
let
input
=
<
TextField
select
=
{
select
}
id
=
{
name
}
name
=
{
name
}
label
=
{
label
}
type
=
{
type
}
variant
=
"outlined"
value
=
{
state
?.[
name
]}
onChange
=
{
onChange
}
error
=
{
!!
error
}
helperText
=
{
error
}
fullWidth
>
{
inputChildren
}
<
/TextField
>
if
(
type
===
"file"
)
{
input
=
<
FileInput
name
=
{
name
}
label
=
{
label
}
onChange
=
{
onChange
}
/
>
}
return
<
Grid
item
xs
=
{
12
}
>
{
input
}
<
/Grid
>
}
FormElement
.
propTypes
=
{
name
:
PropTypes
.
string
.
isRequired
,
label
:
PropTypes
.
string
.
isRequired
,
onChange
:
PropTypes
.
func
.
isRequired
,
state
:
PropTypes
.
object
,
error
:
PropTypes
.
string
,
type
:
PropTypes
.
string
}
export
default
FormElement
;
\ No newline at end of file
planner-front/src/components/UI/HasAccess/HasAccess.js
0 → 100644
View file @
236adc86
import
{
useSelector
}
from
"react-redux"
;
const
HasAccess
=
({
allowed
,
roles
,
children
})
=>
{
const
user
=
useSelector
(
state
=>
state
.
users
?.
user
);
return
allowed
||
roles
?.
includes
(
user
?.
role
)
?
children
:
null
}
export
default
HasAccess
;
\ No newline at end of file
planner-front/src/components/UI/Loader/Loader.js
0 → 100644
View file @
236adc86
import
{
CircularProgress
}
from
"@mui/material"
;
const
Loader
=
({
loading
})
=>
{
return
loading
&&
<
CircularProgress
color
=
"primary"
size
=
{
50
}
style
=
{{
margin
:
"0 auto"
}}
/
>
};
export
default
Loader
;
\ No newline at end of file
planner-front/src/components/UserForm/UserForm.js
0 → 100644
View file @
236adc86
import
{
Button
,
Grid
}
from
"@mui/material"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
FormElement
from
"../UI/Form/FormElement/FormElement"
;
const
UserForm
=
({
state
,
onChange
,
onSubmit
,
getFieldError
,
buttonText
,
resetPassword
})
=>
{
return
<
form
onSubmit
=
{
onSubmit
}
>
<
Grid
container
spacing
=
{
2
}
>
<
FormElement
onChange
=
{
onChange
}
name
=
"email"
label
=
"Email"
state
=
{
state
}
error
=
{
getFieldError
?.(
"email"
)}
/
>
<
FormElement
onChange
=
{
onChange
}
name
=
"password"
label
=
"Password"
type
=
"password"
state
=
{
state
}
error
=
{
getFieldError
?.(
"password"
)}
/
>
<
/Grid
>
<
Button
sx
=
{{
mt
:
"15px"
}}
type
=
"submit"
fullWidth
variant
=
"contained"
color
=
"primary"
>
{
buttonText
}
<
/Button
>
{
/* <Button
component={NavLink}
to={"/forgottenpassword"}
sx={{ mt: "15px" }}
type="submit"
fullWidth
variant="contained"
color="primary"
>
{resetPassword}
</Button> */
}
<
/form
>
}
export
default
UserForm
;
\ No newline at end of file
planner-front/src/components/UserForm/UserRegistrationForm.js
0 → 100644
View file @
236adc86
import
{
Button
,
Grid
}
from
"@mui/material"
;
import
FormElement
from
"../UI/Form/FormElement/FormElement"
;
const
UserRegistrationForm
=
({
state
,
onChange
,
onSubmit
,
getFieldError
,
buttonText
,
fileChangeHandler
})
=>
{
return
<
form
onSubmit
=
{
onSubmit
}
>
<
Grid
container
spacing
=
{
2
}
>
<
FormElement
onChange
=
{
onChange
}
name
=
"name"
label
=
"Name"
state
=
{
state
}
error
=
{
getFieldError
?.(
"name"
)}
/
>
<
FormElement
onChange
=
{
onChange
}
name
=
"surname"
label
=
"Surname"
state
=
{
state
}
error
=
{
getFieldError
?.(
"surname"
)}
/
>
<
FormElement
onChange
=
{
onChange
}
name
=
"email"
label
=
"Email"
state
=
{
state
}
error
=
{
getFieldError
?.(
"email"
)}
/
>
<
FormElement
onChange
=
{
onChange
}
name
=
"number"
label
=
"Number"
state
=
{
state
}
error
=
{
getFieldError
?.(
"number"
)}
/
>
<
FormElement
onChange
=
{
onChange
}
name
=
"password"
label
=
"Password"
type
=
"password"
state
=
{
state
}
error
=
{
getFieldError
?.(
"password"
)}
/
>
{
/* <FormElement
onChange={onChange}
name="displayName"
label="DisplayName"
state={state}
/> */
}
{
/* <FormElement
onChange={fileChangeHandler}
name="avatar"
label="Avatar"
type="file"
state={state}
/> */
}
<
/Grid
>
<
Button
sx
=
{{
mt
:
"15px"
}}
type
=
"submit"
fullWidth
variant
=
"contained"
color
=
"primary"
>
{
buttonText
}
<
/Button
>
<
/form
>
}
export
default
UserRegistrationForm
;
\ No newline at end of file
planner-front/src/constants.js
0 → 100644
View file @
236adc86
export
const
apiUrl
=
"http://localhost:8000"
;
export
const
uploadsUrl
=
`
${
apiUrl
}
/uploads`
;
planner-front/src/containers/ForgottenPassword/ForgottenPassword.js
0 → 100644
View file @
236adc86
// import { useState } from "react";
// import { useDispatch, useSelector } from "react-redux";
// import { useNavigate } from "react-router-dom";
// import Loader from "../../components/UI/Loader/Loader";
// import UserForm from "../../components/UserForm/UserForm";
// import { loginUser } from "../../store/actions/usersActions";
// import PersonIcon from '@mui/icons-material/Person';
// import styled from "@emotion/styled";
// import { Alert, Avatar, Container, Typography } from "@mui/material";
// const StyledContainer = styled(Container)`
// padding-top: 30px;
// padding-bottom: 30px;
// box-shadow: 0 18px 30px 0 rgba(0, 0, 0, 0.6);
// border-radius: 6px;
// `;
// const StyledTitle = styled(Typography)`
// text-align: center;
// font-size: 30px;
// margin-bottom: 30px;
// `;
// const ForgottenPassword = () => {
// const [state, setState] = useState({
// email: '',
// redirectUrl: 'http://localhost:3000/passwordreset'
// });
// const dispatch = useDispatch();
// const { loginError, loading } = useSelector(state => state.users);
// console.log(loginError)
// const navigate = useNavigate("/")
// const inputChangeHandler = (e) => {
// const { name, value } = e.target;
// setState((prevState) => {
// return {
// ...prevState,
// [name]: value
// }
// });
// };
// const submitHandler = async (e) => {
// e.preventDefault();
// await dispatch(loginUser(state, navigate));
// };
// return <>
// <StyledContainer component={"section"} maxWidth={"xs"}>
// {!!loginError && <Alert color="error">{loginError}</Alert>}
// <Avatar sx={{ m: "0 auto 30px" }}>
// <PersonIcon />
// </Avatar>
// <StyledTitle variant={"h1"}>
// Password Reset
// </StyledTitle>
// <UserForm
// onSubmit={submitHandler}
// state={state}
// onChange={inputChangeHandler}
// buttonText={"Sign In"}
// resetPassword={"Forgot your password?"}
// />
// </StyledContainer>
// <Loader loading={loading} />
// </>
// };
// export default ForgottenPassword;
\ No newline at end of file
planner-front/src/containers/Login/Login.js
0 → 100644
View file @
236adc86
import
{
useState
}
from
"react"
;
import
{
useDispatch
,
useSelector
}
from
"react-redux"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
Loader
from
"../../components/UI/Loader/Loader"
;
import
UserForm
from
"../../components/UserForm/UserForm"
;
import
{
loginUser
}
from
"../../store/actions/usersActions"
;
import
PersonIcon
from
'@mui/icons-material/Person'
;
import
styled
from
"@emotion/styled"
;
import
{
Alert
,
Avatar
,
Container
,
Typography
}
from
"@mui/material"
;
const
StyledContainer
=
styled
(
Container
)
`
padding-top: 30px;
padding-bottom: 30px;
box-shadow: 0 18px 30px 0 rgba(0, 0, 0, 0.6);
border-radius: 6px;
`
;
const
StyledTitle
=
styled
(
Typography
)
`
text-align: center;
font-size: 30px;
margin-bottom: 30px;
`
;
const
Login
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
email
:
''
,
password
:
''
});
const
dispatch
=
useDispatch
();
const
{
loginError
,
loading
}
=
useSelector
(
state
=>
state
.
users
);
console
.
log
(
loginError
)
const
navigate
=
useNavigate
(
"/"
)
const
inputChangeHandler
=
(
e
)
=>
{
const
{
name
,
value
}
=
e
.
target
;
setState
((
prevState
)
=>
{
return
{
...
prevState
,
[
name
]:
value
}
});
};
const
submitHandler
=
async
(
e
)
=>
{
e
.
preventDefault
();
await
dispatch
(
loginUser
(
state
,
navigate
));
};
return
<>
<
StyledContainer
component
=
{
"section"
}
maxWidth
=
{
"xs"
}
>
{
!!
loginError
&&
<
Alert
color
=
"error"
>
{
loginError
}
<
/Alert>
}
<
Avatar
sx
=
{{
m
:
"0 auto 30px"
}}
>
<
PersonIcon
/>
<
/Avatar
>
<
StyledTitle
variant
=
{
"h1"
}
>
Sign
In
<
/StyledTitle
>
<
UserForm
onSubmit
=
{
submitHandler
}
state
=
{
state
}
onChange
=
{
inputChangeHandler
}
buttonText
=
{
"Sign In"
}
// resetPassword={"Forgot your password?"}
/
>
<
/StyledContainer
>
<
Loader
loading
=
{
loading
}
/
>
<
/
>
};
export
default
Login
;
\ No newline at end of file
planner-front/src/containers/Register/Register.js
0 → 100644
View file @
236adc86
import
{
useState
}
from
"react"
;
import
{
useDispatch
,
useSelector
}
from
"react-redux"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
Loader
from
"../../components/UI/Loader/Loader"
;
import
UserForm
from
"../../components/UserForm/UserRegistrationForm"
;
import
{
loginUser
,
registerUser
}
from
"../../store/actions/usersActions"
;
import
styled
from
"@emotion/styled"
;
import
{
Avatar
,
Container
,
Typography
}
from
"@mui/material"
;
import
LockIcon
from
"@mui/icons-material/Lock"
;
const
StyledContainer
=
styled
(
Container
)
`
padding-top: 30px;
padding-bottom: 30px;
box-shadow: 0 18px 30px 0 rgba(0, 0, 0, 0.6);
border-radius: 6px;
`
;
const
StyledTitle
=
styled
(
Typography
)
`
text-align: center;
font-size: 30px;
margin-bottom: 30px;
`
;
const
Register
=
()
=>
{
const
[
state
,
setState
]
=
useState
({
name
:
''
,
surname
:
""
,
email
:
""
,
number
:
""
,
password
:
''
,
// avatar: "",
});
const
dispatch
=
useDispatch
();
const
{
registerError
,
loading
}
=
useSelector
(
state
=>
state
.
users
);
const
navigate
=
useNavigate
()
const
fileChangeHandler
=
(
e
)
=>
{
const
name
=
e
.
target
.
name
;
const
file
=
e
.
target
.
files
[
0
];
setState
(
prevState
=>
{
return
{
...
prevState
,
[
name
]:
file
}
})
}
const
inputChangeHandler
=
(
e
)
=>
{
const
{
name
,
value
}
=
e
.
target
;
setState
((
prevState
)
=>
{
return
{
...
prevState
,
[
name
]:
value
}
});
};
const
submitHandler
=
async
(
e
)
=>
{
e
.
preventDefault
();
const
formData
=
new
FormData
();
Object
.
keys
(
state
).
forEach
(
key
=>
{
formData
.
append
(
key
,
state
[
key
]);
})
await
dispatch
(
registerUser
(
formData
,
navigate
));
await
dispatch
(
loginUser
(
state
,
navigate
))
};
const
getFieldError
=
(
fieldname
)
=>
{
return
registerError
?.
errors
?.[
fieldname
]?.
message
}
return
<>
<
StyledContainer
component
=
{
"section"
}
maxWidth
=
{
"xs"
}
>
<
Avatar
sx
=
{{
m
:
"0 auto 30px"
}}
>
<
LockIcon
/>
<
/Avatar
>
<
StyledTitle
variant
=
{
"h1"
}
>
Sign
Up
<
/StyledTitle
>
<
UserForm
onSubmit
=
{
submitHandler
}
state
=
{
state
}
onChange
=
{
inputChangeHandler
}
buttonText
=
{
"Sign Up"
}
getFieldError
=
{
getFieldError
}
fileChangeHandler
=
{
fileChangeHandler
}
/
>
<
/StyledContainer
>
<
Loader
loading
=
{
loading
}
/
>
<
/
>
};
export
default
Register
;
\ No newline at end of file
planner-front/src/index.js
View file @
236adc86
import
React
from
'react'
;
import
ReactDOM
from
'react-dom/client'
;
import
'./index.css'
;
import
ReactDOM
from
'react-dom'
;
import
{
configureStore
}
from
"@reduxjs/toolkit"
;
import
{
Provider
}
from
'react-redux'
;
import
{
BrowserRouter
}
from
'react-router-dom'
;
import
"./index.css"
;
import
App
from
'./App'
;
import
reportWebVitals
from
'./reportWebVitals
'
;
import
usersReduser
from
'./store/reducers/usersReducer
'
;
const
root
=
ReactDOM
.
createRoot
(
document
.
getElementById
(
'root'
));
root
.
render
(
<
React
.
StrictMode
>
<
App
/>
<
/React.StrictMode
>
const
localstorageMiddleware
=
({
getState
})
=>
(
next
)
=>
(
action
)
=>
{
const
result
=
next
(
action
);
localStorage
.
setItem
(
"user"
,
JSON
.
stringify
(
getState
().
users
.
user
));
return
result
;
}
const
loadFromLocalStorage
=
()
=>
{
if
(
localStorage
.
getItem
(
"user"
)
!==
null
)
{
return
{
users
:
{
user
:
JSON
.
parse
(
localStorage
.
getItem
(
"user"
))}}
}
return
undefined
;
}
const
store
=
configureStore
({
reducer
:
{
users
:
usersReduser
},
preloadedState
:
loadFromLocalStorage
(),
middleware
:
(
getDefaultMiddleware
)
=>
getDefaultMiddleware
().
concat
(
localstorageMiddleware
)
});
const
app
=
(
<
BrowserRouter
>
<
Provider
store
=
{
store
}
>
<
App
/>
<
/Provider
>
<
/BrowserRouter
>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals
();
const
root
=
ReactDOM
.
createRoot
(
document
.
getElementById
(
'root'
));
root
.
render
(
app
);
\ No newline at end of file
planner-front/src/logo.svg
deleted
100644 → 0
View file @
bdf3f7b2
<svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 841.9 595.3"
><g
fill=
"#61DAFB"
><path
d=
"M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"
/><circle
cx=
"420.9"
cy=
"296.5"
r=
"45.7"
/><path
d=
"M520.5 78.1z"
/></g></svg>
\ No newline at end of file
planner-front/src/store/actionTypes.js
0 → 100644
View file @
236adc86
export
const
REGISTER_USER_REQUEST
=
"REGISTER_USER_REQUEST"
;
export
const
REGISTER_USER_SUCCESS
=
"REGISTER_USER_SUCCESS"
;
export
const
REGISTER_USER_FAILURE
=
"REGISTER_USER_FAILURE"
;
export
const
LOGIN_USER_SUCCESS
=
"LOGIN_USER_SUCCESS"
;
export
const
LOGIN_USER_FAILURE
=
"LOGIN_USER_FAILURE"
;
export
const
LOGOUT_USER_SUCCESS
=
"LOGOUT_USER_SUCCESS"
;
export
const
LOGOUT_USER_FAILURE
=
"LOGOUT_USER_FAILURE"
;
\ No newline at end of file
planner-front/src/store/actions/commonActions.js
0 → 100644
View file @
236adc86
export
const
showNotification
=
(
message
,
variant
=
"success"
)
=>
{
return
{
type
:
"SHOW_NOTIFICATION"
,
message
,
variant
}
}
export
const
hideNotification
=
()
=>
{
return
{
type
:
"HIDE_NOTIFICATION"
};
};
\ No newline at end of file
planner-front/src/store/actions/usersActions.js
0 → 100644
View file @
236adc86
import
axios
from
"../../axiosPlanner"
;
import
{
LOGIN_USER_FAILURE
,
LOGIN_USER_SUCCESS
,
LOGOUT_USER_FAILURE
,
LOGOUT_USER_SUCCESS
,
REGISTER_USER_FAILURE
,
REGISTER_USER_REQUEST
,
REGISTER_USER_SUCCESS
}
from
"../actionTypes"
import
{
showNotification
}
from
"./commonActions"
;
const
registerUserRequest
=
()
=>
{
return
{
type
:
REGISTER_USER_REQUEST
}
};
const
registerUserSuccess
=
()
=>
{
return
{
type
:
REGISTER_USER_SUCCESS
}
};
const
registerUserFailure
=
(
error
)
=>
{
return
{
type
:
REGISTER_USER_FAILURE
,
error
}
};
export
const
registerUser
=
(
userData
,
navigate
)
=>
{
return
async
(
dispatch
)
=>
{
dispatch
(
registerUserRequest
());
try
{
const
response
=
await
axios
.
post
(
"/users"
,
userData
);
dispatch
(
registerUserSuccess
())
console
.
log
(
response
)
navigate
(
"/"
)
}
catch
(
error
)
{
if
(
error
.
response
?.
data
)
{
dispatch
(
registerUserFailure
(
error
.
response
.
data
));
}
else
{
dispatch
(
registerUserFailure
({
global
:
"Потеряно соедиение"
}));
}
}
}
}
const
loginUserSuccess
=
(
user
)
=>
{
return
{
type
:
LOGIN_USER_SUCCESS
,
user
}
}
const
loginUserFailure
=
(
error
)
=>
{
return
{
type
:
LOGIN_USER_FAILURE
,
error
}
}
const
logoutUserSuccess
=
()
=>
{
return
{
type
:
LOGOUT_USER_SUCCESS
}
}
const
logoutUserFailure
=
(
error
)
=>
{
return
{
type
:
LOGOUT_USER_FAILURE
,
error
}
}
export
const
loginUser
=
(
userData
,
navigate
)
=>
{
return
async
(
dispatch
)
=>
{
try
{
const
response
=
await
axios
.
post
(
"users/sessions"
,
userData
);
dispatch
(
loginUserSuccess
(
response
.
data
));
navigate
(
"/"
)
}
catch
(
e
)
{
console
.
dir
(
e
)
dispatch
(
loginUserFailure
(
e
?.
response
?.
data
?.
err
))
}
}
}
export
const
logoutUser
=
(
navigate
)
=>
{
return
async
(
dispatch
,
getState
)
=>
{
try
{
await
axios
.
delete
(
"/users/sessions"
,
{
headers
:
{
'Authorization'
:
getState
().
users
.
user
?.
token
}
});
dispatch
(
logoutUserSuccess
());
navigate
(
"/"
);
dispatch
(
showNotification
(
"Вы успешно вышли"
));
}
catch
(
e
)
{
dispatch
(
logoutUserFailure
(
e
?.
response
?.
data
));
dispatch
(
showNotification
(
"Не удалось выйти"
,
"error"
));
}
}
}
\ No newline at end of file
planner-front/src/store/reducers/usersReducer.js
0 → 100644
View file @
236adc86
import
{
REGISTER_USER_REQUEST
,
REGISTER_USER_SUCCESS
,
REGISTER_USER_FAILURE
,
LOGIN_USER_SUCCESS
,
LOGIN_USER_FAILURE
,
LOGOUT_USER_SUCCESS
}
from
"../actionTypes"
;
const
initialState
=
{
user
:
null
,
registerError
:
null
,
loginError
:
null
,
loading
:
false
};
const
usersReduser
=
(
state
=
initialState
,
action
)
=>
{
switch
(
action
.
type
)
{
case
REGISTER_USER_REQUEST
:
return
{...
state
,
loading
:
true
};
case
REGISTER_USER_SUCCESS
:
return
{...
state
,
loading
:
false
};
case
REGISTER_USER_FAILURE
:
return
{...
state
,
loading
:
false
,
registerError
:
action
.
error
};
case
LOGIN_USER_SUCCESS
:
return
{...
state
,
user
:
action
.
user
};
case
LOGIN_USER_FAILURE
:
return
{...
state
,
loginError
:
action
.
error
};
case
LOGOUT_USER_SUCCESS
:
return
{...
state
,
user
:
null
};
default
:
return
state
;
}
};
export
default
usersReduser
;
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment