diff --git a/client/src/components/Donation/DonateForm.js b/client/src/components/Donation/DonateForm.js
index 26f30dc196..dcdd8348cd 100644
--- a/client/src/components/Donation/DonateForm.js
+++ b/client/src/components/Donation/DonateForm.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
@@ -20,6 +20,8 @@ import {
} from '../../../../config/donation-settings';
import Spacer from '../helpers/Spacer';
import DonateFormChildViewForHOC from './DonateFormChildViewForHOC';
+import PaypalButton from './PaypalButton';
+import DonateCompletion from './DonateCompletion';
import {
isSignedInSelector,
signInLoadingSelector,
@@ -50,11 +52,18 @@ const mapStateToProps = createSelector(
showLoading
})
);
-
const mapDispatchToProps = {
navigate
};
+const initialState = {
+ donationState: {
+ processing: false,
+ success: false,
+ error: ''
+ }
+};
+
class DonateForm extends Component {
constructor(...args) {
super(...args);
@@ -63,15 +72,30 @@ class DonateForm extends Component {
this.amounts = amountsConfig;
this.state = {
+ ...initialState,
...defaultStateConfig,
processing: false
};
+ this.onDonationStateChange = this.onDonationStateChange.bind(this);
this.getActiveDonationAmount = this.getActiveDonationAmount.bind(this);
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
this.handleSelectAmount = this.handleSelectAmount.bind(this);
this.handleSelectDuration = this.handleSelectDuration.bind(this);
this.hideAmountOptionsCB = this.hideAmountOptionsCB.bind(this);
+ this.resetDonation = this.resetDonation.bind(this);
+ }
+
+ onDonationStateChange(success, processing, error) {
+ this.setState(state => ({
+ ...state,
+ donationState: {
+ ...state.donationState,
+ processing: processing,
+ success: success,
+ error: error
+ }
+ }));
}
getActiveDonationAmount(durationSelected, amountSelected) {
@@ -199,13 +223,64 @@ class DonateForm extends Component {
);
}
+ resetDonation() {
+ return this.setState({ ...initialState });
+ }
+
+ renderCompletion(props) {
+ return ;
+ }
+
render() {
+ const { donationAmount, donationDuration } = this.state;
+ const { handleProcessing } = this.props;
+ const {
+ donationState: { processing, success, error }
+ } = this.state;
+ const subscriptionPayment = donationDuration !== 'onetime';
+ if (processing || success || error) {
+ return this.renderCompletion({
+ processing,
+ success,
+ error,
+ reset: this.resetDonation
+ });
+ }
return (
{this.renderDurationAmountOptions()}
+ {subscriptionPayment ? (
+
+
+ Confirm your donation of ${donationAmount / 100} / year with
+ PayPal:
+
+
+
+ ) : (
+ ''
+ )}
+
+
+
+
+ {subscriptionPayment ? (
+
+
+ Or donate with a credit card:
+
+
+ ) : (
+ ''
+ )}
{this.renderDonationOptions()}
diff --git a/client/src/components/Donation/Donation.css b/client/src/components/Donation/Donation.css
index 3ca7e9908a..65c4ffddd4 100644
--- a/client/src/components/Donation/Donation.css
+++ b/client/src/components/Donation/Donation.css
@@ -169,6 +169,9 @@ li.disabled > a {
color: var(--gray-15) !important;
}
+.donate-page-wrapper,
+.donate-page-wrapper b,
+.donate-page-wrapper h3,
.donate-text p,
.donation-description,
[name='payment-method'] {
diff --git a/client/src/components/Donation/MinimalDonateForm.js b/client/src/components/Donation/MinimalDonateForm.js
index 88bbb27f7d..d2e10b8670 100644
--- a/client/src/components/Donation/MinimalDonateForm.js
+++ b/client/src/components/Donation/MinimalDonateForm.js
@@ -134,6 +134,8 @@ class MinimalDonateForm extends Component {
Confirm your donation of $60 / year with PayPal:
diff --git a/client/src/components/Donation/PaypalButton.js b/client/src/components/Donation/PaypalButton.js
index fb566e0385..fd39f35db9 100644
--- a/client/src/components/Donation/PaypalButton.js
+++ b/client/src/components/Donation/PaypalButton.js
@@ -7,22 +7,33 @@ import { createSelector } from 'reselect';
import { PayPalButton } from 'react-paypal-button-v2';
import { paypalClientId } from '../../../config/env.json';
import { verifySubscriptionPaypal } from '../../utils/ajax';
-import { paypalConfig } from '../../../../config/donation-settings';
-import { signInLoadingSelector, userSelector, executeGA } from '../../redux';
-
-const { durationPlans } = paypalConfig;
+import { paypalConfigurator } from '../../../../config/donation-settings';
+import { signInLoadingSelector, userSelector } from '../../redux';
export class PaypalButton extends Component {
- constructor(...props) {
- super(...props);
- this.state = {
- planId: durationPlans.year['6000'].planId
- };
+ constructor(props) {
+ super(props);
this.handleApproval = this.handleApproval.bind(this);
}
+ state = {};
+
+ static getDerivedStateFromProps(props, state) {
+ const { donationAmount, donationDuration } = props;
+
+ const configurationObj = paypalConfigurator(
+ donationAmount,
+ donationDuration
+ );
+ if (state === configurationObj) {
+ return null;
+ }
+ return { ...configurationObj };
+ }
+
handleApproval = data => {
- this.props.handleProcessing('year', 6000, 'Paypal payment submission');
+ const { amount, duration } = this.state;
+ this.props.handleProcessing(duration, amount, 'Paypal payment submission');
this.props.onDonationStateChange(false, true, '');
verifySubscriptionPaypal(data)
.then(response => {
@@ -46,48 +57,48 @@ export class PaypalButton extends Component {
};
render() {
- return (
- {
- executeGA({
- type: 'event',
- data: {
- category: 'Donation',
- action: `Modal Paypal clicked`
- }
- });
- return actions.subscription.create({
- plan_id: this.state.planId
- });
- }}
- onApprove={data => {
- this.handleApproval(data);
- }}
- onCancel={() => {
- this.props.onDonationStateChange(
- false,
- false,
- 'Payment has been canceled.'
- );
- }}
- onError={() =>
- this.props.onDonationStateChange(false, false, 'Please try again.')
- }
- options={{
- vault: true,
- disableFunding: 'card',
- clientId: paypalClientId
- }}
- style={{
- tagline: false,
- height: 43
- }}
- />
- );
+ const { duration, planId } = this.state;
+ const isOneTimePayment = duration === 'onetime';
+
+ if (!isOneTimePayment) {
+ return (
+ {
+ return actions.subscription.create({
+ plan_id: planId
+ });
+ }}
+ onApprove={data => {
+ this.handleApproval(data);
+ }}
+ onCancel={() => {
+ this.props.onDonationStateChange(
+ false,
+ false,
+ `Uh - oh. It looks like your transaction didn't go through. Could you please try again?`
+ );
+ }}
+ onError={() =>
+ this.props.onDonationStateChange(false, false, 'Please try again.')
+ }
+ options={{
+ vault: true,
+ disableFunding: 'card',
+ clientId: paypalClientId
+ }}
+ style={{
+ tagline: false,
+ height: 43
+ }}
+ />
+ );
+ } else return '';
}
}
const propTypes = {
+ donationAmount: PropTypes.number,
+ donationDuration: PropTypes.string,
handleProcessing: PropTypes.func,
isDonating: PropTypes.bool,
onDonationStateChange: PropTypes.func
diff --git a/config/donation-settings.js b/config/donation-settings.js
index 018a0adad3..62d0721e4e 100644
--- a/config/donation-settings.js
+++ b/config/donation-settings.js
@@ -43,25 +43,38 @@ const donationSubscriptionConfig = {
// Shared paypal configuration
const paypalConfigTypes = {
live: {
- durationPlans: {
- month: {
- '500': {
- planId: 'P-1L11422374370240ULZKX3PA'
- }
+ month: {
+ '500': {
+ planId: 'P-1L11422374370240ULZKX3PA'
+ }
+ },
+ year: {
+ '6000': {
+ planId: 'P-9Y661558DW462253NLZZ2IMQ'
+ },
+ '25000': {
+ planId: 'P-3NN39392MK1889318LZZ2KQY'
+ },
+ '100000': {
+ planId: 'P-7YN43286C4599382LLZZ2JUI'
}
}
},
staging: {
- durationPlans: {
- month: {
- '500': {
- planId: 'P-37N14480BW163382FLZYPVMA'
- }
+ month: {
+ '500': {
+ planId: 'P-37N14480BW163382FLZYPVMA'
+ }
+ },
+ year: {
+ '6000': {
+ planId: 'P-0UY77185EM3077131LZYP6VY'
},
- year: {
- '6000': {
- planId: 'P-0UY77185EM3077131LZYP6VY'
- }
+ '25000': {
+ planId: 'P-7K1585908S634694XLZZTHUQ'
+ },
+ '100000': {
+ planId: 'P-0J5231134H608574XLZZTDLQ'
}
}
}
@@ -72,6 +85,17 @@ const paypalConfig =
? paypalConfigTypes['live']
: paypalConfigTypes['staging'];
+const paypalConfigurator = (donationAmount, donationDuration) => {
+ if (donationDuration === 'onetime') {
+ return { amount: donationAmount, duration: donationDuration };
+ }
+ return {
+ amount: donationAmount,
+ duration: donationDuration,
+ planId: paypalConfig[donationDuration]['' + donationAmount].planId
+ };
+};
+
module.exports = {
durationsConfig,
amountsConfig,
@@ -81,5 +105,6 @@ module.exports = {
donationOneTimeConfig,
donationSubscriptionConfig,
modalDefaultStateConfig,
- paypalConfig
+ paypalConfig,
+ paypalConfigurator
};