feat: update donation plans on donate page. (#40102)

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Ahmad Abdolsaheb
2020-11-06 14:30:14 +03:00
committed by GitHub
parent 7ce85a8f03
commit ca369b8585
10 changed files with 218 additions and 195 deletions

View File

@ -12,9 +12,6 @@ import {
ToggleButton,
ToggleButtonGroup
} from '@freecodecamp/react-bootstrap';
import ApplePay from './assets/ApplePay';
import GooglePay from './assets/GooglePay';
import acceptedCards from './assets/accepted-cards.png';
import {
amountsConfig,
durationsConfig,
@ -241,7 +238,7 @@ class DonateForm extends Component {
const { donationAmount, donationDuration, processing } = this.state;
return !processing ? (
<div>
<h3>Duration and amount:</h3>
<h3>Select gift frequency:</h3>
<Tabs
activeKey={donationDuration}
animation={false}
@ -257,6 +254,7 @@ class DonateForm extends Component {
title={this.durations[duration]}
>
<Spacer />
<h3>Select gift amount:</h3>
<div>
<ToggleButtonGroup
animation={`false`}
@ -306,55 +304,25 @@ class DonateForm extends Component {
</b>
)}
<Spacer />
<Button
block={true}
bsStyle='primary'
className='btn-cta'
id='confirm-donation-btn'
onClick={e => this.handleStripeCheckoutRedirect(e, 'apple pay')}
>
<span>Donate with Apple Pay</span>
<ApplePay className='apple-pay-logo' />
</Button>
<Spacer />
<Button
block={true}
bsStyle='primary'
className='btn-cta'
id='confirm-donation-btn'
onClick={e => this.handleStripeCheckoutRedirect(e, 'google pay')}
>
<span>Donate with Google Pay</span>
<GooglePay className='google-pay-logo' />
</Button>
<Spacer />
<Button
block={true}
bsStyle='primary'
className='btn-cta'
id='confirm-donation-btn'
onClick={e => this.handleStripeCheckoutRedirect(e, 'credit card')}
>
<span>Donate with Card</span>
<img
alt='accepted cards'
className='accepted-cards'
src={acceptedCards}
<div className='donate-btn-group'>
<Button
block={true}
bsStyle='primary'
id='confirm-donation-btn'
onClick={e => this.handleStripeCheckoutRedirect(e, 'credit card')}
>
<b>Credit Card</b>
</Button>
<PaypalButton
addDonation={addDonation}
donationAmount={donationAmount}
donationDuration={donationDuration}
handleProcessing={handleProcessing}
isSubscription={isOneTime ? false : true}
onDonationStateChange={this.onDonationStateChange}
skipAddDonation={!isSignedIn}
/>
</Button>
<Spacer />
<PaypalButton
addDonation={addDonation}
donationAmount={donationAmount}
donationDuration={donationDuration}
handleProcessing={handleProcessing}
isSubscription={isOneTime ? false : true}
onDonationStateChange={this.onDonationStateChange}
skipAddDonation={!isSignedIn}
/>
<Spacer size={2} />
</div>
</div>
);
}
@ -415,12 +383,8 @@ class DonateForm extends Component {
renderPageForm() {
return (
<Row>
<Col sm={10} smOffset={1} xs={12}>
{this.renderDurationAmountOptions()}
</Col>
<Col sm={10} smOffset={1} xs={12}>
{this.renderDonationOptions()}
</Col>
<Col xs={12}>{this.renderDurationAmountOptions()}</Col>
<Col xs={12}>{this.renderDonationOptions()}</Col>
</Row>
);
}

View File

@ -0,0 +1,19 @@
import React from 'react';
import { Row, Col } from '@freecodecamp/react-bootstrap';
const DonateSupportText = () => (
<Row className='donate-text'>
<Col xs={12}>
<hr />
<h4>
<b>Need help with your current or past donations?</b>
</h4>
<p>
Forward a copy of your donation receipt to donors@freecodecamp.org and
tell us how we can help.
</p>
</Col>
</Row>
);
DonateSupportText.displayName = 'DonateText';
export default DonateSupportText;

View File

@ -4,17 +4,8 @@ import { Row, Col } from '@freecodecamp/react-bootstrap';
const DonateText = () => {
return (
<Row className='donate-text'>
<Col sm={10} smOffset={1} xs={12}>
<Col 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.
@ -23,14 +14,6 @@ const DonateText = () => {
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 current or past donations?</b>
</h4>
<p>
Forward a copy of your donation receipt to donors@freecodecamp.org and
tell us how we can help.
</p>
</Col>
</Row>
);

View File

@ -92,7 +92,7 @@
.donate-tabs > .nav-pills > li > a {
text-transform: capitalize;
text-decoration: none;
border: 2px solid var(--yellow-light);
border: 3px solid var(--yellow-light);
border-radius: 0px;
color: var(--gray-85);
margin: 0 1px;
@ -109,7 +109,7 @@
.donate-tabs > .nav-pills > li.active > a:focus {
color: var(--gray-85);
background-color: var(--yellow-light);
border: 2px solid var(--yellow-light);
border: 3px solid var(--yellow-light);
text-decoration: none;
border-radius: 0px;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
@ -125,13 +125,17 @@
}
.amount-values > label {
margin: 0 2px !important;
margin: 0 2px;
color: var(--gray-85);
border: 2px solid var(--yellow-light);
border: 3px solid var(--yellow-light);
border-radius: 0px;
background-color: transparent;
}
.amount-values.btn-group .btn + .btn {
margin: 0 2px;
}
.amount-values > label:hover,
.amount-values > label:focus,
.amount-values > label:active:hover {
@ -155,17 +159,36 @@
.amount-values > label.active:focus {
color: var(--gray-85);
background-color: var(--yellow-light);
border: 2px solid var(--yellow-light);
border: 3px solid var(--yellow-light);
border-radius: 0px;
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
@media (max-width: 500px) {
.amount-values {
display: flex;
flex-wrap: wrap;
}
.amount-values > label {
width: 31.3%;
margin-bottom: 3px;
}
.amount-values.btn-group > .btn:first-child {
margin-left: 2px;
margin-bottom: 3px;
}
.amount-values.btn-group .btn + .btn {
/* margin: 0 2px; */
margin-bottom: 3px;
}
}
li.disabled {
cursor: not-allowed;
}
li.disabled > a {
border: 2px solid var(--gray-15) !important;
border: 3px solid var(--gray-15) !important;
color: var(--gray-15) !important;
}
@ -178,12 +201,6 @@ li.disabled > a {
font-family: 'Lato', sans-serif;
}
@media (max-width: 991px) {
.donate-text {
margin-top: 30px;
}
}
@media (max-width: 400px) {
.donate-tabs > .nav-pills > li > a {
font-size: 0.8rem;
@ -342,13 +359,51 @@ li.disabled > a {
align-self: center;
}
#confirm-donation-btn {
button#confirm-donation-btn {
display: flex;
flex-direction: row;
justify-content: center;
align-content: center;
border-radius: 5px;
background-color: var(--yellow-light);
border-color: var(--yellow-light);
}
button#confirm-donation-btn:active,
button#confirm-donation-btn:active:focus,
button#confirm-donation-btn:hover {
color: var(--secondary-color);
background-color: #f2ba38;
border-color: #f2ba38;
}
.hide {
display: none;
}
.donate-btn-group {
display: flex;
flex-direction: column;
}
.donate-btn-group > * {
width: 100%;
height: 43px;
}
.donate-btn-group button:first-child {
margin-bottom: 10px;
}
@media (min-width: 500px) {
.donate-btn-group {
flex-direction: row;
}
.donate-btn-group > * {
width: 49%;
}
.donate-btn-group button:first-child {
margin-bottom: 0px;
margin-right: auto;
}
}

View File

@ -34,7 +34,7 @@ export class PayPalButtonScriptLoader extends Component {
loadScript(subscription, deleteScript) {
if (deleteScript) scriptRemover('paypal-sdk');
let queries = `?client-id=${this.props.clientId}&disable-funding=credit,card`;
let queries = `?client-id=${this.props.clientId}&disable-funding=credit,card,bancontact,blik,eps,giropay,ideal,mybank,p24,sepa,sofort,venmo`;
if (subscription) queries += '&vault=true';
scriptLoader(

View File

@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import Media from 'react-responsive';
import { Spacer, ImageLoader } from '../../helpers';
import wideImg from '../../../assets/images/landing/wide-image.png';
const propTypes = {
page: PropTypes.string
};
const LARGE_SCREEN_SIZE = 1200;
const imageConfig = {
donate: {
spacerSize: 0,
height: 345,
width: 585
},
landing: {
spacerSize: 2,
height: 442,
width: 750
}
};
function CampersImage({ page }) {
const { spacerSize, height, width } = imageConfig[page];
return (
<Media minWidth={LARGE_SCREEN_SIZE}>
<Spacer size={spacerSize} />
<ImageLoader
alt='freeCodeCamp students at a local study group in South Korea.'
className='landing-page-image'
height={height}
src={wideImg}
width={width}
/>
<p className='text-center caption'>
freeCodeCamp students at a local study group in South Korea.
</p>
</Media>
);
}
CampersImage.displayName = 'CampersImage';
CampersImage.propTypes = propTypes;
export default CampersImage;

View File

@ -1,9 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import Media from 'react-responsive';
import { Col, Row } from '@freecodecamp/react-bootstrap';
import { Spacer, ImageLoader } from '../../helpers';
import wideImg from '../../../assets/images/landing/wide-image.png';
import { Spacer } from '../../helpers';
import Login from '../../Header/components/Login';
import {
AmazonLogo,
@ -12,29 +10,13 @@ import {
SpotifyLogo,
GoogleLogo
} from '../../../assets/images/components';
import CampersImage from './CampersImage';
const propTypes = {
page: PropTypes.string
};
const LARGE_SCREEN_SIZE = 1200;
function landingTop({ page }) {
const landingImageSection = (
<Media minWidth={LARGE_SCREEN_SIZE}>
<Spacer size={2} />
<ImageLoader
alt='Freecodecamp students at a local study'
className='landing-page-image'
height={442}
src={wideImg}
width={750}
/>
<p className='text-center caption'>
freeCodeCamp students at a local study group in South Korea.
</p>
</Media>
);
const BigCallToAction = (
<Login block={true} data-test-label={`${page}-big-cta`}>
{page === 'landing'
@ -65,7 +47,7 @@ function landingTop({ page }) {
</div>
<Spacer />
{BigCallToAction}
{landingImageSection}
<CampersImage page={page} />
<Spacer />
</Col>
</Row>

View File

@ -12,7 +12,7 @@
--gray-90: #0a0a23;
--purple-light: #dbb8ff;
--purple-dark: #5a01a7;
--yellow-light: #f1be32;
--yellow-light: #ffc300;
--yellow-dark: #4d3800;
--blue-light: #99c9ff;
--blue-dark: #002ead;

View File

@ -9,7 +9,9 @@ import { Grid, Row, Col, Alert } from '@freecodecamp/react-bootstrap';
import { Spacer, Loader } from '../components/helpers';
import DonateForm from '../components/Donation/DonateForm';
import DonateText from '../components/Donation/DonateText';
import DonateSupportText from '../components/Donation/DonateSupportText';
import { signInLoadingSelector, userSelector, executeGA } from '../redux';
import CampersImage from '../components/landing/components/CampersImage';
const propTypes = {
executeGA: PropTypes.func,
@ -78,43 +80,42 @@ export class DonatePage extends Component {
<Helmet title='Support our nonprofit | freeCodeCamp.org' />
<Grid className='donate-page-wrapper'>
<Spacer />
<Row>
<Col sm={10} smOffset={1} xs={12}>
<h1 className='text-center'>
{isDonating
? 'Thank You for Your Support'
: 'Become a Supporter'}
</h1>
<Spacer />
</Col>
</Row>
<Row>
<Fragment>
<Col md={6}>
<Row>
<Col sm={10} smOffset={1} xs={12}>
<Col lg={6} lgOffset={0} md={8} mdOffset={2} sm={10} smOffset={1}>
<Row className='donate-text'>
<Col className={'text-center'} xs={12}>
{isDonating ? (
<Alert>
<p>
Thank you for being a supporter of freeCodeCamp. You
currently have a recurring donation.
</p>
<br />
<p>
If you would like to make additional donations, those
will help our nonprofit and our mission, too.
</p>
</Alert>
) : null}
<h2>Thank you for your support</h2>
) : (
<h2>Help us do more</h2>
)}
<Spacer />
</Col>
</Row>
{isDonating ? (
<Alert>
<p>
Thank you for being a supporter of freeCodeCamp. You
currently have a recurring donation.
</p>
<br />
<p>
If you would like to make additional donations, those will
help our nonprofit and our mission, too.
</p>
</Alert>
) : null}
<DonateText isDonating={isDonating} />
<Spacer />
<DonateForm
enableDonationSettingsPage={this.enableDonationSettingsPage}
handleProcessing={this.handleProcessing}
/>
<DonateSupportText />
</Col>
<Col md={6}>
<DonateText />
<Col lg={6}>
<CampersImage page='donate' />
</Col>
</Fragment>
</Row>

View File

@ -1,18 +1,15 @@
// Configuration for client side
const durationsConfig = {
year: 'yearly',
month: 'monthly',
onetime: 'one-time'
};
const amountsConfig = {
year: [100000, 25000, 6000],
month: [25000, 3500, 500],
onetime: [100000, 25000, 6000]
month: [1000, 2000, 3000, 4000, 5000],
onetime: [2500, 5000, 7500, 10000, 15000]
};
const defaultAmount = {
year: 25000,
month: 500,
onetime: 25000
month: 1000,
onetime: 2500
};
const defaultDonation = {
donationAmount: defaultAmount['month'],
@ -25,79 +22,54 @@ const modalDefaultDonation = {
const onetimeSKUConfig = {
live: [
{ amount: '100000', id: 'sku_GwHogRRJrCYGms' },
{ amount: '25000', id: 'sku_GwHnCde23uDH5R' },
{ amount: '6000', id: 'sku_H5mjFgpayAzJzT' }
{ amount: '15000', id: 'sku_IElisJHup0nojP' },
{ amount: '10000', id: 'sku_IEliodY88lglPk' },
{ amount: '7500', id: 'sku_IEli9AXW8DwNtT' },
{ amount: '5000', id: 'sku_IElhJxkNh9UgDp' },
{ amount: '2500', id: 'sku_IElhQtqLgKZC8y' }
],
staging: [
{ amount: '100000', id: 'sku_GvAeUdWLsmGO9O' },
{ amount: '25000', id: 'sku_GvAdXbsotjFi7G' },
{ amount: '6000', id: 'sku_GvAeJDgwjnGAdy' }
{ amount: '15000', id: 'sku_IEPNpHACYJmUwz' },
{ amount: '10000', id: 'sku_IEPMY1OXxnY4WU' },
{ amount: '7500', id: 'sku_IEPLOotEqlMOWC' },
{ amount: '5000', id: 'sku_IEPKAxxAxfMnUI' },
{ amount: '2500', id: 'sku_IEPIgLRzViwq5z' }
]
};
// Configuration for server side
const durationKeysConfig = ['year', 'month', 'onetime'];
const durationKeysConfig = ['month', 'onetime'];
const donationOneTimeConfig = [100000, 25000, 6000];
const donationSubscriptionConfig = {
duration: {
year: 'Yearly',
month: 'Monthly'
},
plans: {
year: [100000, 25000, 6000],
month: [25000, 3500, 500]
}
};
// Shared paypal configuration
// keep the 5 dollars for the modal
const paypalConfigTypes = {
live: {
month: {
'500': {
planId: 'P-1L11422374370240ULZKX3PA'
},
'3500': {
planId: 'P-81U00703FF076883HLZ2PWMI'
},
'25000': {
planId: 'P-7M045671FN915794KLZ2PW6I'
}
},
year: {
'6000': {
planId: 'P-9Y661558DW462253NLZZ2IMQ'
},
'25000': {
planId: 'P-3NN39392MK1889318LZZ2KQY'
},
'100000': {
planId: 'P-7YN43286C4599382LLZZ2JUI'
}
'500': { planId: 'P-1L11422374370240ULZKX3PA' },
'1000': { planId: 'P-61K21421WY874920PL6E36YI' },
'2000': { planId: 'P-31999436LF709112VL6E374A' },
'3000': { planId: 'P-1KY930839N8045117L6E4BKY' },
'4000': { planId: 'P-0JW4843250567551AL6E4CAI' },
'5000': { planId: 'P-0WR49877YD949401BL6E4CTA' }
}
},
staging: {
month: {
'500': {
planId: 'P-37N14480BW163382FLZYPVMA'
},
'3500': {
planId: 'P-3E678937P5715503NLZZTRVY'
},
'25000': {
planId: 'P-97K80194AU368022JLZ2Q27Y'
}
},
year: {
'6000': {
planId: 'P-0UY77185EM3077131LZYP6VY'
},
'25000': {
planId: 'P-7K1585908S634694XLZZTHUQ'
},
'100000': {
planId: 'P-0J5231134H608574XLZZTDLQ'
}
'500': { planId: 'P-37N14480BW163382FLZYPVMA' },
'1000': { planId: 'P-28B62039J8092810UL6E3FXA' },
'2000': { planId: 'P-7HR706961M9170433L6HI5VI' },
'3000': { planId: 'P-35V33574BU596924JL6HI6XY' },
'4000': { planId: 'P-45M45060289267734L6HJSXA' },
'5000': { planId: 'P-0MD70861FY4172444L6HJTUQ' }
}
}
};