Skip to content

Commit eb77483

Browse files
authored
Video-28-PlaceOrder-Screen-Action (basir#28)
1 parent ea753ea commit eb77483

File tree

8 files changed

+129
-6
lines changed

8 files changed

+129
-6
lines changed

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,11 @@ JS AMAZONA
244244
1. create PlaceOrder.js
245245
2. style elements
246246
28. PlaceOrder Screen Action
247-
1. handle form submit
248-
2. create backend api to create order
247+
1. handle place order button click
248+
2. createOrder api
249+
3. create orderModel
250+
4. create orderRouter
251+
5. create post order route
249252
29. Order Screen
250253
1. create OrderScreen.js
251254
2. style elements

backend/data.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export default {
22
products: [
33
{
4-
_id: '1',
4+
_id: '111111111111111111111111',
55
name: 'Hiskywin Full Zip Running Shirts Thermal Workout',
66
category: 'Shirts',
77
image: '/images/product-1.jpg',

backend/models/orderModel.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import mongoose from 'mongoose';
2+
3+
const orderSchema = new mongoose.Schema(
4+
{
5+
orderItems: [
6+
{
7+
name: { type: String, required: true },
8+
image: { type: String, required: true },
9+
price: { type: Number, required: true },
10+
qty: { type: Number, required: true },
11+
product: {
12+
type: mongoose.Schema.Types.ObjectId,
13+
ref: 'Product',
14+
required: true,
15+
},
16+
},
17+
],
18+
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
19+
shipping: {
20+
address: String,
21+
city: String,
22+
postalCode: String,
23+
country: String,
24+
},
25+
payment: {
26+
paymentMethod: String,
27+
paymentResult: {
28+
orderID: String,
29+
payerID: String,
30+
paymentID: String,
31+
},
32+
},
33+
itemsPrice: Number,
34+
taxPrice: Number,
35+
shippingPrice: Number,
36+
totalPrice: Number,
37+
isPaid: { type: Boolean, required: true, default: false },
38+
paidAt: Date,
39+
isDelivered: { type: Boolean, required: true, default: false },
40+
deliveredAt: Date,
41+
},
42+
{
43+
timestamps: true,
44+
}
45+
);
46+
const Order = mongoose.model('Order', orderSchema);
47+
export default Order;

backend/routers/orderRouter.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import express from 'express';
2+
import expressAsyncHandler from 'express-async-handler';
3+
import { isAuth } from '../utils';
4+
import Order from '../models/orderModel';
5+
6+
const orderRouter = express.Router();
7+
8+
orderRouter.post(
9+
'/',
10+
isAuth,
11+
expressAsyncHandler(async (req, res) => {
12+
const order = new Order({
13+
orderItems: req.body.orderItems,
14+
user: req.user._id,
15+
shipping: req.body.shipping,
16+
payment: req.body.payment,
17+
itemsPrice: req.body.itemsPrice,
18+
taxtPrice: req.body.taxtPrice,
19+
shippingPrice: req.body.shippingPrice,
20+
totalPrice: req.body.totalPrice,
21+
});
22+
const createdOrder = await order.save();
23+
res.status(201).send({ message: 'New Order Created', order: createdOrder });
24+
})
25+
);
26+
export default orderRouter;

backend/server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import bodyParser from 'body-parser';
55
import data from './data';
66
import config from './config';
77
import userRouter from './routers/userRouter';
8+
import orderRouter from './routers/orderRouter';
89

910
mongoose
1011
.connect(config.MONGODB_URL, {
@@ -22,6 +23,7 @@ const app = express();
2223
app.use(cors());
2324
app.use(bodyParser.json());
2425
app.use('/api/users', userRouter);
26+
app.use('/api/orders', orderRouter);
2527
app.get('/api/products', (req, res) => {
2628
res.send(data.products);
2729
});

frontend/src/api.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,23 @@ export const update = async ({ name, email, password }) => {
9090
return { error: err.response.data.message || err.message };
9191
}
9292
};
93+
export const createOrder = async (order) => {
94+
try {
95+
const { token } = getUserInfo();
96+
const response = await axios({
97+
url: `${apiUrl}/api/orders`,
98+
method: 'POST',
99+
headers: {
100+
'Content-Type': 'application/json',
101+
Authorization: `Bearer ${token}`,
102+
},
103+
data: order,
104+
});
105+
if (response.statusText !== 'Created') {
106+
throw new Error(response.data.message);
107+
}
108+
return response.data;
109+
} catch (err) {
110+
return { error: err.response ? err.response.data.message : err.message };
111+
}
112+
};

frontend/src/localStorage.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,6 @@ export const getPayment = () => {
6969
export const setPayment = ({ paymentMethod = 'paypal' }) => {
7070
localStorage.setItem('payment', JSON.stringify({ paymentMethod }));
7171
};
72+
export const cleanCart = () => {
73+
localStorage.removeItem('cartItems');
74+
};

frontend/src/srceens/PlaceOrderScreen.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
import { getCartItems, getShipping, getPayment } from '../localStorage';
1+
import {
2+
getCartItems,
3+
getShipping,
4+
getPayment,
5+
cleanCart,
6+
} from '../localStorage';
27
import CheckoutSteps from '../components/CheckoutSteps';
8+
import { showLoading, hideLoading, showMessage } from '../utils';
9+
import { createOrder } from '../api';
310

411
const convertCartToOrder = () => {
512
const orderItems = getCartItems();
@@ -29,7 +36,22 @@ const convertCartToOrder = () => {
2936
};
3037
};
3138
const PlaceOrderScreen = {
32-
after_render: () => {},
39+
after_render: async () => {
40+
document
41+
.getElementById('placeorder-button')
42+
.addEventListener('click', async () => {
43+
const order = convertCartToOrder();
44+
showLoading();
45+
const data = await createOrder(order);
46+
hideLoading();
47+
if (data.error) {
48+
showMessage(data.error);
49+
} else {
50+
cleanCart();
51+
document.location.hash = `/order/${data.order._id}`;
52+
}
53+
});
54+
},
3355
render: () => {
3456
const {
3557
orderItems,
@@ -100,7 +122,7 @@ const PlaceOrderScreen = {
100122
<li><div>Tax</div><div>$${taxPrice}</div></li>
101123
<li class="total"><div>Order Total</div><div>$${totalPrice}</div></li>
102124
<li>
103-
<button class="primary fw">
125+
<button id="placeorder-button" class="primary fw">
104126
Place Order
105127
</button>
106128
</div>

0 commit comments

Comments
 (0)