Skip to content
This repository was archived by the owner on Mar 3, 2024. It is now read-only.

Commit 9fca6c5

Browse files
committed
Added paypal payment button
1 parent d0df7c1 commit 9fca6c5

File tree

11 files changed

+251
-1
lines changed

11 files changed

+251
-1
lines changed

client/package-lock.json

+25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"react-dropzone": "^11.0.1",
1515
"react-icons": "^3.7.0",
1616
"react-image-gallery": "^1.0.7",
17+
"react-paypal-express-checkout": "^1.0.5",
1718
"react-redux": "^7.1.0-rc.1",
1819
"react-router-dom": "^5.0.1",
1920
"react-scripts": "3.4.1",

client/src/_actions/types.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export const LOGOUT_USER = "logout_user";
55
export const ADD_TO_CART_USER = "add_to_cart_user";
66
export const GET_CART_ITEMS_USER = "get_cart_items_user";
77
export const REMOVE_CART_ITEM_USER = "remove_cart_item_user";
8+
export const ON_SUCCESS_BUY_USER = "on_success_buy_user";

client/src/_actions/user_actions.js

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ADD_TO_CART_USER,
88
GET_CART_ITEMS_USER,
99
REMOVE_CART_ITEM_USER,
10+
ON_SUCCESS_BUY_USER,
1011
} from "./types";
1112
import { USER_SERVER } from "../components/Config.js";
1213

@@ -108,3 +109,10 @@ export function removeCartItem(id) {
108109
payload: request,
109110
};
110111
}
112+
113+
export function onSuccessBuy(data) {
114+
return {
115+
type: ON_SUCCESS_BUY_USER,
116+
payload: data,
117+
};
118+
}

client/src/_reducers/user_reducer.js

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ADD_TO_CART_USER,
77
GET_CART_ITEMS_USER,
88
REMOVE_CART_ITEM_USER,
9+
ON_SUCCESS_BUY_USER,
910
} from "../_actions/types";
1011

1112
export default function (state = {}, action) {
@@ -35,6 +36,15 @@ export default function (state = {}, action) {
3536
cartDetail: action.payload.cartDetail,
3637
userData: { ...state.userData, cart: action.payload.cart },
3738
};
39+
case ON_SUCCESS_BUY_USER:
40+
return {
41+
...state,
42+
userData: {
43+
...state.userData,
44+
cart: action.payload.cart,
45+
},
46+
cartDetail: action.payload.cartDetail,
47+
};
3848
default:
3949
return state;
4050
}

client/src/components/utils/Paypal.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from "react";
2+
import PaypalExpressBtn from "react-paypal-express-checkout";
3+
4+
export default class MyApp extends React.Component {
5+
render() {
6+
const onSuccess = (payment) => {
7+
// Congratulation, it came here means everything's fine!
8+
console.log("The payment was succeeded!", payment);
9+
// You can bind the "payment" object's value to your state or props or whatever here, please see below for sample returned data
10+
this.props.onSuccess(payment);
11+
};
12+
13+
const onCancel = (data) => {
14+
// User pressed "cancel" or close Paypal's popup!
15+
console.log("The payment was cancelled!", data);
16+
// You can bind the "data" object's value to your state or props or whatever here, please see below for sample returned data
17+
};
18+
19+
const onError = (err) => {
20+
// The main Paypal's script cannot be loaded or somethings block the loading of that script!
21+
console.log("Error!", err);
22+
// Because the Paypal's main script is loaded asynchronously from "https://www.paypalobjects.com/api/checkout.js"
23+
// => sometimes it may take about 0.5 second for everything to get set, or for the button to appear
24+
};
25+
26+
let env = "sandbox"; // you can set here to 'production' for production
27+
let currency = "USD"; // or you can set this value from your props or state
28+
let total = this.props.toPay; // same as above, this is the total amount (based on currency) to be paid by using Paypal express checkout
29+
// Document on Paypal's currency code: https://developer.paypal.com/docs/classic/api/currency_codes/
30+
31+
const client = {
32+
sandbox:
33+
"ATdlRK1n0Wiy43MJXKOASZPazDEKXE-VI02OxJxtUBmz9MKUqbIsrhYSVu_E_g5QBesorpy24bcnGKyo",
34+
production: "YOUR-PRODUCTION-APP-ID",
35+
};
36+
// In order to get production's app-ID, you will have to send your app to Paypal for approval first
37+
// For sandbox app-ID (after logging into your developer account, please locate the "REST API apps" section, click "Create App"):
38+
// => https://developer.paypal.com/docs/classic/lifecycle/sb_credentials/
39+
// For production app-ID:
40+
// => https://developer.paypal.com/docs/classic/lifecycle/goingLive/
41+
42+
// NB. You can also have many Paypal express checkout buttons on page, just pass in the correct amount and they will work!
43+
return (
44+
<PaypalExpressBtn
45+
env={env}
46+
client={client}
47+
currency={currency}
48+
total={total}
49+
onError={onError}
50+
onSuccess={onSuccess}
51+
onCancel={onCancel}
52+
style={{
53+
size: "large",
54+
color: "blue",
55+
shape: "rect",
56+
label: "checkout",
57+
}}
58+
/>
59+
);
60+
}
61+
}

client/src/components/views/CartPage/CartPage.js

+47-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import React, { useEffect, useState } from "react";
22
import { useDispatch } from "react-redux";
3-
import { getCartItems, removeCartItem } from "../../../_actions/user_actions";
3+
import {
4+
getCartItems,
5+
removeCartItem,
6+
onSuccessBuy,
7+
} from "../../../_actions/user_actions";
48
import UserCardBlock from "./UserCardBlock";
59
import { Result, Empty } from "antd";
10+
import Paypal from "../../utils/Paypal";
11+
import Axios from "axios";
612

713
function CartPage(props) {
814
const dispatch = useDispatch();
@@ -54,6 +60,37 @@ function CartPage(props) {
5460
});
5561
};
5662

63+
const transactionSuccess = (data) => {
64+
let variables = {
65+
cartDetail: props.user.cartDetail,
66+
paymentData: data,
67+
};
68+
69+
Axios.post("/api/users/successBuy", variables).then((response) => {
70+
if (response.data.success) {
71+
setShowSuccess(true);
72+
setShowTotal(false);
73+
74+
dispatch(
75+
onSuccessBuy({
76+
cart: response.data.cart,
77+
cartDetail: response.data.cartDetail,
78+
})
79+
);
80+
} else {
81+
alert("Failed to Purchase Items");
82+
}
83+
});
84+
};
85+
86+
const transactionError = () => {
87+
console.log("Paypal error");
88+
};
89+
90+
const transactionCancelled = () => {
91+
console.log("Transaction cancelled");
92+
};
93+
5794
return (
5895
<div style={{ width: "85%", margin: "3rem auto" }}>
5996
<h1>My Cart </h1>
@@ -82,6 +119,15 @@ function CartPage(props) {
82119
</div>
83120
)}
84121
</div>
122+
123+
{ShowTotal && (
124+
<Paypal
125+
toPay={Total}
126+
onSuccess={transactionSuccess}
127+
transactionError={transactionError}
128+
transactionCancelled={transactionCancelled}
129+
/>
130+
)}
85131
</div>
86132
);
87133
}

package-lock.json

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"author": "John ahn",
1717
"license": "ISC",
1818
"dependencies": {
19+
"async": "^3.2.0",
1920
"bcrypt": "^3.0.6",
2021
"body-parser": "^1.18.3",
2122
"cookie-parser": "^1.4.3",

server/models/Payment.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const mongoose = require("mongoose");
2+
const Schema = mongoose.Schema;
3+
4+
const paymentSchema = mongoose.Schema(
5+
{
6+
user: {
7+
type: Array,
8+
default: [],
9+
},
10+
data: {
11+
type: Array,
12+
default: [],
13+
},
14+
product: {
15+
type: Array,
16+
default: [],
17+
},
18+
},
19+
{ timestamp: true }
20+
);
21+
22+
const Payment = mongoose.model("Payment", paymentSchema);
23+
24+
module.exports = { Payment };

server/routes/users.js

+68
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ const router = express.Router();
33
const { User } = require("../models/User");
44
const { Product } = require("../models/Product");
55
const { auth } = require("../middleware/auth");
6+
const { Payment } = require("../models/Payment");
7+
8+
const async = require("async");
69

710
//=================================
811
// User
@@ -136,4 +139,69 @@ router.get("/removeFromCart", auth, (req, res) => {
136139
);
137140
});
138141

142+
router.post("/successBuy", auth, (req, res) => {
143+
let history = [];
144+
let transactionData = {};
145+
146+
req.body.cartDetail.forEach((item) => {
147+
history.push({
148+
dateOfPurchase: Date.now(),
149+
name: item.title,
150+
id: item._id,
151+
price: item.price,
152+
quantity: item.quantity,
153+
paymentId: req.body.paymentData.paymentID,
154+
});
155+
});
156+
157+
transactionData.user = {
158+
id: req.user._id,
159+
name: req.user.name,
160+
lastname: req.user.lastname,
161+
email: req.user.email,
162+
};
163+
164+
transactionData.data = req.body.paymentData;
165+
transactionData.product = history;
166+
167+
User.findOneAndUpdate(
168+
{ _id: req.user._id },
169+
{ $push: { history: history }, $set: { cart: [] } },
170+
{ new: true },
171+
(err, user) => {
172+
if (err) return res.json({ success: false, err });
173+
174+
const payment = new Payment(transactionData);
175+
payment.save((err, doc) => {
176+
if (err) return res.json({ success: false, err });
177+
178+
let products = [];
179+
doc.product.forEach((item) => {
180+
products.push({ id: item.id, quantity: item.quantity });
181+
});
182+
183+
async.eachSeries(
184+
products,
185+
(item, callback) => {
186+
Product.update(
187+
{ _id: item.id },
188+
{ $inc: { sold: item.quantity } },
189+
{ new: false },
190+
callback
191+
);
192+
},
193+
(err) => {
194+
if (err) return res.json({ success: false, err });
195+
res.status(200).json({
196+
success: true,
197+
cart: user.cart,
198+
cartDetail: [],
199+
});
200+
}
201+
);
202+
});
203+
}
204+
);
205+
});
206+
139207
module.exports = router;

0 commit comments

Comments
 (0)