fix: add paypal image and donate form verification (#37978)

Co-Authored-By: mrugesh <1884376+raisedadead@users.noreply.github.com>
This commit is contained in:
Ahmad Abdolsaheb
2019-12-30 18:40:46 +03:00
committed by mrugesh
parent 390d7671ed
commit 1d855b75b4
6 changed files with 160 additions and 73 deletions

View File

@ -0,0 +1,58 @@
/* eslint-disable max-len */
import React, { Fragment } from 'react';
const propTypes = {};
function DonateWithPayPal(props) {
return (
<Fragment>
<span className='sr-only'>Donate with PayPal</span>
<svg
height={31}
version='1.1'
viewBox='0 0 268 31'
width={200}
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<g fill='none' fillRule='evenodd'>
<g fillRule='nonzero'>
<path
d='m7.266 29.154 0.523-3.322-1.165-0.027h-5.563l3.866-24.513c0.023788-0.1548 0.15738-0.26883 0.314-0.268h9.38c3.114 0 5.263 0.648 6.385 1.927 0.526 0.6 0.861 1.227 1.023 1.917 0.17 0.724 0.173 1.589 7e-3 2.644l-0.012 0.077v0.676l0.526 0.298c0.40156 0.20344 0.7625 0.47864 1.065 0.812 0.45 0.513 0.741 1.165 0.864 1.938 0.127 0.795 0.085 1.741-0.123 2.812-0.24 1.232-0.628 2.305-1.152 3.183-0.46233 0.78655-1.084 1.4678-1.825 2-0.696 0.494-1.523 0.869-2.458 1.109-0.906 0.236-1.939 0.355-3.072 0.355h-0.73c-0.522 0-1.029 0.188-1.427 0.525-0.39744 0.3406-0.66109 0.8112-0.744 1.328l-0.055 0.299-0.924 5.855-0.042 0.215c-0.011 0.068-0.03 0.102-0.058 0.125-0.027124 0.022182-0.060964 0.03452-0.096 0.035h-4.507z'
fill='#253B80'
id='Path'
/>
<path
d='m23.048 7.667c-0.028 0.179-0.06 0.362-0.096 0.55-1.237 6.351-5.469 8.545-10.874 8.545h-2.752c-0.661 0-1.218 0.48-1.321 1.132l-1.409 8.936-0.399 2.533c-0.032166 0.20334 0.026281 0.41056 0.15996 0.56713 0.13367 0.15656 0.32918 0.24687 0.53504 0.24687h4.881c0.578 0 1.069-0.42 1.16-0.99l0.048-0.248 0.919-5.832 0.059-0.32c0.09-0.572 0.582-0.992 1.16-0.992h0.73c4.729 0 8.431-1.92 9.513-7.476 0.452-2.321 0.218-4.259-0.978-5.622-0.37907-0.42164-0.8318-0.77067-1.336-1.03z'
fill='#179BD7'
id='Path'
/>
<path
d='m21.754 7.151c-0.39497-0.11426-0.79677-0.20344-1.203-0.267-0.80268-0.12336-1.6139-0.18255-2.426-0.177h-7.352c-0.57812-3.5635e-4 -1.0702 0.42074-1.159 0.992l-1.564 9.906-0.045 0.289c0.10068-0.65161 0.66166-1.1323 1.321-1.132h2.752c5.405 0 9.637-2.195 10.874-8.545 0.037-0.188 0.068-0.371 0.096-0.55-0.32641-0.17117-0.66661-0.31467-1.017-0.429-0.091862-0.03048-0.18421-0.059484-0.277-0.087z'
fill='#222D65'
id='a'
/>
<path
d='m9.614 7.699c0.088048-0.57153 0.58073-0.9928 1.159-0.991h7.352c0.871 0 1.684 0.057 2.426 0.177 0.50211 0.078912 0.99728 0.19694 1.481 0.353 0.365 0.121 0.704 0.264 1.017 0.429 0.368-2.347-3e-3 -3.945-1.272-5.392-1.399-1.593-3.924-2.275-7.155-2.275h-9.38c-0.66 0-1.223 0.48-1.325 1.133l-3.907 24.765c-0.036828 0.23269 0.029989 0.46984 0.18288 0.64907 0.15289 0.17923 0.37654 0.28261 0.61212 0.28293h5.791l1.454-9.225 1.564-9.906z'
fill='#253B80'
/>
</g>
<text
fill='#000000'
fontFamily='PayPalSansSmallMedium-Regular, PayPal Sans Small Medium'
fontSize={25}
>
<tspan x='44.2924805' y={19}>
Donate with PayPal
</tspan>
</text>
</g>
</svg>
</Fragment>
);
}
DonateWithPayPal.displayName = 'DonateWithPayPal';
DonateWithPayPal.propTypes = propTypes;
export default DonateWithPayPal;

View File

@ -1,50 +0,0 @@
/* eslint-disable max-len */
import React, { Fragment } from 'react';
const propTypes = {};
function Paypal(props) {
return (
<Fragment>
<span className='sr-only'>Paypal</span>
<svg
height={33}
version='1.1'
viewBox='0 0 124 33'
width={124}
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<path
d='M46.211 6.749h-6.839a.95.95 0 0 0-.939.802l-2.766 17.537a.57.57 0 0 0 .564.658h3.265a.95.95 0 0 0 .939-.803l.746-4.73a.95.95 0 0 1 .938-.803h2.165c4.505 0 7.105-2.18 7.784-6.5.306-1.89.013-3.375-.872-4.415-.972-1.142-2.696-1.746-4.985-1.746zM47 13.154c-.374 2.454-2.249 2.454-4.062 2.454h-1.032l.724-4.583a.57.57 0 0 1 .563-.481h.473c1.235 0 2.4 0 3.002.704.359.42.469 1.044.332 1.906zM66.654 13.075h-3.275a.57.57 0 0 0-.563.481l-.145.916-.229-.332c-.709-1.029-2.29-1.373-3.868-1.373-3.619 0-6.71 2.741-7.312 6.586-.313 1.918.132 3.752 1.22 5.031.998 1.176 2.426 1.666 4.125 1.666 2.916 0 4.533-1.875 4.533-1.875l-.146.91a.57.57 0 0 0 .562.66h2.95a.95.95 0 0 0 .939-.803l1.77-11.209a.568.568 0 0 0-.561-.658zm-4.565 6.374c-.316 1.871-1.801 3.127-3.695 3.127-.951 0-1.711-.305-2.199-.883-.484-.574-.668-1.391-.514-2.301.295-1.855 1.805-3.152 3.67-3.152.93 0 1.686.309 2.184.892.499.589.697 1.411.554 2.317zM84.096 13.075h-3.291a.954.954 0 0 0-.787.417l-4.539 6.686-1.924-6.425a.953.953 0 0 0-.912-.678h-3.234a.57.57 0 0 0-.541.754l3.625 10.638-3.408 4.811a.57.57 0 0 0 .465.9h3.287a.949.949 0 0 0 .781-.408l10.946-15.8a.57.57 0 0 0-.468-.895z'
fill='#253B80'
/>
<path
d='M94.992 6.749h-6.84a.95.95 0 0 0-.938.802l-2.766 17.537a.569.569 0 0 0 .562.658h3.51a.665.665 0 0 0 .656-.562l.785-4.971a.95.95 0 0 1 .938-.803h2.164c4.506 0 7.105-2.18 7.785-6.5.307-1.89.012-3.375-.873-4.415-.971-1.142-2.694-1.746-4.983-1.746zm.789 6.405c-.373 2.454-2.248 2.454-4.062 2.454h-1.031l.725-4.583a.568.568 0 0 1 .562-.481h.473c1.234 0 2.4 0 3.002.704.359.42.468 1.044.331 1.906zM115.434 13.075h-3.273a.567.567 0 0 0-.562.481l-.145.916-.23-.332c-.709-1.029-2.289-1.373-3.867-1.373-3.619 0-6.709 2.741-7.311 6.586-.312 1.918.131 3.752 1.219 5.031 1 1.176 2.426 1.666 4.125 1.666 2.916 0 4.533-1.875 4.533-1.875l-.146.91a.57.57 0 0 0 .564.66h2.949a.95.95 0 0 0 .938-.803l1.771-11.209a.571.571 0 0 0-.565-.658zm-4.565 6.374c-.314 1.871-1.801 3.127-3.695 3.127-.949 0-1.711-.305-2.199-.883-.484-.574-.666-1.391-.514-2.301.297-1.855 1.805-3.152 3.67-3.152.93 0 1.686.309 2.184.892.501.589.699 1.411.554 2.317zM119.295 7.23l-2.807 17.858a.569.569 0 0 0 .562.658h2.822c.469 0 .867-.34.939-.803l2.768-17.536a.57.57 0 0 0-.562-.659h-3.16a.571.571 0 0 0-.562.482z'
fill='#179BD7'
/>
<path
d='M7.266 29.154l.523-3.322-1.165-.027H1.061L4.927 1.292a.316.316 0 0 1 .314-.268h9.38c3.114 0 5.263.648 6.385 1.927.526.6.861 1.227 1.023 1.917.17.724.173 1.589.007 2.644l-.012.077v.676l.526.298a3.69 3.69 0 0 1 1.065.812c.45.513.741 1.165.864 1.938.127.795.085 1.741-.123 2.812-.24 1.232-.628 2.305-1.152 3.183a6.547 6.547 0 0 1-1.825 2c-.696.494-1.523.869-2.458 1.109-.906.236-1.939.355-3.072.355h-.73c-.522 0-1.029.188-1.427.525a2.21 2.21 0 0 0-.744 1.328l-.055.299-.924 5.855-.042.215c-.011.068-.03.102-.058.125a.155.155 0 0 1-.096.035H7.266z'
fill='#253B80'
/>
<path
d='M23.048 7.667c-.028.179-.06.362-.096.55-1.237 6.351-5.469 8.545-10.874 8.545H9.326c-.661 0-1.218.48-1.321 1.132L6.596 26.83l-.399 2.533a.704.704 0 0 0 .695.814h4.881c.578 0 1.069-.42 1.16-.99l.048-.248.919-5.832.059-.32c.09-.572.582-.992 1.16-.992h.73c4.729 0 8.431-1.92 9.513-7.476.452-2.321.218-4.259-.978-5.622a4.667 4.667 0 0 0-1.336-1.03z'
fill='#179BD7'
/>
<path
d='M21.754 7.151a9.757 9.757 0 0 0-1.203-.267 15.284 15.284 0 0 0-2.426-.177h-7.352a1.172 1.172 0 0 0-1.159.992L8.05 17.605l-.045.289a1.336 1.336 0 0 1 1.321-1.132h2.752c5.405 0 9.637-2.195 10.874-8.545.037-.188.068-.371.096-.55a6.594 6.594 0 0 0-1.017-.429 9.045 9.045 0 0 0-.277-.087z'
fill='#222D65'
/>
<path
d='M9.614 7.699a1.169 1.169 0 0 1 1.159-.991h7.352c.871 0 1.684.057 2.426.177a9.757 9.757 0 0 1 1.481.353c.365.121.704.264 1.017.429.368-2.347-.003-3.945-1.272-5.392C20.378.682 17.853 0 14.622 0h-9.38c-.66 0-1.223.48-1.325 1.133L.01 25.898a.806.806 0 0 0 .795.932h5.791l1.454-9.225 1.564-9.906z'
fill='#253B80'
/>
</svg>
</Fragment>
);
}
Paypal.displayName = 'Paypal';
Paypal.propTypes = propTypes;
export default Paypal;

View File

@ -1,4 +1,3 @@
/* eslint-disable react/sort-prop-types */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
@ -9,7 +8,8 @@ import {
ControlLabel,
Form,
FormControl,
FormGroup
FormGroup,
Alert
} from '@freecodecamp/react-bootstrap';
import { injectStripe } from 'react-stripe-elements';
@ -19,13 +19,13 @@ import { postChargeStripe } from '../../utils/ajax';
import { userSelector } from '../../redux';
const propTypes = {
showCloseBtn: PropTypes.func,
defaultTheme: PropTypes.string,
donationAmount: PropTypes.number.isRequired,
donationDuration: PropTypes.string.isRequired,
email: PropTypes.string,
getDonationButtonLabel: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool,
showCloseBtn: PropTypes.func,
stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired
}),
@ -53,16 +53,18 @@ class DonateFormChildViewForHOC extends Component {
...initialState,
donationAmount: this.props.donationAmount,
donationDuration: this.props.donationDuration,
isSubmitionValid: null,
email: null,
isEmailValid: true,
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.handleEmailBlur = this.handleEmailBlur.bind(this);
}
getUserEmail() {
@ -80,14 +82,28 @@ class DonateFormChildViewForHOC extends Component {
handleEmailChange(e) {
const newValue = e.target.value;
return this.setState(state => ({
...state,
email: newValue
}));
return this.setState({
email: newValue,
// reset validation
isEmailValid: true
});
}
handleSubmit(e) {
e.preventDefault();
const { isEmailValid, isFormValid } = this.state;
if ((!isEmailValid, !isFormValid)) {
return this.setState({
isSubmitionValid: false
});
}
this.setState({
isSubmitionValid: null
});
const email = this.getUserEmail();
if (!email || !isEmail(email)) {
return this.setState(state => ({
@ -181,21 +197,54 @@ class DonateFormChildViewForHOC extends Component {
return <DonateCompletion {...props} />;
}
handleEmailBlur() {
const emailValue = this.state.email;
const newValidation = isEmail(emailValue);
return this.setState({
isEmailValid: newValidation
});
}
renderErrorMessage() {
const { isEmailValid, isFormValid } = this.state;
let message = '';
if (!isEmailValid && !isFormValid)
message = (
<p>
Please enter valid email address, credit card number, and expiration
date.
</p>
);
else if (!isEmailValid)
message = <p>Please enter a valid email address.</p>;
else
message = (
<p>Please enter valid credit card number and expiration date.</p>
);
return <Alert bsStyle='danger'>{message}</Alert>;
}
renderDonateForm() {
const { isFormValid } = this.state;
const { isEmailValid, isSubmitionValid, email } = this.state;
const { getDonationButtonLabel, theme, defaultTheme } = this.props;
return (
<Form className='donation-form' onSubmit={this.handleSubmit}>
<div>{isSubmitionValid !== null ? this.renderErrorMessage() : ''}</div>
<FormGroup className='donation-email-container'>
<ControlLabel>
Email (we'll send you a tax-deductible donation receipt):
</ControlLabel>
<FormControl
className={!isEmailValid && email ? 'email--invalid' : ''}
key='3'
onBlur={this.handleEmailBlur}
onChange={this.handleEmailChange}
placeholder='me@example.com'
required={true}
type='text'
value={this.getUserEmail()}
value={this.state.email || ''}
/>
</FormGroup>
<StripeCardForm
@ -205,7 +254,7 @@ class DonateFormChildViewForHOC extends Component {
<Button
block={true}
bsStyle='primary'
disabled={!isFormValid}
className='btn-cta'
id='confirm-donation-btn'
type='submit'
>
@ -215,8 +264,11 @@ class DonateFormChildViewForHOC extends Component {
);
}
componentWillReceiveProps({ donationAmount, donationDuration }) {
componentWillReceiveProps({ donationAmount, donationDuration, email }) {
this.setState({ donationAmount, donationDuration });
if (this.state.email === null && email) {
this.setState({ email });
}
}
render() {

View File

@ -41,14 +41,22 @@
font-weight: normal;
}
.donation-form .btn {
.donation-form .btn-cta,
.btn-cta.paypal-button {
white-space: normal;
font-size: 1rem;
font-weight: 700;
}
.donate-input-element {
padding-top: 8px;
}
.donation-form .form-control::placeholder {
color: #707070;
}
.donation-form .form-control:focus,
.StripeElement--focus {
border-color: #66afe9;
outline: 0;
@ -56,6 +64,13 @@
0 0 8px rgba(102, 175, 233, 0.6);
}
.donation-form .email--invalid.form-control:focus,
.donation-form .email--invalid,
.donation-form .StripeElement--invalid {
border-color: #eb1c26;
color: #eb1c26;
}
.wallet {
word-break: break-all;
}
@ -236,6 +251,17 @@ li.disabled > a {
width: 200px;
}
.paypal-button {
display: flex;
align-items: center;
justify-content: center;
}
.paypal-button svg {
margin-top: 5px;
height: 22px;
}
@media screen and (min-width: 355px) {
.form-payment-methods {
height: 30px;

View File

@ -20,6 +20,7 @@ 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,');
@ -187,14 +188,14 @@ class YearEndDonationForm extends Component {
>
<input type='hidden' name='cmd' value='_s-xclick' />
<input type='hidden' name='hosted_button_id' value='9C73W6CWSLNPW' />
<input
<button
type='submit'
name='submit'
className='btn btn-block'
title='Donate to freeCodeCamp.org using PayPal'
alt='Donate to freeCodeCamp.org using PayPal'
value='Donate using PayPal'
/>
className='btn btn-block btn-cta paypal-button'
alt='donate with paypal'
>
<DonateWithPayPal />
</button>
</form>
);
}

View File

@ -42,20 +42,20 @@
padding: 20px 0px;
}
.certificate-outer-wrapper .btn {
.certificate-outer-wrapper .donation-completion .btn {
background-color: var(--gray-15);
border-color: var(--gray-85);
color: var(--gray-85);
}
.certificate-outer-wrapper .btn:hover {
.certificate-outer-wrapper .donation-completion .btn:hover {
border-color: var(--gray-85);
background-color: var(--gray-85);
color: var(--gray-05);
}
.certificate-outer-wrapper .btn[disabled],
.certificate-outer-wrapper .btn[disabled]:hover {
.certificate-outer-wrapper .donation-completion .btn[disabled],
.certificate-outer-wrapper .donation-completion .btn[disabled]:hover {
background-color: var(--gray-15);
border-color: var(--quaternary-color);
color: var(--quaternary-color);