diff --git a/client/src/components/Donation/donation.css b/client/src/components/Donation/Donation.css
similarity index 55%
rename from client/src/components/Donation/donation.css
rename to client/src/components/Donation/Donation.css
index 8d1b4229b8..3477da2134 100644
--- a/client/src/components/Donation/donation.css
+++ b/client/src/components/Donation/Donation.css
@@ -1,5 +1,5 @@
.donation-modal {
- font-size: 1.2rem;
+ font-size: 0.8rem;
}
.donation-modal p {
@@ -18,43 +18,12 @@
width:80%;
justify-content: center;
margin: 0 auto;
- height: 300px;
-}
-
-#donate-amount-panel ul {
- list-style: none;
- display: flex;
- margin-left: 0px;
-}
-
-#donate-amount-panel li {
- flex: 0.20;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
-#donate-amount-panel a {
- width: calc(100% - 20px);
- height: 75px;
- display: flex;
- justify-content: center;
- align-items: center;
- border: 2px solid #006400;
-}
-
-#donate-amount-panel a:hover, #donate-amount-panel a:focus, #donate-amount-panel a.active {
- text-decoration: none;
- color: white;
- background-color: #006400;
- font-weight: bold;
}
.donation-elements {
display: flex;
- height: 100%;
- flex-direction: column;
- justify-content: space-evenly;
+ flex-direction: row;
+ justify-content: space-between;
}
#donation-completion-body {
@@ -72,11 +41,6 @@
margin: 0 10px;
}
-.donation-email-container {
- width: 80%;
- margin: 0 auto;
-}
-
.donation-email-container label {
display: flex;
flex-direction: column;
@@ -85,12 +49,9 @@
.donation-email-container input {
color: #006400;
font-weight: normal;
- border: none;
}
.maybe-later-container {
- width: 80%;
- margin: 50px auto 0;
display: flex;
justify-content: center;
}
@@ -104,3 +65,30 @@
font-size: 18px;
cursor: pointer;
}
+
+.donate-input-element {
+ padding-top: 8px;
+}
+
+.donate-card-element {
+ min-width: 280px;
+ flex: 1 1 auto;
+}
+
+.donate-expiry-element {
+ min-width: 120px;
+ flex: 0 0 auto;
+}
+
+.donate-cvc-element {
+ min-width: 80px;
+ flex: 0 0 auto;
+}
+
+.StripeElement--focus {
+ border-color: #66afe9;
+ outline: 0;
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
+}
+
+
diff --git a/client/src/components/Donation/components/CardForm.js b/client/src/components/Donation/components/CardForm.js
deleted file mode 100644
index 64910c5895..0000000000
--- a/client/src/components/Donation/components/CardForm.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React, { PureComponent } from 'react';
-import PropTypes from 'prop-types';
-import { Button } from '@freecodecamp/react-bootstrap';
-
-import StripCardForm from './StripeCardForm';
-
-const propTypes = {
- amount: PropTypes.number.isRequired,
- handleSubmit: PropTypes.func.isRequired
-};
-
-class CardForm extends PureComponent {
- constructor(...props) {
- super(...props);
-
- this.state = {
- isFormValid: false
- };
-
- this.getValidationState = this.getValidationState.bind(this);
- this.submit = this.submit.bind(this);
- }
-
- submit(e) {
- e.preventDefault();
- this.props.handleSubmit();
- }
-
- getValidationState(isFormValid) {
- this.setState(state => ({
- ...state,
- isFormValid
- }));
- }
-
- render() {
- const { amount } = this.props;
- const { isFormValid } = this.state;
- return (
-
- );
- }
-}
-CardForm.displayName = 'CardForm';
-CardForm.propTypes = propTypes;
-
-export default CardForm;
diff --git a/client/src/components/Donation/components/DonateCompletion.js b/client/src/components/Donation/components/DonateCompletion.js
index 615ed06c1d..9a7f774444 100644
--- a/client/src/components/Donation/components/DonateCompletion.js
+++ b/client/src/components/Donation/components/DonateCompletion.js
@@ -11,7 +11,7 @@ const propTypes = {
success: PropTypes.bool
};
-function DonateCompletion({ processing, reset, success, error = null }) {
+function DonateCompletion({ close, processing, reset, success, error = null }) {
/* eslint-disable no-nested-ternary */
const style = processing ? 'info' : success ? 'success' : 'danger';
const heading = processing
@@ -43,6 +43,7 @@ function DonateCompletion({ processing, reset, success, error = null }) {
)}
+ {!processing && }
);
diff --git a/client/src/components/Donation/components/DonateForm.js b/client/src/components/Donation/components/DonateForm.js
index 2c683d2d9d..ca6189cb77 100644
--- a/client/src/components/Donation/components/DonateForm.js
+++ b/client/src/components/Donation/components/DonateForm.js
@@ -1,13 +1,22 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import isEmail from 'validator/lib/isEmail';
-
-import CardForm from './CardForm';
+import {
+ Button,
+ ControlLabel,
+ Form,
+ FormControl,
+ FormGroup
+} from '@freecodecamp/react-bootstrap';
import { injectStripe } from 'react-stripe-elements';
+
+import Spacer from '../../../components/helpers/Spacer';
+import StripeCardForm from './StripeCardForm';
import { postJSON$ } from '../../../templates/Challenges/utils/ajax-stream.js';
const propTypes = {
email: PropTypes.string,
+ maybeButton: PropTypes.func.isRequired,
renderCompletion: PropTypes.func.isRequired,
stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired
@@ -28,14 +37,31 @@ class DonateForm extends Component {
this.state = {
...initialSate,
- email: null
+ email: null,
+ isFormValid: false
};
this.getUserEmail = this.getUserEmail.bind(this);
+ this.getValidationState = this.getValidationState.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.postDonation = this.postDonation.bind(this);
this.resetDonation = this.resetDonation.bind(this);
+ this.submit = this.submit.bind(this);
+ }
+
+
+ getUserEmail() {
+ const { email: stateEmail } = this.state;
+ const { email: propsEmail } = this.props;
+ return stateEmail || propsEmail || '';
+ }
+
+ getValidationState(isFormValid) {
+ this.setState(state => ({
+ ...state,
+ isFormValid
+ }));
}
handleEmailChange(e) {
@@ -75,12 +101,6 @@ class DonateForm extends Component {
});
}
- getUserEmail() {
- const { email: stateEmail } = this.state;
- const { email: propsEmail } = this.props;
- return stateEmail || propsEmail || '';
- }
-
postDonation(token) {
const { donationAmount: amount } = this.state;
this.setState(state => ({
@@ -118,50 +138,50 @@ class DonateForm extends Component {
);
}
- renderDonateForm() {
- return (
-
-
-
- freeCodeCamp.org is a tiny nonprofit that's helping millions of
- people learn to code for free.
-
-
- Join 4,180 supporters.
-
-
- Your $5 / month donation will help keep tech education free and
- open.
-
-
-
- {this.renderEmailInput()}
-
-
- );
- }
-
- renderEmailInput() {
- return (
-
-
-
- );
+ submit(e) {
+ e.preventDefault();
+ this.handleSubmit();
}
resetDonation() {
return this.setState(() => initialSate);
}
+ renderDonateForm() {
+ const { isFormValid } = this.state;
+ return (
+
+
+ {this.props.maybeButton()}
+
+ );
+ }
+
render() {
const {
donationState: { processing, success, error }
diff --git a/client/src/components/Donation/Donation.js b/client/src/components/Donation/components/DonateModal.js
similarity index 57%
rename from client/src/components/Donation/Donation.js
rename to client/src/components/Donation/components/DonateModal.js
index d5e70772d5..b688bf2d7c 100644
--- a/client/src/components/Donation/Donation.js
+++ b/client/src/components/Donation/components/DonateModal.js
@@ -3,20 +3,24 @@ import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
-import { Modal } from '@freecodecamp/react-bootstrap';
+import { Modal, Button } from '@freecodecamp/react-bootstrap';
import { StripeProvider, Elements } from 'react-stripe-elements';
-import ga from '../../analytics';
-import DonateForm from './components/DonateForm';
-import DonateCompletion from './components/DonateCompletion';
+import { stripePublicKey } from '../../../../config/env.json';
+
+import ga from '../../../analytics';
+import DonateForm from './DonateForm';
+import DonateCompletion from './DonateCompletion';
import {
userSelector,
closeDonationModal,
isDonationModalOpenSelector
-} from '../../redux';
+} from '../../../redux';
-import './donation.css';
-import poweredByStripe from '../../images/powered_by_stripe.svg';
+import PoweredByStripe from './poweredByStripe';
+import DonateText from './DonateText';
+
+import '../Donation.css';
const mapStateToProps = createSelector(
userSelector,
@@ -38,9 +42,7 @@ const propTypes = {
show: PropTypes.bool
};
-const stripeKey = 'pk_live_E6Z6xPM8pEsJziHW905zpAvF';
-
-class DonationModal extends Component {
+class DonateModal extends Component {
constructor(...props) {
super(...props);
this.state = {
@@ -54,7 +56,7 @@ class DonationModal extends Component {
/* eslint-disable react/no-did-mount-set-state */
this.setState(state => ({
...state,
- stripe: window.Stripe(stripeKey)
+ stripe: window.Stripe(stripePublicKey)
}));
} else {
document.querySelector('#stripe-js').addEventListener('load', () => {
@@ -62,7 +64,7 @@ class DonationModal extends Component {
console.info('stripe has loaded');
this.setState(state => ({
...state,
- stripe: window.Stripe(stripeKey)
+ stripe: window.Stripe(stripePublicKey)
}));
});
}
@@ -77,12 +79,13 @@ class DonationModal extends Component {
renderMaybe() {
const { closeDonationModal } = this.props;
const handleClick = e => {
+ console.log(e.target);
e.preventDefault();
return closeDonationModal();
};
return (
-
+
);
}
@@ -93,36 +96,34 @@ class DonationModal extends Component {
ga.modalview('/donation-modal');
}
return (
-
-
-
-
-
- Support Our NonProfit
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ Support Our NonProfit
+
+
+
+
+
+
+
+
+
+
+
+
);
}
}
-DonationModal.displayName = 'DonationModal';
-DonationModal.propTypes = propTypes;
+DonateModal.displayName = 'DonateModal';
+DonateModal.propTypes = propTypes;
export default connect(
mapStateToProps,
@@ -131,4 +132,4 @@ export default connect(
{
pure: false
}
-)(DonationModal);
+)(DonateModal);
diff --git a/client/src/components/Donation/components/DonateText.js b/client/src/components/Donation/components/DonateText.js
new file mode 100644
index 0000000000..90e9221b73
--- /dev/null
+++ b/client/src/components/Donation/components/DonateText.js
@@ -0,0 +1,23 @@
+import React, { Component } from 'react';
+
+class DonateText extends Component {
+ render() {
+ return (
+
+
+ freeCodeCamp.org is a tiny nonprofit that's helping millions of
+ people learn to code for free.
+
+
+ Join 4,180 supporters.
+
+
+ Your $5 / month donation will help keep tech education free and
+ open.
+
+
+ );
+ }
+}
+
+export default DonateText;
diff --git a/client/src/components/Donation/components/StripeCardForm.js b/client/src/components/Donation/components/StripeCardForm.js
index f538a84019..2033c3fc8c 100644
--- a/client/src/components/Donation/components/StripeCardForm.js
+++ b/client/src/components/Donation/components/StripeCardForm.js
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
CardNumberElement,
@@ -7,17 +7,20 @@ import {
} from 'react-stripe-elements';
import { ControlLabel, FormGroup } from '@freecodecamp/react-bootstrap';
+import '../Donation.css';
+
const propTypes = {
getValidationState: PropTypes.func.isRequired
};
const style = {
base: {
- color: '#006400'
+ color: '#006400',
+ fontSize: '18px'
}
};
-class StripCardForm extends PureComponent {
+class StripeCardForm extends Component {
constructor(...props) {
super(...props);
@@ -74,23 +77,35 @@ class StripCardForm extends PureComponent {
return (
- Your Card Number:
-
+ Card Number:
+
- Your Card Expiration Month:
-
+ Expiry:
+
- Your Card CVC (3-digit security number):
-
+ CVC:
+
);
}
}
-StripCardForm.displayName = 'StripCardForm';
-StripCardForm.propTypes = propTypes;
+StripeCardForm.displayName = 'StripeCardForm';
+StripeCardForm.propTypes = propTypes;
-export default StripCardForm;
+export default StripeCardForm;
diff --git a/client/src/components/icons/poweredByStripe.js b/client/src/components/Donation/components/poweredByStripe.js
similarity index 100%
rename from client/src/components/icons/poweredByStripe.js
rename to client/src/components/Donation/components/poweredByStripe.js
diff --git a/client/src/components/Donation/index.js b/client/src/components/Donation/index.js
index ed478f8eb8..39cf10aca2 100644
--- a/client/src/components/Donation/index.js
+++ b/client/src/components/Donation/index.js
@@ -1 +1 @@
-export { default } from './Donation';
+export { default } from './components/DonateModal';
diff --git a/client/src/components/layouts/Learn.js b/client/src/components/layouts/Learn.js
index b6bda95557..2ff4ecce37 100644
--- a/client/src/components/layouts/Learn.js
+++ b/client/src/components/layouts/Learn.js
@@ -1,7 +1,7 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
-import DonationModal from '../Donation';
+import DonateModal from '../Donation';
import 'prismjs/themes/prism.css';
import 'react-reflex/styles.css';
@@ -11,7 +11,7 @@ function LearnLayout({ children }) {
return (
{children}
-
+
);
}
diff --git a/client/src/images/powered_by_stripe.svg b/client/src/images/powered_by_stripe.svg
deleted file mode 100644
index 43a92fa8ea..0000000000
--- a/client/src/images/powered_by_stripe.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
\ No newline at end of file
diff --git a/client/src/pages/donate.js b/client/src/pages/donate.js
index b79961aa66..8ae738e856 100644
--- a/client/src/pages/donate.js
+++ b/client/src/pages/donate.js
@@ -5,13 +5,16 @@ import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { StripeProvider, Elements } from 'react-stripe-elements';
import { createSelector } from 'reselect';
+import { Row, Col } from '@freecodecamp/react-bootstrap';
+import { stripePublicKey } from '../../config/env.json';
import { userSelector } from '../redux';
import Spacer from '../components/helpers/Spacer';
import DonateForm from '../components/Donation/components/DonateForm';
import DonateCompletion from '../components/Donation/components/DonateCompletion';
-import PoweredByStripe from '../components/icons/poweredByStripe';
+import DonateText from '../components/Donation/components/DonateText';
+import PoweredByStripe from '../components/Donation/components/poweredByStripe';
import './index.css';
@@ -24,16 +27,12 @@ const mapStateToProps = createSelector(userSelector, ({ email = '' }) => ({
email
}));
-// Stripe public key
-const stripeKey = 'pk_live_E6Z6xPM8pEsJziHW905zpAvF';
-
class IndexPage extends Component {
constructor(...props) {
super(...props);
this.state = {
stripe: null
};
-
this.handleStripeLoad = this.handleStripeLoad.bind(this);
}
componentDidMount() {
@@ -41,7 +40,7 @@ class IndexPage extends Component {
/* eslint-disable react/no-did-mount-set-state */
this.setState(state => ({
...state,
- stripe: window.Stripe(stripeKey)
+ stripe: window.Stripe(stripePublicKey)
}));
} else {
document
@@ -63,41 +62,47 @@ class IndexPage extends Component {
console.info('stripe has loaded');
this.setState(state => ({
...state,
- stripe: window.Stripe(stripeKey)
+ stripe: window.Stripe(stripePublicKey)
}));
}
renderCompletion(props) {
return {}} {...props} />;
}
+
render() {
const { email = '' } = this.props;
return (
-
+
+
+
+ Become a Supporter
+
+
+
+
+
+
+
+ null}
+ renderCompletion={this.renderCompletion}
+ />
+
+
+
+
+
+
+
);
}
}
diff --git a/client/src/redux/index.js b/client/src/redux/index.js
index 7956348051..1e71d6dbf9 100644
--- a/client/src/redux/index.js
+++ b/client/src/redux/index.js
@@ -255,6 +255,10 @@ export const reducer = handleActions(
...state,
showDonationModal: true
}),
+ [types.closeDonationModal]: state => ({
+ ...state,
+ showDonationModal: false
+ }),
[types.showCert]: state => ({
...state,
showCert: {},
diff --git a/config/env.js b/config/env.js
index 9d240e1e74..d258bbd70b 100644
--- a/config/env.js
+++ b/config/env.js
@@ -11,6 +11,7 @@ const {
FORUM_LOCATION: forum,
NEWS_LOCATION: news,
LOCALE: locale,
+ STRIPE_PUBLIC: stripePublicKey,
} = process.env;
const locations = {
@@ -20,4 +21,4 @@ const locations = {
newsLocation: news
};
-module.exports = Object.assign(locations, { locale });
+module.exports = Object.assign(locations, { locale, stripePublicKey });