fix: add donation ga and tests (#38003)

* fix: add donation ga

* feat: add ga-saga tests
This commit is contained in:
Ahmad Abdolsaheb
2020-02-04 08:43:56 +03:00
committed by GitHub
parent 992ee98cc1
commit 24eb2c4310
19 changed files with 360 additions and 168 deletions

View File

@@ -34,6 +34,7 @@ const numToCommas = num =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
const propTypes = {
handleProcessing: PropTypes.func,
isDonating: PropTypes.bool,
isSignedIn: PropTypes.bool,
navigate: PropTypes.func.isRequired,
@@ -191,7 +192,7 @@ class DonateForm extends Component {
}
renderDonationOptions() {
const { stripe } = this.props;
const { stripe, handleProcessing } = this.props;
const { donationAmount, donationDuration, paymentType } = this.state;
return (
<div>
@@ -203,6 +204,7 @@ class DonateForm extends Component {
donationAmount={donationAmount}
donationDuration={donationDuration}
getDonationButtonLabel={this.getDonationButtonLabel}
handleProcessing={handleProcessing}
hideAmountOptionsCB={this.hideAmountOptionsCB}
/>
</Elements>

View File

@@ -24,6 +24,7 @@ const propTypes = {
donationDuration: PropTypes.string.isRequired,
email: PropTypes.string,
getDonationButtonLabel: PropTypes.func.isRequired,
handleProcessing: PropTypes.func,
isSignedIn: PropTypes.bool,
showCloseBtn: PropTypes.func,
stripe: PropTypes.shape({
@@ -146,8 +147,11 @@ class DonateFormChildViewForHOC extends Component {
// change the donation modal button label to close
// or display the close button for the cert donation section
if (this.props.showCloseBtn) {
this.props.showCloseBtn();
if (this.props.handleProcessing) {
this.props.handleProcessing(
this.state.donationDuration,
Math.round(this.state.donationAmount / 100)
);
}
return postChargeStripe({

View File

@@ -11,11 +11,11 @@ import Heart from '../../assets/icons/Heart';
import Cup from '../../assets/icons/Cup';
import MinimalDonateForm from './MinimalDonateForm';
import ga from '../../analytics';
import {
closeDonationModal,
isDonationModalOpenSelector,
isBlockDonationModalSelector
isBlockDonationModalSelector,
executeGA
} from '../../redux';
import { challengeMetaSelector } from '../../templates/Challenges/redux';
@@ -36,7 +36,8 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
closeDonationModal
closeDonationModal,
executeGA
},
dispatch
);
@@ -45,18 +46,44 @@ const propTypes = {
activeDonors: PropTypes.number,
block: PropTypes.string,
closeDonationModal: PropTypes.func.isRequired,
executeGA: PropTypes.func,
isBlockDonation: PropTypes.bool,
show: PropTypes.bool
};
function DonateModal({ show, block, isBlockDonation, closeDonationModal }) {
function DonateModal({
show,
block,
isBlockDonation,
closeDonationModal,
executeGA
}) {
const [closeLabel, setCloseLabel] = React.useState(false);
const showCloseBtn = () => {
const handleProcessing = (duration, amount) => {
executeGA({
type: 'event',
data: {
category: 'donation',
action: 'Modal strip form submission',
label: duration,
value: amount
}
});
setCloseLabel(true);
};
if (show) {
ga.modalview('/donation-modal');
executeGA({ type: 'modal', data: '/donation-modal' });
executeGA({
type: 'event',
data: {
category: 'Donation',
action: `Displayed ${
isBlockDonation ? 'block' : 'progress'
} donation modal`,
nonInteraction: true
}
});
}
const donationText = (
@@ -101,7 +128,7 @@ function DonateModal({ show, block, isBlockDonation, closeDonationModal }) {
<Modal.Body>
{isBlockDonation ? blockDonationText : progressDonationText}
<Spacer />
<MinimalDonateForm showCloseBtn={showCloseBtn} />
<MinimalDonateForm handleProcessing={handleProcessing} />
<Spacer />
<Row>
<Col sm={4} smOffset={4} xs={8} xsOffset={2}>

View File

@@ -19,8 +19,8 @@ import './Donation.css';
const propTypes = {
defaultTheme: PropTypes.string,
handleProcessing: PropTypes.func,
isDonating: PropTypes.bool,
showCloseBtn: PropTypes.func,
stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired
})
@@ -79,7 +79,7 @@ class MinimalDonateForm extends Component {
render() {
const { donationAmount, donationDuration, stripe } = this.state;
const { showCloseBtn, defaultTheme } = this.props;
const { handleProcessing, defaultTheme } = this.props;
return (
<Row>
@@ -93,7 +93,7 @@ class MinimalDonateForm extends Component {
getDonationButtonLabel={() =>
`Confirm your donation of $5 per month`
}
showCloseBtn={showCloseBtn}
handleProcessing={handleProcessing}
/>
</Elements>
</StripeProvider>

View File

@@ -5,9 +5,8 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { Link } from 'gatsby';
import ga from '../../../analytics';
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
import { completedChallengesSelector } from '../../../redux';
import { completedChallengesSelector, executeGA } from '../../../redux';
import Caret from '../../../assets/icons/Caret';
import { blockNameify } from '../../../../utils/blockNameify';
import GreenPass from '../../../assets/icons/GreenPass';
@@ -29,12 +28,13 @@ const mapStateToProps = (state, ownProps) => {
};
const mapDispatchToProps = dispatch =>
bindActionCreators({ toggleBlock }, dispatch);
bindActionCreators({ toggleBlock, executeGA }, dispatch);
const propTypes = {
blockDashedName: PropTypes.string,
challenges: PropTypes.array,
completedChallenges: PropTypes.arrayOf(PropTypes.string),
executeGA: PropTypes.func,
intro: PropTypes.shape({
fields: PropTypes.shape({ slug: PropTypes.string.isRequired }),
frontmatter: PropTypes.shape({
@@ -58,19 +58,25 @@ export class Block extends Component {
}
handleBlockClick() {
const { blockDashedName, toggleBlock } = this.props;
ga.event({
category: 'Map Block Click',
action: blockDashedName
const { blockDashedName, toggleBlock, executeGA } = this.props;
executeGA({
type: 'event',
data: {
category: 'Map Block Click',
action: blockDashedName
}
});
return toggleBlock(blockDashedName);
}
handleChallengeClick(slug) {
return () => {
return ga.event({
category: 'Map Challenge Click',
action: slug
return this.props.executeGA({
type: 'event',
data: {
category: 'Map Challenge Click',
action: slug
}
});
};
}

View File

@@ -44,6 +44,7 @@ test('<Block expanded snapshot', () => {
test('<Block /> should handle toggle clicks correctly', async () => {
const toggleSpy = jest.fn();
const toggleMapSpy = jest.fn();
const executeGA = jest.fn();
const props = {
blockDashedName: 'block-a',
@@ -51,6 +52,7 @@ test('<Block /> should handle toggle clicks correctly', async () => {
completedChallenges: mockCompleted,
intro: mockIntroNodes[0],
isExpanded: false,
executeGA: executeGA,
toggleBlock: toggleSpy,
toggleMapModal: toggleMapSpy
};

View File

@@ -2,8 +2,7 @@ import React, { Fragment, Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import ga from '../../analytics';
import { fetchUser, isSignedInSelector } from '../../redux';
import { fetchUser, isSignedInSelector, executeGA } from '../../redux';
import { createSelector } from 'reselect';
const mapStateToProps = createSelector(
@@ -13,7 +12,7 @@ const mapStateToProps = createSelector(
})
);
const mapDispatchToProps = { fetchUser };
const mapDispatchToProps = { fetchUser, executeGA };
class CertificationLayout extends Component {
componentDidMount() {
@@ -21,7 +20,7 @@ class CertificationLayout extends Component {
if (!isSignedIn) {
fetchUser();
}
ga.pageview(pathname);
this.props.executeGA({ type: 'page', data: pathname });
}
render() {
return <Fragment>{this.props.children}</Fragment>;
@@ -31,6 +30,7 @@ class CertificationLayout extends Component {
CertificationLayout.displayName = 'CertificationLayout';
CertificationLayout.propTypes = {
children: PropTypes.any,
executeGA: PropTypes.func,
fetchUser: PropTypes.func.isRequired,
isSignedIn: PropTypes.bool,
pathname: PropTypes.string.isRequired

View File

@@ -6,13 +6,13 @@ import { createSelector } from 'reselect';
import Helmet from 'react-helmet';
import fontawesome from '@fortawesome/fontawesome';
import ga from '../../analytics';
import {
fetchUser,
isSignedInSelector,
onlineStatusChange,
isOnlineSelector,
userSelector
userSelector,
executeGA
} from '../../redux';
import { flashMessageSelector, removeFlashMessage } from '../Flash/redux';
@@ -68,6 +68,7 @@ const metaKeywords = [
const propTypes = {
children: PropTypes.node.isRequired,
executeGA: PropTypes.func,
fetchUser: PropTypes.func.isRequired,
flashMessage: PropTypes.shape({
id: PropTypes.string,
@@ -101,27 +102,27 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = dispatch =>
bindActionCreators(
{ fetchUser, removeFlashMessage, onlineStatusChange },
{ fetchUser, removeFlashMessage, onlineStatusChange, executeGA },
dispatch
);
class DefaultLayout extends Component {
componentDidMount() {
const { isSignedIn, fetchUser, pathname } = this.props;
const { isSignedIn, fetchUser, pathname, executeGA } = this.props;
if (!isSignedIn) {
fetchUser();
}
ga.pageview(pathname);
executeGA({ type: 'page', data: pathname });
window.addEventListener('online', this.updateOnlineStatus);
window.addEventListener('offline', this.updateOnlineStatus);
}
componentDidUpdate(prevProps) {
const { pathname } = this.props;
const { pathname, executeGA } = this.props;
const { pathname: prevPathname } = prevProps;
if (pathname !== prevPathname) {
ga.pageview(pathname);
executeGA({ type: 'page', data: pathname });
}
}