Skip to content

Commit 36bb281

Browse files
authored
Video-30-PayPal-Payment (basir#30)
1 parent 585c803 commit 36bb281

File tree

6 files changed

+143
-7
lines changed

6 files changed

+143
-7
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,16 @@ JS AMAZONA
253253
1. create OrderScreen.js
254254
2. style elements
255255
30. PayPal Payment
256-
1. add paypal checkout script
257-
2. show paypal button
258-
3. update order after payment
256+
1. get client id from paypal
257+
2. set it in .env file
258+
3. create route form /api/paypal/clientId
259+
4. create getPaypalClientID in api.js
260+
5. add paypal checkout script in OrderScreen.js
261+
6. show paypal button
262+
7. update order after payment
263+
8. create payOrder in api.js
264+
9. create route for /:id/pay in orderRouter.js
265+
10. rerender after pay order
259266
31. User Order History
260267
1. Create order history api
261268
2. Show orders in profile screen

backend/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ dotenv.config();
55
export default {
66
MONGODB_URL: process.env.MONGODB_URL,
77
JWT_SECRET: process.env.JWT_SECRET,
8+
PAYPAL_CLIENT_ID: process.env.PAYPAL_CLIENT_ID,
89
};

backend/routers/orderRouter.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,24 @@ orderRouter.post(
3434
res.status(201).send({ message: 'New Order Created', order: createdOrder });
3535
})
3636
);
37-
37+
orderRouter.put(
38+
'/:id/pay',
39+
isAuth,
40+
expressAsyncHandler(async (req, res) => {
41+
const order = await Order.findById(req.params.id);
42+
if (order) {
43+
order.isPaid = true;
44+
order.paidAt = Date.now();
45+
order.payment.paymentResult = {
46+
payerID: req.body.payerID,
47+
paymentID: req.body.paymentID,
48+
orderID: req.body.orderID,
49+
};
50+
const updatedOrder = await order.save();
51+
res.send({ message: 'Order Paid', order: updatedOrder });
52+
} else {
53+
res.status(404).send({ message: 'Order Not Found.' });
54+
}
55+
})
56+
);
3857
export default orderRouter;

backend/server.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ app.use(cors());
2424
app.use(bodyParser.json());
2525
app.use('/api/users', userRouter);
2626
app.use('/api/orders', orderRouter);
27+
app.get('/api/paypal/clientId', (req, res) => {
28+
res.send({ clientId: config.PAYPAL_CLIENT_ID });
29+
});
2730
app.get('/api/products', (req, res) => {
2831
res.send(data.products);
2932
});

frontend/src/api.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,37 @@ export const getOrder = async (id) => {
128128
return { error: err.message };
129129
}
130130
};
131+
132+
export const getPaypalClientId = async () => {
133+
const response = await axios({
134+
url: `${apiUrl}/api/paypal/clientId`,
135+
headers: {
136+
'Content-Type': 'application/json',
137+
},
138+
});
139+
if (response.statusText !== 'OK') {
140+
throw new Error(response.data.message);
141+
}
142+
return response.data.clientId;
143+
};
144+
145+
export const payOrder = async (orderId, paymentResult) => {
146+
try {
147+
const { token } = getUserInfo();
148+
const response = await axios({
149+
url: `${apiUrl}/api/orders/${orderId}/pay`,
150+
method: 'PUT',
151+
headers: {
152+
'Content-Type': 'application/json',
153+
Authorization: `Bearer ${token}`,
154+
},
155+
data: paymentResult,
156+
});
157+
if (response.statusText !== 'OK') {
158+
throw new Error(response.data.message);
159+
}
160+
return response.data;
161+
} catch (err) {
162+
return { error: err.response ? err.response.data.message : err.message };
163+
}
164+
};

frontend/src/srceens/OrderScreen.js

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,74 @@
1-
import { parseRequestUrl } from '../utils';
2-
import { getOrder } from '../api';
1+
import {
2+
parseRequestUrl,
3+
showLoading,
4+
hideLoading,
5+
showMessage,
6+
rerender,
7+
} from '../utils';
8+
import { getOrder, getPaypalClientId, payOrder } from '../api';
39

10+
const addPaypalSdk = async (totalPrice) => {
11+
const clientId = await getPaypalClientId();
12+
showLoading();
13+
if (!window.paypal) {
14+
const script = document.createElement('script');
15+
script.type = 'text/javascript';
16+
script.src = 'https://www.paypalobjects.com/api/checkout.js';
17+
script.async = true;
18+
script.onload = () => handlePayment(clientId, totalPrice);
19+
document.body.appendChild(script);
20+
} else {
21+
handlePayment(clientId, totalPrice);
22+
}
23+
};
24+
const handlePayment = (clientId, totalPrice) => {
25+
window.paypal.Button.render(
26+
{
27+
env: 'sandbox',
28+
client: {
29+
sandbox: clientId,
30+
production: '',
31+
},
32+
locale: 'en_US',
33+
style: {
34+
size: 'responsive',
35+
color: 'gold',
36+
shape: 'pill',
37+
},
38+
39+
commit: true,
40+
payment(data, actions) {
41+
return actions.payment.create({
42+
transactions: [
43+
{
44+
amount: {
45+
total: totalPrice,
46+
currency: 'USD',
47+
},
48+
},
49+
],
50+
});
51+
},
52+
onAuthorize(data, actions) {
53+
return actions.payment.execute().then(async () => {
54+
showLoading();
55+
await payOrder(parseRequestUrl().id, {
56+
orderID: data.orderID,
57+
payerID: data.payerID,
58+
paymentID: data.paymentID,
59+
});
60+
hideLoading();
61+
showMessage('Payment was successfull.', () => {
62+
rerender(OrderScreen);
63+
});
64+
});
65+
},
66+
},
67+
'#paypal-button'
68+
).then(() => {
69+
hideLoading();
70+
});
71+
};
472
const OrderScreen = {
573
after_render: async () => {},
674
render: async () => {
@@ -19,6 +87,9 @@ const OrderScreen = {
1987
isPaid,
2088
paidAt,
2189
} = await getOrder(request.id);
90+
if (!isPaid) {
91+
addPaypalSdk(totalPrice);
92+
}
2293
return `
2394
<div>
2495
<h1>Order ${_id}</h1>
@@ -83,7 +154,8 @@ const OrderScreen = {
83154
<li><div>Items</div><div>$${itemsPrice}</div></li>
84155
<li><div>Shipping</div><div>$${shippingPrice}</div></li>
85156
<li><div>Tax</div><div>$${taxPrice}</div></li>
86-
<li class="total"><div>Order Total</div><div>$${totalPrice}</div></li>
157+
<li class="total"><div>Order Total</div><div>$${totalPrice}</div></li>
158+
<li><div class="fw" id="paypal-button"></div></li>
87159
<li>
88160
89161
</div>

0 commit comments

Comments
 (0)