feat: add supporters page (#52711)

This commit is contained in:
Ahmad Abdolsaheb
2023-12-23 03:19:11 +03:00
committed by GitHub
parent 2159498b92
commit 67faed73d0
15 changed files with 387 additions and 107 deletions

View File

@@ -16,7 +16,9 @@
"other-ways-url": "https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp",
"download-irs-url": "https://s3.amazonaws.com/freecodecamp/Free+Code+Camp+Inc+IRS+Determination+Letter.pdf",
"download-990-url": "https://freecodecamp.s3.amazonaws.com/freeCodeCamp+2019+f990.pdf",
"one-time-url": "https://paypal.me/freecodecamp"
"one-time-url": "https://paypal.me/freecodecamp",
"one-time-external-url": "https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp/#how-can-i-make-a-one-time-donation",
"mail-check-url": "https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp/#can-i-mail-a-physical-check"
},
"nav": {
"contribute": "https://contribute.freecodecamp.org/#/",

View File

@@ -36,6 +36,8 @@
"profile": "Profile",
"news": "News",
"donate": "Donate",
"supporters": "Supporters",
"go-to-supporters": "Go to Supporters Page",
"update-settings": "Update my account settings",
"sign-me-out": "Sign me out of freeCodeCamp",
"flag-user": "Flag This User's Account for Abuse",
@@ -386,6 +388,7 @@
"chal-preview": "Challenge Preview",
"donation-record-not-found": "Your donation record has not been found.",
"sign-in-card-update": "Sign in to update your card",
"sign-in-see-benefits": "Sign in to see your supporter benefits",
"card-has-been-updated": "Your card has been updated successfully.",
"contact-support-mistake": "If you think there has been a mistake, please contact us at donors@freecodecamp.org",
"cert-map-estimates": {
@@ -474,7 +477,7 @@
"processing": "We are processing your donation.",
"redirecting": "Redirecting...",
"thanks": "Thanks for donating",
"thank-you": "Thank you for being a supporter.",
"thank-you": "Thank You for Being a Supporter",
"success-card-update": "Your card has been updated successfully.",
"additional": "You can make an additional one-time donation of any amount using this link: <0>{{url}}</0>",
"help-more": "Help Our Charity Do More",
@@ -483,7 +486,7 @@
"error-2": "Something is not right. Please contact donors@freecodecamp.org",
"error-3": "Please try again or contact donors@freecodecamp.org",
"free-tech": "Your donations will support free technology education for people all over the world.",
"no-halo": "If you don't see a gold halo around your profile picture, contact donors@freecodecamp.org.",
"visit-supporters": "Visit supporters page to learn about your supporter benefits.",
"gift-frequency": "Select gift frequency:",
"gift-amount": "Select gift amount:",
"confirm": "Confirm your donation:",
@@ -529,6 +532,7 @@
"why-donate-2": "You also help us create new resources for you to use to expand your own technology skills.",
"bigger-donation": "Want to make a bigger one-time donation, mail us a check, or give in other ways?",
"other-ways": "Here are many <0>other ways you can support our charity's mission</0>.",
"if-support-further": "If you want to support our charity further, please consider <0>making a one-time donation</0>, <1>sending us a check</1>, or <2>learning about other ways you could support our charity.</2>",
"failed-pay": "Uh - oh. It looks like your transaction didn't go through. Could you please try again?",
"try-again": "Please try again.",
"card-number": "Your Card Number:",
@@ -573,14 +577,15 @@
"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.",
"crucial-contribution": "Your contribution will be crucial in creating resources that empower millions of people to learn new skills and support their families.",
"if-another-monthly": "If you want to make another monthly donation, please proceed with selecting your monthly donation amount.",
"support-benefits-title": "Benefits from becoming a Supporter:",
"support-benefits-1": "No more donation prompt popups",
"support-benefits-2": "You'll get a Supporter badge",
"support-benefits-3": "Your profile image will get a golden halo around it",
"support-benefits-4": "You'll gain access to special Supporter Discord channels",
"support-benefits-5": "And more benefits to come in 2024",
"exclusive-features": "Here is the list of exclusive features for you as a Supporter:",
"current-initiatives-title": "Current Initiatives:",
"your-donation-helps-followings": "Your donation makes the following initiatives possible:",
"current-initiatives-1": "Creating new JavaScript and Python curricula",
"current-initiatives-2": "Creating English and math curricula",
"current-initiatives-3": "Translating our curriculum and tutorials into 32 languages",
@@ -631,6 +636,7 @@
"email": "Email",
"and": "and",
"update-your-card": "Update your card",
"supporters-page-title": "Supporters page",
"change-theme": "Sign in to change theme.",
"translation-pending": "Help us translate",
"certification-project": "Certification Project",

View File

@@ -0,0 +1,29 @@
import React from 'react';
function SupporterBadge(
props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>
): JSX.Element {
return (
<>
<svg
xmlns='http://www.w3.org/2000/svg'
width='304'
height='347'
viewBox='0 0 304 347'
fill='currentColor'
{...props}
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M0.5 -0.5V261L147.5 347L303.5 261V-0.5H0.5ZM68.625 61.9398C68.6211 60.616 67.7036 59.3001 66.786 58.3863C65.4624 57.4725 64.088 57.0196 62.7683 57.0235C58.7037 57.0313 52.7454 61.2369 45.6002 69.3319C25.7459 91.9846 15.602 113.927 16.012 146.283C16.4571 178.624 24.3832 202.354 41.9144 223.843C50.9181 235.179 57.8135 241.006 62.7409 240.994C64.0607 240.994 65.8919 240.072 66.7509 239.155C67.6645 237.831 68.5742 236.456 68.5742 235.136C68.5664 232.442 66.7274 229.295 62.249 225.292C40.9539 205.01 29.9979 178.839 29.9198 146.252C29.8495 116.797 40.2667 92.3751 60.9761 72.4324C65.9426 67.3326 68.6289 64.2281 68.625 61.9398ZM175.561 152.082C173.541 151.566 174.198 148.64 175.284 143.8C178.383 129.999 184.975 100.635 142.959 67.192C142.959 67.192 150.405 90.8522 112.859 143.651C77.276 193.646 124.091 224.496 129.131 227.612C129.406 227.79 129.562 227.873 129.562 227.873C129.562 227.873 129.411 227.786 129.131 227.612C125.903 225.528 106.418 210.506 133.701 165.972C135.302 163.323 137.052 160.75 138.953 157.956C143.343 151.502 148.535 143.868 154.543 131.397C154.543 131.397 162.165 142.156 158.186 165.48C152.921 196.666 177.176 192.362 183.174 191.297H183.174C183.955 191.158 184.426 191.075 184.483 191.132C195.372 203.954 176.028 226.313 174.149 227.811C174.05 227.877 174.019 227.898 174.062 227.873C174.085 227.86 174.114 227.839 174.149 227.811L174.157 227.805C176.973 225.931 230.459 190.319 189.957 137.684C189.149 138.492 188.273 140.138 187.259 142.044C184.661 146.926 181.156 153.514 175.561 152.082ZM236.132 61.9164C236.136 60.5926 237.053 59.2766 237.971 58.3629C239.294 57.4491 240.669 56.9961 241.988 57C246.053 57.0078 252.011 61.2135 259.157 69.3085C279.011 91.9611 289.155 113.903 288.745 146.26C288.3 178.6 280.374 202.331 262.842 223.82C253.839 235.156 246.943 240.982 242.016 240.97C240.696 240.967 238.865 240.049 238.006 239.131C237.092 237.807 236.182 236.433 236.182 235.113C236.19 232.419 238.029 229.271 242.508 225.269C263.803 204.986 274.759 178.815 274.837 146.228C274.907 116.773 264.49 92.3477 243.781 72.409C238.814 67.3091 236.128 64.2047 236.132 61.9164Z'
fill='currentColor'
/>
</svg>
</>
);
}
SupporterBadge.displayName = 'SupporterBadge';
export default SupporterBadge;

View File

@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
import Spinner from 'react-spinkit';
import { Alert } from '@freecodecamp/ui';
import { Spacer } from '../helpers';
import { Link, Spacer } from '../helpers';
type DonateCompletionProps = {
error: string | null;
@@ -50,7 +50,20 @@ function DonateCompletion({
{success && (
<div>
<p>{t('donate.free-tech')}</p>
{isSignedIn && <p>{t('donate.no-halo')}</p>}
{isSignedIn && (
<>
<p>{t('donate.visit-supporters')}</p>
<Link
className='btn'
key='supporters'
sameTab={false}
to='/supporters'
>
{t('buttons.go-to-supporters')}
</Link>
</>
)}
</div>
)}
{error && <p>{error}</p>}

View File

@@ -33,9 +33,11 @@ export const CtaText = (): JSX.Element => {
};
export const ThankYouMessage = ({
askForDonation
askForDonation,
thankContributon
}: {
askForDonation: boolean;
thankContributon?: boolean;
}): JSX.Element => {
const { t } = useTranslation();
return (
@@ -43,25 +45,32 @@ export const ThankYouMessage = ({
<h1 data-playwright-test-label='main-head' data-cy='donate.thank-you'>
{t('donate.thank-you')}
</h1>
{askForDonation && (
{(askForDonation || thankContributon) && (
<>
<Spacer size='medium' />
<p data-cy='donate.crucial-contribution'>
{t('donate.crucial-contribution')}
</p>
<p data-cy='donate.bigger-donation'>
{t('donate.bigger-donation')}{' '}
<Trans i18nKey='donate.other-ways'>
<a data-cy='donate-link' href={t('links:donate.other-ways-url')}>
placeholder
</a>
</Trans>
</p>
<p data-cy='donate.make-another-monthly'>
{t('donate.if-another-monthly')}
</p>
</>
)}
{askForDonation && <OtherWaysToSupport />}
</>
);
};
export const OtherWaysToSupport = (): JSX.Element => {
const { t } = useTranslation();
return (
<>
<p data-cy='donate.if-support-further'>
<Trans i18nKey='donate.if-support-further'>
<a href={t('links:donate.one-time-external-url')}>placeholder</a>
<a href={t('links:donate.mail-check-url')}>placeholder</a>
<a data-cy='donate-link' href={t('links:donate.other-ways-url')}>
placeholder
</a>
</Trans>
</p>
</>
);
};
@@ -198,27 +207,50 @@ export const DonationFaqText = (): JSX.Element => {
);
};
export const SupportBenefitsText = (): JSX.Element => {
export const SupportBenefitsText = ({
isSupportersPage
}: {
isSupportersPage?: boolean;
}): JSX.Element => {
const { t } = useTranslation();
return (
<>
<h2>{t('donate.support-benefits-title')}</h2>
<ul>
<li>{t('donate.support-benefits-1')}</li>
<li>{t('donate.support-benefits-2')}</li>
<li>{t('donate.support-benefits-3')}</li>
<li>{t('donate.support-benefits-4')}</li>
<li>{t('donate.support-benefits-5')}</li>
</ul>
<h2>
{isSupportersPage
? t('donate.exclusive-features')
: t('donate.support-benefits-title')}
</h2>
<BenefitsList />
</>
);
};
export const CurrentInitiativesText = (): JSX.Element => {
const BenefitsList = (): JSX.Element => {
const { t } = useTranslation();
return (
<ul>
<li>{t('donate.support-benefits-1')}</li>
<li>{t('donate.support-benefits-2')}</li>
<li>{t('donate.support-benefits-3')}</li>
<li>{t('donate.support-benefits-4')}</li>
<li>{t('donate.support-benefits-5')}</li>
</ul>
);
};
export const CurrentInitiativesText = ({
isSupportersPage
}: {
isSupportersPage?: boolean;
}): JSX.Element => {
const { t } = useTranslation();
return (
<>
<h2>{t('donate.current-initiatives-title')}</h2>
<h2>
{isSupportersPage
? t('donate.your-donation-helps-followings')
: t('donate.current-initiatives-title')}
</h2>
<ul>
<li>{t('donate.current-initiatives-1')}</li>
<li>{t('donate.current-initiatives-2')}</li>

View File

@@ -638,22 +638,22 @@ a.patreon-button:hover {
/* donation page */
.donate-page-container h1,
.donate-page-container h2,
.donate-page-container h3 {
.donate-supporter-page-section h1,
.donate-supporter-page-section h2,
.donate-supporter-page-section h3 {
font-family: var(--font-family-sans-serif);
}
.donate-page-container h1 {
.donate-supporter-page-section h1 {
font-size: 2.5rem;
}
.donate-page-container .donation-section > div {
.donate-supporter-page-section .donation-section > div {
margin-top: 40px;
margin-bottom: 40px;
}
.donate-page-container .donation-section {
.donate-supporter-page-section .donation-section {
display: flex;
justify-content: center;
align-items: center;
@@ -661,11 +661,12 @@ a.patreon-button:hover {
min-height: 60vh;
}
.donate-page-container .paypal-buttons-container {
.donate-supporter-page-section .paypal-buttons-container {
margin-bottom: 0;
}
.dark-palette .gradient-container {
position: relative;
background: linear-gradient(
-10deg,
rgb(7 40 94) 35%,
@@ -676,6 +677,7 @@ a.patreon-button:hover {
}
.light-palette .gradient-container {
position: relative;
background: linear-gradient(
-10deg,
rgb(223 243 255) 35%,
@@ -689,19 +691,48 @@ a.patreon-button:hover {
);
}
.supporters-background {
background-repeat: repeat;
}
.dark-palette .supporters-background {
background-image: url("data:image/svg+xml,%3Csvg width='248' height='307' viewBox='0 0 248 307' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M125 154V193.7L147.317 206.756L171 193.7V154H125ZM135.343 163.479C135.342 163.278 135.203 163.079 135.063 162.94C134.862 162.801 134.654 162.732 134.453 162.733C133.836 162.734 132.932 163.373 131.847 164.602C128.833 168.041 127.293 171.372 127.355 176.284C127.423 181.194 128.626 184.796 131.287 188.059C132.654 189.78 133.701 190.664 134.449 190.663C134.65 190.663 134.928 190.523 135.058 190.383C135.197 190.182 135.335 189.974 135.335 189.773C135.334 189.364 135.054 188.886 134.375 188.279C131.142 185.2 129.478 181.226 129.466 176.279C129.456 171.807 131.037 168.1 134.181 165.072C134.935 164.298 135.343 163.827 135.343 163.479ZM151.577 177.164C151.27 177.086 151.37 176.642 151.535 175.907C152.005 173.812 153.006 169.354 146.627 164.277C146.627 164.277 147.758 167.869 142.058 175.884C136.656 183.474 143.763 188.158 144.528 188.631C144.57 188.658 144.594 188.671 144.594 188.671C144.594 188.671 144.571 188.657 144.528 188.631C144.038 188.314 141.08 186.034 145.222 179.273C145.465 178.871 145.731 178.48 146.019 178.056C146.686 177.076 147.474 175.917 148.386 174.024C148.386 174.024 149.543 175.657 148.939 179.198C148.14 183.933 151.822 183.279 152.733 183.118C152.851 183.097 152.923 183.084 152.931 183.093C154.584 185.039 151.648 188.434 151.362 188.661C151.347 188.671 151.343 188.674 151.349 188.671C151.353 188.669 151.357 188.665 151.362 188.661L151.364 188.66C151.791 188.376 159.911 182.969 153.762 174.978C153.64 175.101 153.507 175.351 153.353 175.64C152.958 176.382 152.426 177.382 151.577 177.164ZM160.773 163.476C160.773 163.275 160.912 163.075 161.052 162.936C161.253 162.798 161.461 162.729 161.662 162.729C162.279 162.731 163.183 163.369 164.268 164.598C167.282 168.037 168.822 171.368 168.76 176.28C168.692 181.19 167.489 184.793 164.828 188.055C163.461 189.776 162.414 190.661 161.666 190.659C161.465 190.658 161.187 190.519 161.057 190.38C160.918 190.179 160.78 189.97 160.78 189.77C160.781 189.361 161.061 188.883 161.741 188.275C164.973 185.196 166.637 181.223 166.649 176.276C166.659 171.804 165.078 168.096 161.934 165.069C161.18 164.294 160.772 163.823 160.773 163.476Z' fill='%23FEB13E' fill-opacity='0.1'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 1V40.6997L22.3168 53.7558L46 40.6997V1H0ZM10.3425 10.4794C10.3419 10.2784 10.2026 10.0786 10.0633 9.93991C9.86238 9.80119 9.65373 9.73242 9.45338 9.73301C8.83631 9.7342 7.93176 10.3727 6.84701 11.6016C3.83281 15.0406 2.29282 18.3718 2.35506 23.284C2.42263 28.1938 3.62594 31.7964 6.28744 35.0588C7.65435 36.7798 8.70116 37.6643 9.44923 37.6625C9.64958 37.6625 9.92759 37.5226 10.058 37.3833C10.1967 37.1823 10.3348 36.9736 10.3348 36.7733C10.3336 36.3642 10.0544 35.8864 9.37454 35.2787C6.14162 32.1996 4.47833 28.2264 4.46648 23.2792C4.45581 18.8075 6.03729 15.0999 9.1813 12.0723C9.93529 11.2981 10.3431 10.8268 10.3425 10.4794ZM26.5768 24.1643C26.2701 24.0859 26.3698 23.6417 26.5348 22.9069C27.0051 20.8118 28.006 16.3539 21.6273 11.2767C21.6273 11.2767 22.7577 14.8686 17.0577 22.8843C11.6557 30.4742 18.7628 35.1577 19.5279 35.6309C19.5697 35.6578 19.5935 35.6705 19.5935 35.6705C19.5935 35.6705 19.5706 35.6572 19.5279 35.6309C19.038 35.3145 16.0798 33.0339 20.2218 26.273C20.4649 25.8708 20.7306 25.4802 21.0191 25.056C21.6856 24.0761 22.4739 22.9172 23.386 21.024C23.386 21.024 24.5431 22.6573 23.939 26.1983C23.1397 30.9329 26.822 30.2793 27.7326 30.1177C27.8511 30.0967 27.9227 30.084 27.9313 30.0926C29.5844 32.0392 26.6478 35.4336 26.3624 35.6611C26.3474 35.6711 26.3427 35.6743 26.3492 35.6705C26.3526 35.6685 26.357 35.6654 26.3624 35.6611L26.3637 35.6602C26.7912 35.3756 34.9112 29.9691 28.7623 21.9785C28.6397 22.1011 28.5067 22.351 28.3528 22.6403C27.9583 23.3816 27.4261 24.3817 26.5768 24.1643ZM35.7725 10.4757C35.7731 10.2747 35.9124 10.075 36.0517 9.93623C36.2527 9.79751 36.4613 9.72874 36.6617 9.72933C37.2787 9.73052 38.1833 10.369 39.2681 11.5979C42.2822 15.037 43.8222 18.3681 43.76 23.2803C43.6924 28.1901 42.4891 31.7928 39.8276 35.0551C38.4607 36.7761 37.4139 37.6606 36.6658 37.6588C36.4655 37.6582 36.1875 37.5189 36.0571 37.3796C35.9184 37.1786 35.7802 36.97 35.7802 36.7696C35.7814 36.3605 36.0606 35.8827 36.7405 35.2751C39.9734 32.1959 41.6367 28.2227 41.6486 23.2755C41.6592 18.8038 40.0778 15.0956 36.9338 12.0686C36.1798 11.2944 35.7719 10.8231 35.7725 10.4757Z' fill='%23FEB13E' fill-opacity='0.1'/%3E%3C/svg%3E%0A");
}
.light-palette .supporters-background {
background-image: url("data:image/svg+xml,%3Csvg width='248' height='307' viewBox='0 0 248 307' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M125 154V193.7L147.317 206.756L171 193.7V154H125ZM135.343 163.479C135.342 163.278 135.203 163.079 135.063 162.94C134.862 162.801 134.654 162.732 134.453 162.733C133.836 162.734 132.932 163.373 131.847 164.602C128.833 168.041 127.293 171.372 127.355 176.284C127.423 181.194 128.626 184.796 131.287 188.059C132.654 189.78 133.701 190.664 134.449 190.663C134.65 190.663 134.928 190.523 135.058 190.383C135.197 190.182 135.335 189.974 135.335 189.773C135.334 189.364 135.054 188.886 134.375 188.279C131.142 185.2 129.478 181.226 129.466 176.279C129.456 171.807 131.037 168.1 134.181 165.072C134.935 164.298 135.343 163.827 135.343 163.479ZM151.577 177.164C151.27 177.086 151.37 176.642 151.535 175.907C152.005 173.812 153.006 169.354 146.627 164.277C146.627 164.277 147.758 167.869 142.058 175.884C136.656 183.474 143.763 188.158 144.528 188.631C144.57 188.658 144.594 188.671 144.594 188.671C144.594 188.671 144.571 188.657 144.528 188.631C144.038 188.314 141.08 186.034 145.222 179.273C145.465 178.871 145.731 178.48 146.019 178.056C146.686 177.076 147.474 175.917 148.386 174.024C148.386 174.024 149.543 175.657 148.939 179.198C148.14 183.933 151.822 183.279 152.733 183.118C152.851 183.097 152.923 183.084 152.931 183.093C154.584 185.039 151.648 188.434 151.362 188.661C151.347 188.671 151.343 188.674 151.349 188.671C151.353 188.669 151.357 188.665 151.362 188.661L151.364 188.66C151.791 188.376 159.911 182.969 153.762 174.978C153.64 175.101 153.507 175.351 153.353 175.64C152.958 176.382 152.426 177.382 151.577 177.164ZM160.773 163.476C160.773 163.275 160.912 163.075 161.052 162.936C161.253 162.798 161.461 162.729 161.662 162.729C162.279 162.731 163.183 163.369 164.268 164.598C167.282 168.037 168.822 171.368 168.76 176.28C168.692 181.19 167.489 184.793 164.828 188.055C163.461 189.776 162.414 190.661 161.666 190.659C161.465 190.658 161.187 190.519 161.057 190.38C160.918 190.179 160.78 189.97 160.78 189.77C160.781 189.361 161.061 188.883 161.741 188.275C164.973 185.196 166.637 181.223 166.649 176.276C166.659 171.804 165.078 168.096 161.934 165.069C161.18 164.294 160.772 163.823 160.773 163.476Z' fill='%23FEB13E' fill-opacity='0.2'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 1V40.6997L22.3168 53.7558L46 40.6997V1H0ZM10.3425 10.4794C10.3419 10.2784 10.2026 10.0786 10.0633 9.93991C9.86238 9.80119 9.65373 9.73242 9.45338 9.73301C8.83631 9.7342 7.93176 10.3727 6.84701 11.6016C3.83281 15.0406 2.29282 18.3718 2.35506 23.284C2.42263 28.1938 3.62594 31.7964 6.28744 35.0588C7.65435 36.7798 8.70116 37.6643 9.44923 37.6625C9.64958 37.6625 9.92759 37.5226 10.058 37.3833C10.1967 37.1823 10.3348 36.9736 10.3348 36.7733C10.3336 36.3642 10.0544 35.8864 9.37454 35.2787C6.14162 32.1996 4.47833 28.2264 4.46648 23.2792C4.45581 18.8075 6.03729 15.0999 9.1813 12.0723C9.93529 11.2981 10.3431 10.8268 10.3425 10.4794ZM26.5768 24.1643C26.2701 24.0859 26.3698 23.6417 26.5348 22.9069C27.0051 20.8118 28.006 16.3539 21.6273 11.2767C21.6273 11.2767 22.7577 14.8686 17.0577 22.8843C11.6557 30.4742 18.7628 35.1577 19.5279 35.6309C19.5697 35.6578 19.5935 35.6705 19.5935 35.6705C19.5935 35.6705 19.5706 35.6572 19.5279 35.6309C19.038 35.3145 16.0798 33.0339 20.2218 26.273C20.4649 25.8708 20.7306 25.4802 21.0191 25.056C21.6856 24.0761 22.4739 22.9172 23.386 21.024C23.386 21.024 24.5431 22.6573 23.939 26.1983C23.1397 30.9329 26.822 30.2793 27.7326 30.1177C27.8511 30.0967 27.9227 30.084 27.9313 30.0926C29.5844 32.0392 26.6478 35.4336 26.3624 35.6611C26.3474 35.6711 26.3427 35.6743 26.3492 35.6705C26.3526 35.6685 26.357 35.6654 26.3624 35.6611L26.3637 35.6602C26.7912 35.3756 34.9112 29.9691 28.7623 21.9785C28.6397 22.1011 28.5067 22.351 28.3528 22.6403C27.9583 23.3816 27.4261 24.3817 26.5768 24.1643ZM35.7725 10.4757C35.7731 10.2747 35.9124 10.075 36.0517 9.93623C36.2527 9.79751 36.4613 9.72874 36.6617 9.72933C37.2787 9.73052 38.1833 10.369 39.2681 11.5979C42.2822 15.037 43.8222 18.3681 43.76 23.2803C43.6924 28.1901 42.4891 31.7928 39.8276 35.0551C38.4607 36.7761 37.4139 37.6606 36.6658 37.6588C36.4655 37.6582 36.1875 37.5189 36.0571 37.3796C35.9184 37.1786 35.7802 36.97 35.7802 36.7696C35.7814 36.3605 36.0606 35.8827 36.7405 35.2751C39.9734 32.1959 41.6367 28.2227 41.6486 23.2755C41.6592 18.8038 40.0778 15.0956 36.9338 12.0686C36.1798 11.2944 35.7719 10.8231 35.7725 10.4757Z' fill='%23FEB13E' fill-opacity='0.2'/%3E%3C/svg%3E%0A");
}
@media screen and (min-width: 991px) {
.donate-page-container .form-payment-methods {
.donate-supporter-page-section .form-payment-methods {
height: 22px;
width: 220px;
}
}
@media screen and (min-width: 1200px) {
.donate-page-container .form-payment-methods {
.donate-supporter-page-section .form-payment-methods {
height: 25px;
width: 250px;
}
.donate-page-container .donation-section {
.donate-supporter-page-section .donation-section {
flex-direction: row;
}
}
.supporter-badge-container {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 2em 0;
}
@media screen and (min-width: 1200px) {
.supporter-badge-container {
justify-content: left;
}
}
.supporter-badge-container svg {
height: 6em;
width: auto;
}

View File

@@ -1,8 +1,7 @@
import {
faCheckSquare,
faSquare,
faExternalLinkAlt,
faHeart
faExternalLinkAlt
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React, { Fragment } from 'react';
@@ -14,6 +13,7 @@ import { updateMyTheme } from '../../../redux/settings/actions';
import { Link } from '../../helpers';
import { type ThemeProps, Themes } from '../../settings/theme';
import { User } from '../../../redux/prop-types';
import SupporterBadge from '../../../assets/icons/supporter-badge';
export interface NavLinksProps extends Pick<ThemeProps, 'toggleNightMode'> {
displayMenu: boolean;
@@ -34,42 +34,34 @@ interface DonateButtonProps {
handleMenuKeyDown: (event: React.KeyboardEvent<HTMLAnchorElement>) => void;
}
type DonateItemProps = Pick<DonateButtonProps, 'handleMenuKeyDown'> & {
donateText: string;
};
const DonateItem = ({ handleMenuKeyDown, donateText }: DonateItemProps) => (
<li key='donate'>
<Link
className='nav-link'
onKeyDown={handleMenuKeyDown}
sameTab={false}
to='/donate'
data-test-label='dropdown-donate-button'
>
{donateText}
</Link>
</li>
);
const ThankYouMessage = ({ message }: { message: string }) => (
<li className='nav-link nav-link-flex nav-link-header' key='donate'>
{message}
<FontAwesomeIcon icon={faHeart} />
</li>
);
const DonateButton = ({
isUserDonating,
handleMenuKeyDown
}: DonateButtonProps) => {
const { t } = useTranslation();
if (isUserDonating) return <ThankYouMessage message={t('donate.thanks')} />;
return (
<DonateItem
handleMenuKeyDown={handleMenuKeyDown}
donateText={t('buttons.donate')}
/>
<li key={isUserDonating ? 'supporter' : 'donate'}>
<Link
className={`nav-link nav-link-flex nav-link-header ${
isUserDonating && 'nav-link-supporter'
}`}
onKeyDown={handleMenuKeyDown}
sameTab={false}
to={isUserDonating ? '/supporters' : '/donate'}
data-test-label={
isUserDonating ? 'dropdown-support-button' : 'dropdown-donate-button'
}
>
{isUserDonating ? (
<>
{t('buttons.supporters')}
<SupporterBadge />
</>
) : (
<>{t('buttons.donate')}</>
)}
</Link>
</li>
);
};

View File

@@ -172,6 +172,24 @@ li > button.nav-link-signout:not([aria-disabled='true']):is(:hover, :focus) {
color: var(--gray-45);
}
.nav-link-supporter {
color: var(--yellow-light);
background: var(--yellow-dark);
}
.nav-link-supporter:hover,
.nav-link-supporter:active,
.nav-link-supporter:focus,
.nav-link-supporter:focus-visible {
color: var(--yellow-dark) !important;
background: var(--yellow-light) !important;
}
.nav-link-supporter svg {
height: auto;
width: 1em;
}
/**
* Check mark for current language
*/

View File

@@ -523,9 +523,9 @@ blockquote .small {
.alert .btn,
[role='alert'] .btn {
background-color: #d9edf7;
color: #31708f;
border-color: #31708f;
background-color: transparent;
color: inherit;
border-color: inherit;
}
.alert .btn:hover,
.alert .btn:focus,

View File

@@ -23,3 +23,9 @@
.avatar-camper .avatar-container {
border-width: 10px;
}
.supporter svg {
height: 1.2em;
width: auto;
margin: 0 0.2em -0.3em 0.2em;
}

View File

@@ -1,8 +1,4 @@
import {
faAward,
faCalendar,
faHeart
} from '@fortawesome/free-solid-svg-icons';
import { faAward, faCalendar } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import type { TFunction } from 'i18next';
@@ -14,6 +10,7 @@ import { getLangCode } from '../../../../../shared/config/i18n';
import type { User } from '../../../redux/prop-types';
import { AvatarRenderer } from '../../helpers';
import Link from '../../helpers/link';
import SupporterBadge from '../../../assets/icons/supporter-badge';
import SocialIcons from './social-icons';
import './camper.css';
@@ -85,7 +82,6 @@ function Camper({
isDonating={isDonating}
isTopContributor={yearsTopContributor.length > 0}
picture={picture}
userName={username}
/>
</Col>
</Row>
@@ -102,7 +98,8 @@ function Camper({
{location && <p className='text-center location'>{location}</p>}
{isDonating && (
<p className='text-center supporter'>
<FontAwesomeIcon icon={faHeart} /> {t('profile.supporter')}
<SupporterBadge />
{t('profile.supporter')}
</p>
)}
{about && <p className='bio text-center'>{about}</p>}

View File

@@ -82,24 +82,30 @@ function DonatePage({
<>
<Helmet title={`${t('donate.title')} | freeCodeCamp.org`} />
<Container fluid={true} className='gradient-container'>
<Container className='donate-page-container'>
<Row className={'donation-section'}>
<Col lg={6} lgOffset={0} md={8} mdOffset={1} sm={12}>
{isDonating ? (
<ThankYouMessage askForDonation={!donationFormState.success} />
) : (
<CtaText />
)}
</Col>
<Col lg={6} lgOffset={0} md={12}>
<MultiTierDonationForm
paymentContext={PaymentContext.DonatePage}
/>
</Col>
</Row>
<Container className='donate-supporter-page-section'>
<main>
<Row className={'donation-section'}>
<Col lg={6} lgOffset={0} md={8} mdOffset={1} sm={12}>
{isDonating ? (
<ThankYouMessage
askForDonation={!donationFormState.success}
/>
) : (
<CtaText />
)}
</Col>
<Col lg={6} lgOffset={0} md={8} mdOffset={1} sm={12}>
{!isDonating || donationFormState.success ? (
<MultiTierDonationForm
paymentContext={PaymentContext.DonatePage}
/>
) : null}
</Col>
</Row>
</main>
</Container>
</Container>
<Container className='donate-page-container'>
<Container className='donate-supporter-page-section'>
<Row>
<Col lg={6} lgOffset={0} md={8} mdOffset={2} sm={10}>
<Spacer size='large' />
@@ -133,7 +139,7 @@ function DonatePage({
</Col>
</Row>
</Container>
<Container className='donate-page-container'>
<Container className='donate-supporter-page-section'>
<Row>
<Col lg={10} lgOffset={0} md={8} mdOffset={2} sm={10}>
<DonationFaqText />

View File

@@ -0,0 +1,152 @@
import React from 'react';
import Helmet from 'react-helmet';
import { withTranslation, useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Container, Row, Col } from '@freecodecamp/ui';
import BigCallToAction from '../components/landing/components/big-call-to-action';
import { Spacer } from '../components/helpers';
import {
isSignedInSelector,
isDonatingSelector,
updateCardStateSelector
} from '../redux/selectors';
import { updateCard, updateCardComplete } from '../redux/actions';
import { UpdateCardState } from '../redux/types';
import {
DonationFaqText,
ThankYouMessage,
SupportBenefitsText,
CurrentInitiativesText
} from '../components/Donation/donation-text-components';
import SupporterBadge from '../assets/icons/supporter-badge';
interface SupportersPageProps {
isNewEmail: boolean;
resetDonationFormState: () => void;
isSignedIn: boolean;
isDonating: boolean;
updateCardState: UpdateCardState;
updateCard: () => void;
updateCardComplete: () => void;
}
const mapStateToProps = createSelector(
isSignedInSelector,
isDonatingSelector,
updateCardStateSelector,
(
isSignedIn: boolean,
isDonating: boolean,
updateCardState: UpdateCardState
) => ({
isSignedIn,
isDonating,
updateCardState
})
);
const mapDispatchToProps = { updateCard, updateCardComplete };
function ConditionalContent({
isSignedIn,
isDonating
}: {
isSignedIn: boolean;
isDonating: boolean;
}) {
const { t } = useTranslation();
if (isSignedIn && !isDonating) {
return (
<Col md={12}>
<Spacer size='large' />
<h1 id='content-start' className='text-center'>
{t('learn.donation-record-not-found')}
</h1>
<Spacer size='medium' />
<p className='text-center'>{t('learn.contact-support-mistake')}</p>
<Spacer size='large' />
</Col>
);
} else if (isSignedIn && isDonating) {
return (
<>
<Col lg={6} lgOffset={0} md={8} mdOffset={1} sm={12}>
<div className='supporter-badge-container'>
<SupporterBadge />
</div>
<ThankYouMessage askForDonation={false} thankContributon={true} />
</Col>
<Col lg={6} lgOffset={0} md={8} mdOffset={1} sm={12}>
<CurrentInitiativesText isSupportersPage={true} />
<Spacer size='medium' />
<SupportBenefitsText isSupportersPage={true} />
</Col>
</>
);
} else
return (
<Col md={12}>
<Spacer size='large' />
<h1 id='content-start' className='text-center'>
{t('learn.sign-in-see-benefits')}
</h1>
<Spacer size='large' />
<BigCallToAction text={t('buttons.sign-in')} />
<Spacer size='large' />
</Col>
);
}
function SupportersPage({ isSignedIn, isDonating }: SupportersPageProps) {
const { t } = useTranslation();
return (
<>
<Helmet>
<title>{t('misc.supporters-page-title')} | freeCodeCamp.org</title>
</Helmet>
<Container
fluid={true}
className={`${isDonating && 'supporters-background'} `}
>
<Container className='donate-supporter-page-section'>
<main>
<Row className={'donation-section'}>
<ConditionalContent
isSignedIn={isSignedIn}
isDonating={isDonating}
/>
</Row>
</main>
</Container>
</Container>
<Container fluid={true}>
<Row>
<Col sm={12}>
<hr />
</Col>
</Row>
</Container>
<Container className='donate-supporter-page-section'>
<Spacer size='large' />
<Row>
<Col lg={10} lgOffset={0} md={8} mdOffset={2} sm={10}>
<DonationFaqText />
</Col>
</Row>
<Spacer size='large' />
</Container>
</>
);
}
SupportersPage.displayName = 'Supporters-Page';
export default connect(
mapStateToProps,
mapDispatchToProps
)(withTranslation()(SupportersPage));

View File

@@ -8,24 +8,20 @@ describe('Donate page', () => {
cy.visit('/donate');
cy.get('[data-cy="donate.thank-you"]').should(
'have.text',
'Thank you for being a supporter.'
'Thank You for Being a Supporter'
);
cy.get('[data-cy="donate.crucial-contribution"]').should(
'have.text',
'Your contribution will be crucial in creating resources that empower millions of people to learn new skills and support their families.'
);
cy.get('[data-cy="donate.bigger-donation"]').should(
cy.get('[data-cy="donate.if-support-further"]').should(
'have.text',
"Want to make a bigger one-time donation, mail us a check, or give in other ways? Here are many other ways you can support our charity's mission."
'If you want to support our charity further, please consider making a one-time donation, sending us a check, or learning about other ways you could support our charity.'
);
cy.get('[data-cy="donate-link"]').should(
'contain.attr',
'href',
'https://www.freecodecamp.org/news/how-to-donate-to-free-code-camp'
);
cy.get('[data-cy="donate.make-another-monthly"]').should(
'have.text',
'If you want to make another monthly donation, please proceed with selecting your monthly donation amount.'
);
});
});

View File

@@ -104,7 +104,7 @@ describe('Donor Navigation Menu', () => {
'have.class',
'gold-border'
);
cy.get(navigationItems['navigation-list']).contains('Thanks for donating');
cy.get(navigationItems['navigation-list']).contains('Supporters');
});
});