feat: add reconfigurable paypal button to donate page
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
a2c7659f2d
commit
cdc8b1e8e5
@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component, Fragment } 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';
|
||||||
@ -20,6 +20,8 @@ import {
|
|||||||
} from '../../../../config/donation-settings';
|
} from '../../../../config/donation-settings';
|
||||||
import Spacer from '../helpers/Spacer';
|
import Spacer from '../helpers/Spacer';
|
||||||
import DonateFormChildViewForHOC from './DonateFormChildViewForHOC';
|
import DonateFormChildViewForHOC from './DonateFormChildViewForHOC';
|
||||||
|
import PaypalButton from './PaypalButton';
|
||||||
|
import DonateCompletion from './DonateCompletion';
|
||||||
import {
|
import {
|
||||||
isSignedInSelector,
|
isSignedInSelector,
|
||||||
signInLoadingSelector,
|
signInLoadingSelector,
|
||||||
@ -50,11 +52,18 @@ const mapStateToProps = createSelector(
|
|||||||
showLoading
|
showLoading
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
navigate
|
navigate
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
donationState: {
|
||||||
|
processing: false,
|
||||||
|
success: false,
|
||||||
|
error: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class DonateForm extends Component {
|
class DonateForm extends Component {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
@ -63,15 +72,30 @@ class DonateForm extends Component {
|
|||||||
this.amounts = amountsConfig;
|
this.amounts = amountsConfig;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
...initialState,
|
||||||
...defaultStateConfig,
|
...defaultStateConfig,
|
||||||
processing: false
|
processing: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.onDonationStateChange = this.onDonationStateChange.bind(this);
|
||||||
this.getActiveDonationAmount = this.getActiveDonationAmount.bind(this);
|
this.getActiveDonationAmount = this.getActiveDonationAmount.bind(this);
|
||||||
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
|
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
|
||||||
this.handleSelectAmount = this.handleSelectAmount.bind(this);
|
this.handleSelectAmount = this.handleSelectAmount.bind(this);
|
||||||
this.handleSelectDuration = this.handleSelectDuration.bind(this);
|
this.handleSelectDuration = this.handleSelectDuration.bind(this);
|
||||||
this.hideAmountOptionsCB = this.hideAmountOptionsCB.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) {
|
getActiveDonationAmount(durationSelected, amountSelected) {
|
||||||
@ -199,13 +223,64 @@ class DonateForm extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetDonation() {
|
||||||
|
return this.setState({ ...initialState });
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCompletion(props) {
|
||||||
|
return <DonateCompletion {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
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 (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
<Col sm={10} smOffset={1} xs={12}>
|
||||||
{this.renderDurationAmountOptions()}
|
{this.renderDurationAmountOptions()}
|
||||||
</Col>
|
</Col>
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
<Col sm={10} smOffset={1} xs={12}>
|
||||||
|
{subscriptionPayment ? (
|
||||||
|
<Fragment>
|
||||||
|
<b>
|
||||||
|
Confirm your donation of ${donationAmount / 100} / year with
|
||||||
|
PayPal:
|
||||||
|
</b>
|
||||||
|
<Spacer />
|
||||||
|
</Fragment>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
<PaypalButton
|
||||||
|
donationAmount={donationAmount}
|
||||||
|
donationDuration={donationDuration}
|
||||||
|
handleProcessing={handleProcessing}
|
||||||
|
onDonationStateChange={this.onDonationStateChange}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col sm={10} smOffset={1} xs={12}>
|
||||||
|
{subscriptionPayment ? (
|
||||||
|
<Fragment>
|
||||||
|
<Spacer />
|
||||||
|
<b>Or donate with a credit card:</b>
|
||||||
|
<Spacer />
|
||||||
|
</Fragment>
|
||||||
|
) : (
|
||||||
|
''
|
||||||
|
)}
|
||||||
{this.renderDonationOptions()}
|
{this.renderDonationOptions()}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -169,6 +169,9 @@ li.disabled > a {
|
|||||||
color: var(--gray-15) !important;
|
color: var(--gray-15) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.donate-page-wrapper,
|
||||||
|
.donate-page-wrapper b,
|
||||||
|
.donate-page-wrapper h3,
|
||||||
.donate-text p,
|
.donate-text p,
|
||||||
.donation-description,
|
.donation-description,
|
||||||
[name='payment-method'] {
|
[name='payment-method'] {
|
||||||
|
@ -134,6 +134,8 @@ class MinimalDonateForm extends Component {
|
|||||||
<b>Confirm your donation of $60 / year with PayPal:</b>
|
<b>Confirm your donation of $60 / year with PayPal:</b>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<PaypalButton
|
<PaypalButton
|
||||||
|
donationAmount={donationAmount}
|
||||||
|
donationDuration={donationDuration}
|
||||||
handleProcessing={handleProcessing}
|
handleProcessing={handleProcessing}
|
||||||
onDonationStateChange={this.onDonationStateChange}
|
onDonationStateChange={this.onDonationStateChange}
|
||||||
/>
|
/>
|
||||||
|
@ -7,22 +7,33 @@ import { createSelector } from 'reselect';
|
|||||||
import { PayPalButton } from 'react-paypal-button-v2';
|
import { PayPalButton } from 'react-paypal-button-v2';
|
||||||
import { paypalClientId } from '../../../config/env.json';
|
import { paypalClientId } from '../../../config/env.json';
|
||||||
import { verifySubscriptionPaypal } from '../../utils/ajax';
|
import { verifySubscriptionPaypal } from '../../utils/ajax';
|
||||||
import { paypalConfig } from '../../../../config/donation-settings';
|
import { paypalConfigurator } from '../../../../config/donation-settings';
|
||||||
import { signInLoadingSelector, userSelector, executeGA } from '../../redux';
|
import { signInLoadingSelector, userSelector } from '../../redux';
|
||||||
|
|
||||||
const { durationPlans } = paypalConfig;
|
|
||||||
|
|
||||||
export class PaypalButton extends Component {
|
export class PaypalButton extends Component {
|
||||||
constructor(...props) {
|
constructor(props) {
|
||||||
super(...props);
|
super(props);
|
||||||
this.state = {
|
|
||||||
planId: durationPlans.year['6000'].planId
|
|
||||||
};
|
|
||||||
this.handleApproval = this.handleApproval.bind(this);
|
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 => {
|
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, '');
|
this.props.onDonationStateChange(false, true, '');
|
||||||
verifySubscriptionPaypal(data)
|
verifySubscriptionPaypal(data)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
@ -46,18 +57,15 @@ export class PaypalButton extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { duration, planId } = this.state;
|
||||||
|
const isOneTimePayment = duration === 'onetime';
|
||||||
|
|
||||||
|
if (!isOneTimePayment) {
|
||||||
return (
|
return (
|
||||||
<PayPalButton
|
<PayPalButton
|
||||||
createSubscription={(data, actions) => {
|
createSubscription={(data, actions) => {
|
||||||
executeGA({
|
|
||||||
type: 'event',
|
|
||||||
data: {
|
|
||||||
category: 'Donation',
|
|
||||||
action: `Modal Paypal clicked`
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return actions.subscription.create({
|
return actions.subscription.create({
|
||||||
plan_id: this.state.planId
|
plan_id: planId
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
onApprove={data => {
|
onApprove={data => {
|
||||||
@ -67,7 +75,7 @@ export class PaypalButton extends Component {
|
|||||||
this.props.onDonationStateChange(
|
this.props.onDonationStateChange(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
'Payment has been canceled.'
|
`Uh - oh. It looks like your transaction didn't go through. Could you please try again?`
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
onError={() =>
|
onError={() =>
|
||||||
@ -84,10 +92,13 @@ export class PaypalButton extends Component {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
} else return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
|
donationAmount: PropTypes.number,
|
||||||
|
donationDuration: PropTypes.string,
|
||||||
handleProcessing: PropTypes.func,
|
handleProcessing: PropTypes.func,
|
||||||
isDonating: PropTypes.bool,
|
isDonating: PropTypes.bool,
|
||||||
onDonationStateChange: PropTypes.func
|
onDonationStateChange: PropTypes.func
|
||||||
|
@ -43,16 +43,24 @@ const donationSubscriptionConfig = {
|
|||||||
// Shared paypal configuration
|
// Shared paypal configuration
|
||||||
const paypalConfigTypes = {
|
const paypalConfigTypes = {
|
||||||
live: {
|
live: {
|
||||||
durationPlans: {
|
|
||||||
month: {
|
month: {
|
||||||
'500': {
|
'500': {
|
||||||
planId: 'P-1L11422374370240ULZKX3PA'
|
planId: 'P-1L11422374370240ULZKX3PA'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
year: {
|
||||||
|
'6000': {
|
||||||
|
planId: 'P-9Y661558DW462253NLZZ2IMQ'
|
||||||
|
},
|
||||||
|
'25000': {
|
||||||
|
planId: 'P-3NN39392MK1889318LZZ2KQY'
|
||||||
|
},
|
||||||
|
'100000': {
|
||||||
|
planId: 'P-7YN43286C4599382LLZZ2JUI'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
staging: {
|
staging: {
|
||||||
durationPlans: {
|
|
||||||
month: {
|
month: {
|
||||||
'500': {
|
'500': {
|
||||||
planId: 'P-37N14480BW163382FLZYPVMA'
|
planId: 'P-37N14480BW163382FLZYPVMA'
|
||||||
@ -61,7 +69,12 @@ const paypalConfigTypes = {
|
|||||||
year: {
|
year: {
|
||||||
'6000': {
|
'6000': {
|
||||||
planId: 'P-0UY77185EM3077131LZYP6VY'
|
planId: 'P-0UY77185EM3077131LZYP6VY'
|
||||||
}
|
},
|
||||||
|
'25000': {
|
||||||
|
planId: 'P-7K1585908S634694XLZZTHUQ'
|
||||||
|
},
|
||||||
|
'100000': {
|
||||||
|
planId: 'P-0J5231134H608574XLZZTDLQ'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,6 +85,17 @@ const paypalConfig =
|
|||||||
? paypalConfigTypes['live']
|
? paypalConfigTypes['live']
|
||||||
: paypalConfigTypes['staging'];
|
: 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 = {
|
module.exports = {
|
||||||
durationsConfig,
|
durationsConfig,
|
||||||
amountsConfig,
|
amountsConfig,
|
||||||
@ -81,5 +105,6 @@ module.exports = {
|
|||||||
donationOneTimeConfig,
|
donationOneTimeConfig,
|
||||||
donationSubscriptionConfig,
|
donationSubscriptionConfig,
|
||||||
modalDefaultStateConfig,
|
modalDefaultStateConfig,
|
||||||
paypalConfig
|
paypalConfig,
|
||||||
|
paypalConfigurator
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user