Revert "feat(client): unify GA and add to donation" (#38001)

This reverts commit 78df306707.
This commit is contained in:
mrugesh
2020-01-01 12:04:50 +05:30
committed by GitHub
parent 89ddd4bb7e
commit 8e605d8b85
18 changed files with 108 additions and 303 deletions

View File

@ -15,8 +15,7 @@ import {
showCert, showCert,
userFetchStateSelector, userFetchStateSelector,
usernameSelector, usernameSelector,
isDonatingSelector, isDonatingSelector
executeGA
} from '../redux'; } from '../redux';
import validCertNames from '../../utils/validCertNames'; import validCertNames from '../../utils/validCertNames';
import { createFlashMessage } from '../components/Flash/redux'; import { createFlashMessage } from '../components/Flash/redux';
@ -38,7 +37,6 @@ const propTypes = {
certDashedName: PropTypes.string, certDashedName: PropTypes.string,
certName: PropTypes.string, certName: PropTypes.string,
createFlashMessage: PropTypes.func.isRequired, createFlashMessage: PropTypes.func.isRequired,
executeGA: PropTypes.func,
fetchState: PropTypes.shape({ fetchState: PropTypes.shape({
pending: PropTypes.bool, pending: PropTypes.bool,
complete: PropTypes.bool, complete: PropTypes.bool,
@ -76,20 +74,19 @@ const mapStateToProps = (state, { certName }) => {
}; };
const mapDispatchToProps = dispatch => const mapDispatchToProps = dispatch =>
bindActionCreators({ createFlashMessage, showCert, executeGA }, dispatch); bindActionCreators({ createFlashMessage, showCert }, dispatch);
class ShowCertification extends Component { class ShowCertification extends Component {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
this.state = { this.state = {
isDonationSubmitted: false, closeBtn: false,
isDonationDisplayed: false, donationClosed: false
isDonationClosed: false
}; };
this.hideDonationSection = this.hideDonationSection.bind(this); this.hideDonationSection = this.hideDonationSection.bind(this);
this.handleProcessing = this.handleProcessing.bind(this); this.showDonationCloseBtn = this.showDonationCloseBtn.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -100,53 +97,12 @@ class ShowCertification extends Component {
return null; return null;
} }
shouldComponentUpdate(nextProps) {
const {
userFetchState: { complete: userComplete },
signedInUserName,
isDonating,
cert: { username = '' },
executeGA
} = nextProps;
const { isDonationDisplayed } = this.state;
if (
!isDonationDisplayed &&
userComplete &&
signedInUserName === username &&
!isDonating
) {
this.setState({
isDonationDisplayed: true
});
executeGA({
type: 'event',
data: {
category: 'Donation',
action: 'Displayed Certificate Donation',
nonInteraction: true
}
});
}
return true;
}
hideDonationSection() { hideDonationSection() {
this.setState({ isDonationDisplayed: false, isDonationClosed: true }); this.setState({ donationClosed: true });
} }
handleProcessing(duration, amount) { showDonationCloseBtn() {
this.props.executeGA({ this.setState({ closeBtn: true });
type: 'event',
data: {
category: 'donation',
action: 'certificate stripe form submission',
label: duration,
value: amount
}
});
this.setState({ isDonationSubmitted: true });
} }
render() { render() {
@ -155,14 +111,13 @@ class ShowCertification extends Component {
fetchState, fetchState,
validCertName, validCertName,
createFlashMessage, createFlashMessage,
certName certName,
signedInUserName,
isDonating,
userFetchState
} = this.props; } = this.props;
const { const { donationClosed, closeBtn } = this.state;
isDonationSubmitted,
isDonationDisplayed,
isDonationClosed
} = this.state;
if (!validCertName) { if (!validCertName) {
createFlashMessage(standardErrorMessage); createFlashMessage(standardErrorMessage);
@ -170,6 +125,7 @@ class ShowCertification extends Component {
} }
const { pending, complete, errored } = fetchState; const { pending, complete, errored } = fetchState;
const { complete: userComplete } = userFetchState;
if (pending) { if (pending) {
return <Loader fullScreen={true} />; return <Loader fullScreen={true} />;
@ -193,6 +149,8 @@ class ShowCertification extends Component {
completionTime completionTime
} = cert; } = cert;
let conditionalDonationSection = '';
const donationCloseBtn = ( const donationCloseBtn = (
<div> <div>
<Button <Button
@ -206,9 +164,15 @@ class ShowCertification extends Component {
</div> </div>
); );
let donationSection = ( if (
userComplete &&
signedInUserName === username &&
!isDonating &&
!donationClosed
) {
conditionalDonationSection = (
<Grid className='donation-section'> <Grid className='donation-section'>
{!isDonationSubmitted && ( {!closeBtn && (
<Row> <Row>
<Col sm={10} smOffset={1} xs={12}> <Col sm={10} smOffset={1} xs={12}>
<p> <p>
@ -222,20 +186,21 @@ class ShowCertification extends Component {
</Row> </Row>
)} )}
<MinimalDonateForm <MinimalDonateForm
handleProcessing={this.handleProcessing} showCloseBtn={this.showDonationCloseBtn}
defaultTheme='light' defaultTheme='light'
/> />
<Row> <Row>
<Col sm={4} smOffset={4} xs={6} xsOffset={3}> <Col sm={4} smOffset={4} xs={6} xsOffset={3}>
{isDonationSubmitted && donationCloseBtn} {closeBtn ? donationCloseBtn : ''}
</Col> </Col>
</Row> </Row>
</Grid> </Grid>
); );
}
return ( return (
<div className='certificate-outer-wrapper'> <div className='certificate-outer-wrapper'>
{isDonationDisplayed && !isDonationClosed ? donationSection : ''} {conditionalDonationSection}
<Grid className='certificate-wrapper certification-namespace'> <Grid className='certificate-wrapper certification-namespace'>
<Row> <Row>
<header> <header>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,10 +26,9 @@ const numToCommas = num =>
num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
const propTypes = { const propTypes = {
handleProcessing: PropTypes.func, showCloseBtn: PropTypes.func,
defaultTheme: PropTypes.string, defaultTheme: PropTypes.string,
isDonating: PropTypes.bool, isDonating: PropTypes.bool,
executeGA: PropTypes.func,
stripe: PropTypes.shape({ stripe: PropTypes.shape({
createToken: PropTypes.func.isRequired createToken: PropTypes.func.isRequired
}) })
@ -48,7 +47,6 @@ class YearEndDonationForm extends Component {
this.handleSelectAmount = this.handleSelectAmount.bind(this); this.handleSelectAmount = this.handleSelectAmount.bind(this);
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
this.handlePaypalSubmission = this.handlePaypalSubmission.bind(this);
} }
componentDidMount() { componentDidMount() {
@ -91,13 +89,14 @@ class YearEndDonationForm extends Component {
renderDonationOptions() { renderDonationOptions() {
const { donationAmount, stripe } = this.state; const { donationAmount, stripe } = this.state;
const { handleProcessing, defaultTheme } = this.props;
const { showCloseBtn, defaultTheme } = this.props;
return ( return (
<div> <div>
<StripeProvider stripe={stripe}> <StripeProvider stripe={stripe}>
<Elements> <Elements>
<DonateFormChildViewForHOC <DonateFormChildViewForHOC
handleProcessing={handleProcessing} showCloseBtn={showCloseBtn}
defaultTheme={defaultTheme} defaultTheme={defaultTheme}
donationAmount={donationAmount} donationAmount={donationAmount}
donationDuration='onetime' donationDuration='onetime'
@ -180,23 +179,12 @@ class YearEndDonationForm extends Component {
); );
} }
handlePaypalSubmission() {
this.props.executeGA({
type: 'event',
data: {
category: 'donation',
action: 'year end gift paypal button click'
}
});
}
renderPayPalDonations() { renderPayPalDonations() {
return ( return (
<form <form
action='https://www.paypal.com/cgi-bin/webscr' action='https://www.paypal.com/cgi-bin/webscr'
method='post' method='post'
target='_top' target='_top'
onSubmit={this.handlePaypalSubmission}
> >
<input type='hidden' name='cmd' value='_s-xclick' /> <input type='hidden' name='cmd' value='_s-xclick' />
<input type='hidden' name='hosted_button_id' value='9C73W6CWSLNPW' /> <input type='hidden' name='hosted_button_id' value='9C73W6CWSLNPW' />

View File

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

View File

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

View File

@ -1,7 +1,6 @@
import React, { Component, Fragment } from 'react'; import React, { Component, Fragment } from 'react';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap'; import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
@ -10,11 +9,10 @@ import { stripePublicKey } from '../../config/env.json';
import { Spacer, Loader } from '../components/helpers'; import { Spacer, Loader } from '../components/helpers';
import DonateForm from '../components/Donation/DonateForm'; import DonateForm from '../components/Donation/DonateForm';
import DonateText from '../components/Donation/DonateText'; import DonateText from '../components/Donation/DonateText';
import { signInLoadingSelector, userSelector, executeGA } from '../redux'; import { signInLoadingSelector, userSelector } from '../redux';
import { stripeScriptLoader } from '../utils/scriptLoaders'; import { stripeScriptLoader } from '../utils/scriptLoaders';
const propTypes = { const propTypes = {
executeGA: PropTypes.func,
isDonating: PropTypes.bool, isDonating: PropTypes.bool,
showLoading: PropTypes.bool.isRequired showLoading: PropTypes.bool.isRequired
}; };
@ -28,14 +26,6 @@ const mapStateToProps = createSelector(
}) })
); );
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
executeGA
},
dispatch
);
export class DonatePage extends Component { export class DonatePage extends Component {
constructor(...props) { constructor(...props) {
super(...props); super(...props);
@ -43,19 +33,11 @@ export class DonatePage extends Component {
stripe: null, stripe: null,
enableSettings: false enableSettings: false
}; };
this.handleProcessing = this.handleProcessing.bind(this);
this.handleStripeLoad = this.handleStripeLoad.bind(this); this.handleStripeLoad = this.handleStripeLoad.bind(this);
} }
componentDidMount() { componentDidMount() {
this.props.executeGA({
type: 'event',
data: {
category: 'Donation',
action: `Displayed donate page`,
nonInteraction: true
}
});
if (window.Stripe) { if (window.Stripe) {
this.handleStripeLoad(); this.handleStripeLoad();
} else if (document.querySelector('#stripe-js')) { } else if (document.querySelector('#stripe-js')) {
@ -74,18 +56,6 @@ export class DonatePage extends Component {
} }
} }
handleProcessing(duration, amount) {
this.props.executeGA({
type: 'event',
data: {
category: 'donation',
action: 'donate page stripe form submission',
label: duration,
value: amount
}
});
}
handleStripeLoad() { handleStripeLoad() {
// Create Stripe instance once Stripe.js loads // Create Stripe instance once Stripe.js loads
console.info('stripe has loaded'); console.info('stripe has loaded');
@ -118,7 +88,6 @@ export class DonatePage extends Component {
<Col md={6}> <Col md={6}>
<DonateForm <DonateForm
enableDonationSettingsPage={this.enableDonationSettingsPage} enableDonationSettingsPage={this.enableDonationSettingsPage}
handleProcessing={this.handleProcessing}
stripe={stripe} stripe={stripe}
/> />
</Col> </Col>
@ -136,7 +105,4 @@ export class DonatePage extends Component {
DonatePage.displayName = 'DonatePage'; DonatePage.displayName = 'DonatePage';
DonatePage.propTypes = propTypes; DonatePage.propTypes = propTypes;
export default connect( export default connect(mapStateToProps)(DonatePage);
mapStateToProps,
mapDispatchToProps
)(DonatePage);

View File

@ -1,48 +1,11 @@
import React, { useEffect } from 'react'; import React from 'react';
import Helmet from 'react-helmet'; import Helmet from 'react-helmet';
import { Grid } from '@freecodecamp/react-bootstrap'; import { Grid } from '@freecodecamp/react-bootstrap';
import { connect } from 'react-redux';
import { executeGA } from '../redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import { Spacer, FullWidthRow } from '../components/helpers'; import { Spacer, FullWidthRow } from '../components/helpers';
import YearEndDonationForm from '../components/YearEndGift/YearEndDonationForm'; import YearEndDonationForm from '../components/YearEndGift/YearEndDonationForm';
const mapDispatchToProps = dispatch => function YearEndGiftPage() {
bindActionCreators(
{
executeGA
},
dispatch
);
const propTypes = {
executeGA: PropTypes.func
};
function YearEndGiftPage({ executeGA }) {
useEffect(() => {
executeGA({
type: 'event',
data: {
category: 'Donation',
action: `Displayed year end gift page`,
nonInteraction: true
}
});
}, [executeGA]);
const handleProcessing = (duration, amount) => {
executeGA({
type: 'event',
data: {
category: 'donation',
action: 'year-end-gift strip form submission',
label: duration,
value: amount
}
});
};
return ( return (
<> <>
<Helmet title='Support our nonprofit | freeCodeCamp.org' /> <Helmet title='Support our nonprofit | freeCodeCamp.org' />
@ -50,11 +13,7 @@ function YearEndGiftPage({ executeGA }) {
<main> <main>
<Spacer /> <Spacer />
<FullWidthRow> <FullWidthRow>
<YearEndDonationForm <YearEndDonationForm defaultTheme='light' />
defaultTheme='light'
executeGA={executeGA}
handleProcessing={handleProcessing}
/>
</FullWidthRow> </FullWidthRow>
<Spacer /> <Spacer />
<Spacer /> <Spacer />
@ -65,9 +24,5 @@ function YearEndGiftPage({ executeGA }) {
} }
YearEndGiftPage.displayName = 'YearEndGiftPage'; YearEndGiftPage.displayName = 'YearEndGiftPage';
YearEndGiftPage.propTypes = propTypes;
export default connect( export default YearEndGiftPage;
null,
mapDispatchToProps
)(YearEndGiftPage);

View File

@ -1,11 +0,0 @@
import { takeEvery } from 'redux-saga/effects';
import ga from '../analytics';
function* callGaType({ payload: { type, data } }) {
const GaTypes = { event: ga.event, page: ga.pageview, modal: ga.modalview };
GaTypes[type](data);
}
export function createGaSaga(types) {
return [takeEvery(types.executeGA, callGaType)];
}

View File

@ -11,7 +11,6 @@ import { createReportUserSaga } from './report-user-saga';
import { createShowCertSaga } from './show-cert-saga'; import { createShowCertSaga } from './show-cert-saga';
import { createNightModeSaga } from './night-mode-saga'; import { createNightModeSaga } from './night-mode-saga';
import { createDonationSaga } from './donation-saga'; import { createDonationSaga } from './donation-saga';
import { createGaSaga } from './ga-saga';
import hardGoToEpic from './hard-go-to-epic'; import hardGoToEpic from './hard-go-to-epic';
import failedUpdatesEpic from './failed-updates-epic'; import failedUpdatesEpic from './failed-updates-epic';
@ -66,7 +65,6 @@ export const types = createTypes(
'onlineStatusChange', 'onlineStatusChange',
'resetUserData', 'resetUserData',
'tryToShowDonationModal', 'tryToShowDonationModal',
'executeGA',
'submitComplete', 'submitComplete',
'updateComplete', 'updateComplete',
'updateCurrentChallengeId', 'updateCurrentChallengeId',
@ -86,7 +84,6 @@ export const sagas = [
...createAcceptTermsSaga(types), ...createAcceptTermsSaga(types),
...createAppMountSaga(types), ...createAppMountSaga(types),
...createDonationSaga(types), ...createDonationSaga(types),
...createGaSaga(types),
...createFetchUserSaga(types), ...createFetchUserSaga(types),
...createShowCertSaga(types), ...createShowCertSaga(types),
...createReportUserSaga(types), ...createReportUserSaga(types),
@ -98,9 +95,6 @@ export const appMount = createAction(types.appMount);
export const tryToShowDonationModal = createAction( export const tryToShowDonationModal = createAction(
types.tryToShowDonationModal types.tryToShowDonationModal
); );
export const executeGA = createAction(types.executeGA);
export const allowBlockDonationRequests = createAction( export const allowBlockDonationRequests = createAction(
types.allowBlockDonationRequests types.allowBlockDonationRequests
); );

View File

@ -6,8 +6,10 @@ import { createSelector } from 'reselect';
import { Button, Modal } from '@freecodecamp/react-bootstrap'; import { Button, Modal } from '@freecodecamp/react-bootstrap';
import { useStaticQuery, graphql } from 'gatsby'; import { useStaticQuery, graphql } from 'gatsby';
import ga from '../../../analytics';
import Login from '../../../components/Header/components/Login'; import Login from '../../../components/Header/components/Login';
import CompletionModalBody from './CompletionModalBody'; import CompletionModalBody from './CompletionModalBody';
import { dasherize } from '../../../../../utils/slugs'; import { dasherize } from '../../../../../utils/slugs';
import './completion-modal.css'; import './completion-modal.css';
@ -23,7 +25,7 @@ import {
lastBlockChalSubmitted lastBlockChalSubmitted
} from '../redux'; } from '../redux';
import { isSignedInSelector, executeGA } from '../../../redux'; import { isSignedInSelector } from '../../../redux';
const mapStateToProps = createSelector( const mapStateToProps = createSelector(
challengeFilesSelector, challengeFilesSelector,
@ -58,8 +60,7 @@ const mapDispatchToProps = function(dispatch) {
}, },
lastBlockChalSubmitted: () => { lastBlockChalSubmitted: () => {
dispatch(lastBlockChalSubmitted()); dispatch(lastBlockChalSubmitted());
}, }
executeGA
}; };
return () => dispatchers; return () => dispatchers;
}; };
@ -69,7 +70,6 @@ const propTypes = {
close: PropTypes.func.isRequired, close: PropTypes.func.isRequired,
completedChallengesIds: PropTypes.array, completedChallengesIds: PropTypes.array,
currentBlockIds: PropTypes.array, currentBlockIds: PropTypes.array,
executeGA: PropTypes.func,
files: PropTypes.object.isRequired, files: PropTypes.object.isRequired,
id: PropTypes.string, id: PropTypes.string,
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
@ -190,7 +190,7 @@ export class CompletionModalInner extends Component {
const { completedPercent } = this.state; const { completedPercent } = this.state;
if (isOpen) { if (isOpen) {
executeGA({ type: 'modal', data: '/completion-modal' }); ga.modalview('/completion-modal');
} }
const dashedName = dasherize(title); const dashedName = dasherize(title);
return ( return (

View File

@ -4,22 +4,21 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Button, Modal } from '@freecodecamp/react-bootstrap'; import { Button, Modal } from '@freecodecamp/react-bootstrap';
import ga from '../../../analytics';
import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux'; import { createQuestion, closeModal, isHelpModalOpenSelector } from '../redux';
import { executeGA } from '../../../redux';
import './help-modal.css'; import './help-modal.css';
const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) }); const mapStateToProps = state => ({ isOpen: isHelpModalOpenSelector(state) });
const mapDispatchToProps = dispatch => const mapDispatchToProps = dispatch =>
bindActionCreators( bindActionCreators(
{ createQuestion, executeGA, closeHelpModal: () => closeModal('help') }, { createQuestion, closeHelpModal: () => closeModal('help') },
dispatch dispatch
); );
const propTypes = { const propTypes = {
closeHelpModal: PropTypes.func.isRequired, closeHelpModal: PropTypes.func.isRequired,
createQuestion: PropTypes.func.isRequired, createQuestion: PropTypes.func.isRequired,
executeGA: PropTypes.func,
isOpen: PropTypes.bool isOpen: PropTypes.bool
}; };
@ -28,9 +27,9 @@ const RSA =
export class HelpModal extends Component { export class HelpModal extends Component {
render() { render() {
const { isOpen, closeHelpModal, createQuestion, executeGA } = this.props; const { isOpen, closeHelpModal, createQuestion } = this.props;
if (isOpen) { if (isOpen) {
executeGA({ type: 'modal', data: '/help-modal' }); ga.modalview('/help-modal');
} }
return ( return (
<Modal dialogClassName='help-modal' onHide={closeHelpModal} show={isOpen}> <Modal dialogClassName='help-modal' onHide={closeHelpModal} show={isOpen}>

View File

@ -5,14 +5,13 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { Button, Modal } from '@freecodecamp/react-bootstrap'; import { Button, Modal } from '@freecodecamp/react-bootstrap';
import ga from '../../../analytics';
import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux'; import { isResetModalOpenSelector, closeModal, resetChallenge } from '../redux';
import { executeGA } from '../../../redux';
import './reset-modal.css'; import './reset-modal.css';
const propTypes = { const propTypes = {
close: PropTypes.func.isRequired, close: PropTypes.func.isRequired,
executeGA: PropTypes.func,
isOpen: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired,
reset: PropTypes.func.isRequired reset: PropTypes.func.isRequired
}; };
@ -26,11 +25,7 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = dispatch => const mapDispatchToProps = dispatch =>
bindActionCreators( bindActionCreators(
{ { close: () => closeModal('reset'), reset: () => resetChallenge() },
close: () => closeModal('reset'),
executeGA,
reset: () => resetChallenge()
},
dispatch dispatch
); );
@ -40,7 +35,7 @@ function withActions(...fns) {
function ResetModal({ reset, close, isOpen }) { function ResetModal({ reset, close, isOpen }) {
if (isOpen) { if (isOpen) {
executeGA({ type: 'modal', data: '/reset-modal' }); ga.modalview('/reset-modal');
} }
return ( return (
<Modal <Modal

View File

@ -4,30 +4,26 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Modal } from '@freecodecamp/react-bootstrap'; import { Modal } from '@freecodecamp/react-bootstrap';
import ga from '../../../analytics';
import { closeModal, isVideoModalOpenSelector } from '../redux'; import { closeModal, isVideoModalOpenSelector } from '../redux';
import { executeGA } from '../../../redux';
import './video-modal.css'; import './video-modal.css';
const mapStateToProps = state => ({ isOpen: isVideoModalOpenSelector(state) }); const mapStateToProps = state => ({ isOpen: isVideoModalOpenSelector(state) });
const mapDispatchToProps = dispatch => const mapDispatchToProps = dispatch =>
bindActionCreators( bindActionCreators({ closeVideoModal: () => closeModal('video') }, dispatch);
{ closeVideoModal: () => closeModal('video'), executeGA },
dispatch
);
const propTypes = { const propTypes = {
closeVideoModal: PropTypes.func.isRequired, closeVideoModal: PropTypes.func.isRequired,
executeGA: propTypes.func,
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
videoUrl: PropTypes.string videoUrl: PropTypes.string
}; };
export class VideoModal extends Component { export class VideoModal extends Component {
render() { render() {
const { isOpen, closeVideoModal, videoUrl, executeGA } = this.props; const { isOpen, closeVideoModal, videoUrl } = this.props;
if (isOpen) { if (isOpen) {
executeGA({ type: 'modal', data: '/completion-modal' }); ga.modalview('/video-modal');
} }
return ( return (
<Modal <Modal