Skip to content

Commit

Permalink
Merge pull request #4778 from Automattic/add/guides-tracking
Browse files Browse the repository at this point in the history
GuidedTours: Add step tracking
  • Loading branch information
ehg committed Apr 21, 2016
2 parents 4214ff8 + 17872e9 commit 591f771
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 21 deletions.
24 changes: 16 additions & 8 deletions client/guidestours/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* External dependencies
*/
import React, { Component } from 'react'
import React, { Component } from 'react';
import { connect } from 'react-redux';

/**
* Internal dependencies
*/
import { getSelectedSite, getGuidesTourState } from 'state/ui/selectors';
import { nextGuidesTourStep } from 'state/ui/actions';
import { nextGuidesTourStep, quitGuidesTour } from 'state/ui/actions';
import { query } from './positioning';
import {
GuidesBasicStep,
Expand All @@ -21,7 +21,7 @@ import {
class GuidesTours extends Component {
constructor() {
super();
this.bind( 'next', 'quit' );
this.bind( 'next', 'quit', 'finish' );
}

bind( ...methods ) {
Expand All @@ -35,7 +35,7 @@ class GuidesTours extends Component {

shouldComponentUpdate( nextProps ) {
return this.props.tourState !== nextProps.tourState;
}
}

componentWillUpdate( nextProps ) {
const { stepConfig } = nextProps.tourState;
Expand All @@ -58,12 +58,18 @@ class GuidesTours extends Component {

next() {
const nextStepName = this.props.tourState.stepConfig.next;
this.props.nextGuidesTourStep( nextStepName );
this.props.nextGuidesTourStep( { stepName: nextStepName } );
}

quit() {
quit( options = {} ) {
this.currentTarget && this.currentTarget.classList.remove( 'guidestours__overlay' );
this.props.nextGuidesTourStep( null );
this.props.quitGuidesTour( Object.assign( {
stepName: this.props.tourState.stepName
}, options ) );
}

finish() {
this.quit( { finished: true } );
}

render() {
Expand All @@ -87,7 +93,8 @@ class GuidesTours extends Component {
key={ stepConfig.target }
target={ this.currentTarget }
onNext={ this.next }
onQuit={ this.quit } />
onQuit={ this.quit }
onFinish={ this.finish } />
</div>
);
}
Expand All @@ -98,4 +105,5 @@ export default connect( ( state ) => ( {
tourState: getGuidesTourState( state ),
} ), {
nextGuidesTourStep,
quitGuidesTour,
} )( GuidesTours );
61 changes: 56 additions & 5 deletions client/guidestours/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ class GuidesFinishStep extends Component {
const stepPos = getStepPosition( this.props );
const stepCoords = posToCss( stepPos );

const { text, onQuit, linkUrl, linkLabel } = this.props;
const { text, onFinish, linkUrl, linkLabel } = this.props;

return (
<Card className="guidestours__step" style={ stepCoords } >
<p>{ text }</p>
<div className="guidestours__single-button-row">
<Button onClick={ onQuit } primary>{ this.props.translate( 'Finish Tour' ) }</Button>
<Button onClick={ onFinish } primary>{ this.props.translate( 'Finish Tour' ) }</Button>
</div>
<div className="guidestours__external-link">
<ExternalLink target="_blank" icon={ true } href={ linkUrl }>{ linkLabel }</ExternalLink>
Expand Down Expand Up @@ -164,20 +164,71 @@ class GuidesActionStep extends Component {

GuidesBasicStep.propTypes = {
target: PropTypes.object,
type: PropTypes.string,
placement: PropTypes.string,
// text can be a translated string or a translated string with components
text: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array
] ),
next: PropTypes.string,
onNext: PropTypes.func.isRequired,
onQuit: PropTypes.func.isRequired,
};

GuidesActionStep.propTypes = {
target: PropTypes.object.isRequired,
placement: PropTypes.string,
// text can be a translated string or a translated string with components
text: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array
] ),
next: PropTypes.string,
onNext: PropTypes.func.isRequired,
onQuit: PropTypes.func.isRequired,
};

GuidesLinkStep.propTypes = {
target: PropTypes.object,
placement: PropTypes.string,
// text can be a translated string or a translated string with components
// attached
text: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array
] ),
linkLabel: PropTypes.string,
linkUrl: PropTypes.string,
next: PropTypes.string,
onNext: PropTypes.func.isRequired,
onQuit: PropTypes.func.isRequired,
};

GuidesFirstStep.propTypes = {
target: PropTypes.object,
placement: PropTypes.string,
// text can be a translated string or a translated string with components
text: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array
] ),
next: PropTypes.string,
style: PropTypes.object,
onNext: PropTypes.func.isRequired,
onQuit: PropTypes.func.isRequired,
};

GuidesFinishStep.propTypes = {
target: PropTypes.object,
placement: PropTypes.string,
// text can be a translated string or a translated string with components
text: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.array
] ),
linkLabel: PropTypes.string,
linkUrl: PropTypes.string,
onFinish: PropTypes.func.isRequired,
};

class GuidesPointer extends Component {
render() {
return (
Expand Down
46 changes: 40 additions & 6 deletions client/state/ui/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import {
UPDATE_GUIDESTOUR,
} from 'state/action-types';

import {
withAnalytics,
recordTracksEvent,
} from 'state/analytics/actions';

/**
* Returns an action object to be used in signalling that a site has been set
* as selected.
Expand Down Expand Up @@ -50,19 +55,48 @@ export function setSection( section, options = {} ) {
* @param {Object} options Options object, see fn signature.
* @return {Object} Action object
*/
export function showGuidesTour( { shouldShow, shouldDelay = false, tour = 'main', siteId = null } ) {
return {
export function showGuidesTour( { shouldShow, shouldDelay = false, tour = 'main' } ) {
const showAction = {
type: SHOW_GUIDESTOUR,
shouldShow,
shouldDelay,
tour,
siteId,
}
};

const trackEvent = recordTracksEvent( 'calypso_guided_tours_show', {
tour,
} );

return withAnalytics( trackEvent, showAction );
}

export function nextGuidesTourStep( stepName ) {
return {
export function quitGuidesTour( { tour = 'main', stepName, finished } ) {
const quitAction = {
type: UPDATE_GUIDESTOUR,
shouldShow: false,
shouldReallyShow: false,
shouldDelay: false,
tour,
stepName,
};

const trackEvent = recordTracksEvent( `calypso_guided_tours_${ finished ? 'finished' : 'quit' }`, {
step: stepName,
tour,
} );

return withAnalytics( trackEvent, quitAction );
}
export function nextGuidesTourStep( { tour = 'main', stepName } ) {
const nextAction = {
type: UPDATE_GUIDESTOUR,
stepName,
};

const trackEvent = recordTracksEvent( 'calypso_guided_tours_next_step', {
step: stepName,
tour,
} );

return withAnalytics( trackEvent, nextAction );
}
1 change: 0 additions & 1 deletion client/state/ui/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export function guidesTour( state = {}, action ) {
shouldDelay: action.shouldDelay,
shouldReallyShow: ( action.shouldShow || state.shouldShow ) && ! action.shouldDelay,
tour: action.tour,
siteId: action.siteId,
};
case UPDATE_GUIDESTOUR:
return Object.assign( {}, state, omit( action, 'type' ) );
Expand Down
1 change: 0 additions & 1 deletion client/state/ui/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ describe( 'selectors', () => {
stepName: 'sidebar',
shouldShow: true,
tour: 'main',
siteId: 2916284,
}
}
} );
Expand Down

0 comments on commit 591f771

Please sign in to comment.