Commit ba5af6c4 authored by Egor Kremnev's avatar Egor Kremnev

add edit user

parent 2584765b
...@@ -3,7 +3,7 @@ const rootPath = __dirname; ...@@ -3,7 +3,7 @@ const rootPath = __dirname;
module.exports = { module.exports = {
rootPath, rootPath,
port: 8001, port: 8010,
uploadPath: path.join(rootPath, 'public', 'uploads'), uploadPath: path.join(rootPath, 'public', 'uploads'),
db: { db: {
host: 'mongodb://127.0.0.1', host: 'mongodb://127.0.0.1',
......
...@@ -18,6 +18,32 @@ router.post('/', async (req, res) => { ...@@ -18,6 +18,32 @@ router.post('/', async (req, res) => {
} }
}); });
router.put('/', auth, async (req, res) => {
const user = req.user;
if (
req.body.oldPassword.trim()
&&
!await user.checkPassword(req.body.oldPassword.toString())
) {
return res
.status(400)
.send({error: 'Old password incorrect'});
}
try {
user.password = req.body.password || user.password;
user.username = req.body.username || user.username;
await user.save();
res.send(user);
} catch (e) {
res
.status(400)
.send({error: e.message});
}
});
router.post('/login', async (req, res) => { router.post('/login', async (req, res) => {
const user = await User.findOne({username: req.body.username}); const user = await User.findOne({username: req.body.username});
...@@ -42,10 +68,7 @@ router.post('/login', async (req, res) => { ...@@ -42,10 +68,7 @@ router.post('/login', async (req, res) => {
}); });
router.get('/profile', auth, async (req, res) => { router.get('/profile', auth, async (req, res) => {
res.send({ res.send(req.user);
message: "Большой большой сикрет",
username: req.user.username
});
}); });
router.delete('/logout', auth, async (req, res) => { router.delete('/logout', auth, async (req, res) => {
......
import {Navigate, Outlet, Route, Routes as RoutesSwitch} from "react-router-dom"; import {Navigate, Outlet, Route, Routes as RoutesSwitch} from "react-router-dom";
import {LOGIN, MAIN, PRODUCT_ADD, PRODUCT_LIST, PRODUCT_VIEW, REGISTER} from "./constants/routes"; import {LOGIN, MAIN, PRODUCT_ADD, PRODUCT_LIST, PRODUCT_VIEW, REGISTER, USER_PROFILE} from "./constants/routes";
import AddProduct from "./containers/AddProduct/AddProduct"; import AddProduct from "./containers/AddProduct/AddProduct";
import Layout from "./components/Layout/Layout"; import Layout from "./components/Layout/Layout";
import Products from "./containers/Products/Products"; import Products from "./containers/Products/Products";
import Register from "./containers/Auth/Register/Register"; import Register from "./containers/Auth/Register/Register";
import Login from "./containers/Auth/Login/Login"; import Login from "./containers/Auth/Login/Login";
import User from "./containers/User/User";
const ProtectedRoute = ({isAllowed, redirectPath, children}) => { const ProtectedRoute = ({isAllowed, redirectPath, children}) => {
if (!isAllowed) { if (!isAllowed) {
...@@ -22,6 +23,13 @@ const Routes = ({user}) => { ...@@ -22,6 +23,13 @@ const Routes = ({user}) => {
<AddProduct /> <AddProduct />
</ProtectedRoute>; </ProtectedRoute>;
const userProfile = <ProtectedRoute
isAllowed={!!user}
redirectPath={LOGIN}
>
<User />
</ProtectedRoute>;
return <RoutesSwitch> return <RoutesSwitch>
<Route element={<Layout />}> <Route element={<Layout />}>
<Route index element={<Products />}/> <Route index element={<Products />}/>
...@@ -29,6 +37,7 @@ const Routes = ({user}) => { ...@@ -29,6 +37,7 @@ const Routes = ({user}) => {
<Route path={LOGIN} element={<Login />}/> <Route path={LOGIN} element={<Login />}/>
<Route path={PRODUCT_LIST} element={<Products />}/> <Route path={PRODUCT_LIST} element={<Products />}/>
<Route path={PRODUCT_ADD} element={productAdd}/> <Route path={PRODUCT_ADD} element={productAdd}/>
<Route path={USER_PROFILE} element={userProfile}/>
<Route path={PRODUCT_VIEW} element={<h1>Show product</h1>}/> <Route path={PRODUCT_VIEW} element={<h1>Show product</h1>}/>
</Route> </Route>
</RoutesSwitch>; </RoutesSwitch>;
......
...@@ -2,8 +2,8 @@ import {useState} from "react"; ...@@ -2,8 +2,8 @@ import {useState} from "react";
import {Button, Menu, MenuItem} from '@mui/material'; import {Button, Menu, MenuItem} from '@mui/material';
import {useDispatch} from "react-redux"; import {useDispatch} from "react-redux";
import {logoutUser} from "../../../../../store/actions/usersActions"; import {logoutUser} from "../../../../../store/actions/usersActions";
import {useNavigate} from "react-router-dom"; import {NavLink, useNavigate} from "react-router-dom";
import {MAIN} from "../../../../../constants/routes"; import {MAIN, USER_PROFILE} from "../../../../../constants/routes";
const UserMenu = ({user}) => { const UserMenu = ({user}) => {
const navigate = useNavigate(); const navigate = useNavigate();
...@@ -33,7 +33,7 @@ const UserMenu = ({user}) => { ...@@ -33,7 +33,7 @@ const UserMenu = ({user}) => {
onClose={handleClose} onClose={handleClose}
keepMounted keepMounted
> >
<MenuItem>Profile</MenuItem> <MenuItem component={NavLink} to={USER_PROFILE}>Profile</MenuItem>
<MenuItem>My account</MenuItem> <MenuItem>My account</MenuItem>
<MenuItem <MenuItem
onClick={() => dispatch(logoutUser({callback: () => navigate(MAIN)}))} onClick={() => dispatch(logoutUser({callback: () => navigate(MAIN)}))}
......
import {useState} from "react";
import {Button, Grid} from "@mui/material";
import FormElement from "../../UI/Form/FormElement/FormElement";
const UserForm = ({onFormSubmit, user}) => {
const [state, setState] = useState({
oldPassword: "",
password: "",
username: user.username
});
const submitFormHandler = e => {
e.preventDefault();
onFormSubmit(state);
};
const inputChangeHandler = e => {
const name = e.target.name;
const value = e.target.value;
setState(prevState => {
return {...prevState, [name]: value};
});
};
return (
<form
autoComplete="off"
onSubmit={submitFormHandler}
>
<Grid container direction="column" spacing={2}>
<FormElement
id="oldPassword"
label="Old Password"
required={!!state.password.trim()}
value={state.oldPassword}
onChange={inputChangeHandler}
name="oldPassword"
/>
<FormElement
id="password"
label="New password"
required={!!state.oldPassword.trim()}
value={state.password}
onChange={inputChangeHandler}
name="password"
/>
<FormElement
id="username"
label="Username"
value={state.username}
onChange={inputChangeHandler}
name="username"
/>
<Grid item xs>
<Button type="submit" color="primary" variant="contained">
Save
</Button>
</Grid>
</Grid>
</form>
);
};
export default UserForm;
export const apiUrl = "http://localhost:8001"; export const apiUrl = "http://localhost:8010";
export const uploadUrl = apiUrl + '/uploads'; export const uploadUrl = apiUrl + '/uploads';
...@@ -4,3 +4,4 @@ export const PRODUCT_LIST = '/products/'; ...@@ -4,3 +4,4 @@ export const PRODUCT_LIST = '/products/';
export const PRODUCT_VIEW = '/products/:id'; export const PRODUCT_VIEW = '/products/:id';
export const REGISTER = '/register'; export const REGISTER = '/register';
export const LOGIN = '/login'; export const LOGIN = '/login';
export const USER_PROFILE = '/user/profile';
import {useDispatch, useSelector} from "react-redux";
import {Typography} from "@mui/material";
import UserForm from "../../components/User/UserForm/UserForm";
import {useNavigate} from "react-router-dom";
import {updateUser} from "../../store/actions/usersActions";
const User = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const user = useSelector(({usersState}) => usersState.user);
const onFormSubmit = async data => {
await dispatch(updateUser({data, callback: () => navigate('/')}));
};
return (
<>
<Typography variant='h4'>
Edit {user.username}
</Typography>
<UserForm
onFormSubmit={onFormSubmit}
user={user}
/>
</>
);
};
export default User;
...@@ -44,3 +44,18 @@ export const logoutUser = createAsyncThunk( ...@@ -44,3 +44,18 @@ export const logoutUser = createAsyncThunk(
throw e; throw e;
}) })
); );
export const updateUser = createAsyncThunk(
'users/update',
async ({data, callback}, {dispatch}) => await axiosApi
.put('/users', data)
.then(res => {
dispatch(setUser(res.data));
callback();
})
.catch(e => {
if (e?.response?.data) dispatch(setLoginError(e.response.data));
else dispatch(setLoginError(e));
throw e;
})
);
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