Files
freeCodeCamp/client/src/components/Donation/PaypalButton.tsx
Nicolás Restrepo e34ec814ef feat(client): migrate donate module to ts (#42561)
* change DonationTextComponent extension to tsx

* migrate DonationTextComponents to ts

* change DonationModal extension to tsx

* add @types/react-redux

* migrate DonationModal to ts

* change PaypalButton extension to ts

* change DonateCompletion extension to tsx

* migrate DonateCompletion to TypeScript

* change PayPalButtonLoader extension to tsx

* first changes in paypal button (help needed)

* first changes in PayPalButtonScriptLoader (help needed)

* change DonateForm extension to tsx

* migrate donate module to ts

* Update client/src/components/Donation/DonateForm.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* Update client/src/components/Donation/DonationModal.tsx

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* Update client/src/components/Donation/DonationModal.tsx

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* Update client/src/components/Donation/DonateForm.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* Update client/src/components/Donation/DonateForm.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* Delete console.log client/src/components/Donation/DonationModal.tsx

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* applied changes requested

* fix: readjust default one time amount

* fix types

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* chore: restore comments.json

* fix: type assertion

* fix: specific DonateForm props

* Apply suggestions from code review

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* Update client/src/components/Donation/PaypalButton.tsx

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix:set default stat for paypalbutton

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
Co-authored-by: Ahmad Abdolsaheb <ahmad.abdolsaheb@gmail.com>
2021-08-04 11:21:11 +01:00

214 lines
5.7 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable camelcase */
import React, { Component } from 'react';
import { withTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import {
paypalConfigurator,
paypalConfigTypes,
defaultDonation
} from '../../../../config/donation-settings';
import envData from '../../../../config/env.json';
import { signInLoadingSelector, userSelector } from '../../redux';
import PayPalButtonScriptLoader from './PayPalButtonScriptLoader';
type PaypalButtonProps = {
addDonation: (data: AddDonationData) => void;
donationAmount: number;
donationDuration: string;
handleProcessing: (
duration: string,
amount: number,
action: string
) => unknown;
isDonating: boolean;
onDonationStateChange: ({
redirecting,
processing,
success,
error
}: {
redirecting: boolean;
processing: boolean;
success: boolean;
error: string | null;
}) => void;
skipAddDonation?: boolean;
t: (label: string) => string;
theme: string;
isSubscription?: boolean;
};
type PaypalButtonState = {
amount: number;
duration: string;
planId: string | null;
};
export interface AddDonationData {
redirecting: boolean;
processing: boolean;
success: boolean;
error: string | null;
}
const {
paypalClientId,
deploymentEnv
}: { paypalClientId: string | null; deploymentEnv: 'staging' | 'live' } =
envData as {
paypalClientId: string | null;
deploymentEnv: 'staging' | 'live';
};
export class PaypalButton extends Component<
PaypalButtonProps,
PaypalButtonState
> {
static displayName = 'PaypalButton';
state: PaypalButtonState = {
amount: defaultDonation.donationAmount,
duration: defaultDonation.donationDuration,
planId: null
};
constructor(props: PaypalButtonProps) {
super(props);
this.handleApproval = this.handleApproval.bind(this);
}
static getDerivedStateFromProps(props: PaypalButtonProps): PaypalButtonState {
const { donationAmount, donationDuration } = props;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const configurationObj: {
amount: number;
duration: string;
planId: string | null;
} = paypalConfigurator(
donationAmount,
donationDuration,
paypalConfigTypes[deploymentEnv || 'staging']
);
// re-implement it as a deep comparison.
// if (state === configurationObj) {
// return null;
// }
return { ...configurationObj };
}
handleApproval = (data: AddDonationData, isSubscription: boolean): void => {
const { amount, duration } = this.state;
const { skipAddDonation = false } = this.props;
// Skip the api if user is not signed in or if its a one-time donation
if (!skipAddDonation || isSubscription) {
this.props.addDonation(data);
}
this.props.handleProcessing(duration, amount, 'Paypal payment submission');
// Show success anytime because the payment has gone through paypal
this.props.onDonationStateChange({
redirecting: false,
processing: false,
success: true,
error: data.error ? data.error : null
});
};
render(): JSX.Element | null {
const { duration, planId, amount } = this.state;
const { t, theme } = this.props;
const isSubscription = duration !== 'onetime';
const buttonColor = theme === 'night' ? 'white' : 'gold';
if (!paypalClientId) {
return null;
}
return (
<div className={'paypal-buttons-container'}>
{/* help needed */}
<PayPalButtonScriptLoader
clientId={paypalClientId}
createOrder={(
data: unknown,
actions: {
order: {
create: (arg0: {
purchase_units: {
amount: { currency_code: string; value: string };
}[];
}) => unknown;
};
}
) => {
return actions.order.create({
purchase_units: [
{
amount: {
currency_code: 'USD',
value: (amount / 100).toString()
}
}
]
});
}}
createSubscription={(
data: unknown,
actions: {
subscription: {
create: (arg0: { plan_id: string | null }) => unknown;
};
}
) => {
return actions.subscription.create({
plan_id: planId
});
}}
isSubscription={isSubscription}
onApprove={(data: AddDonationData) => {
this.handleApproval(data, isSubscription);
}}
onCancel={() => {
this.props.onDonationStateChange({
redirecting: false,
processing: false,
success: false,
error: t('donate.failed-pay')
});
}}
onError={() =>
this.props.onDonationStateChange({
redirecting: false,
processing: false,
success: false,
error: t('donate.try-again')
})
}
planId={planId}
style={{
tagline: false,
height: 43,
color: buttonColor
}}
/>
</div>
);
}
}
const mapStateToProps = createSelector(
userSelector,
signInLoadingSelector,
({ isDonating }: { isDonating: boolean }, showLoading: boolean) => ({
isDonating,
showLoading
})
);
PaypalButton.displayName = 'PaypalButton';
export default connect(mapStateToProps)(withTranslation()(PaypalButton));