mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-20 12:03:11 -04:00
Add donation animation AB test (#53343)
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com> Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
This commit is contained in:
@@ -93,7 +93,9 @@
|
||||
"link-account": "Link Account",
|
||||
"unlink-account": "Unlink Account",
|
||||
"update-card": "Update your card",
|
||||
"donate-now": "Donate Now"
|
||||
"donate-now": "Donate Now",
|
||||
"confirm-amount": "Confirm amount",
|
||||
"skip-advertisement": "Skip Advertisement"
|
||||
},
|
||||
"landing": {
|
||||
"big-heading-1": "Learn to code — for free.",
|
||||
@@ -578,6 +580,7 @@
|
||||
"other-support": "If there is some other way you'd like to support our charity and its mission that isn't listed here, or if you have any questions at all, please email Quincy at quincy@freecodecamp.org.",
|
||||
"bear-progress-alt": "Illustration of an adorable teddy bear with a pleading expression holding an empty money jar.",
|
||||
"bear-completion-alt": "Illustration of an adorable teddy bear holding a large trophy.",
|
||||
"flying-bear": "Illustration of an adorable teddy bear wearing a graduation cap and flying with a Supporter badge.",
|
||||
"crucial-contribution": "Your contribution will be crucial in creating resources that empower millions of people to learn new skills and support their families.",
|
||||
"support-benefits-title": "Benefits from becoming a Supporter:",
|
||||
"support-benefits-1": "No more donation prompt popups",
|
||||
@@ -598,7 +601,14 @@
|
||||
"community-achivements-3": "Merged <0>2,753</0> code contributions into our open source repositories on GitHub",
|
||||
"community-achivements-4": "Translated <0>2,106,203</0> words to make our curriculum and tutorials more accessible to speakers of many world languages",
|
||||
"as-you-see": "As you can see, we're getting things done. So you can rest assured that we'll put your donations to good use.",
|
||||
"get-benefits": "Get the benefits and the knowledge that you’re helping our charity change education for the better. Become a Supporter today."
|
||||
"get-benefits": "Get the benefits and the knowledge that you’re helping our charity change education for the better. Become a supporter today.",
|
||||
"modal-benefits-title": "Support us",
|
||||
"help-us-more-certifications": "Help us build more certifications",
|
||||
"remove-donation-popups": "Remove donation popups",
|
||||
"help-millions-learn": "Help millions of people learn",
|
||||
"reach-goals-faster": "Reach your goals faster",
|
||||
"remove-distractions": "Remove distractions",
|
||||
"animation-description": "This is a 20 second animated advertisement to encourage campers to become supporters of freeCodeCamp. The animation starts with a teddy bear who becomes a supporter. As a result, distracting pop-ups disappear and the bear gets to complete all of its goals. Then, it graduates and becomes an education super hero helping people around the world."
|
||||
},
|
||||
"report": {
|
||||
"sign-in": "You need to be signed in to report a user",
|
||||
|
||||
5
client/src/assets/images/donation-bear-animation.svg
Normal file
5
client/src/assets/images/donation-bear-animation.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 104 KiB |
5
client/src/assets/images/supporter-bear.svg
Normal file
5
client/src/assets/images/supporter-bear.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 20 KiB |
306
client/src/components/Donation/donation-modal-body.tsx
Normal file
306
client/src/components/Donation/donation-modal-body.tsx
Normal file
@@ -0,0 +1,306 @@
|
||||
import { Modal } from '@freecodecamp/react-bootstrap';
|
||||
import { Col, Row } from '@freecodecamp/ui';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useFeature } from '@growthbook/growthbook-react';
|
||||
import BearProgressModal from '../../assets/images/components/bear-progress-modal';
|
||||
import BearBlockCompletion from '../../assets/images/components/bear-block-completion-modal';
|
||||
import { closeDonationModal } from '../../redux/actions';
|
||||
import { Spacer } from '../helpers';
|
||||
import { PaymentContext } from '../../../../shared/config/donation-settings'; //
|
||||
import donationAnimation from '../../assets/images/donation-bear-animation.svg';
|
||||
import supporterBear from '../../assets/images/supporter-bear.svg';
|
||||
import MultiTierDonationForm from './multi-tier-donation-form';
|
||||
import { ModalBenefitList } from './donation-text-components';
|
||||
|
||||
type RecentlyClaimedBlock = null | { block: string; superBlock: string };
|
||||
|
||||
type DonationModalBodyProps = {
|
||||
activeDonors?: number;
|
||||
closeDonationModal: typeof closeDonationModal;
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
executeGA: (arg: { event: string; action: string }) => void;
|
||||
};
|
||||
|
||||
const Illustration = ({
|
||||
recentlyClaimedBlock,
|
||||
showAnimation
|
||||
}: {
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
showAnimation?: boolean;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
if (showAnimation) {
|
||||
return (
|
||||
<img
|
||||
alt={t('donate.flying-bear')}
|
||||
id={'supporter-bear'}
|
||||
src={supporterBear}
|
||||
data-playwright-test-label='not-found-image'
|
||||
/>
|
||||
);
|
||||
} else
|
||||
return recentlyClaimedBlock ? (
|
||||
<BearBlockCompletion className='donation-icon' />
|
||||
) : (
|
||||
<BearProgressModal className='donation-icon' />
|
||||
);
|
||||
};
|
||||
|
||||
function ModalHeader({
|
||||
recentlyClaimedBlock,
|
||||
showHeaderAndFooter,
|
||||
donationAttempted,
|
||||
showForm,
|
||||
donationAnimationFlag
|
||||
}: {
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
showHeaderAndFooter: boolean;
|
||||
donationAttempted: boolean;
|
||||
showForm: boolean;
|
||||
donationAnimationFlag: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
if (!showHeaderAndFooter || donationAttempted) {
|
||||
return null;
|
||||
} else if (!donationAnimationFlag) {
|
||||
return (
|
||||
<Row className='text-center block-modal-text'>
|
||||
<Col sm={10} smOffset={1} xs={12}>
|
||||
{recentlyClaimedBlock !== null && (
|
||||
<b>
|
||||
{t('donate.nicely-done', {
|
||||
block: t(
|
||||
`intro:${recentlyClaimedBlock.superBlock}.blocks.${recentlyClaimedBlock.block}.title`
|
||||
)
|
||||
})}
|
||||
</b>
|
||||
)}
|
||||
<h2>{t('donate.help-us-develop')}</h2>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else if (!showForm) {
|
||||
return (
|
||||
<Row className='text-center block-modal-text'>
|
||||
<Col sm={10} smOffset={1} xs={12}>
|
||||
<h2>{t('donate.modal-benefits-title')}</h2>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function CloseButtonRow({
|
||||
donationAttempted,
|
||||
closeDonationModal
|
||||
}: {
|
||||
donationAttempted: boolean;
|
||||
closeDonationModal: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Row>
|
||||
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>
|
||||
<button
|
||||
className='close-button'
|
||||
type='button'
|
||||
onClick={closeDonationModal}
|
||||
>
|
||||
{donationAttempted ? t('buttons.close') : t('buttons.ask-later')}
|
||||
</button>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
const Benefits = ({
|
||||
setShowForm,
|
||||
executeGA
|
||||
}: {
|
||||
setShowForm: (arg: boolean) => void;
|
||||
executeGA: (arg: { event: string; action: string }) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleBecomeSupporterClick = () => {
|
||||
executeGA({
|
||||
event: 'donation_related',
|
||||
action: `Modal Become Supporter Click`
|
||||
});
|
||||
setShowForm(true);
|
||||
};
|
||||
return (
|
||||
<Row className={'donate-btn-group'}>
|
||||
<Col xs={12}>
|
||||
<ModalBenefitList />
|
||||
<Spacer size='small' />
|
||||
<button
|
||||
className='text-center confirm-donation-btn donate-btn-group'
|
||||
type='submit'
|
||||
onClick={handleBecomeSupporterClick}
|
||||
>
|
||||
{t('donate.become-supporter')}
|
||||
</button>
|
||||
<Spacer size='medium' />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
const AnimationContainer = ({
|
||||
setIsAnimationVisible
|
||||
}: {
|
||||
setIsAnimationVisible: (arg: boolean) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<p style={{ opacity: 0, position: 'absolute' }}>
|
||||
{t('donate.animation-description')}{' '}
|
||||
</p>
|
||||
<div className='donation-animation-container' aria-hidden='true'>
|
||||
<div className='donation-animation-bullet-points'>
|
||||
<p className='donation-animation-bullet-1'>
|
||||
{t('donate.become-supporter')}
|
||||
</p>
|
||||
<p className='donation-animation-bullet-2'>
|
||||
{t('donate.remove-distractions')}
|
||||
</p>
|
||||
<p className='donation-animation-bullet-3'>
|
||||
{t('donate.reach-goals-faster')}
|
||||
</p>
|
||||
<p className='donation-animation-bullet-4'>
|
||||
{t('donate.help-millions-learn')}
|
||||
</p>
|
||||
</div>
|
||||
<img
|
||||
alt=''
|
||||
src={donationAnimation}
|
||||
id={'donation-animation'}
|
||||
data-playwright-test-label='not-found-image'
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={{ opacity: 0, position: 'absolute' }}
|
||||
className={'sr-only'}
|
||||
onClick={() => setIsAnimationVisible(false)}
|
||||
>
|
||||
{t('buttons.skip-advertisement')}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const BecomeASupporterConfirmation = ({
|
||||
donationAnimationFlag,
|
||||
recentlyClaimedBlock,
|
||||
showHeaderAndFooter,
|
||||
closeDonationModal,
|
||||
donationAttempted,
|
||||
showForm,
|
||||
setShowHeaderAndFooter,
|
||||
handleProcessing,
|
||||
setShowForm,
|
||||
executeGA
|
||||
}: {
|
||||
donationAnimationFlag: boolean;
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
showHeaderAndFooter: boolean;
|
||||
closeDonationModal: () => void;
|
||||
donationAttempted: boolean;
|
||||
showForm: boolean;
|
||||
setShowHeaderAndFooter: (arg: boolean) => void;
|
||||
handleProcessing: () => void;
|
||||
setShowForm: (arg: boolean) => void;
|
||||
executeGA: (arg: { event: string; action: string }) => void;
|
||||
}) => {
|
||||
return (
|
||||
<div className='no-delay-fade-in'>
|
||||
<div className='donation-icon-container'>
|
||||
<Illustration
|
||||
showAnimation={donationAnimationFlag}
|
||||
recentlyClaimedBlock={recentlyClaimedBlock}
|
||||
/>
|
||||
</div>
|
||||
<ModalHeader
|
||||
recentlyClaimedBlock={recentlyClaimedBlock}
|
||||
showHeaderAndFooter={showHeaderAndFooter}
|
||||
donationAttempted={donationAttempted}
|
||||
showForm={showForm}
|
||||
donationAnimationFlag={donationAnimationFlag}
|
||||
/>
|
||||
<Spacer size='small' />
|
||||
{showForm || !donationAnimationFlag ? (
|
||||
<MultiTierDonationForm
|
||||
setShowHeaderAndFooter={setShowHeaderAndFooter}
|
||||
handleProcessing={handleProcessing}
|
||||
paymentContext={PaymentContext.Modal}
|
||||
isMinimalForm={true}
|
||||
isAnimationEnabled={donationAnimationFlag}
|
||||
/>
|
||||
) : (
|
||||
<Benefits setShowForm={setShowForm} executeGA={executeGA} />
|
||||
)}
|
||||
{(showHeaderAndFooter || donationAttempted) && (
|
||||
<CloseButtonRow
|
||||
closeDonationModal={closeDonationModal}
|
||||
donationAttempted={donationAttempted}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function DonationModalBody({
|
||||
closeDonationModal,
|
||||
recentlyClaimedBlock,
|
||||
executeGA
|
||||
}: DonationModalBodyProps): JSX.Element {
|
||||
const [donationAttempted, setDonationAttempted] = useState(false);
|
||||
const [showHeaderAndFooter, setShowHeaderAndFooter] = useState(true);
|
||||
const donationAnimationFlag = useFeature('donation-animation').on;
|
||||
const [isAnimationVisible, setIsAnimationVisible] = useState(true);
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const handleProcessing = () => {
|
||||
setDonationAttempted(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setIsAnimationVisible(false);
|
||||
}, 20000); // 20000 milliseconds = 20 seconds
|
||||
|
||||
// Clear the timer if the component unmounts
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Modal.Body>
|
||||
<div aria-live={'polite'}>
|
||||
{donationAnimationFlag && isAnimationVisible ? (
|
||||
<AnimationContainer setIsAnimationVisible={setIsAnimationVisible} />
|
||||
) : (
|
||||
<BecomeASupporterConfirmation
|
||||
donationAnimationFlag={donationAnimationFlag}
|
||||
recentlyClaimedBlock={recentlyClaimedBlock}
|
||||
showHeaderAndFooter={showHeaderAndFooter}
|
||||
closeDonationModal={closeDonationModal}
|
||||
donationAttempted={donationAttempted}
|
||||
showForm={showForm}
|
||||
setShowHeaderAndFooter={setShowHeaderAndFooter}
|
||||
handleProcessing={handleProcessing}
|
||||
setShowForm={setShowForm}
|
||||
executeGA={executeGA}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Modal.Body>
|
||||
);
|
||||
}
|
||||
|
||||
DonationModalBody.displayName = 'DonationModalBody';
|
||||
|
||||
export default DonationModalBody;
|
||||
@@ -1,15 +1,11 @@
|
||||
import { Modal } from '@freecodecamp/react-bootstrap';
|
||||
import { Col, Row } from '@freecodecamp/ui';
|
||||
import { WindowLocation } from '@reach/router';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { goToAnchor } from 'react-scrollable-anchor';
|
||||
import { bindActionCreators, Dispatch, AnyAction } from 'redux';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import BearProgressModal from '../../assets/images/components/bear-progress-modal';
|
||||
import BearBlockCompletion from '../../assets/images/components/bear-block-completion-modal';
|
||||
import { closeDonationModal, executeGA } from '../../redux/actions';
|
||||
import {
|
||||
isDonationModalOpenSelector,
|
||||
@@ -17,9 +13,7 @@ import {
|
||||
} from '../../redux/selectors';
|
||||
import { isLocationSuperBlock } from '../../utils/path-parsers';
|
||||
import { playTone } from '../../utils/tone';
|
||||
import { Spacer } from '../helpers';
|
||||
import { PaymentContext } from '../../../../shared/config/donation-settings'; //
|
||||
import MultiTierDonationForm from './multi-tier-donation-form';
|
||||
import DonationModalBody from './donation-modal-body';
|
||||
|
||||
type RecentlyClaimedBlock = null | { block: string; superBlock: string };
|
||||
|
||||
@@ -50,65 +44,6 @@ type DonateModalProps = {
|
||||
show: boolean;
|
||||
};
|
||||
|
||||
const Illustration = ({
|
||||
recentlyClaimedBlock
|
||||
}: {
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
}) => {
|
||||
return recentlyClaimedBlock ? (
|
||||
<BearBlockCompletion className='donation-icon' />
|
||||
) : (
|
||||
<BearProgressModal className='donation-icon' />
|
||||
);
|
||||
};
|
||||
|
||||
function ModalHeader({
|
||||
recentlyClaimedBlock
|
||||
}: {
|
||||
recentlyClaimedBlock: RecentlyClaimedBlock;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Row className='text-center block-modal-text'>
|
||||
<Col sm={10} smOffset={1} xs={12}>
|
||||
{recentlyClaimedBlock !== null && (
|
||||
<b>
|
||||
{t('donate.nicely-done', {
|
||||
block: t(
|
||||
`intro:${recentlyClaimedBlock.superBlock}.blocks.${recentlyClaimedBlock.block}.title`
|
||||
)
|
||||
})}
|
||||
</b>
|
||||
)}
|
||||
<h2>{t('donate.help-us-develop')}</h2>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
function CloseButtonRow({
|
||||
donationAttempted,
|
||||
closeDonationModal
|
||||
}: {
|
||||
donationAttempted: boolean;
|
||||
closeDonationModal: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Row>
|
||||
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>
|
||||
<button
|
||||
className='close-button'
|
||||
type='button'
|
||||
onClick={closeDonationModal}
|
||||
>
|
||||
{donationAttempted ? t('buttons.close') : t('buttons.ask-later')}
|
||||
</button>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
function DonateModal({
|
||||
show,
|
||||
closeDonationModal,
|
||||
@@ -116,13 +51,6 @@ function DonateModal({
|
||||
location,
|
||||
recentlyClaimedBlock
|
||||
}: DonateModalProps): JSX.Element {
|
||||
const [donationAttempted, setDonationAttempted] = useState(false);
|
||||
const [showHeaderAndFooter, setShowHeaderAndFooter] = useState(true);
|
||||
|
||||
const handleProcessing = () => {
|
||||
setDonationAttempted(true);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
void playTone('donation');
|
||||
@@ -149,28 +77,13 @@ function DonateModal({
|
||||
className='donation-modal'
|
||||
onExited={handleModalHide}
|
||||
show={show}
|
||||
data-cy='donation-modal'
|
||||
>
|
||||
<Modal.Body className='no-delay-fade-in'>
|
||||
<div className='donation-icon-container'>
|
||||
<Illustration recentlyClaimedBlock={recentlyClaimedBlock} />
|
||||
</div>
|
||||
{showHeaderAndFooter && !donationAttempted && (
|
||||
<ModalHeader recentlyClaimedBlock={recentlyClaimedBlock} />
|
||||
)}
|
||||
<Spacer size='small' />
|
||||
<MultiTierDonationForm
|
||||
setShowHeaderAndFooter={setShowHeaderAndFooter}
|
||||
handleProcessing={handleProcessing}
|
||||
paymentContext={PaymentContext.Modal}
|
||||
isMinimalForm={true}
|
||||
/>
|
||||
{(showHeaderAndFooter || donationAttempted) && (
|
||||
<CloseButtonRow
|
||||
closeDonationModal={closeDonationModal}
|
||||
donationAttempted={donationAttempted}
|
||||
/>
|
||||
)}
|
||||
</Modal.Body>
|
||||
<DonationModalBody
|
||||
closeDonationModal={closeDonationModal}
|
||||
recentlyClaimedBlock={recentlyClaimedBlock}
|
||||
executeGA={executeGA}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
||||
import { useTranslation, Trans } from 'react-i18next';
|
||||
import Caret from '../../assets/icons/caret';
|
||||
import { Spacer } from '../helpers';
|
||||
import GreenPass from '../../assets/icons/green-pass';
|
||||
|
||||
const POBOX = (
|
||||
<>
|
||||
@@ -225,7 +226,7 @@ export const SupportBenefitsText = ({
|
||||
);
|
||||
};
|
||||
|
||||
const BenefitsList = (): JSX.Element => {
|
||||
export const BenefitsList = (): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<ul>
|
||||
@@ -317,3 +318,23 @@ export const GetSupporterBenefitsText = ({
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ModalBenefitList = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<ul>
|
||||
<li>
|
||||
<GreenPass aria-disabled={true} />
|
||||
{t('donate.help-us-more-certifications')}
|
||||
</li>
|
||||
<li>
|
||||
<GreenPass aria-disabled={true} />
|
||||
{t('donate.remove-donation-popups')}
|
||||
</li>
|
||||
<li>
|
||||
<GreenPass aria-disabled={true} />
|
||||
{t('donate.help-millions-learn')}
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -273,6 +273,19 @@ li.disabled > a {
|
||||
.donation-modal p {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.donation-modal ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.donation-modal li {
|
||||
list-style-type: none;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.donation-modal li svg {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.donation-label-modal {
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
@@ -736,3 +749,139 @@ a.patreon-button:hover {
|
||||
height: 6em;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#supporter-bear {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.donation-animation-container,
|
||||
.donation-animation-bullet-points {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-points p {
|
||||
position: absolute;
|
||||
color: white;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
font-size: 200%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-1 {
|
||||
animation-name: animation-bullet-1;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-2 {
|
||||
animation-name: animation-bullet-2;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-3 {
|
||||
animation-name: animation-bullet-3;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-4 {
|
||||
animation-name: animation-bullet-4;
|
||||
}
|
||||
|
||||
.donation-animation-bullet-1,
|
||||
.donation-animation-bullet-2,
|
||||
.donation-animation-bullet-3,
|
||||
.donation-animation-bullet-4 {
|
||||
opacity: 0;
|
||||
animation-fill-mode: forwards;
|
||||
animation-duration: 20s;
|
||||
margin-top: 40px;
|
||||
animation-timing-function: normal;
|
||||
}
|
||||
|
||||
@keyframes animation-bullet-1 {
|
||||
1% {
|
||||
opacity: 0;
|
||||
margin-top: 40px;
|
||||
}
|
||||
2.5% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
19.5% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
21% {
|
||||
opacity: 0;
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation-bullet-2 {
|
||||
21% {
|
||||
opacity: 0;
|
||||
margin-top: 40px;
|
||||
}
|
||||
22.5% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
38.5% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
40% {
|
||||
opacity: 0;
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation-bullet-3 {
|
||||
40% {
|
||||
opacity: 0;
|
||||
margin-top: 40px;
|
||||
}
|
||||
41.5% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
64% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
65.5% {
|
||||
opacity: 0;
|
||||
margin-top: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation-bullet-4 {
|
||||
65.5% {
|
||||
opacity: 0;
|
||||
margin-top: 40px;
|
||||
}
|
||||
67% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
96% {
|
||||
opacity: 1;
|
||||
margin-top: 80px;
|
||||
}
|
||||
97.5% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tester-text {
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.donation-animation-bullet-points p {
|
||||
font-size: 150%;
|
||||
}
|
||||
#donation-animation {
|
||||
object-fit: cover;
|
||||
min-height: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,15 +27,18 @@ type MultiTierDonationFormProps = {
|
||||
paymentContext: PaymentContext;
|
||||
isMinimalForm?: boolean;
|
||||
defaultTheme?: Themes;
|
||||
isAnimationEnabled?: boolean;
|
||||
};
|
||||
function SelectionTabs({
|
||||
donationAmount,
|
||||
setDonationAmount,
|
||||
setShowDonateForm
|
||||
setShowDonateForm,
|
||||
isAnimationEnabled
|
||||
}: {
|
||||
donationAmount: DonationAmount;
|
||||
setDonationAmount: React.Dispatch<React.SetStateAction<DonationAmount>>;
|
||||
setShowDonateForm: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
isAnimationEnabled?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const switchTab = (value: string): void => {
|
||||
@@ -97,7 +100,9 @@ function SelectionTabs({
|
||||
data-cy='donation-tier-selection-button'
|
||||
onClick={() => setShowDonateForm(true)}
|
||||
>
|
||||
{t('buttons.donate')}
|
||||
{isAnimationEnabled
|
||||
? t('buttons.confirm-amount')
|
||||
: t('buttons.donate')}
|
||||
</button>
|
||||
<Spacer size='medium' />
|
||||
</Col>
|
||||
@@ -138,7 +143,8 @@ const MultiTierDonationForm: React.FC<MultiTierDonationFormProps> = ({
|
||||
handleProcessing,
|
||||
setShowHeaderAndFooter,
|
||||
isMinimalForm,
|
||||
paymentContext
|
||||
paymentContext,
|
||||
isAnimationEnabled
|
||||
}) => {
|
||||
const [donationAmount, setDonationAmount] = useState(defaultTierAmount);
|
||||
|
||||
@@ -155,6 +161,7 @@ const MultiTierDonationForm: React.FC<MultiTierDonationFormProps> = ({
|
||||
donationAmount={donationAmount}
|
||||
setDonationAmount={setDonationAmount}
|
||||
setShowDonateForm={setShowDonateForm}
|
||||
isAnimationEnabled={isAnimationEnabled}
|
||||
/>
|
||||
</div>
|
||||
<div {...(!showDonateForm && { className: 'hide' })}>
|
||||
|
||||
@@ -34,8 +34,6 @@ describe('Donate page', () => {
|
||||
projects.forEach(project => submitProject(project));
|
||||
|
||||
// pop up modal
|
||||
cy.contains(
|
||||
'Nicely done. You just completed Front End Development Libraries Projects.'
|
||||
);
|
||||
cy.get("[data-cy='donation-modal']");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user