Skip to content

Commit 98cf7a7

Browse files
authored
Video-40-Admin-Orders (basir#40)
1 parent fc7808a commit 98cf7a7

File tree

8 files changed

+168
-23
lines changed

8 files changed

+168
-23
lines changed

README.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -339,36 +339,44 @@ Feel free to take a look at the course preview and enroll if it is along with yo
339339
1. update ProductListScreen.js
340340
2. handle delete button
341341
3. rerender after deletion
342-
40. Show Categories In Sidebar Menu
343-
1. update ProductListScreen.js
344-
2. handle delete button
345-
3. rerender after deletion
346-
41. Admin Orders
342+
40. Admin Orders
347343
1. create Admin Order menu in header
348344
2. create AdminOrder.js
349345
3. load orders from backend
350346
4. list them in the screen
351347
5. show delete and edit button
352348
6. redirect to order details on edit action
353-
42. Edit Order
349+
41. Edit Order
354350
1. if order is payed show deliver button for admin
355351
2. handle click on deliver button
356352
3. set state to delivered
357-
43. Delete Order
358-
1. update OrderListScreen.js
359-
2. handle delete button
360-
3. rerender after deletion
361-
44. Show Summary Report in Dashboard
353+
42. Show Summary Report in Dashboard
362354
1. create summary section
363355
2. style summary
364356
3. create summary backend
365357
4. create getSummary in api.js
366358
5. load data in dashboard screen
367359
6. show 3 boxes for Users, Orders and Sales
368-
45. Show Chart in Dashboard
360+
43. Show Chart in Dashboard
369361
1. import chartist
370362
2. add chartist css to index.html
371363
3. create linear chart for daily sales
372364
4. create pie chart for product categories
373-
46. Publish heroku
365+
44. Publish heroku
374366
1. publish steps
367+
45. Product Search Bar
368+
1. create search bar in Header.js
369+
2. add style
370+
3. handle submit form
371+
4. edit parse url to get query string
372+
5. update product list api for search keyword
373+
46. Show Categories In Sidebar Menu
374+
1. create aside-open-button in Header.js
375+
2. add event to open aside
376+
3. create Aside.js component
377+
4. Add style aside
378+
5. after render close it on click on close button
379+
6. Use it in index.html
380+
7. Update index.js to render aside 9.
381+
8. call getCategories
382+
9. create getCategories in api.js

backend/routers/orderRouter.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
import express from 'express';
22
import expressAsyncHandler from 'express-async-handler';
3-
import { isAuth } from '../utils';
3+
import { isAuth, isAdmin } from '../utils';
44
import Order from '../models/orderModel';
55

66
const orderRouter = express.Router();
7+
8+
orderRouter.get(
9+
'/',
10+
isAuth,
11+
isAdmin,
12+
expressAsyncHandler(async (req, res) => {
13+
const orders = await Order.find({}).populate('user');
14+
res.send(orders);
15+
})
16+
);
17+
718
orderRouter.get(
819
'/mine',
920
isAuth,
@@ -42,6 +53,21 @@ orderRouter.post(
4253
res.status(201).send({ message: 'New Order Created', order: createdOrder });
4354
})
4455
);
56+
orderRouter.delete(
57+
'/:id',
58+
isAuth,
59+
isAdmin,
60+
expressAsyncHandler(async (req, res) => {
61+
const order = await Order.findById(req.params.id);
62+
if (order) {
63+
const deletedOrder = await order.remove();
64+
res.send({ message: 'Order Deleted', product: deletedOrder });
65+
} else {
66+
res.status(404).send({ message: 'Order Not Found' });
67+
}
68+
})
69+
);
70+
4571
orderRouter.put(
4672
'/:id/pay',
4773
isAuth,

backend/routers/productRouter.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import express from 'express';
2-
import expressAysncHandler from 'express-async-handler';
2+
import expressAsyncHandler from 'express-async-handler';
33
import { isAuth, isAdmin } from '../utils';
44
import Product from '../models/productModel';
55

66
const productRouter = express.Router();
77
productRouter.get(
88
'/',
9-
expressAysncHandler(async (req, res) => {
9+
expressAsyncHandler(async (req, res) => {
1010
const products = await Product.find({});
1111
res.send(products);
1212
})
1313
);
1414
productRouter.get(
1515
'/:id',
16-
expressAysncHandler(async (req, res) => {
16+
expressAsyncHandler(async (req, res) => {
1717
const product = await Product.findById(req.params.id);
1818
res.send(product);
1919
})
@@ -23,7 +23,7 @@ productRouter.post(
2323
'/',
2424
isAuth,
2525
isAdmin,
26-
expressAysncHandler(async (req, res) => {
26+
expressAsyncHandler(async (req, res) => {
2727
const product = new Product({
2828
name: 'sample product',
2929
description: 'sample desc',
@@ -45,7 +45,7 @@ productRouter.put(
4545
'/:id',
4646
isAuth,
4747
isAdmin,
48-
expressAysncHandler(async (req, res) => {
48+
expressAsyncHandler(async (req, res) => {
4949
const productId = req.params.id;
5050
const product = await Product.findById(productId);
5151
if (product) {
@@ -71,7 +71,7 @@ productRouter.delete(
7171
'/:id',
7272
isAuth,
7373
isAdmin,
74-
expressAysncHandler(async (req, res) => {
74+
expressAsyncHandler(async (req, res) => {
7575
const product = await Product.findById(req.params.id);
7676
if (product) {
7777
const deletedProduct = await product.remove();

frontend/src/api.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,45 @@ export const createOrder = async (order) => {
212212
return { error: err.response ? err.response.data.message : err.message };
213213
}
214214
};
215+
export const getOrders = async () => {
216+
try {
217+
const { token } = getUserInfo();
218+
const response = await axios({
219+
url: `${apiUrl}/api/orders`,
220+
method: 'GET',
221+
headers: {
222+
'Content-Type': 'application/json',
223+
Authorization: `Bearer ${token}`,
224+
},
225+
});
226+
if (response.statusText !== 'OK') {
227+
throw new Error(response.data.message);
228+
}
229+
return response.data;
230+
} catch (err) {
231+
console.log(err);
232+
return { error: err.response.data.message || err.message };
233+
}
234+
};
235+
export const deleteOrder = async (orderId) => {
236+
try {
237+
const { token } = getUserInfo();
238+
const response = await axios({
239+
url: `${apiUrl}/api/orders/${orderId}`,
240+
method: 'DELETE',
241+
headers: {
242+
'Content-Type': 'application/json',
243+
Authorization: `Bearer ${token}`,
244+
},
245+
});
246+
if (response.statusText !== 'OK') {
247+
throw new Error(response.data.message);
248+
}
249+
return response.data;
250+
} catch (err) {
251+
return { error: err.response.data.message || err.message };
252+
}
253+
};
215254
export const getOrder = async (id) => {
216255
try {
217256
const { token } = getUserInfo();

frontend/src/components/Header.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ const Header = {
1212
name
1313
? `<a href="/#/profile">${name}</a>`
1414
: `<a href="/#/signin">Sign-In</a>`
15-
}
16-
15+
}
1716
<a href="/#/cart">Cart</a>
1817
${isAdmin ? `<a href="/#/dashboard">Dashboard</a>` : ''}
1918
</div>`;

frontend/src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import OrderScreen from './srceens/OrderScreen';
1414
import DashboardScreen from './srceens/DashboardScreen';
1515
import ProductListScreen from './srceens/ProductListScreen';
1616
import ProductEditScreen from './srceens/ProductEditScreen';
17+
import OrderListScreen from './srceens/OrderListScreen';
1718

1819
const routes = {
1920
'/': HomeScreen,
@@ -30,6 +31,7 @@ const routes = {
3031
'/placeorder': PlaceOrderScreen,
3132
'/dashboard': DashboardScreen,
3233
'/productlist': ProductListScreen,
34+
'/orderlist': OrderListScreen,
3335
};
3436
const router = async () => {
3537
showLoading();
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import DashboardMenu from '../components/DashboardMenu';
2+
import { getOrders, deleteOrder } from '../api';
3+
import { showLoading, hideLoading, rerender, showMessage } from '../utils';
4+
5+
const OrderListScreen = {
6+
after_render: () => {
7+
const deleteButtons = document.getElementsByClassName('delete-button');
8+
Array.from(deleteButtons).forEach((deleteButton) => {
9+
deleteButton.addEventListener('click', async () => {
10+
if (confirm('Are you sure to delete this order?')) {
11+
showLoading();
12+
const data = await deleteOrder(deleteButton.id);
13+
if (data.error) {
14+
showMessage(data.error);
15+
} else {
16+
rerender(OrderListScreen);
17+
}
18+
hideLoading();
19+
}
20+
});
21+
});
22+
},
23+
render: async () => {
24+
const orders = await getOrders();
25+
return `
26+
<div class="dashboard">
27+
${DashboardMenu.render({ selected: 'orders' })}
28+
<div class="dashboard-content">
29+
<h1>Orders</h1>
30+
31+
<div class="order-list">
32+
<table>
33+
<thead>
34+
<tr>
35+
<th>ID</th>
36+
<th>DATE</th>
37+
<th>TOTAL</th>
38+
<th>USER</th>
39+
<th>PAID AT</th>
40+
<th>DELIVERED AT</th>
41+
<th class="tr-action">ACTION</th>
42+
<tr>
43+
</thead>
44+
<tbody>
45+
${orders
46+
.map(
47+
(order) => `
48+
<tr>
49+
<td>${order._id}</td>
50+
<td>${order.createdAt}</td>
51+
<td>${order.totalPrice}</td>
52+
<td>${order.user.name}</td>
53+
<td>${order.paidAt || 'No'}</td>
54+
<td>${order.deliveredAt || 'No'}</td>
55+
<td>
56+
<button id="${order._id}" class="edit-button">Edit</button>
57+
<button id="${order._id}" class="delete-button">Delete</button>
58+
</td>
59+
</tr>
60+
`
61+
)
62+
.join('\n')}
63+
</tbody>
64+
</table>
65+
</div>
66+
</div>
67+
</div>
68+
`;
69+
},
70+
};
71+
export default OrderListScreen;

frontend/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ td {
408408
flex: 4 1 80rem;
409409
padding: 1rem;
410410
}
411-
411+
.order-list button,
412412
.product-list button {
413413
font-size: 1.3rem;
414414
padding: 0.5rem;

0 commit comments

Comments
 (0)