feat: a/b test lock icon (#45499)
* feat: a/b test * Update client/i18n/locales/english/translations.json * Apply suggestions from code review
This commit is contained in:
@ -52,7 +52,6 @@
|
||||
"@reach/router": "1.3.4",
|
||||
"@stripe/react-stripe-js": "1.7.0",
|
||||
"@stripe/stripe-js": "1.25.0",
|
||||
"@types/canvas-confetti": "1.4.2",
|
||||
"@types/react-scrollable-anchor": "0.6.1",
|
||||
"algoliasearch": "4.13.0",
|
||||
"assert": "2.0.0",
|
||||
@ -61,7 +60,6 @@
|
||||
"bezier-easing": "2.1.0",
|
||||
"browser-cookies": "1.2.0",
|
||||
"buffer": "6.0.3",
|
||||
"canvas-confetti": "1.5.1",
|
||||
"chai": "4.3.6",
|
||||
"crypto-browserify": "3.12.0",
|
||||
"date-fns": "2.27.0",
|
||||
|
@ -23,7 +23,8 @@ import {
|
||||
defaultDonationFormState,
|
||||
userSelector,
|
||||
postChargeStripe,
|
||||
postChargeStripeCard
|
||||
postChargeStripeCard,
|
||||
isAVariantSelector
|
||||
} from '../../redux';
|
||||
import Spacer from '../helpers/spacer';
|
||||
import { Themes } from '../settings/theme';
|
||||
@ -33,6 +34,7 @@ import type { AddDonationData } from './paypal-button';
|
||||
import PaypalButton from './paypal-button';
|
||||
import StripeCardForm, { HandleAuthentication } from './stripe-card-form';
|
||||
import WalletsWrapper from './walletsButton';
|
||||
import SecurityLockIcon from './security-lock-icon';
|
||||
|
||||
import './donation.css';
|
||||
|
||||
@ -78,6 +80,7 @@ type DonateFormProps = {
|
||||
) => string;
|
||||
theme: Themes;
|
||||
updateDonationFormState: (state: AddDonationData) => unknown;
|
||||
isAVariant: boolean;
|
||||
};
|
||||
|
||||
const mapStateToProps = createSelector(
|
||||
@ -86,19 +89,22 @@ const mapStateToProps = createSelector(
|
||||
isDonatingSelector,
|
||||
donationFormStateSelector,
|
||||
userSelector,
|
||||
isAVariantSelector,
|
||||
(
|
||||
showLoading: DonateFormProps['showLoading'],
|
||||
isSignedIn: DonateFormProps['isSignedIn'],
|
||||
isDonating: DonateFormProps['isDonating'],
|
||||
donationFormState: DonateFormState,
|
||||
{ email, theme }: { email: string; theme: Themes }
|
||||
{ email, theme }: { email: string; theme: Themes },
|
||||
isAVariant: boolean
|
||||
) => ({
|
||||
isSignedIn,
|
||||
isDonating,
|
||||
showLoading,
|
||||
donationFormState,
|
||||
email,
|
||||
theme
|
||||
theme,
|
||||
isAVariant
|
||||
})
|
||||
);
|
||||
|
||||
@ -315,7 +321,8 @@ class DonateForm extends Component<DonateFormProps, DonateFormComponentState> {
|
||||
t,
|
||||
isMinimalForm,
|
||||
isSignedIn,
|
||||
isDonating
|
||||
isDonating,
|
||||
isAVariant
|
||||
} = this.props;
|
||||
const priorityTheme = defaultTheme ? defaultTheme : theme;
|
||||
const isOneTime = donationDuration === 'onetime';
|
||||
@ -328,6 +335,7 @@ class DonateForm extends Component<DonateFormProps, DonateFormComponentState> {
|
||||
return (
|
||||
<>
|
||||
<b className={isMinimalForm ? 'donation-label-modal' : ''}>
|
||||
{isAVariant === false && <SecurityLockIcon />}
|
||||
{this.getDonationButtonLabel()}:
|
||||
</b>
|
||||
<Spacer />
|
||||
@ -366,6 +374,7 @@ class DonateForm extends Component<DonateFormProps, DonateFormComponentState> {
|
||||
processing={processing}
|
||||
t={t}
|
||||
theme={priorityTheme}
|
||||
isAVariant={isAVariant}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -334,6 +334,10 @@ li.disabled > a {
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.confirm-donation-btn svg.svg-inline--fa.fa-lock {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 355px) {
|
||||
.form-payment-methods {
|
||||
height: 30px;
|
||||
|
14
client/src/components/Donation/security-lock-icon.tsx
Normal file
14
client/src/components/Donation/security-lock-icon.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { faLock } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
const SecurityLockIcon = (): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<FontAwesomeIcon icon={faLock} />
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SecurityLockIcon;
|
@ -17,6 +17,7 @@ import React, { useState } from 'react';
|
||||
import envData from '../../../../config/env.json';
|
||||
import { Themes } from '../settings/theme';
|
||||
import { AddDonationData } from './paypal-button';
|
||||
import SecurityLockIcon from './security-lock-icon';
|
||||
|
||||
const { stripePublicKey }: { stripePublicKey: string | null } = envData;
|
||||
|
||||
@ -34,6 +35,7 @@ interface FormPropTypes {
|
||||
t: (label: string) => string;
|
||||
theme: Themes;
|
||||
processing: boolean;
|
||||
isAVariant: boolean;
|
||||
}
|
||||
|
||||
interface Element {
|
||||
@ -49,7 +51,8 @@ const StripeCardForm = ({
|
||||
t,
|
||||
onDonationStateChange,
|
||||
postStripeCardDonation,
|
||||
processing
|
||||
processing,
|
||||
isAVariant
|
||||
}: FormPropTypes): JSX.Element => {
|
||||
const [isSubmissionValid, setSubmissionValidity] = useState(true);
|
||||
const [isTokenizing, setTokenizing] = useState(false);
|
||||
@ -167,7 +170,8 @@ const StripeCardForm = ({
|
||||
disabled={!stripe || !elements || isSubmitting}
|
||||
type='submit'
|
||||
>
|
||||
Donate
|
||||
{isAVariant === false && <SecurityLockIcon />}
|
||||
{t('buttons.donate')}
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
take
|
||||
} from 'redux-saga/effects';
|
||||
import i18next from 'i18next';
|
||||
import { fireConfetti } from '../utils/fire-confetti';
|
||||
|
||||
import {
|
||||
addDonation,
|
||||
@ -28,8 +27,7 @@ import {
|
||||
postChargeStripeComplete,
|
||||
postChargeStripeError,
|
||||
postChargeStripeCardComplete,
|
||||
postChargeStripeCardError,
|
||||
isAVariantSelector
|
||||
postChargeStripeCardError
|
||||
} from './';
|
||||
|
||||
const defaultDonationErrorMessage = i18next.t('donate.error-2');
|
||||
@ -40,12 +38,6 @@ function* showDonateModalSaga() {
|
||||
yield delay(200);
|
||||
const recentlyClaimedBlock = yield select(recentlyClaimedBlockSelector);
|
||||
yield put(openDonationModal());
|
||||
if (recentlyClaimedBlock) {
|
||||
const isAVariant = yield select(isAVariantSelector);
|
||||
if (isAVariant === false) {
|
||||
fireConfetti();
|
||||
}
|
||||
}
|
||||
yield take(appTypes.closeDonationModal);
|
||||
if (recentlyClaimedBlock) {
|
||||
yield put(preventBlockDonationRequests());
|
||||
|
@ -1,48 +0,0 @@
|
||||
import confetti from 'canvas-confetti';
|
||||
|
||||
export const fireConfetti = () => {
|
||||
const count = 200;
|
||||
const defaults = {
|
||||
origin: { y: 0.7 },
|
||||
zIndex: 10000
|
||||
};
|
||||
|
||||
function fire(
|
||||
particleRatio: number,
|
||||
opts: {
|
||||
spread?: number;
|
||||
startVelocity?: number;
|
||||
decay?: number;
|
||||
scalar?: number;
|
||||
}
|
||||
) {
|
||||
confetti(
|
||||
Object.assign({}, defaults, opts, {
|
||||
particleCount: Math.floor(count * particleRatio)
|
||||
})
|
||||
)?.catch(err => console.log(err));
|
||||
}
|
||||
|
||||
fire(0.25, {
|
||||
spread: 26,
|
||||
startVelocity: 55
|
||||
});
|
||||
fire(0.2, {
|
||||
spread: 60
|
||||
});
|
||||
fire(0.35, {
|
||||
spread: 100,
|
||||
decay: 0.91,
|
||||
scalar: 0.8
|
||||
});
|
||||
fire(0.1, {
|
||||
spread: 120,
|
||||
startVelocity: 25,
|
||||
decay: 0.92,
|
||||
scalar: 1.2
|
||||
});
|
||||
fire(0.1, {
|
||||
spread: 120,
|
||||
startVelocity: 45
|
||||
});
|
||||
};
|
@ -94,7 +94,7 @@ const patreonDefaultPledgeAmount = 500;
|
||||
|
||||
const aBTestConfig = {
|
||||
isTesting: true,
|
||||
type: 'badgeProgressModalCopy'
|
||||
type: 'addSecurityLock'
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
28
package-lock.json
generated
28
package-lock.json
generated
@ -985,7 +985,6 @@
|
||||
"@reach/router": "1.3.4",
|
||||
"@stripe/react-stripe-js": "1.7.0",
|
||||
"@stripe/stripe-js": "1.25.0",
|
||||
"@types/canvas-confetti": "1.4.2",
|
||||
"@types/react-scrollable-anchor": "0.6.1",
|
||||
"algoliasearch": "4.13.0",
|
||||
"assert": "2.0.0",
|
||||
@ -994,7 +993,6 @@
|
||||
"bezier-easing": "2.1.0",
|
||||
"browser-cookies": "1.2.0",
|
||||
"buffer": "6.0.3",
|
||||
"canvas-confetti": "1.5.1",
|
||||
"chai": "4.3.6",
|
||||
"crypto-browserify": "3.12.0",
|
||||
"date-fns": "2.27.0",
|
||||
@ -15173,11 +15171,6 @@
|
||||
"@types/responselike": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/canvas-confetti": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.4.2.tgz",
|
||||
"integrity": "sha512-t45KUDHlwrD9PJVRHc5z1SlXhO82BQEgMKUXGEV1KnWLFMPA6Y5LfUsLTHHzH9KcKDHZLEiYYH5nIDcjRKWNTg=="
|
||||
},
|
||||
"node_modules/@types/chai": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz",
|
||||
@ -20421,15 +20414,6 @@
|
||||
"resolved": "https://registry.npmjs.org/canonical-json/-/canonical-json-0.0.4.tgz",
|
||||
"integrity": "sha1-ZXnAcsPbXEd+xB3JePvyuPQQdKM="
|
||||
},
|
||||
"node_modules/canvas-confetti": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.5.1.tgz",
|
||||
"integrity": "sha512-Ncz+oZJP6OvY7ti4E1slxVlyAV/3g7H7oQtcCDXgwGgARxPnwYY9PW5Oe+I8uvspYNtuHviAdgA0LfcKFWJfpg==",
|
||||
"funding": {
|
||||
"type": "donate",
|
||||
"url": "https://www.paypal.me/kirilvatev"
|
||||
}
|
||||
},
|
||||
"node_modules/capture-exit": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
|
||||
@ -56530,7 +56514,6 @@
|
||||
"@stripe/stripe-js": "1.25.0",
|
||||
"@testing-library/jest-dom": "5.16.2",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@types/canvas-confetti": "1.4.2",
|
||||
"@types/react-scrollable-anchor": "0.6.1",
|
||||
"algoliasearch": "4.13.0",
|
||||
"assert": "2.0.0",
|
||||
@ -56541,7 +56524,6 @@
|
||||
"bezier-easing": "2.1.0",
|
||||
"browser-cookies": "1.2.0",
|
||||
"buffer": "6.0.3",
|
||||
"canvas-confetti": "1.5.1",
|
||||
"chai": "4.3.6",
|
||||
"chokidar": "3.5.3",
|
||||
"copy-webpack-plugin": "9.1.0",
|
||||
@ -65612,11 +65594,6 @@
|
||||
"@types/responselike": "*"
|
||||
}
|
||||
},
|
||||
"@types/canvas-confetti": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.4.2.tgz",
|
||||
"integrity": "sha512-t45KUDHlwrD9PJVRHc5z1SlXhO82BQEgMKUXGEV1KnWLFMPA6Y5LfUsLTHHzH9KcKDHZLEiYYH5nIDcjRKWNTg=="
|
||||
},
|
||||
"@types/chai": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz",
|
||||
@ -70080,11 +70057,6 @@
|
||||
"resolved": "https://registry.npmjs.org/canonical-json/-/canonical-json-0.0.4.tgz",
|
||||
"integrity": "sha1-ZXnAcsPbXEd+xB3JePvyuPQQdKM="
|
||||
},
|
||||
"canvas-confetti": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.5.1.tgz",
|
||||
"integrity": "sha512-Ncz+oZJP6OvY7ti4E1slxVlyAV/3g7H7oQtcCDXgwGgARxPnwYY9PW5Oe+I8uvspYNtuHviAdgA0LfcKFWJfpg=="
|
||||
},
|
||||
"capture-exit": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
|
||||
|
Reference in New Issue
Block a user