feat: add paypal script loader for one time and subscription (#38553)

* fix: add one-time payment sdk script loader

* fix: remove paypal credit
This commit is contained in:
Ahmad Abdolsaheb
2020-04-20 22:16:34 +03:00
committed by GitHub
parent 2915582461
commit 7db718141b
6 changed files with 178 additions and 113 deletions

View File

@ -4264,8 +4264,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
"optional": true
}, },
"slice-ansi": { "slice-ansi": {
"version": "3.0.0", "version": "3.0.0",
@ -7805,8 +7804,7 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -7824,13 +7822,11 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -7843,18 +7839,15 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -7957,8 +7950,7 @@
}, },
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"bundled": true, "bundled": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -7968,7 +7960,6 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -7981,20 +7972,17 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "1.2.5", "version": "1.2.5",
"bundled": true, "bundled": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.9.0", "version": "2.9.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -8011,7 +7999,6 @@
"mkdirp": { "mkdirp": {
"version": "0.5.3", "version": "0.5.3",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
@ -8067,8 +8054,7 @@
}, },
"npm-normalize-package-bin": { "npm-normalize-package-bin": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"npm-packlist": { "npm-packlist": {
"version": "1.4.8", "version": "1.4.8",
@ -8093,8 +8079,7 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -8104,7 +8089,6 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -8173,8 +8157,7 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -8204,7 +8187,6 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -8222,7 +8204,6 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -8261,13 +8242,11 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.1.1", "version": "3.1.1",
"bundled": true, "bundled": true
"optional": true
} }
} }
}, },
@ -10303,14 +10282,12 @@
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
"optional": true
}, },
"ansi-styles": { "ansi-styles": {
"version": "4.2.1", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"optional": true,
"requires": { "requires": {
"@types/color-name": "^1.1.1", "@types/color-name": "^1.1.1",
"color-convert": "^2.0.1" "color-convert": "^2.0.1"
@ -10351,7 +10328,6 @@
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"optional": true,
"requires": { "requires": {
"color-name": "~1.1.4" "color-name": "~1.1.4"
} }
@ -10359,8 +10335,7 @@
"color-name": { "color-name": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
"optional": true
}, },
"emoji-regex": { "emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
@ -10377,8 +10352,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
"optional": true
}, },
"mimic-fn": { "mimic-fn": {
"version": "2.1.0", "version": "2.1.0",
@ -10441,7 +10415,6 @@
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"optional": true,
"requires": { "requires": {
"ansi-regex": "^5.0.0" "ansi-regex": "^5.0.0"
} }
@ -15560,15 +15533,6 @@
} }
} }
}, },
"react-paypal-button-v2": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/react-paypal-button-v2/-/react-paypal-button-v2-2.6.1.tgz",
"integrity": "sha512-ia1zzdRgziSfnJ/UueM6i0omEocbv4cge3mBRmpA6WSyxsX6c501HWHVwvXMEbTDCPK5+0ZKewhBzf/wq618Cg==",
"requires": {
"prop-types": "^15.7.2",
"rimraf": "^3.0.0"
}
},
"react-prop-types": { "react-prop-types": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz", "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz",

View File

@ -56,7 +56,6 @@
"react-identicons": "^1.1.7", "react-identicons": "^1.1.7",
"react-instantsearch-dom": "^6.0.0-beta.0", "react-instantsearch-dom": "^6.0.0-beta.0",
"react-monaco-editor": "^0.31.0", "react-monaco-editor": "^0.31.0",
"react-paypal-button-v2": "^2.6.1",
"react-redux": "^5.0.7", "react-redux": "^5.0.7",
"react-reflex": "^3.0.18", "react-reflex": "^3.0.18",
"react-responsive": "^6.1.1", "react-responsive": "^6.1.1",

View File

@ -240,18 +240,6 @@ class DonateForm extends Component {
this.setState({ processing: hide }); this.setState({ processing: hide });
} }
renderPayPalMeLink(donationAmount) {
const payPalMeLinkURL =
'https://paypal.me/freecodecamp/' + donationAmount / 100 + 'USD';
return (
<Button
block={true}
className='paypal-button-onetime'
href={payPalMeLinkURL}
></Button>
);
}
renderDonationOptions() { renderDonationOptions() {
const { handleProcessing, isSignedIn } = this.props; const { handleProcessing, isSignedIn } = this.props;
const { donationAmount, donationDuration } = this.state; const { donationAmount, donationDuration } = this.state;
@ -308,17 +296,14 @@ class DonateForm extends Component {
/> />
</Button> </Button>
<Spacer /> <Spacer />
{isOneTime ? (
this.renderPayPalMeLink(donationAmount)
) : (
<PaypalButton <PaypalButton
donationAmount={donationAmount} donationAmount={donationAmount}
donationDuration={donationDuration} donationDuration={donationDuration}
handleProcessing={handleProcessing} handleProcessing={handleProcessing}
isSubscription={isOneTime ? false : true}
onDonationStateChange={this.onDonationStateChange} onDonationStateChange={this.onDonationStateChange}
skipAddDonation={!isSignedIn} skipAddDonation={!isSignedIn}
/> />
)}
<Spacer size={2} /> <Spacer size={2} />
</div> </div>
); );

View File

@ -0,0 +1,100 @@
/* eslint-disable camelcase */
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import { scriptLoader, scriptRemover } from '../../utils/scriptLoaders';
import { Loader } from '../../components/helpers';
export class PayPalButtonScriptLoader extends Component {
state = { isSdkLoaded: window.paypal && true, isSubscription: true };
static getDerivedStateFromProps(props, state) {
const { isSubscription } = props;
if (isSubscription !== state.isSubscription) {
return { isSubscription: isSubscription };
}
return null;
}
componentDidMount() {
if (!window.paypal) {
this.loadScript(this.props.isSubscription);
}
}
componentDidUpdate(prevProps) {
if (prevProps.isSubscription !== this.state.isSubscription) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ isSdkLoaded: false });
this.loadScript(this.state.isSubscription, true);
}
}
loadScript(subscription, deleteScript) {
if (deleteScript) scriptRemover('paypal-sdk');
let queries = `?client-id=${this.props.clinetId}&disable-funding=credit,card`;
if (subscription) queries += '&vault=true';
scriptLoader(
'paypal-sdk',
'paypal-sdk',
true,
`https://www.paypal.com/sdk/js${queries}`,
this.OnScriptLoad
);
}
OnScriptLoad = () => {
this.setState({ isSdkLoaded: true });
};
render() {
const { isSdkLoaded, isSubscription } = this.state;
const {
onApprove,
onError,
onCancel,
createSubscription,
createOrder,
style
} = this.props;
if (!isSdkLoaded) return <Loader />;
const Button = window.paypal.Buttons.driver('react', {
React,
ReactDOM
});
return (
<Button
createOrder={isSubscription ? null : createOrder}
createSubscription={isSubscription ? createSubscription : null}
onApprove={onApprove}
onCancel={onCancel}
onError={onError}
style={style}
/>
);
}
}
const propTypes = {
clinetId: PropTypes.string,
createOrder: PropTypes.func,
createSubscription: PropTypes.func,
donationAmount: PropTypes.number,
donationDuration: PropTypes.string,
isSubscription: PropTypes.bool,
onApprove: PropTypes.func,
onCancel: PropTypes.func,
onError: PropTypes.func,
style: PropTypes.object
};
PayPalButtonScriptLoader.displayName = 'PayPalButtonScriptLoader';
PayPalButtonScriptLoader.propTypes = propTypes;
export default PayPalButtonScriptLoader;

View File

@ -4,7 +4,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { PayPalButton } from 'react-paypal-button-v2'; import PayPalButtonScriptLoader from './PayPalButtonScriptLoader';
import { paypalClientId, deploymentEnv } from '../../../config/env.json'; import { paypalClientId, deploymentEnv } from '../../../config/env.json';
import { verifySubscriptionPaypal } from '../../utils/ajax'; import { verifySubscriptionPaypal } from '../../utils/ajax';
import { import {
@ -38,7 +38,7 @@ export class PaypalButton extends Component {
handleApproval = data => { handleApproval = data => {
const { amount, duration } = this.state; const { amount, duration } = this.state;
const { skipAddDonation = false } = this.props; const { skipAddDonation = false } = this.props;
if (!skipAddDonation) { if (!skipAddDonation || duration === 'oneTime') {
this.props.handleProcessing( this.props.handleProcessing(
duration, duration,
amount, amount,
@ -73,19 +73,34 @@ export class PaypalButton extends Component {
}; };
render() { render() {
const { duration, planId } = this.state; const { duration, planId, amount } = this.state;
const isOneTimePayment = duration === 'onetime'; const isSubscription = duration !== 'onetime';
if (!isOneTimePayment) {
return ( return (
<PayPalButton <PayPalButtonScriptLoader
amount={amount}
clinetId={paypalClientId}
createOrder={(data, actions) => {
return actions.order.create({
purchase_units: [
{
amount: {
currency_code: 'USD',
value: (amount / 100).toString()
}
}
]
});
}}
createSubscription={(data, actions) => { createSubscription={(data, actions) => {
return actions.subscription.create({ return actions.subscription.create({
plan_id: planId plan_id: planId
}); });
}} }}
onApprove={data => { isSubscription={isSubscription}
onApprove={(data, actions) => {
return actions.order.capture().then(function(data) {
this.handleApproval(data); this.handleApproval(data);
});
}} }}
onCancel={() => { onCancel={() => {
this.props.onDonationStateChange( this.props.onDonationStateChange(
@ -97,18 +112,13 @@ export class PaypalButton extends Component {
onError={() => onError={() =>
this.props.onDonationStateChange(false, false, 'Please try again.') this.props.onDonationStateChange(false, false, 'Please try again.')
} }
options={{ plantId={planId}
vault: true,
disableFunding: 'credit,card',
clientId: paypalClientId
}}
style={{ style={{
tagline: false, tagline: false,
height: 43 height: 43
}} }}
/> />
); );
} else return '';
} }
} }

View File

@ -10,6 +10,13 @@ export const scriptLoader = (id, key, async, src, onload, text) => {
document.getElementsByTagName('head')[0].appendChild(s); document.getElementsByTagName('head')[0].appendChild(s);
}; };
export const scriptRemover = id => {
let script = document.getElementById(id);
if (script) {
script.remove();
}
};
export const stripeScriptLoader = onload => export const stripeScriptLoader = onload =>
scriptLoader( scriptLoader(
'stripe-js', 'stripe-js',