Commit 236adc86 authored by Ibadullina Inabat's avatar Ibadullina Inabat

Реализована возможность зарегистрироваться и залогиниться на главной странице

parent bdf3f7b2
import logo from './logo.svg'; import {Routes, Route, Outlet, Navigate} from "react-router-dom";
import './App.css'; 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 ( const ProtectedRoute = ({isAllowed, roles, redirectUrl, children}) => {
<div className="App"> const user = useSelector(state => state.users?.user);
<header className="App-header"> if (!isAllowed && !roles?.includes(user?.role)) {
<img src={logo} className="App-logo" alt="logo" /> return <Navigate to={redirectUrl}/>
<p> }
Edit <code>src/App.js</code> and save to reload. return children || <Outlet/>
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
} }
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; export default App;
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();
});
import axios from "axios";
import {apiUrl} from "./constants";
const instance = axios.create({
baseURL: apiUrl
});
export default instance;
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
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
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;
// 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;
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
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
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
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
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
export const apiUrl = "http://localhost:8000";
export const uploadsUrl = `${apiUrl}/uploads`;
// 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
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
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
import React from 'react'; import ReactDOM from 'react-dom';
import ReactDOM from 'react-dom/client'; import { configureStore } from "@reduxjs/toolkit";
import './index.css'; import {Provider} from 'react-redux';
import {BrowserRouter} from 'react-router-dom';
import "./index.css";
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import usersReduser from './store/reducers/usersReducer';
const root = ReactDOM.createRoot(document.getElementById('root')); const localstorageMiddleware = ({getState}) => (next) => (action) => {
root.render( const result = next(action);
<React.StrictMode> localStorage.setItem("user", JSON.stringify(getState().users.user));
<App /> return result;
</React.StrictMode> }
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 const root = ReactDOM.createRoot(document.getElementById('root'));
// to log results (for example: reportWebVitals(console.log)) root.render(app);
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals \ No newline at end of file
reportWebVitals();
<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
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
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
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
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment