fix: remove all year-end gift implementation (#38030)
This commit is contained in:
@ -14,7 +14,6 @@ const log = debug('fcc:boot:donate');
|
|||||||
|
|
||||||
export default function donateBoot(app, done) {
|
export default function donateBoot(app, done) {
|
||||||
let stripe = false;
|
let stripe = false;
|
||||||
const { User } = app.models;
|
|
||||||
const api = app.loopback.Router();
|
const api = app.loopback.Router();
|
||||||
const donateRouter = app.loopback.Router();
|
const donateRouter = app.loopback.Router();
|
||||||
|
|
||||||
@ -170,6 +169,16 @@ export default function donateBoot(app, done) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return Promise.resolve(user)
|
return Promise.resolve(user)
|
||||||
|
.then(nonDonatingUser => {
|
||||||
|
const { isDonating } = nonDonatingUser;
|
||||||
|
if (isDonating) {
|
||||||
|
throw {
|
||||||
|
message: `User already has active donation(s).`,
|
||||||
|
type: 'AlreadyDonatingError'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return nonDonatingUser;
|
||||||
|
})
|
||||||
.then(createCustomer)
|
.then(createCustomer)
|
||||||
.then(customer => {
|
.then(customer => {
|
||||||
return duration === 'onetime'
|
return duration === 'onetime'
|
||||||
@ -184,92 +193,10 @@ export default function donateBoot(app, done) {
|
|||||||
})
|
})
|
||||||
.then(createAsyncUserDonation)
|
.then(createAsyncUserDonation)
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (err.type === 'StripeCardError') {
|
if (
|
||||||
return res.status(402).send({ error: err.message });
|
err.type === 'StripeCardError' ||
|
||||||
}
|
err.type === 'AlreadyDonatingError'
|
||||||
return res
|
) {
|
||||||
.status(500)
|
|
||||||
.send({ error: 'Donation failed due to a server error.' });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createStripeDonationYearEnd(req, res) {
|
|
||||||
const { user, body } = req;
|
|
||||||
|
|
||||||
const {
|
|
||||||
amount,
|
|
||||||
duration,
|
|
||||||
token: { email, id }
|
|
||||||
} = body;
|
|
||||||
|
|
||||||
if (amount < 1 || duration !== 'onetime' || !isEmail(email)) {
|
|
||||||
return res.status(500).send({
|
|
||||||
error: 'The donation form had invalid values for this submission.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const fccUser = user
|
|
||||||
? Promise.resolve(user)
|
|
||||||
: new Promise((resolve, reject) =>
|
|
||||||
User.findOrCreate(
|
|
||||||
{ where: { email } },
|
|
||||||
{ email },
|
|
||||||
(err, instance, isNew) => {
|
|
||||||
log('is new user instance: ', isNew);
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
return resolve(instance);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
let donatingUser = {};
|
|
||||||
let donation = {
|
|
||||||
email,
|
|
||||||
amount,
|
|
||||||
duration,
|
|
||||||
provider: 'stripe',
|
|
||||||
startDate: new Date(Date.now()).toISOString()
|
|
||||||
};
|
|
||||||
|
|
||||||
const createCustomer = user => {
|
|
||||||
donatingUser = user;
|
|
||||||
return stripe.customers.create({
|
|
||||||
email,
|
|
||||||
card: id
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createOneTimeCharge = customer => {
|
|
||||||
donation.customerId = customer.id;
|
|
||||||
return stripe.charges.create({
|
|
||||||
amount: amount,
|
|
||||||
currency: 'usd',
|
|
||||||
customer: customer.id
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const createAsyncUserDonation = () => {
|
|
||||||
donatingUser
|
|
||||||
.createDonation(donation)
|
|
||||||
.toPromise()
|
|
||||||
.catch(err => {
|
|
||||||
throw new Error(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return Promise.resolve(fccUser)
|
|
||||||
.then(createCustomer)
|
|
||||||
.then(customer => {
|
|
||||||
return createOneTimeCharge(customer).then(charge => {
|
|
||||||
donation.subscriptionId = 'one-time-charge-prefix-' + charge.id;
|
|
||||||
return res.send(charge);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(createAsyncUserDonation)
|
|
||||||
.catch(err => {
|
|
||||||
if (err.type === 'StripeCardError') {
|
|
||||||
return res.status(402).send({ error: err.message });
|
return res.status(402).send({ error: err.message });
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
@ -333,12 +260,10 @@ export default function donateBoot(app, done) {
|
|||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
api.post('/charge-stripe', createStripeDonation);
|
api.post('/charge-stripe', createStripeDonation);
|
||||||
api.post('/charge-stripe-year-end', createStripeDonationYearEnd);
|
|
||||||
api.post('/create-hmac-hash', createHmacHash);
|
api.post('/create-hmac-hash', createHmacHash);
|
||||||
donateRouter.use('/donate', api);
|
donateRouter.use('/donate', api);
|
||||||
app.use(donateRouter);
|
app.use(donateRouter);
|
||||||
app.use('/internal', donateRouter);
|
app.use('/internal', donateRouter);
|
||||||
app.use('/unauthenticated', donateRouter);
|
|
||||||
connectToStripe().then(done);
|
connectToStripe().then(done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,25 +9,16 @@ const propTypes = {
|
|||||||
error: PropTypes.string,
|
error: PropTypes.string,
|
||||||
processing: PropTypes.bool,
|
processing: PropTypes.bool,
|
||||||
reset: PropTypes.func.isRequired,
|
reset: PropTypes.func.isRequired,
|
||||||
success: PropTypes.bool,
|
success: PropTypes.bool
|
||||||
yearEndGift: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function DonateCompletion({
|
function DonateCompletion({ processing, reset, success, error = null }) {
|
||||||
processing,
|
|
||||||
reset,
|
|
||||||
success,
|
|
||||||
error = null,
|
|
||||||
yearEndGift = false
|
|
||||||
}) {
|
|
||||||
/* eslint-disable no-nested-ternary */
|
/* eslint-disable no-nested-ternary */
|
||||||
const style = processing ? 'info' : success ? 'success' : 'danger';
|
const style = processing ? 'info' : success ? 'success' : 'danger';
|
||||||
const heading = processing
|
const heading = processing
|
||||||
? 'We are processing your donation.'
|
? 'We are processing your donation.'
|
||||||
: success
|
: success
|
||||||
? yearEndGift
|
? 'Thank you for being a supporter.'
|
||||||
? 'Thank you for your donation.'
|
|
||||||
: 'Thank you for being a supporter.'
|
|
||||||
: 'Something went wrong with your donation.';
|
: 'Something went wrong with your donation.';
|
||||||
return (
|
return (
|
||||||
<Alert bsStyle={style} className='donation-completion'>
|
<Alert bsStyle={style} className='donation-completion'>
|
||||||
@ -43,7 +34,7 @@ function DonateCompletion({
|
|||||||
name='line-scale'
|
name='line-scale'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{success && !yearEndGift && (
|
{success && (
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
Your donations will support free technology education for people
|
Your donations will support free technology education for people
|
||||||
@ -55,11 +46,6 @@ function DonateCompletion({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{success && yearEndGift && (
|
|
||||||
<div>
|
|
||||||
<p>You should receive a receipt in your email.</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{error && <p>{error}</p>}
|
{error && <p>{error}</p>}
|
||||||
</div>
|
</div>
|
||||||
<div className='donation-completion-buttons'>
|
<div className='donation-completion-buttons'>
|
||||||
|
@ -29,8 +29,7 @@ const propTypes = {
|
|||||||
stripe: PropTypes.shape({
|
stripe: PropTypes.shape({
|
||||||
createToken: PropTypes.func.isRequired
|
createToken: PropTypes.func.isRequired
|
||||||
}),
|
}),
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string
|
||||||
yearEndGift: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
const initialState = {
|
const initialState = {
|
||||||
donationState: {
|
donationState: {
|
||||||
@ -134,7 +133,6 @@ class DonateFormChildViewForHOC extends Component {
|
|||||||
|
|
||||||
postDonation(token) {
|
postDonation(token) {
|
||||||
const { donationAmount: amount, donationDuration: duration } = this.state;
|
const { donationAmount: amount, donationDuration: duration } = this.state;
|
||||||
const { yearEndGift } = this.props;
|
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
...state,
|
...state,
|
||||||
donationState: {
|
donationState: {
|
||||||
@ -152,7 +150,7 @@ class DonateFormChildViewForHOC extends Component {
|
|||||||
this.props.showCloseBtn();
|
this.props.showCloseBtn();
|
||||||
}
|
}
|
||||||
|
|
||||||
return postChargeStripe(yearEndGift, {
|
return postChargeStripe({
|
||||||
token,
|
token,
|
||||||
amount,
|
amount,
|
||||||
duration
|
duration
|
||||||
@ -275,14 +273,12 @@ class DonateFormChildViewForHOC extends Component {
|
|||||||
const {
|
const {
|
||||||
donationState: { processing, success, error }
|
donationState: { processing, success, error }
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const { yearEndGift } = this.props;
|
|
||||||
if (processing || success || error) {
|
if (processing || success || error) {
|
||||||
return this.renderCompletion({
|
return this.renderCompletion({
|
||||||
processing,
|
processing,
|
||||||
success,
|
success,
|
||||||
error,
|
error,
|
||||||
reset: this.resetDonation,
|
reset: this.resetDonation
|
||||||
yearEndGift
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.renderDonateForm();
|
return this.renderDonateForm();
|
||||||
|
@ -1,284 +0,0 @@
|
|||||||
/* eslint-disable react/sort-prop-types */
|
|
||||||
/* eslint-disable react/jsx-sort-props */
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import {
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
ControlLabel,
|
|
||||||
FormControl,
|
|
||||||
FormGroup,
|
|
||||||
Button
|
|
||||||
} from '@freecodecamp/react-bootstrap';
|
|
||||||
import { StripeProvider, Elements } from 'react-stripe-elements';
|
|
||||||
import { Spacer } from '../helpers';
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
import DonateFormChildViewForHOC from '../Donation/DonateFormChildViewForHOC';
|
|
||||||
|
|
||||||
import './YearEndGift.css';
|
|
||||||
import '../Donation/Donation.css';
|
|
||||||
import { stripePublicKey } from '../../../../config/env.json';
|
|
||||||
import { stripeScriptLoader } from '../../utils/scriptLoaders';
|
|
||||||
import DonateWithPayPal from '../../assets/icons/DonateWithPayPal';
|
|
||||||
|
|
||||||
const numToCommas = num =>
|
|
||||||
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
showCloseBtn: PropTypes.func,
|
|
||||||
defaultTheme: PropTypes.string,
|
|
||||||
isDonating: PropTypes.bool,
|
|
||||||
stripe: PropTypes.shape({
|
|
||||||
createToken: PropTypes.func.isRequired
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
class YearEndDonationForm extends Component {
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args);
|
|
||||||
this.state = {
|
|
||||||
donationAmount: 25000,
|
|
||||||
showOtherAmounts: false,
|
|
||||||
stripe: null
|
|
||||||
};
|
|
||||||
this.handleStripeLoad = this.handleStripeLoad.bind(this);
|
|
||||||
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
|
|
||||||
this.handleSelectAmount = this.handleSelectAmount.bind(this);
|
|
||||||
this.handleChange = this.handleChange.bind(this);
|
|
||||||
this.handleClick = this.handleClick.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (window.Stripe) {
|
|
||||||
this.handleStripeLoad();
|
|
||||||
} else if (document.querySelector('#stripe-js')) {
|
|
||||||
document
|
|
||||||
.querySelector('#stripe-js')
|
|
||||||
.addEventListener('load', this.handleStripeLoad);
|
|
||||||
} else {
|
|
||||||
stripeScriptLoader(this.handleStripeLoad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
const stripeMountPoint = document.querySelector('#stripe-js');
|
|
||||||
if (stripeMountPoint) {
|
|
||||||
stripeMountPoint.removeEventListener('load', this.handleStripeLoad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleStripeLoad() {
|
|
||||||
// Create Stripe instance once Stripe.js loads
|
|
||||||
if (stripePublicKey) {
|
|
||||||
this.setState(state => ({
|
|
||||||
...state,
|
|
||||||
stripe: window.Stripe(stripePublicKey)
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getDonationButtonLabel() {
|
|
||||||
const { donationAmount } = this.state;
|
|
||||||
let donationBtnLabel = `Confirm your donation`;
|
|
||||||
donationBtnLabel = `Confirm your one-time donation of $${numToCommas(
|
|
||||||
donationAmount / 100
|
|
||||||
)}`;
|
|
||||||
return donationBtnLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDonationOptions() {
|
|
||||||
const { donationAmount, stripe } = this.state;
|
|
||||||
|
|
||||||
const { showCloseBtn, defaultTheme } = this.props;
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<StripeProvider stripe={stripe}>
|
|
||||||
<Elements>
|
|
||||||
<DonateFormChildViewForHOC
|
|
||||||
showCloseBtn={showCloseBtn}
|
|
||||||
defaultTheme={defaultTheme}
|
|
||||||
donationAmount={donationAmount}
|
|
||||||
donationDuration='onetime'
|
|
||||||
getDonationButtonLabel={this.getDonationButtonLabel}
|
|
||||||
yearEndGift={true}
|
|
||||||
/>
|
|
||||||
</Elements>
|
|
||||||
</StripeProvider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSelectAmount(e) {
|
|
||||||
this.setState({ donationAmount: Number(e.target.value) });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange(e) {
|
|
||||||
if (isNaN(e.target.value)) return;
|
|
||||||
const amount = Math.floor(e.target.value) * 100;
|
|
||||||
this.setState({ donationAmount: amount });
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAmountRadio() {
|
|
||||||
return (
|
|
||||||
<form className='radio-container'>
|
|
||||||
<label>Suggested gift amounts:</label>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
value={100000}
|
|
||||||
checked={this.state.donationAmount === 100000}
|
|
||||||
onChange={this.handleSelectAmount}
|
|
||||||
/>
|
|
||||||
$1,000
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
value={25000}
|
|
||||||
checked={this.state.donationAmount === 25000}
|
|
||||||
onChange={this.handleSelectAmount}
|
|
||||||
/>
|
|
||||||
$250
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<label>
|
|
||||||
<input
|
|
||||||
type='radio'
|
|
||||||
value={10000}
|
|
||||||
checked={this.state.donationAmount === 10000}
|
|
||||||
onChange={this.handleSelectAmount}
|
|
||||||
/>
|
|
||||||
$100
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCustomAmountInput() {
|
|
||||||
return (
|
|
||||||
<form>
|
|
||||||
<FormGroup controlId='formBasicText'>
|
|
||||||
<ControlLabel>Or give a custom amount:</ControlLabel>
|
|
||||||
<FormControl
|
|
||||||
type='text'
|
|
||||||
value={this.state.donationAmount / 100}
|
|
||||||
placeholder='Enter Amount'
|
|
||||||
onChange={this.handleChange}
|
|
||||||
/>
|
|
||||||
<FormControl.Feedback />
|
|
||||||
</FormGroup>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderPayPalDonations() {
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
action='https://www.paypal.com/cgi-bin/webscr'
|
|
||||||
method='post'
|
|
||||||
target='_top'
|
|
||||||
>
|
|
||||||
<input type='hidden' name='cmd' value='_s-xclick' />
|
|
||||||
<input type='hidden' name='hosted_button_id' value='9C73W6CWSLNPW' />
|
|
||||||
<button
|
|
||||||
type='submit'
|
|
||||||
name='submit'
|
|
||||||
className='btn btn-block btn-cta paypal-button'
|
|
||||||
alt='donate with paypal'
|
|
||||||
>
|
|
||||||
<DonateWithPayPal />
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderForm(item) {
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
action='https://www.paypal.com/cgi-bin/webscr'
|
|
||||||
method='post'
|
|
||||||
target='_blank'
|
|
||||||
>
|
|
||||||
<input defaultValue='_s-xclick' name='cmd' type='hidden' />{' '}
|
|
||||||
<input
|
|
||||||
defaultValue={item.defaultValueHash}
|
|
||||||
name='hosted_button_id'
|
|
||||||
type='hidden'
|
|
||||||
/>{' '}
|
|
||||||
<input
|
|
||||||
className='btn btn-block'
|
|
||||||
value={item.defaultValue}
|
|
||||||
name='submit'
|
|
||||||
type='submit'
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick() {
|
|
||||||
this.setState({ showOtherAmounts: true, donationAmount: 25000 });
|
|
||||||
}
|
|
||||||
|
|
||||||
renderOtherPaymentButton() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Button className='btn-link' onClick={this.handleClick}>
|
|
||||||
<b>Or give a custom amount</b>
|
|
||||||
</Button>
|
|
||||||
<Spacer />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Row>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
<b>
|
|
||||||
Thank you again for supporting freeCodeCamp.org with a one-time
|
|
||||||
year-end gift. Please enter your credit card information below.
|
|
||||||
</b>
|
|
||||||
<Spacer />
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
{this.renderAmountRadio()}
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
{this.state.showOtherAmounts
|
|
||||||
? this.renderCustomAmountInput()
|
|
||||||
: this.renderOtherPaymentButton()}
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
{this.renderDonationOptions()}
|
|
||||||
<Spacer />
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12} style={{ marginBottom: '5px' }}>
|
|
||||||
<b>Or give using PayPal:</b>
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
{this.renderPayPalDonations()}
|
|
||||||
<Spacer />
|
|
||||||
</Col>
|
|
||||||
<Col sm={10} smOffset={1} xs={12}>
|
|
||||||
<b>
|
|
||||||
If you need a receipt from your taxes, reply to Quincy's email he
|
|
||||||
sent you.
|
|
||||||
</b>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
YearEndDonationForm.displayName = 'YearEndDonationForm';
|
|
||||||
YearEndDonationForm.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default YearEndDonationForm;
|
|
@ -1,18 +0,0 @@
|
|||||||
.radio-container ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-container li label {
|
|
||||||
padding: 7px 20px 6px 0px;
|
|
||||||
max-width: 100%;
|
|
||||||
height: 40px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.radio-container li label input {
|
|
||||||
height: 17px;
|
|
||||||
width: 17px;
|
|
||||||
margin: auto 5px auto 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import Helmet from 'react-helmet';
|
|
||||||
import { Grid, Alert } from '@freecodecamp/react-bootstrap';
|
|
||||||
|
|
||||||
import { Spacer, FullWidthRow } from '../components/helpers';
|
|
||||||
|
|
||||||
import '../components/Donation/Donation.css';
|
|
||||||
|
|
||||||
function YearEndGiftPage() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet title='Support our nonprofit | freeCodeCamp.org' />
|
|
||||||
<Grid>
|
|
||||||
<main>
|
|
||||||
<Spacer size={3} />
|
|
||||||
<FullWidthRow>
|
|
||||||
<Alert bsStyle='success' className='donation-completion'>
|
|
||||||
<div>
|
|
||||||
<h4>
|
|
||||||
<b>Thank you for your donation.</b>
|
|
||||||
</h4>
|
|
||||||
<p>You should receive a receipt in your email.</p>
|
|
||||||
</div>
|
|
||||||
</Alert>
|
|
||||||
</FullWidthRow>
|
|
||||||
<Spacer size={2} />
|
|
||||||
</main>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
YearEndGiftPage.displayName = 'YearEndGiftPage';
|
|
||||||
|
|
||||||
export default YearEndGiftPage;
|
|
@ -1,28 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import Helmet from 'react-helmet';
|
|
||||||
import { Grid } from '@freecodecamp/react-bootstrap';
|
|
||||||
|
|
||||||
import { Spacer, FullWidthRow } from '../components/helpers';
|
|
||||||
import YearEndDonationForm from '../components/YearEndGift/YearEndDonationForm';
|
|
||||||
|
|
||||||
function YearEndGiftPage() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet title='Support our nonprofit | freeCodeCamp.org' />
|
|
||||||
<Grid>
|
|
||||||
<main>
|
|
||||||
<Spacer />
|
|
||||||
<FullWidthRow>
|
|
||||||
<YearEndDonationForm defaultTheme='light' />
|
|
||||||
</FullWidthRow>
|
|
||||||
<Spacer />
|
|
||||||
<Spacer />
|
|
||||||
</main>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
YearEndGiftPage.displayName = 'YearEndGiftPage';
|
|
||||||
|
|
||||||
export default YearEndGiftPage;
|
|
@ -50,10 +50,8 @@ export function getArticleById(shortId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** POST **/
|
/** POST **/
|
||||||
export function postChargeStripe(yearEndGift, body) {
|
export function postChargeStripe(body) {
|
||||||
return yearEndGift
|
return post('/donate/charge-stripe', body);
|
||||||
? postUnauthenticated('/donate/charge-stripe-year-end', body)
|
|
||||||
: post('/donate/charge-stripe', body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postCreateHmacHash(body) {
|
export function postCreateHmacHash(body) {
|
||||||
|
@ -29,11 +29,7 @@ export default function layoutSelector({ element, props }) {
|
|||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (
|
if (/^\/donation(\/.*)*|^\/donate(\/.*)*/.test(pathname)) {
|
||||||
/^\/donation(\/.*)*|^\/donate(\/.*)*/.test(pathname) ||
|
|
||||||
/^\/year-end-gift-successful(\/.*)*/.test(pathname) ||
|
|
||||||
/^\/year-end-gift(\/.*)*/.test(pathname)
|
|
||||||
) {
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout pathname={pathname} useTheme={false}>
|
<DefaultLayout pathname={pathname} useTheme={false}>
|
||||||
{element}
|
{element}
|
||||||
|
Reference in New Issue
Block a user