feat(client): Unify donation loading state (#43179)
* initial loading state unification * feat(client): show buttons after 3 seconds * fix: use window.setInterval explicitly Otherwise TS assumes that it's node's setInterval * feat(client): remove spinner when first button load * feat(client): move the loader to the donate page button area * feat(client): extract grid from modal donation form * feat(client): remove duplicate donation forms * feat(client):extract unused components from donationForm * feat(client): load paypal on load not onInit (for perf) * feat(client): set paypal loading state if stripe already loaded * feat(clinet):make lpaypal oading condition strickt. * Apply suggestions from code review Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> * feat: clean up Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@ -265,7 +265,7 @@ const ShowCertification = (props: IShowCertificationProps): JSX.Element => {
|
||||
</Row>
|
||||
)}
|
||||
<Row>
|
||||
<Col md={8} mdOffset={2} xs={12}>
|
||||
<Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
|
||||
<DonateForm
|
||||
defaultTheme='default'
|
||||
handleProcessing={handleProcessing}
|
||||
|
@ -24,6 +24,7 @@ function DonateCompletion({
|
||||
const { t } = useTranslation();
|
||||
const style =
|
||||
processing || redirecting ? 'info' : success ? 'success' : 'danger';
|
||||
|
||||
const heading = redirecting
|
||||
? `${t('donate.redirecting')}`
|
||||
: processing
|
||||
@ -31,6 +32,7 @@ function DonateCompletion({
|
||||
: success
|
||||
? `${t('donate.thank-you')}`
|
||||
: `${t('donate.error')}`;
|
||||
|
||||
return (
|
||||
<Alert bsStyle={style} className='donation-completion'>
|
||||
<h4>
|
||||
|
@ -2,19 +2,12 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import {
|
||||
Col,
|
||||
Row,
|
||||
Tab,
|
||||
Tabs,
|
||||
ToggleButton,
|
||||
ToggleButtonGroup
|
||||
} from '@freecodecamp/react-bootstrap';
|
||||
|
||||
import type { Token } from '@stripe/stripe-js';
|
||||
import React, { Component } from 'react';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import Spinner from 'react-spinkit';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import {
|
||||
@ -48,12 +41,19 @@ const numToCommas = (num: number): string =>
|
||||
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
|
||||
|
||||
type DonateFormState = {
|
||||
donationAmount: number;
|
||||
donationDuration: string;
|
||||
processing: boolean;
|
||||
redirecting: boolean;
|
||||
success: boolean;
|
||||
error: string;
|
||||
loading: {
|
||||
stripe: boolean;
|
||||
paypal: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
type DonateFromComponentState = {
|
||||
donationAmount: number;
|
||||
donationDuration: string;
|
||||
};
|
||||
|
||||
type DonateFormProps = {
|
||||
@ -99,7 +99,7 @@ const mapDispatchToProps = {
|
||||
postChargeStripe
|
||||
};
|
||||
|
||||
class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
class DonateForm extends Component<DonateFormProps, DonateFromComponentState> {
|
||||
static displayName = 'DonateForm';
|
||||
durations: { month: 'monthly'; onetime: 'one-time' };
|
||||
amounts: { month: number[]; onetime: number[] };
|
||||
@ -116,22 +116,16 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
? modalDefaultDonation
|
||||
: defaultDonation;
|
||||
|
||||
this.state = {
|
||||
...initialAmountAndDuration,
|
||||
processing: false,
|
||||
redirecting: false,
|
||||
success: false,
|
||||
error: ''
|
||||
};
|
||||
this.state = { ...initialAmountAndDuration };
|
||||
|
||||
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);
|
||||
this.postStripeDonation = this.postStripeDonation.bind(this);
|
||||
this.handlePaymentButtonLoad = this.handlePaymentButtonLoad.bind(this);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@ -141,9 +135,23 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
onDonationStateChange(donationState: AddDonationData) {
|
||||
// scroll to top
|
||||
window.scrollTo(0, 0);
|
||||
this.props.updateDonationFormState(donationState);
|
||||
this.props.updateDonationFormState({
|
||||
...this.props.donationFormState,
|
||||
...donationState
|
||||
});
|
||||
}
|
||||
|
||||
handlePaymentButtonLoad(provider: 'stripe' | 'paypal') {
|
||||
this.props.updateDonationFormState({
|
||||
...this.props.donationFormState,
|
||||
loading: {
|
||||
...this.props.donationFormState.loading,
|
||||
[provider]: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// onload
|
||||
getActiveDonationAmount(
|
||||
durationSelected: 'month' | 'onetime',
|
||||
amountSelected: number
|
||||
@ -213,19 +221,6 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
this.setState({ donationAmount });
|
||||
}
|
||||
|
||||
renderAmountButtons(duration: 'month' | 'onetime') {
|
||||
return this.amounts[duration].map((amount: number) => (
|
||||
<ToggleButton
|
||||
className='amount-value'
|
||||
id={`${this.durations[duration]}-donation-${amount}`}
|
||||
key={`${this.durations[duration]}-donation-${amount}`}
|
||||
value={amount}
|
||||
>
|
||||
{this.getFormattedAmountLabel(amount)}
|
||||
</ToggleButton>
|
||||
));
|
||||
}
|
||||
|
||||
renderDonationDescription() {
|
||||
const { donationAmount, donationDuration } = this.state;
|
||||
const { t } = this.props;
|
||||
@ -243,113 +238,22 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
);
|
||||
}
|
||||
|
||||
renderDurationAmountOptions() {
|
||||
const { donationAmount, donationDuration, processing } = this.state;
|
||||
const { t } = this.props;
|
||||
|
||||
return !processing ? (
|
||||
<div>
|
||||
<h3>{t('donate.gift-frequency')}</h3>
|
||||
<Tabs
|
||||
activeKey={donationDuration}
|
||||
animation={false}
|
||||
bsStyle='pills'
|
||||
className='donate-tabs'
|
||||
id='Duration'
|
||||
onSelect={this.handleSelectDuration}
|
||||
>
|
||||
{(Object.keys(this.durations) as ['month' | 'onetime']).map(
|
||||
duration => (
|
||||
<Tab
|
||||
eventKey={duration}
|
||||
key={duration}
|
||||
title={this.durations[duration]}
|
||||
>
|
||||
<Spacer />
|
||||
<h3>{t('donate.gift-amount')}</h3>
|
||||
<div>
|
||||
<ToggleButtonGroup
|
||||
animation={`false`}
|
||||
className='amount-values'
|
||||
name='amounts'
|
||||
onChange={this.handleSelectAmount}
|
||||
type='radio'
|
||||
value={this.getActiveDonationAmount(
|
||||
duration,
|
||||
donationAmount
|
||||
)}
|
||||
>
|
||||
{this.renderAmountButtons(duration)}
|
||||
</ToggleButtonGroup>
|
||||
<Spacer />
|
||||
{this.renderDonationDescription()}
|
||||
</div>
|
||||
</Tab>
|
||||
)
|
||||
)}
|
||||
</Tabs>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
hideAmountOptionsCB(hide: boolean) {
|
||||
this.setState({ processing: hide });
|
||||
}
|
||||
|
||||
renderDonationOptions() {
|
||||
const {
|
||||
handleProcessing,
|
||||
isSignedIn,
|
||||
addDonation,
|
||||
t,
|
||||
defaultTheme,
|
||||
theme
|
||||
} = this.props;
|
||||
const { donationAmount, donationDuration } = this.state;
|
||||
const isOneTime = donationDuration === 'onetime';
|
||||
const formlabel = `${t(
|
||||
isOneTime ? 'donate.confirm-2' : 'donate.confirm-3',
|
||||
{ usd: donationAmount / 100 }
|
||||
)}:`;
|
||||
|
||||
const walletlabel = `${t(
|
||||
isOneTime ? 'donate.wallet-label' : 'donate.wallet-label-1',
|
||||
{ usd: donationAmount / 100 }
|
||||
)}:`;
|
||||
const priorityTheme = defaultTheme ? defaultTheme : theme;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<b>{formlabel}</b>
|
||||
<Spacer />
|
||||
<div className='donate-btn-group'>
|
||||
<WalletsWrapper
|
||||
amount={donationAmount}
|
||||
label={walletlabel}
|
||||
onDonationStateChange={this.onDonationStateChange}
|
||||
postStripeDonation={this.postStripeDonation}
|
||||
refreshErrorMessage={t('donate.refresh-needed')}
|
||||
theme={priorityTheme}
|
||||
/>
|
||||
<PaypalButton
|
||||
addDonation={addDonation}
|
||||
donationAmount={donationAmount}
|
||||
donationDuration={donationDuration}
|
||||
handleProcessing={handleProcessing}
|
||||
isSubscription={isOneTime ? false : true}
|
||||
onDonationStateChange={this.onDonationStateChange}
|
||||
skipAddDonation={!isSignedIn}
|
||||
theme={priorityTheme}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
resetDonation() {
|
||||
return this.props.updateDonationFormState({ ...defaultDonationFormState });
|
||||
}
|
||||
|
||||
paymentButtonsLoader() {
|
||||
return (
|
||||
<div className=' donation-completion donation-completion-loading'>
|
||||
<Spinner
|
||||
className='script-loading-spinner'
|
||||
fadeIn='none'
|
||||
name='line-scale'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderCompletion(props: {
|
||||
processing: boolean;
|
||||
redirecting: boolean;
|
||||
@ -360,24 +264,36 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
return <DonateCompletion {...props} />;
|
||||
}
|
||||
|
||||
renderModalForm() {
|
||||
renderButtonGroup() {
|
||||
const { donationAmount, donationDuration } = this.state;
|
||||
const { handleProcessing, addDonation, defaultTheme, theme, t } =
|
||||
this.props;
|
||||
const {
|
||||
donationFormState: { loading },
|
||||
handleProcessing,
|
||||
addDonation,
|
||||
defaultTheme,
|
||||
theme,
|
||||
t,
|
||||
isMinimalForm
|
||||
} = this.props;
|
||||
const paymentButtonsLoading = loading.stripe && loading.paypal;
|
||||
const priorityTheme = defaultTheme ? defaultTheme : theme;
|
||||
const isOneTime = donationDuration === 'onetime';
|
||||
const walletlabel = `${t(
|
||||
isOneTime ? 'donate.wallet-label' : 'donate.wallet-label-1',
|
||||
{ usd: donationAmount / 100 }
|
||||
)}:`;
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
|
||||
<b className='donation-label'>{this.getDonationButtonLabel()}:</b>
|
||||
<>
|
||||
<b className={isMinimalForm ? 'donation-label-modal' : ''}>
|
||||
{this.getDonationButtonLabel()}:
|
||||
</b>
|
||||
<Spacer />
|
||||
<div className='donate-btn-group'>
|
||||
{paymentButtonsLoading && this.paymentButtonsLoader()}
|
||||
<div className={'donate-btn-group'}>
|
||||
<WalletsWrapper
|
||||
amount={donationAmount}
|
||||
handlePaymentButtonLoad={this.handlePaymentButtonLoad}
|
||||
label={walletlabel}
|
||||
onDonationStateChange={this.onDonationStateChange}
|
||||
postStripeDonation={this.postStripeDonation}
|
||||
@ -388,22 +304,23 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
addDonation={addDonation}
|
||||
donationAmount={donationAmount}
|
||||
donationDuration={donationDuration}
|
||||
handlePaymentButtonLoad={this.handlePaymentButtonLoad}
|
||||
handleProcessing={handleProcessing}
|
||||
isPaypalLoading={loading.paypal}
|
||||
onDonationStateChange={this.onDonationStateChange}
|
||||
theme={defaultTheme ? defaultTheme : theme}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
renderPageForm() {
|
||||
return (
|
||||
<Row>
|
||||
<Col xs={12}>{this.renderDonationDescription()}</Col>
|
||||
<Col xs={12}>{this.renderDonationOptions()}</Col>
|
||||
</Row>
|
||||
<>
|
||||
<div>{this.renderDonationDescription()}</div>
|
||||
<div>{this.renderButtonGroup()}</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -412,6 +329,7 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
donationFormState: { processing, success, error, redirecting },
|
||||
isMinimalForm
|
||||
} = this.props;
|
||||
|
||||
if (success || error) {
|
||||
return this.renderCompletion({
|
||||
processing,
|
||||
@ -434,7 +352,7 @@ class DonateForm extends Component<DonateFormProps, DonateFormState> {
|
||||
reset: this.resetDonation
|
||||
})}
|
||||
<div className={processing || redirecting ? 'hide' : ''}>
|
||||
{isMinimalForm ? this.renderModalForm() : this.renderPageForm()}
|
||||
{isMinimalForm ? this.renderButtonGroup() : this.renderPageForm()}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -25,6 +25,9 @@
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.donation-completion-loading {
|
||||
min-height: 154px;
|
||||
}
|
||||
|
||||
.donation-completion-buttons {
|
||||
display: flex;
|
||||
@ -245,7 +248,7 @@ li.disabled > a {
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.donation-label,
|
||||
.donation-label-modal,
|
||||
.donation-modal p,
|
||||
.donation-modal b {
|
||||
text-align: center;
|
||||
|
@ -158,7 +158,14 @@ function DonateModal({
|
||||
<Modal.Body>
|
||||
{recentlyClaimedBlock ? blockDonationText : progressDonationText}
|
||||
<Spacer />
|
||||
<DonateForm handleProcessing={handleProcessing} isMinimalForm={true} />
|
||||
<Row>
|
||||
<Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
|
||||
<DonateForm
|
||||
handleProcessing={handleProcessing}
|
||||
isMinimalForm={true}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Spacer />
|
||||
<Row>
|
||||
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>
|
||||
|
@ -2,7 +2,6 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import { Loader } from '../../components/helpers';
|
||||
import { scriptLoader, scriptRemover } from '../../utils/script-loaders';
|
||||
|
||||
import type { AddDonationData } from './PaypalButton';
|
||||
@ -32,9 +31,15 @@ type PayPalButtonScriptLoaderProps = {
|
||||
data: AddDonationData,
|
||||
actions?: { order: { capture: () => Promise<unknown> } }
|
||||
) => unknown;
|
||||
isPaypalLoading: boolean;
|
||||
onCancel: () => unknown;
|
||||
onError: () => unknown;
|
||||
style: unknown;
|
||||
onLoad: () => void;
|
||||
style: {
|
||||
color: string;
|
||||
height: number;
|
||||
tagline: boolean;
|
||||
};
|
||||
planId: string | null;
|
||||
};
|
||||
|
||||
@ -81,16 +86,24 @@ export class PayPalButtonScriptLoader extends Component<
|
||||
componentDidMount(): void {
|
||||
if (!window.paypal) {
|
||||
this.loadScript(this.props.isSubscription, false);
|
||||
} else if (this.props.isPaypalLoading) {
|
||||
this.props.onLoad();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: {
|
||||
isSubscription: boolean;
|
||||
style: unknown;
|
||||
style: {
|
||||
color: string;
|
||||
height: number;
|
||||
tagline: boolean;
|
||||
};
|
||||
}): void {
|
||||
if (
|
||||
prevProps.isSubscription !== this.state.isSubscription ||
|
||||
prevProps.style !== this.props.style
|
||||
prevProps.style.color !== this.props.style.color ||
|
||||
prevProps.style.tagline !== this.props.style.tagline ||
|
||||
prevProps.style.height !== this.props.style.height
|
||||
) {
|
||||
// eslint-disable-next-line react/no-did-update-set-state
|
||||
this.setState({ isSdkLoaded: false });
|
||||
@ -114,6 +127,7 @@ export class PayPalButtonScriptLoader extends Component<
|
||||
|
||||
onScriptLoad = (): void => {
|
||||
this.setState({ isSdkLoaded: true });
|
||||
this.props.onLoad();
|
||||
};
|
||||
|
||||
captureOneTimePayment(
|
||||
@ -144,7 +158,7 @@ export class PayPalButtonScriptLoader extends Component<
|
||||
style
|
||||
} = this.props;
|
||||
|
||||
if (!isSdkLoaded) return <Loader />;
|
||||
if (!isSdkLoaded) return <></>;
|
||||
|
||||
// TODO: fill in the full list of props instead of any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -36,10 +36,12 @@ type PaypalButtonProps = {
|
||||
success: boolean;
|
||||
error: string | null;
|
||||
}) => void;
|
||||
isPaypalLoading: boolean;
|
||||
skipAddDonation?: boolean;
|
||||
t: (label: string) => string;
|
||||
theme: string;
|
||||
isSubscription?: boolean;
|
||||
handlePaymentButtonLoad: (provider: 'stripe' | 'paypal') => void;
|
||||
};
|
||||
|
||||
type PaypalButtonState = {
|
||||
@ -53,6 +55,10 @@ export interface AddDonationData {
|
||||
processing: boolean;
|
||||
success: boolean;
|
||||
error: string | null;
|
||||
loading?: {
|
||||
stripe: boolean;
|
||||
paypal: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const {
|
||||
@ -120,7 +126,7 @@ export class PaypalButton extends Component<
|
||||
|
||||
render(): JSX.Element | null {
|
||||
const { duration, planId, amount } = this.state;
|
||||
const { t, theme } = this.props;
|
||||
const { t, theme, isPaypalLoading } = this.props;
|
||||
const isSubscription = duration !== 'onetime';
|
||||
const buttonColor = theme === 'night' ? 'white' : 'gold';
|
||||
if (!paypalClientId) {
|
||||
@ -167,6 +173,7 @@ export class PaypalButton extends Component<
|
||||
plan_id: planId
|
||||
});
|
||||
}}
|
||||
isPaypalLoading={isPaypalLoading}
|
||||
isSubscription={isSubscription}
|
||||
onApprove={(data: AddDonationData) => {
|
||||
this.handleApproval(data, isSubscription);
|
||||
@ -179,14 +186,16 @@ export class PaypalButton extends Component<
|
||||
error: t('donate.failed-pay')
|
||||
});
|
||||
}}
|
||||
onError={() =>
|
||||
onError={() => {
|
||||
this.props.handlePaymentButtonLoad('paypal');
|
||||
this.props.onDonationStateChange({
|
||||
redirecting: false,
|
||||
processing: false,
|
||||
success: false,
|
||||
error: t('donate.try-again')
|
||||
})
|
||||
}
|
||||
});
|
||||
}}
|
||||
onLoad={() => this.props.handlePaymentButtonLoad('paypal')}
|
||||
planId={planId}
|
||||
style={{
|
||||
tagline: false,
|
||||
|
90
client/src/components/Donation/duration-amount-options.tsx
Normal file
90
client/src/components/Donation/duration-amount-options.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import {
|
||||
Tab,
|
||||
Tabs,
|
||||
ToggleButton,
|
||||
ToggleButtonGroup
|
||||
} from '@freecodecamp/react-bootstrap';
|
||||
import React from 'react';
|
||||
|
||||
import Spacer from '../helpers/spacer';
|
||||
|
||||
interface OptionsProps {
|
||||
amounts: { month: []; onetime: [] };
|
||||
month: [];
|
||||
onetime: [];
|
||||
durations: { month: string; onetime: string };
|
||||
getFormattedAmountLabel: (amount: number) => string;
|
||||
getActiveDonationAmount: (
|
||||
duration: 'month' | 'onetime',
|
||||
donationAmount: number
|
||||
) => number;
|
||||
handleSelectDuration: unknown;
|
||||
handleSelectAmount: unknown;
|
||||
donationDuration: 'month' | 'onetime';
|
||||
donationAmount: 500 | 1000;
|
||||
t: (
|
||||
label: string,
|
||||
{ usd, hours }?: { usd?: string | number; hours?: string }
|
||||
) => string;
|
||||
}
|
||||
|
||||
const DurationAmountOptions = ({
|
||||
donationDuration,
|
||||
donationAmount,
|
||||
amounts,
|
||||
durations,
|
||||
getFormattedAmountLabel,
|
||||
getActiveDonationAmount,
|
||||
handleSelectDuration,
|
||||
handleSelectAmount,
|
||||
t
|
||||
}: OptionsProps): JSX.Element => {
|
||||
const renderAmountButtons = (duration: 'month' | 'onetime'): unknown => {
|
||||
return amounts[duration].map((amount: number) => (
|
||||
<ToggleButton
|
||||
className='amount-value'
|
||||
id={`${durations[duration]}-donation-${amount}`}
|
||||
key={`${durations[duration]}-donation-${amount}`}
|
||||
value={amount}
|
||||
>
|
||||
{getFormattedAmountLabel(amount)}
|
||||
</ToggleButton>
|
||||
));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
s<h3>{t('donate.gift-frequency')}</h3>
|
||||
<Tabs
|
||||
activeKey={donationDuration}
|
||||
animation={false}
|
||||
bsStyle='pills'
|
||||
className='donate-tabs'
|
||||
id='Duration'
|
||||
onSelect={handleSelectDuration}
|
||||
>
|
||||
{(Object.keys(durations) as ['month' | 'onetime']).map(duration => (
|
||||
<Tab eventKey={duration} key={duration} title={durations[duration]}>
|
||||
<Spacer />
|
||||
<h3>{t('donate.gift-amount')}</h3>
|
||||
<div>
|
||||
<ToggleButtonGroup
|
||||
animation={`false`}
|
||||
className='amount-values'
|
||||
name='amounts'
|
||||
onChange={handleSelectAmount}
|
||||
type='radio'
|
||||
value={getActiveDonationAmount(duration, donationAmount)}
|
||||
>
|
||||
{renderAmountButtons(duration)}
|
||||
</ToggleButtonGroup>
|
||||
<Spacer />
|
||||
</div>
|
||||
</Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DurationAmountOptions;
|
@ -22,6 +22,7 @@ interface WrapperProps {
|
||||
) => void;
|
||||
onDonationStateChange: (donationState: AddDonationData) => void;
|
||||
refreshErrorMessage: string;
|
||||
handlePaymentButtonLoad: (provider: 'stripe' | 'paypal') => void;
|
||||
}
|
||||
interface WalletsButtonProps extends WrapperProps {
|
||||
stripe: Stripe | null;
|
||||
@ -34,7 +35,8 @@ const WalletsButton = ({
|
||||
theme,
|
||||
refreshErrorMessage,
|
||||
postStripeDonation,
|
||||
onDonationStateChange
|
||||
onDonationStateChange,
|
||||
handlePaymentButtonLoad
|
||||
}: WalletsButtonProps) => {
|
||||
const [token, setToken] = useState<Token | null>(null);
|
||||
const [paymentRequest, setPaymentRequest] = useState<PaymentRequest | null>(
|
||||
@ -71,7 +73,7 @@ const WalletsButton = ({
|
||||
checkpaymentPossiblity(false);
|
||||
}
|
||||
});
|
||||
}, [label, amount, stripe, postStripeDonation]);
|
||||
}, [label, amount, stripe, postStripeDonation, handlePaymentButtonLoad]);
|
||||
|
||||
const displayRefreshError = (): void => {
|
||||
onDonationStateChange({
|
||||
@ -87,10 +89,12 @@ const WalletsButton = ({
|
||||
{canMakePayment && paymentRequest && (
|
||||
<PaymentRequestButtonElement
|
||||
onClick={() => {
|
||||
console.log('click');
|
||||
if (token) {
|
||||
displayRefreshError();
|
||||
}
|
||||
}}
|
||||
onReady={() => handlePaymentButtonLoad('stripe')}
|
||||
options={{
|
||||
style: {
|
||||
paymentRequestButton: {
|
||||
|
@ -6,7 +6,8 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.fcc-loader .sk-spinner {
|
||||
.fcc-loader .sk-spinner,
|
||||
.script-loading-spinner {
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,11 @@ function DonatePage({
|
||||
</Alert>
|
||||
) : null}
|
||||
<DonationText />
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<DonateForm handleProcessing={handleProcessing} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className='donate-support'>
|
||||
<Col xs={12}>
|
||||
<hr />
|
||||
|
@ -33,7 +33,11 @@ export const defaultDonationFormState = {
|
||||
redirecting: false,
|
||||
processing: false,
|
||||
success: false,
|
||||
error: ''
|
||||
error: '',
|
||||
loading: {
|
||||
stripe: true,
|
||||
paypal: true
|
||||
}
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
|
Reference in New Issue
Block a user