├── .babelrc
├── .eslintrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── dist
└── index.js
├── index.js
├── package.json
├── scripts
└── mocha_runner.js
└── src
└── index.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-2", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "browser": true,
5 | "node": true,
6 | "es6": true
7 | },
8 | "ecmaFeatures": {
9 | "modules": true
10 | },
11 | "rules": {
12 | "no-bitwise": 2,
13 | "no-else-return": 2,
14 | "no-eq-null": 2,
15 | "no-extra-parens": 0,
16 | "no-floating-decimal": 2,
17 | "no-inner-declarations": [2, "both"],
18 | "no-lonely-if": 2,
19 | "no-multiple-empty-lines": [2, {"max": 3}],
20 | "no-self-compare": 2,
21 | "no-underscore-dangle": 0,
22 | "no-use-before-define": 0,
23 | "no-unused-expressions": 0,
24 | "no-void": 2,
25 | "brace-style": [2, "1tbs"],
26 | "camelcase": [1, {"properties": "never"}],
27 | "consistent-return": 0,
28 | "comma-style": [2, "last"],
29 | "complexity": [1, 12],
30 | "func-names": 0,
31 | "guard-for-in": 2,
32 | "indent": [2, 4],
33 | "max-len": [0, 120, 4],
34 | "new-cap": [2, {"newIsCap": true, "capIsNew": false}],
35 | "quotes": [2, "single"],
36 | "keyword-spacing": [2, {"before": true, "after": true}],
37 | "space-before-blocks": [2, "always"],
38 | "array-bracket-spacing": [2, "never"],
39 | "space-in-parens": [2, "never"],
40 | "strict": [0],
41 | "valid-jsdoc": 2,
42 | "wrap-iife": [2, "any"],
43 | "yoda": [1, "never"]
44 | },
45 | "plugins": [
46 | "react"
47 | ],
48 | "globals": {
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *~
3 | *.iml
4 | .*.haste_cache.*
5 | .DS_Store
6 | .idea
7 | .babelrc
8 | .eslintrc
9 | npm-debug.log
10 | lib
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 thinhvo0108
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-paypal-express-checkout
2 | React component that renders Paypal's express check out button
3 |
4 | ## Install
5 |
6 | ```bash
7 | npm install --save react-paypal-express-checkout
8 | ```
9 |
10 | or
11 | ```bash
12 | yarn add react-paypal-express-checkout
13 | ```
14 |
15 | ## Usage
16 |
17 | ## Simplest Example (with minimum set of parameters, this will use the "sandbox" environment)
18 |
19 | ```javascript
20 | import PaypalExpressBtn from 'react-paypal-express-checkout';
21 |
22 | export default class MyApp extends React.Component {
23 | render() {
24 | const client = {
25 | sandbox: 'Your-Sandbox-Client-ID',
26 | production: 'Your-Production-Client-ID',
27 | }
28 | return (
29 |
30 | );
31 | }
32 | }
33 | ```
34 |
35 | ### Full Example
36 |
37 | ```javascript
38 | import React from 'react';
39 | import PaypalExpressBtn from 'react-paypal-express-checkout';
40 |
41 | export default class MyApp extends React.Component {
42 | render() {
43 | const onSuccess = (payment) => {
44 | // 1, 2, and ... Poof! You made it, everything's fine and dandy!
45 | console.log("Payment successful!", payment);
46 | // You can bind the "payment" object's value to your state or props or whatever here, please see below for sample returned data
47 | }
48 |
49 | const onCancel = (data) => {
50 | // The user pressed "cancel" or closed the PayPal popup
51 | console.log('Payment cancelled!', data);
52 | // You can bind the "data" object's value to your state or props or whatever here, please see below for sample returned data
53 | }
54 |
55 | const onError = (err) => {
56 | // The main Paypal script could not be loaded or something blocked the script from loading
57 | console.log("Error!", err);
58 | // Because the Paypal's main script is loaded asynchronously from "https://www.paypalobjects.com/api/checkout.js"
59 | // => sometimes it may take about 0.5 second for everything to get set, or for the button to appear
60 | }
61 |
62 | let env = 'sandbox'; // you can set this string to 'production'
63 | let currency = 'USD'; // you can set this string from your props or state
64 | let total = 1; // this is the total amount (based on currency) to charge
65 | // Document on Paypal's currency code: https://developer.paypal.com/docs/classic/api/currency_codes/
66 |
67 | const client = {
68 | sandbox: 'YOUR-SANDBOX-APP-ID',
69 | production: 'YOUR-PRODUCTION-APP-ID',
70 | }
71 | // In order to get production's app-ID, you will have to send your app to Paypal for approval first
72 | // For your sandbox Client-ID (after logging into your developer account, please locate the "REST API apps" section, click "Create App" unless you have already done so):
73 | // => https://developer.paypal.com/docs/classic/lifecycle/sb_credentials/
74 | // Note: IGNORE the Sandbox test AppID - this is ONLY for Adaptive APIs, NOT REST APIs)
75 | // For production app-ID:
76 | // => https://developer.paypal.com/docs/classic/lifecycle/goingLive/
77 |
78 | // NB. You can also have many Paypal express checkout buttons on page, just pass in the correct amount and they will work!
79 | return (
80 |
81 | );
82 | }
83 | }
84 | ```
85 |
86 | ### Props
87 |
88 | - `env: String (default: "sandbox")` - You can set this to "production" for production
89 | - `client: Object (with "sandbox" and "production" as keys)` - MUST set, please see the above example
90 | - `currency: String ("USD", "JPY" etc.)` - MUST set, please see the above example
91 | - `total: Number (1.00 or 1 - depends on currency)` - MUST set, please see the above example
92 | - `shipping: Number (1 or 2 or 3)` - Ability to change if a shipping address is included in checkout, 0 is default and means optional, 1 is no shipping address, 2 is shipping is required
93 | - `onError: Callback function (happens when Paypal's main script cannot be loaded)` - If not set, this will take the above function (in example) as a default return
94 | - `onSuccess: Callback function (happens after payment has been finished successfully)` - If not set, this will take the above function (in example) as a default return
95 | - `onCancel: Callback function (happens when users press "cancel" or close Paypal's popup)` - If not set, this will take the above function (in example) as a default return
96 | - `paymentOptions: (optional) enable many options: full "transactions" object and also "note_to_payer", "redirect_urls", "intent" etc.` - https://developer.paypal.com/docs/integration/direct/payments/authorize-and-capture-payments/#authorize-the-payment
97 | https://developer.paypal.com/docs/api/payments/v1/
98 |
99 | - `style: (optional) change appearance of Paypal button based on their document: size, color, shape, label` - https://developer.paypal.com/docs/integration/direct/express-checkout/integration-jsv4/customize-button/
100 |
101 | ## Sample Returned Data
102 |
103 | - `onSuccess` - the returned `payment` object will look like:
104 | + `{paid: true, cancelled: false, payerID: "H8S4CU73PFRAG", paymentID: "PAY-47J75876PA321622TLESPATA", paymentToken: "EC-8FE085188N269774L", returnUrl: "https://www.sandbox.paypal.com/?paymentId=PAY-47J75876PA321622TLESPATA&token=EC-8FE085188N269774L&PayerID=H8S4CU73PFRAG"}`
105 | - `onCancel` - the returned `data` object will look like:
106 | + `{paymentToken: "EC-42A825696K839141X", cancelUrl: "https://www.sandbox.paypal.com?token=EC-42A825696K839141X"}`
107 |
108 | ### Reference Document on How to Have Paypal's Developer Account and Merchant + Buyer accounts
109 |
110 | - In fact, please just go to Paypal's developer page, login with your "Real" Paypal account:
111 | + Click on the "Sandbox accounts" on the left hand side
112 | + You will see Merchant + Buyer accounts have been created automatically
113 | + You can then change password, profile, can also clone those accounts, or create more accounts (choose country, default currency, set amount for new accounts)
114 | - You can check balance & transaction history of those testing accounts (the same as real accounts) by login with the accounts' credentials with:
115 | + https://www.sandbox.paypal.com/
116 | - Official documents here: (just be patient and go step-by-step, by clicking their next topic's button on page, you can then understand the whole process!)
117 | + https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/create_payment_button/
118 |
119 | ## TODO
120 |
121 | - Upgrade this library into more advanced Paypal button library (with features like recurring, add-to-cart, checkout-now etc.)
122 | - Fork & pull-request are very welcomed!
123 |
124 | ## Thank you
125 |
126 | - [React NPM Boilerplate](https://github.com/juliancwirko/react-npm-boilerplate)
127 |
128 | ## License
129 |
130 | MIT
131 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | if (typeof define === "function" && define.amd) {
3 | define(['exports', 'react', 'react-dom', 'react-async-script-loader', 'prop-types'], factory);
4 | } else if (typeof exports !== "undefined") {
5 | factory(exports, require('react'), require('react-dom'), require('react-async-script-loader'), require('prop-types'));
6 | } else {
7 | var mod = {
8 | exports: {}
9 | };
10 | factory(mod.exports, global.react, global.reactDom, global.reactAsyncScriptLoader, global.propTypes);
11 | global.index = mod.exports;
12 | }
13 | })(this, function (exports, _react, _reactDom, _reactAsyncScriptLoader, _propTypes) {
14 | 'use strict';
15 |
16 | Object.defineProperty(exports, "__esModule", {
17 | value: true
18 | });
19 |
20 | var _react2 = _interopRequireDefault(_react);
21 |
22 | var _reactDom2 = _interopRequireDefault(_reactDom);
23 |
24 | var _reactAsyncScriptLoader2 = _interopRequireDefault(_reactAsyncScriptLoader);
25 |
26 | var _propTypes2 = _interopRequireDefault(_propTypes);
27 |
28 | function _interopRequireDefault(obj) {
29 | return obj && obj.__esModule ? obj : {
30 | default: obj
31 | };
32 | }
33 |
34 | function _classCallCheck(instance, Constructor) {
35 | if (!(instance instanceof Constructor)) {
36 | throw new TypeError("Cannot call a class as a function");
37 | }
38 | }
39 |
40 | var _createClass = function () {
41 | function defineProperties(target, props) {
42 | for (var i = 0; i < props.length; i++) {
43 | var descriptor = props[i];
44 | descriptor.enumerable = descriptor.enumerable || false;
45 | descriptor.configurable = true;
46 | if ("value" in descriptor) descriptor.writable = true;
47 | Object.defineProperty(target, descriptor.key, descriptor);
48 | }
49 | }
50 |
51 | return function (Constructor, protoProps, staticProps) {
52 | if (protoProps) defineProperties(Constructor.prototype, protoProps);
53 | if (staticProps) defineProperties(Constructor, staticProps);
54 | return Constructor;
55 | };
56 | }();
57 |
58 | function _possibleConstructorReturn(self, call) {
59 | if (!self) {
60 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
61 | }
62 |
63 | return call && (typeof call === "object" || typeof call === "function") ? call : self;
64 | }
65 |
66 | function _inherits(subClass, superClass) {
67 | if (typeof superClass !== "function" && superClass !== null) {
68 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
69 | }
70 |
71 | subClass.prototype = Object.create(superClass && superClass.prototype, {
72 | constructor: {
73 | value: subClass,
74 | enumerable: false,
75 | writable: true,
76 | configurable: true
77 | }
78 | });
79 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
80 | }
81 |
82 | var PaypalButton = function (_React$Component) {
83 | _inherits(PaypalButton, _React$Component);
84 |
85 | function PaypalButton(props) {
86 | _classCallCheck(this, PaypalButton);
87 |
88 | var _this = _possibleConstructorReturn(this, (PaypalButton.__proto__ || Object.getPrototypeOf(PaypalButton)).call(this, props));
89 |
90 | window.React = _react2.default;
91 | window.ReactDOM = _reactDom2.default;
92 | _this.state = {
93 | showButton: false
94 | };
95 | return _this;
96 | }
97 |
98 | _createClass(PaypalButton, [{
99 | key: 'componentWillReceiveProps',
100 | value: function componentWillReceiveProps(_ref) {
101 | var isScriptLoaded = _ref.isScriptLoaded,
102 | isScriptLoadSucceed = _ref.isScriptLoadSucceed;
103 |
104 | if (!this.state.show) {
105 | if (isScriptLoaded && !this.props.isScriptLoaded) {
106 | if (isScriptLoadSucceed) {
107 | this.setState({ showButton: true });
108 | } else {
109 | console.log('Cannot load Paypal script!');
110 | this.props.onError();
111 | }
112 | }
113 | }
114 | }
115 | }, {
116 | key: 'componentDidMount',
117 | value: function componentDidMount() {
118 | var _props = this.props,
119 | isScriptLoaded = _props.isScriptLoaded,
120 | isScriptLoadSucceed = _props.isScriptLoadSucceed;
121 |
122 | if (isScriptLoaded && isScriptLoadSucceed) {
123 | this.setState({ showButton: true });
124 | }
125 | }
126 | }, {
127 | key: 'render',
128 | value: function render() {
129 | var _this2 = this;
130 |
131 | var payment = function payment() {
132 | return paypal.rest.payment.create(_this2.props.env, _this2.props.client, Object.assign({
133 | transactions: [{ amount: { total: _this2.props.total, currency: _this2.props.currency } }]
134 | }, _this2.props.paymentOptions), {
135 | input_fields: {
136 | // any values other than null, and the address is not returned after payment execution.
137 | no_shipping: _this2.props.shipping
138 | }
139 | });
140 | };
141 |
142 | var onAuthorize = function onAuthorize(data, actions) {
143 | return actions.payment.execute().then(function (payment_data) {
144 | // console.log(`payment_data: ${JSON.stringify(payment_data, null, 1)}`)
145 | var payment = Object.assign({}, _this2.props.payment);
146 | payment.paid = true;
147 | payment.cancelled = false;
148 | payment.payerID = data.payerID;
149 | payment.paymentID = data.paymentID;
150 | payment.paymentToken = data.paymentToken;
151 | payment.returnUrl = data.returnUrl;
152 | // getting buyer's shipping address and email
153 | payment.address = payment_data.payer.payer_info.shipping_address;
154 | payment.email = payment_data.payer.payer_info.email;
155 | _this2.props.onSuccess(payment);
156 | });
157 | };
158 |
159 | var ppbtn = '';
160 | if (this.state.showButton) {
161 | ppbtn = _react2.default.createElement(paypal.Button.react, {
162 | env: this.props.env,
163 | client: this.props.client,
164 | style: this.props.style,
165 | payment: payment,
166 | commit: true,
167 | onAuthorize: onAuthorize,
168 | onCancel: this.props.onCancel
169 |
170 | // "Error: Unrecognized prop: shipping" was caused by the next line
171 | // shipping={this.props.shipping}
172 | });
173 | }
174 | return _react2.default.createElement(
175 | 'div',
176 | null,
177 | ppbtn
178 | );
179 | }
180 | }]);
181 |
182 | return PaypalButton;
183 | }(_react2.default.Component);
184 |
185 | PaypalButton.propTypes = {
186 | currency: _propTypes2.default.string.isRequired,
187 | total: _propTypes2.default.number.isRequired,
188 | client: _propTypes2.default.object.isRequired,
189 | style: _propTypes2.default.object
190 | };
191 |
192 | PaypalButton.defaultProps = {
193 | paymentOptions: {},
194 | env: 'sandbox',
195 | // null means buyer address is returned in the payment execution response
196 | shipping: null,
197 | onSuccess: function onSuccess(payment) {
198 | console.log('The payment was succeeded!', payment);
199 | },
200 | onCancel: function onCancel(data) {
201 | console.log('The payment was cancelled!', data);
202 | },
203 | onError: function onError(err) {
204 | console.log('Error loading Paypal script!', err);
205 | }
206 | };
207 |
208 | exports.default = (0, _reactAsyncScriptLoader2.default)('https://www.paypalobjects.com/api/checkout.js')(PaypalButton);
209 | });
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./dist/index');
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-paypal-express-checkout",
3 | "version": "1.0.5",
4 | "description": "React component that renders Paypal's express check out button",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/thinhvo0108/react-paypal-express-checkout.git"
8 | },
9 | "author": "Thinh Vo ",
10 | "license": "MIT",
11 | "bugs": {
12 | "url": "https://github.com/thinhvo0108/react-paypal-express-checkout/issues"
13 | },
14 | "homepage": "https://github.com/thinhvo0108/react-paypal-express-checkout",
15 | "keywords": [
16 | "react-component",
17 | "react",
18 | "react-paypal",
19 | "paypal-checkout",
20 | "express-checkout",
21 | "paypal-express-checkout",
22 | "paypal-button",
23 | "checkout-button",
24 | "paypal-checkout-button",
25 | "paypal",
26 | "express",
27 | "button",
28 | "checkout",
29 | "check-out"
30 | ],
31 | "options": {
32 | "mocha": "--require scripts/mocha_runner src/**/__tests__/**/*.js"
33 | },
34 | "scripts": {
35 | "prepublish": "babel --plugins 'transform-es2015-modules-umd' src --ignore __tests__ --out-dir ./dist",
36 | "lint": "eslint ./src",
37 | "lintfix": "eslint ./src --fix",
38 | "testonly": "mocha $npm_package_options_mocha",
39 | "test": "npm run lint && npm run testonly",
40 | "test-watch": "npm run testonly -- --watch --watch-extensions js"
41 | },
42 | "devDependencies": {
43 | "babel-cli": "^6.6.4",
44 | "babel-core": "^6.7.4",
45 | "babel-eslint": "^6.0.2",
46 | "babel-plugin-transform-es2015-modules-umd": "^6.6.5",
47 | "babel-polyfill": "^6.7.4",
48 | "babel-preset-es2015": "^6.6.0",
49 | "babel-preset-react": "^6.5.0",
50 | "babel-preset-stage-2": "^6.5.0",
51 | "chai": "^3.5.0",
52 | "enzyme": "^2.2.0",
53 | "eslint": "^2.7.0",
54 | "eslint-plugin-babel": "^3.1.0",
55 | "eslint-plugin-react": "^4.2.3",
56 | "jsdom": "^8.1.0",
57 | "mocha": "^2.4.5",
58 | "nodemon": "^1.9.1",
59 | "react-addons-test-utils": "^15.0.0",
60 | "react": "^16.0.0",
61 | "react-dom": "^16.0.0",
62 | "sinon": "^1.17.3"
63 | },
64 | "peerDependencies": {
65 | "react": "~0.14.8 || ^15.5.0",
66 | "react-dom": "~0.14.8 || ^15.5.0"
67 | },
68 | "dependencies": {
69 | "babel-runtime": "^6.6.1",
70 | "prop-types": "^15.5.10",
71 | "react-async-script-loader": "^0.3.0"
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/scripts/mocha_runner.js:
--------------------------------------------------------------------------------
1 | var jsdom = require('jsdom').jsdom;
2 |
3 | var exposedProperties = ['window', 'navigator', 'document'];
4 |
5 | global.document = jsdom('');
6 | global.window = document.defaultView;
7 | Object.keys(document.defaultView).forEach((property) => {
8 | if (typeof global[property] === 'undefined') {
9 | exposedProperties.push(property);
10 | global[property] = document.defaultView[property];
11 | }
12 | });
13 |
14 | global.navigator = {
15 | userAgent: 'node.js'
16 | };
17 |
18 | documentRef = document;
19 |
20 | require('babel-core/register');
21 | require('babel-polyfill');
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import scriptLoader from 'react-async-script-loader';
4 | import PropTypes from 'prop-types';
5 |
6 | class PaypalButton extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | window.React = React;
10 | window.ReactDOM = ReactDOM;
11 | this.state = {
12 | showButton: false
13 | }
14 | }
15 |
16 | componentWillReceiveProps ({ isScriptLoaded, isScriptLoadSucceed }) {
17 | if (!this.state.show) {
18 | if (isScriptLoaded && !this.props.isScriptLoaded) {
19 | if (isScriptLoadSucceed) {
20 | this.setState({ showButton: true });
21 | } else {
22 | console.log('Cannot load Paypal script!');
23 | this.props.onError();
24 | }
25 | }
26 | }
27 | }
28 |
29 | componentDidMount() {
30 | const { isScriptLoaded, isScriptLoadSucceed } = this.props;
31 | if (isScriptLoaded && isScriptLoadSucceed) {
32 | this.setState({ showButton: true });
33 | }
34 | }
35 |
36 | render() {
37 | let payment = () => {
38 | return paypal.rest.payment.create(this.props.env, this.props.client, Object.assign({
39 | transactions: [
40 | { amount: { total: this.props.total, currency: this.props.currency } }
41 | ]
42 | }, this.props.paymentOptions), {
43 | input_fields: {
44 | // any values other than null, and the address is not returned after payment execution.
45 | no_shipping: this.props.shipping
46 | }
47 | });
48 | }
49 |
50 | const onAuthorize = (data, actions) => {
51 | return actions.payment.execute().then((payment_data) => {
52 | // console.log(`payment_data: ${JSON.stringify(payment_data, null, 1)}`)
53 | const payment = Object.assign({}, this.props.payment);
54 | payment.paid = true;
55 | payment.cancelled = false;
56 | payment.payerID = data.payerID;
57 | payment.paymentID = data.paymentID;
58 | payment.paymentToken = data.paymentToken;
59 | payment.returnUrl = data.returnUrl;
60 | // getting buyer's shipping address and email
61 | payment.address = payment_data.payer.payer_info.shipping_address;
62 | payment.email = payment_data.payer.payer_info.email;
63 | this.props.onSuccess(payment);
64 | })
65 | }
66 |
67 | let ppbtn = '';
68 | if (this.state.showButton) {
69 | ppbtn =
81 | }
82 | return {ppbtn}
;
83 | }
84 | }
85 |
86 | PaypalButton.propTypes = {
87 | currency: PropTypes.string.isRequired,
88 | total: PropTypes.number.isRequired,
89 | client: PropTypes.object.isRequired,
90 | style: PropTypes.object
91 | }
92 |
93 | PaypalButton.defaultProps = {
94 | paymentOptions: {},
95 | env: 'sandbox',
96 | // null means buyer address is returned in the payment execution response
97 | shipping: null,
98 | onSuccess: (payment) => {
99 | console.log('The payment was succeeded!', payment);
100 | },
101 | onCancel: (data) => {
102 | console.log('The payment was cancelled!', data)
103 | },
104 | onError: (err) => {
105 | console.log('Error loading Paypal script!', err)
106 | }
107 | };
108 |
109 | export default scriptLoader('https://www.paypalobjects.com/api/checkout.js')(PaypalButton);
110 |
--------------------------------------------------------------------------------