Skip to content

Commit 540754b

Browse files
authored
Video-25-User-Profile-Screen (basir#25)
1 parent 9b0829d commit 540754b

File tree

7 files changed

+143
-3
lines changed

7 files changed

+143
-3
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ JS AMAZONA
228228
3. after_render handle form submit
229229
4. create profile update request in frontend
230230
5. create profile update api in backend
231-
6. implement sign out
231+
6. create isAuth in utils.js and use in update profile
232+
7. implement sign out
232233
26. Create Checkout Wizard Header Component
233234
1. create component
234235
2. style component

backend/routers/userRouter.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import express from 'express';
22
import expressAsyncHandler from 'express-async-handler';
33
import User from '../models/userModel';
4-
import { generateToken } from '../utils';
4+
import { generateToken, isAuth } from '../utils';
55

66
const userRouter = express.Router();
77

@@ -68,4 +68,29 @@ userRouter.post(
6868
}
6969
})
7070
);
71+
userRouter.put(
72+
'/:id',
73+
isAuth,
74+
expressAsyncHandler(async (req, res) => {
75+
const user = await User.findById(req.params.id);
76+
77+
if (!user) {
78+
res.status(404).send({
79+
message: 'User Not Found',
80+
});
81+
} else {
82+
user.name = req.body.name || user.name;
83+
user.email = req.body.email || user.email;
84+
user.password = req.body.password || user.password;
85+
const updatedUser = await user.save();
86+
res.send({
87+
_id: updatedUser._id,
88+
name: updatedUser.name,
89+
email: updatedUser.email,
90+
isAdmin: updatedUser.isAdmin,
91+
token: generateToken(updatedUser),
92+
});
93+
}
94+
})
95+
);
7196
export default userRouter;

backend/utils.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,19 @@ export const generateToken = (user) => {
1212
config.JWT_SECRET
1313
);
1414
};
15+
export const isAuth = (req, res, next) => {
16+
const bearerToken = req.headers.authorization;
17+
if (!bearerToken) {
18+
res.status(401).send({ message: 'Token is not supplied' });
19+
} else {
20+
const token = bearerToken.slice(7, bearerToken.length);
21+
jwt.verify(token, config.JWT_SECRET, (err, data) => {
22+
if (err) {
23+
res.status(401).send({ message: 'Invalid Token' });
24+
} else {
25+
req.user = data;
26+
next();
27+
}
28+
});
29+
}
30+
};

frontend/src/api.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import axios from 'axios';
22
import { apiUrl } from './config';
3+
import { getUserInfo } from './localStorage';
34

45
export const getProduct = async (id) => {
56
try {
@@ -64,3 +65,28 @@ export const register = async ({ name, email, password }) => {
6465
return { error: err.response.data.message || err.message };
6566
}
6667
};
68+
export const update = async ({ name, email, password }) => {
69+
try {
70+
const { _id, token } = getUserInfo();
71+
const response = await axios({
72+
url: `${apiUrl}/api/users/${_id}`,
73+
method: 'PUT',
74+
headers: {
75+
'Content-Type': 'application/json',
76+
Authorization: `Bearer ${token}`,
77+
},
78+
data: {
79+
name,
80+
email,
81+
password,
82+
},
83+
});
84+
if (response.statusText !== 'OK') {
85+
throw new Error(response.data.message);
86+
}
87+
return response.data;
88+
} catch (err) {
89+
console.log(err);
90+
return { error: err.response.data.message || err.message };
91+
}
92+
};

frontend/src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import CartScreen from './srceens/CartScreen';
66
import SigninScreen from './srceens/SigninScreen';
77
import Header from './components/Header';
88
import RegisterScreen from './srceens/RegisterScreen';
9+
import ProfileScreen from './srceens/ProfileScreen';
910

1011
const routes = {
1112
'/': HomeScreen,
@@ -14,6 +15,7 @@ const routes = {
1415
'/cart': CartScreen,
1516
'/signin': SigninScreen,
1617
'/register': RegisterScreen,
18+
'/profile': ProfileScreen,
1719
};
1820
const router = async () => {
1921
showLoading();
@@ -28,7 +30,7 @@ const router = async () => {
2830
await Header.after_render();
2931
const main = document.getElementById('main-container');
3032
main.innerHTML = await screen.render();
31-
await screen.after_render();
33+
if (screen.after_render) await screen.after_render();
3234
hideLoading();
3335
};
3436
window.addEventListener('load', router);

frontend/src/localStorage.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ export const setUserInfo = ({
2727
})
2828
);
2929
};
30+
export const clearUser = () => {
31+
localStorage.removeItem('userInfo');
32+
};
3033
export const getUserInfo = () => {
3134
return localStorage.getItem('userInfo')
3235
? JSON.parse(localStorage.getItem('userInfo'))
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { update } from '../api';
2+
import { getUserInfo, setUserInfo, clearUser } from '../localStorage';
3+
import { showLoading, hideLoading, showMessage } from '../utils';
4+
5+
const ProfileScreen = {
6+
after_render: () => {
7+
document.getElementById('signout-button').addEventListener('click', () => {
8+
clearUser();
9+
document.location.hash = '/';
10+
});
11+
document
12+
.getElementById('profile-form')
13+
.addEventListener('submit', async (e) => {
14+
e.preventDefault();
15+
showLoading();
16+
const data = await update({
17+
name: document.getElementById('name').value,
18+
email: document.getElementById('email').value,
19+
password: document.getElementById('password').value,
20+
});
21+
hideLoading();
22+
if (data.error) {
23+
showMessage(data.error);
24+
} else {
25+
setUserInfo(data);
26+
document.location.hash = '/';
27+
}
28+
});
29+
},
30+
render: () => {
31+
const { name, email } = getUserInfo();
32+
if (!name) {
33+
document.location.hash = '/';
34+
}
35+
return `
36+
<div class="form-container">
37+
<form id="profile-form">
38+
<ul class="form-items">
39+
<li>
40+
<h1>User Profile</h1>
41+
</li>
42+
<li>
43+
<label for="name">Name</label>
44+
<input type="name" name="name" id="name" value="${name}" />
45+
</li>
46+
<li>
47+
<label for="email">Email</label>
48+
<input type="email" name="email" id="email" value="${email}" />
49+
</li>
50+
<li>
51+
<label for="password">Password</label>
52+
<input type="password" name="password" id="password" />
53+
</li>
54+
<li>
55+
<button type="submit" class="primary">Update</button>
56+
</li>
57+
<li>
58+
<button type="button" id="signout-button" >Sign Out</button>
59+
</li>
60+
61+
</ul>
62+
</form>
63+
</div>
64+
`;
65+
},
66+
};
67+
export default ProfileScreen;

0 commit comments

Comments
 (0)