Skip to content
Permalink
Browse files

fix(donate): implement donate page

  • Loading branch information
raisedadead committed Dec 20, 2019
1 parent 5609a13 commit e4590fed5c5b25e2a0fa22c36060a8070dac8c34
@@ -170,16 +170,6 @@ export default function donateBoot(app, done) {
};

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(customer => {
return duration === 'onetime'
@@ -194,10 +184,7 @@ export default function donateBoot(app, done) {
})
.then(createAsyncUserDonation)
.catch(err => {
if (
err.type === 'StripeCardError' ||
err.type === 'AlreadyDonatingError'
) {
if (err.type === 'StripeCardError') {
return res.status(402).send({ error: err.message });
}
return res
@@ -7,7 +7,7 @@ import { createSelector } from 'reselect';
import { Grid, Row, Col, Image, Button } from '@freecodecamp/react-bootstrap';
import FreeCodeCampLogo from '../assets/icons/freeCodeCampLogo';
// eslint-disable-next-line max-len
import MinimalDonateForm from '../components/Donation/components/MinimalDonateForm';
import MinimalDonateForm from '../components/Donation/MinimalDonateForm';

import {
showCertSelector,
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Alert, Button } from '@freecodecamp/react-bootstrap';
import Spinner from 'react-spinkit';

import '../Donation.css';
import './Donation.css';

const propTypes = {
error: PropTypes.string,
@@ -18,19 +18,17 @@ import {
durationsConfig,
defaultAmount,
defaultStateConfig
} from '../../../../../config/donation-settings';
} from '../../../../config/donation-settings';
import { apiLocation } from '../../../../config/env.json';
import Spacer from '../../helpers/Spacer';
import Spacer from '../helpers/Spacer';
import DonateFormChildViewForHOC from './DonateFormChildViewForHOC';
import {
userSelector,
isSignedInSelector,
signInLoadingSelector,
hardGoTo as navigate
} from '../../../redux';
} from '../../redux';

import '../Donation.css';
import DonateCompletion from './DonateCompletion.js';
import './Donation.css';

const numToCommas = num =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
@@ -46,11 +44,9 @@ const propTypes = {
};

const mapStateToProps = createSelector(
userSelector,
signInLoadingSelector,
isSignedInSelector,
({ isDonating }, showLoading, isSignedIn) => ({
isDonating,
(showLoading, isSignedIn) => ({
isSignedIn,
showLoading
})
@@ -74,8 +70,7 @@ class DonateForm extends Component {

this.state = {
...defaultStateConfig,
processing: false,
isDonating: this.props.isDonating
processing: false
};

this.getActiveDonationAmount = this.getActiveDonationAmount.bind(this);
@@ -222,17 +217,7 @@ class DonateForm extends Component {
}

render() {
const { isSignedIn, navigate, showLoading, isDonating } = this.props;

if (isDonating) {
return (
<Row>
<Col sm={10} smOffset={1} xs={12}>
<DonateCompletion success={true} />
</Col>
</Row>
);
}
const { isSignedIn, navigate, showLoading } = this.props;

return (
<Row>
@@ -15,8 +15,8 @@ import { injectStripe } from 'react-stripe-elements';

import StripeCardForm from './StripeCardForm';
import DonateCompletion from './DonateCompletion';
import { postChargeStripe } from '../../../utils/ajax';
import { userSelector } from '../../../redux';
import { postChargeStripe } from '../../utils/ajax';
import { userSelector } from '../../redux';

const propTypes = {
showCloseBtn: PropTypes.func,
@@ -0,0 +1,39 @@
import React from 'react';
import { Row, Col } from '@freecodecamp/react-bootstrap';

const DonateText = () => {
return (
<Row className='donate-text'>
<Col sm={10} smOffset={1} xs={12}>
<p>freeCodeCamp is a highly efficient education nonprofit.</p>
<p>
In 2019 alone, we provided 18 million hours of free education to
people around the world.
</p>
<p>
Since freeCodeCamp's total budget is only $373,000, that means every
dollar you donate to freeCodeCamp translates into 50 hours worth of
technology education.
</p>
<p>
When you donate to freeCodeCamp, you help people learn new skills and
provide for their families.
</p>
<p>
You also help us create new resources for you to use to expand your
own technology skills.
</p>
<hr />
<h4>
<b>Need help with your existing or past donations?</b>
</h4>
<p>
Send an email to team@freeCodeCamp.org with a copy of your donation
receipt and we will be happy to resolve your query.
</p>
</Col>
</Row>
);
};
DonateText.displayName = 'DonateText';
export default DonateText;
@@ -5,22 +5,22 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Modal, Button, Col, Row } from '@freecodecamp/react-bootstrap';
import { Spacer } from '../../../components/helpers';
import { blockNameify } from '../../../../utils/blockNameify';
import Heart from '../../../assets/icons/Heart';
import Cup from '../../../assets/icons/Cup';
import { Spacer } from '../helpers';
import { blockNameify } from '../../../utils/blockNameify';
import Heart from '../../assets/icons/Heart';
import Cup from '../../assets/icons/Cup';
import MinimalDonateForm from './MinimalDonateForm';

import ga from '../../../analytics';
import ga from '../../analytics';
import {
closeDonationModal,
isDonationModalOpenSelector,
isBlockDonationModalSelector
} from '../../../redux';
} from '../../redux';

import { challengeMetaSelector } from '../../../templates/Challenges/redux';
import { challengeMetaSelector } from '../../templates/Challenges/redux';

import '../Donation.css';
import './Donation.css';

const mapStateToProps = createSelector(
isDonationModalOpenSelector,
@@ -1,5 +1,3 @@
/* eslint-disable react/sort-prop-types */
/* eslint-disable react/jsx-sort-props */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
@@ -10,23 +8,19 @@ import { StripeProvider, Elements } from 'react-stripe-elements';
import {
amountsConfig,
durationsConfig,
defaultStateConfig
} from '../../../../../config/donation-settings';
modalDefaultStateConfig
} from '../../../../config/donation-settings';
import { stripePublicKey } from '../../../../config/env.json';
import { stripeScriptLoader } from '../../utils/scriptLoaders';
import DonateFormChildViewForHOC from './DonateFormChildViewForHOC';
import { userSelector } from '../../../redux';
import { userSelector } from '../../redux';

import '../Donation.css';
import DonateCompletion from './DonateCompletion.js';
import { stripePublicKey } from '../../../../../config/env.json';
import { stripeScriptLoader } from '../../../utils/scriptLoaders';

const numToCommas = num =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
import './Donation.css';

const propTypes = {
showCloseBtn: PropTypes.func,
defaultTheme: PropTypes.string,
isDonating: PropTypes.bool,
showCloseBtn: PropTypes.func,
stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired
})
@@ -39,21 +33,19 @@ const mapStateToProps = createSelector(
})
);

class ModalDonateForm extends Component {
class MinimalDonateForm extends Component {
constructor(...args) {
super(...args);

this.durations = durationsConfig;
this.amounts = amountsConfig;

this.state = {
...defaultStateConfig,
...modalDefaultStateConfig,
isDonating: this.props.isDonating,
stripe: null
};
this.handleSelectPaymentType = this.handleSelectPaymentType.bind(this);
this.handleStripeLoad = this.handleStripeLoad.bind(this);
this.getDonationButtonLabel = this.getDonationButtonLabel.bind(this);
}

componentDidMount() {
@@ -85,91 +77,36 @@ class ModalDonateForm extends Component {
}
}

handleSelectPaymentType(e) {
this.setState({
paymentType: e.currentTarget.value
});
}

getFormatedAmountLabel(amount) {
return `$${numToCommas(amount / 100)}`;
}

getDonationButtonLabel() {
const { donationAmount, donationDuration } = this.state;
let donationBtnLabel = `Confirm your donation`;
if (donationDuration === 'onetime') {
donationBtnLabel = `Confirm your one-time donation of ${this.getFormatedAmountLabel(
donationAmount
)}`;
} else {
donationBtnLabel = `Confirm your donation of ${this.getFormatedAmountLabel(
donationAmount
)} ${donationDuration === 'month' ? 'per month' : 'per year'}`;
}
return donationBtnLabel;
}

renderDonationOptions() {
const {
donationAmount,
donationDuration,
paymentType,
stripe
} = this.state;

render() {
const { donationAmount, donationDuration, stripe } = this.state;
const { showCloseBtn, defaultTheme } = this.props;

return (
<div>
{paymentType === 'Card' ? (
<Row>
<Col sm={10} smOffset={1} xs={12}>
<StripeProvider stripe={stripe}>
<Elements>
<DonateFormChildViewForHOC
showCloseBtn={showCloseBtn}
defaultTheme={defaultTheme}
donationAmount={donationAmount}
donationDuration={donationDuration}
getDonationButtonLabel={this.getDonationButtonLabel}
getDonationButtonLabel={() =>
`Confirm your donation of $5 per month`
}
showCloseBtn={showCloseBtn}
/>
</Elements>
</StripeProvider>
) : (
<p>
PayPal is currently unavailable. Please use a Credit/Debit card
instead.
</p>
)}
</div>
);
}

render() {
const { isDonating } = this.props;

if (isDonating) {
return (
<Row>
<Col sm={10} smOffset={1} xs={12}>
<DonateCompletion success={true} />
</Col>
</Row>
);
}

return (
<Row>
<Col sm={10} smOffset={1} xs={12}>
{this.renderDonationOptions()}
</Col>
</Row>
);
}
}

ModalDonateForm.displayName = 'ModalDonateForm';
ModalDonateForm.propTypes = propTypes;
MinimalDonateForm.displayName = 'MinimalDonateForm';
MinimalDonateForm.propTypes = propTypes;

export default connect(
mapStateToProps,
null
)(ModalDonateForm);
)(MinimalDonateForm);

0 comments on commit e4590fe

Please sign in to comment.
You can’t perform that action at this time.