Add/wcpay usage tracking request (https://github.com/woocommerce/woocommerce-admin/pull/5248)
Fixes woocommerce/woocommerce-admin#5294 and Automattic/woocommerce-paymentswoocommerce/woocommerce-admin#810 . Changes: * Update UsageModal UI to have two action buttons instead of 'Count me in' checkbox. * Make UsageModal configurable with custom title, message and buttons text. * Add customized modal to request site usage tracking after WC Payments KYC flow is completed.
This commit is contained in:
parent
cc5e500085
commit
5dab25382f
|
@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
|
|||
import { get, isFunction, identity } from 'lodash';
|
||||
import { parse } from 'qs';
|
||||
import { Spinner } from '@woocommerce/components';
|
||||
import { getHistory } from '@woocommerce/navigation';
|
||||
import { getHistory, getQuery } from '@woocommerce/navigation';
|
||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||
import {
|
||||
PLUGINS_STORE_NAME,
|
||||
|
@ -32,6 +32,12 @@ const StoreAlerts = lazy( () =>
|
|||
import( /* webpackChunkName: "store-alerts" */ './store-alerts' )
|
||||
);
|
||||
|
||||
const WCPayUsageModal = lazy( () =>
|
||||
import(
|
||||
/* webpackChunkName: "wcpay-usage-modal" */ '../task-list/tasks/payments/wcpay-usage-modal'
|
||||
)
|
||||
);
|
||||
|
||||
export class PrimaryLayout extends Component {
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
|
@ -121,6 +127,15 @@ class _Layout extends Component {
|
|||
return parse( search );
|
||||
}
|
||||
|
||||
isWCPaySettingsPage() {
|
||||
const { page, section, tab } = getQuery();
|
||||
return (
|
||||
page === 'wc-settings' &&
|
||||
tab === 'checkout' &&
|
||||
section === 'woocommerce_payments'
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isEmbedded, ...restProps } = this.props;
|
||||
const { location, page } = this.props;
|
||||
|
@ -146,6 +161,12 @@ class _Layout extends Component {
|
|||
</div>
|
||||
</PrimaryLayout>
|
||||
) }
|
||||
|
||||
{ isEmbedded && this.isWCPaySettingsPage() && (
|
||||
<Suspense fallback={ null }>
|
||||
<WCPayUsageModal />
|
||||
</Suspense>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -141,6 +141,69 @@
|
|||
}
|
||||
}
|
||||
|
||||
.components-modal__frame.woocommerce-usage-modal {
|
||||
width: 600px;
|
||||
max-width: 100%;
|
||||
|
||||
.components-modal__header {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.woocommerce-usage-modal__wrapper {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
a {
|
||||
color: $studio-gray-60;
|
||||
}
|
||||
|
||||
button.is-primary {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-usage-modal__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: $gap;
|
||||
|
||||
button {
|
||||
margin-left: $gap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-payments__usage-modal {
|
||||
.components-modal__header {
|
||||
height: auto;
|
||||
padding: 24px 24px 0 24px;
|
||||
|
||||
.components-modal__header-heading {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-payments__usage-modal-message {
|
||||
padding: $gap 0;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.woocommerce-payments__usage-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: $gap 0;
|
||||
|
||||
button {
|
||||
margin-left: $gap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.components-modal__frame.woocommerce-cart-modal {
|
||||
width: 600px;
|
||||
max-width: 100%;
|
||||
|
|
|
@ -6,12 +6,7 @@ import { Component } from '@wordpress/element';
|
|||
import { compose } from '@wordpress/compose';
|
||||
import { withDispatch, withSelect } from '@wordpress/data';
|
||||
import interpolateComponents from 'interpolate-components';
|
||||
import {
|
||||
Button,
|
||||
CheckboxControl,
|
||||
FormToggle,
|
||||
Modal,
|
||||
} from '@wordpress/components';
|
||||
import { Button, Modal } from '@wordpress/components';
|
||||
import { Link } from '@woocommerce/components';
|
||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||
|
||||
|
@ -19,17 +14,9 @@ class UsageModal extends Component {
|
|||
constructor( props ) {
|
||||
super( props );
|
||||
this.state = {
|
||||
allowTracking: props.allowTracking,
|
||||
isLoadingScripts: false,
|
||||
isRequestStarted: false,
|
||||
};
|
||||
|
||||
this.onTrackingChange = this.onTrackingChange.bind( this );
|
||||
}
|
||||
|
||||
onTrackingChange() {
|
||||
this.setState( {
|
||||
allowTracking: ! this.state.allowTracking,
|
||||
} );
|
||||
}
|
||||
|
||||
async componentDidUpdate( prevProps, prevState ) {
|
||||
|
@ -40,7 +27,13 @@ class UsageModal extends Component {
|
|||
onContinue,
|
||||
createNotice,
|
||||
} = this.props;
|
||||
const { isLoadingScripts } = this.state;
|
||||
const { isLoadingScripts, isRequestStarted } = this.state;
|
||||
|
||||
// We can't rely on isRequesting props only because option update might be triggered by other component.
|
||||
if ( ! isRequestStarted ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRequestSuccessful =
|
||||
! isRequesting &&
|
||||
! isLoadingScripts &&
|
||||
|
@ -66,13 +59,17 @@ class UsageModal extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
updateTracking() {
|
||||
const { allowTracking } = this.state;
|
||||
updateTracking( { allowTracking } ) {
|
||||
const { updateOptions } = this.props;
|
||||
|
||||
if ( allowTracking && typeof window.wcTracks.enable === 'function' ) {
|
||||
this.setState( { isLoadingScripts: true } );
|
||||
window.wcTracks.enable( () => {
|
||||
// Don't update state if component is unmounted already
|
||||
if ( ! this._isMounted ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState( { isLoadingScripts: false } );
|
||||
} );
|
||||
} else if ( ! allowTracking ) {
|
||||
|
@ -80,11 +77,20 @@ class UsageModal extends Component {
|
|||
}
|
||||
|
||||
const trackingValue = allowTracking ? 'yes' : 'no';
|
||||
this.setState( { isRequestStarted: true } );
|
||||
updateOptions( {
|
||||
woocommerce_allow_tracking: trackingValue,
|
||||
} );
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._isMounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._isMounted = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
// Bail if site has already opted in to tracking
|
||||
if ( this.props.allowTracking ) {
|
||||
|
@ -94,9 +100,10 @@ class UsageModal extends Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
const { allowTracking } = this.state;
|
||||
const { isRequesting } = this.props;
|
||||
const trackingMessage = interpolateComponents( {
|
||||
const {
|
||||
isRequesting,
|
||||
title = __( 'Build a better WooCommerce', 'woocommerce-admin' ),
|
||||
message = interpolateComponents( {
|
||||
mixedString: __(
|
||||
'Get improved features and faster fixes by sharing non-sensitive data via {{link}}usage tracking{{/link}} ' +
|
||||
'that shows us how WooCommerce is used. No personal data is tracked or stored.',
|
||||
|
@ -111,48 +118,46 @@ class UsageModal extends Component {
|
|||
/>
|
||||
),
|
||||
},
|
||||
} );
|
||||
} ),
|
||||
dismissActionText = __( 'No thanks', 'woocommerce-admin' ),
|
||||
acceptActionText = __( 'Yes, count me in!', 'woocommerce-admin' ),
|
||||
} = this.props;
|
||||
|
||||
const { isRequestStarted } = this.state;
|
||||
const isBusy = isRequestStarted && isRequesting;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={ __(
|
||||
'Build a better WooCommerce',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
title={ title }
|
||||
isDismissible={ this.props.isDismissible }
|
||||
onRequestClose={ () => this.props.onClose() }
|
||||
className="woocommerce-profile-wizard__usage-modal"
|
||||
className="woocommerce-usage-modal"
|
||||
>
|
||||
<div className="woocommerce-profile-wizard__usage-wrapper">
|
||||
<div className="woocommerce-profile-wizard__usage-modal-message">
|
||||
{ trackingMessage }
|
||||
</div>
|
||||
<div className="woocommerce-profile-wizard__tracking">
|
||||
<CheckboxControl
|
||||
className="woocommerce-profile-wizard__tracking-checkbox"
|
||||
checked={ allowTracking }
|
||||
label={ __(
|
||||
'Yes, count me in!',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
onChange={ this.onTrackingChange }
|
||||
/>
|
||||
|
||||
<FormToggle
|
||||
aria-hidden="true"
|
||||
checked={ allowTracking }
|
||||
onChange={ this.onTrackingChange }
|
||||
onClick={ ( e ) => e.stopPropagation() }
|
||||
tabIndex="-1"
|
||||
/>
|
||||
<div className="woocommerce-usage-modal__wrapper">
|
||||
<div className="woocommerce-usage-modal__message">
|
||||
{ message }
|
||||
</div>
|
||||
<div className="woocommerce-usage-modal__actions">
|
||||
<Button
|
||||
isSecondary
|
||||
isBusy={ isBusy }
|
||||
onClick={ () =>
|
||||
this.updateTracking( { allowTracking: false } )
|
||||
}
|
||||
>
|
||||
{ dismissActionText }
|
||||
</Button>
|
||||
<Button
|
||||
isPrimary
|
||||
isBusy={ isRequesting }
|
||||
onClick={ () => this.updateTracking() }
|
||||
isBusy={ isBusy }
|
||||
onClick={ () =>
|
||||
this.updateTracking( { allowTracking: true } )
|
||||
}
|
||||
>
|
||||
{ __( 'Continue', 'woocommerce-admin' ) }
|
||||
{ acceptActionText }
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -474,30 +474,6 @@
|
|||
cursor: help;
|
||||
}
|
||||
|
||||
.components-modal__frame.woocommerce-profile-wizard__usage-modal {
|
||||
width: 600px;
|
||||
max-width: 100%;
|
||||
|
||||
.components-modal__header {
|
||||
border-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.woocommerce-profile-wizard__usage-wrapper {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
a {
|
||||
color: $studio-gray-60;
|
||||
}
|
||||
|
||||
button.is-primary {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-business-extensions {
|
||||
margin-left: -$gap;
|
||||
margin-right: -$gap;
|
||||
|
|
|
@ -65,7 +65,7 @@ class Payments extends Component {
|
|||
: 'stripe';
|
||||
}
|
||||
|
||||
markConfigured( method ) {
|
||||
markConfigured( method, queryParams = {} ) {
|
||||
const { clearTaskStatusCache } = this.props;
|
||||
const { enabledMethods } = this.state;
|
||||
|
||||
|
@ -82,7 +82,9 @@ class Payments extends Component {
|
|||
payment_method: method,
|
||||
} );
|
||||
|
||||
getHistory().push( getNewPath( { task: 'payments' }, '/', {} ) );
|
||||
getHistory().push(
|
||||
getNewPath( { ...queryParams, task: 'payments' }, '/', {} )
|
||||
);
|
||||
}
|
||||
|
||||
getCurrentMethod() {
|
||||
|
|
|
@ -28,6 +28,7 @@ import PayPal from './paypal';
|
|||
import Klarna from './klarna';
|
||||
import PayFast from './payfast';
|
||||
import EWay from './eway';
|
||||
import WCPayUsageModal from './wcpay-usage-modal';
|
||||
|
||||
export function installActivateAndConnectWcpay(
|
||||
resolve,
|
||||
|
@ -147,6 +148,7 @@ export function getPaymentMethods( {
|
|||
{ wcPayIsConnected && wcPaySettingsLink }
|
||||
{ ! wcPayIsConnected && <p>{ tosPrompt }</p> }
|
||||
{ profileItems.setup_client && <p>{ wcPayDocPrompt }</p> }
|
||||
<WCPayUsageModal />
|
||||
</Fragment>
|
||||
),
|
||||
before: <WCPayIcon />,
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { useState } from '@wordpress/element';
|
||||
import { getQuery, updateQueryString } from '@woocommerce/navigation';
|
||||
import interpolateComponents from 'interpolate-components';
|
||||
import { Link } from '@woocommerce/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import UsageModal from '../../../profile-wizard/steps/usage-modal';
|
||||
|
||||
const WCPayUsageModal = () => {
|
||||
const query = getQuery();
|
||||
const shouldDisplayModal = query[ 'wcpay-connection-success' ] === '1';
|
||||
const [ isOpen, setIsOpen ] = useState( shouldDisplayModal );
|
||||
|
||||
if ( ! isOpen ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
setIsOpen( false );
|
||||
updateQueryString( { 'wcpay-connection-success': undefined } );
|
||||
};
|
||||
|
||||
const title = __(
|
||||
'Help us build a better WooCommerce Payments experience',
|
||||
'woocommerce-admin'
|
||||
);
|
||||
const trackingMessage = interpolateComponents( {
|
||||
mixedString: __(
|
||||
'By agreeing to share non-sensitive {{link}}usage data{{/link}}, you’ll help us improve features and optimize the WooCommerce Payments experience. You can opt out at any time.',
|
||||
'woocommerce-admin'
|
||||
),
|
||||
components: {
|
||||
link: (
|
||||
<Link
|
||||
href="https://woocommerce.com/usage-tracking"
|
||||
target="_blank"
|
||||
type="external"
|
||||
/>
|
||||
),
|
||||
},
|
||||
} );
|
||||
|
||||
return (
|
||||
<UsageModal
|
||||
isDismissible={ false }
|
||||
title={ title }
|
||||
message={ trackingMessage }
|
||||
acceptActionText={ __( 'I agree', 'woocommerce-admin' ) }
|
||||
dismissActionText={ __( 'No thanks', 'woocommerce-admin' ) }
|
||||
onContinue={ closeModal }
|
||||
onClose={ closeModal }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default WCPayUsageModal;
|
|
@ -19,7 +19,7 @@ class WCPay extends Component {
|
|||
'woocommerce-admin'
|
||||
)
|
||||
);
|
||||
markConfigured( 'wcpay' );
|
||||
markConfigured( 'wcpay', { 'wcpay-connection-success': '1' } );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,13 +73,13 @@ export async function completeStoreDetailsSection( storeDetails = {} ) {
|
|||
text: 'Build a better WooCommerce',
|
||||
} );
|
||||
|
||||
// Query for "Continue" buttons
|
||||
const continueButtons = await page.$$( 'button.is-primary' );
|
||||
expect( continueButtons ).toHaveLength( 2 );
|
||||
// Query for primary buttons: "Continue" and "Yes, count me in"
|
||||
const primaryButtons = await page.$$( 'button.is-primary' );
|
||||
expect( primaryButtons ).toHaveLength( 2 );
|
||||
|
||||
await Promise.all( [
|
||||
// Click on "Continue" button of the usage pop-up window to move to the next step
|
||||
continueButtons[ 1 ].click(),
|
||||
// Click on "No thanks" button of the usage pop-up window to move to the next step
|
||||
await page.click( 'button.is-secondary', { text: 'No thanks' } ),
|
||||
|
||||
// Wait for "In which industry does the store operate?" section to load
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
|
|
Loading…
Reference in New Issue