Add CES submission
This commit is contained in:
parent
7aa37d609f
commit
4b27f831f7
|
@ -10,7 +10,7 @@ import { withDispatch } from '@wordpress/data';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import CustomerFeedbackModal from './customer-feedback-modal';
|
||||
import { CustomerFeedbackModal } from './customer-feedback-modal';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
|
@ -29,7 +29,7 @@ const noop = () => {};
|
|||
* @param {Function} props.onModalShownCallback Function to call when the modal is shown.
|
||||
* @param {Object} props.icon Icon (React component) to be shown on the notice.
|
||||
*/
|
||||
export function CustomerEffortScore( {
|
||||
function CustomerEffortScoreComponent( {
|
||||
recordScoreCallback,
|
||||
label,
|
||||
createNotice,
|
||||
|
@ -82,7 +82,7 @@ export function CustomerEffortScore( {
|
|||
);
|
||||
}
|
||||
|
||||
CustomerEffortScore.propTypes = {
|
||||
CustomerEffortScoreComponent.propTypes = {
|
||||
/**
|
||||
* The function to call to record the score.
|
||||
*/
|
||||
|
@ -113,7 +113,7 @@ CustomerEffortScore.propTypes = {
|
|||
icon: PropTypes.element,
|
||||
};
|
||||
|
||||
export default compose(
|
||||
const CustomerEffortScore = compose(
|
||||
withDispatch( ( dispatch ) => {
|
||||
const { createNotice } = dispatch( 'core/notices2' );
|
||||
|
||||
|
@ -121,4 +121,6 @@ export default compose(
|
|||
createNotice,
|
||||
};
|
||||
} )
|
||||
)( CustomerEffortScore );
|
||||
)( CustomerEffortScoreComponent );
|
||||
|
||||
export { CustomerEffortScore };
|
||||
|
|
|
@ -30,9 +30,11 @@ import { __ } from '@wordpress/i18n';
|
|||
function CustomerFeedbackModal( {
|
||||
recordScoreCallback,
|
||||
label,
|
||||
defaultScore = NaN,
|
||||
}: {
|
||||
recordScoreCallback: ( score: number, comments: string ) => void;
|
||||
label: string;
|
||||
defaultScore?: number;
|
||||
} ): JSX.Element | null {
|
||||
const options = [
|
||||
{
|
||||
|
@ -57,7 +59,7 @@ function CustomerFeedbackModal( {
|
|||
},
|
||||
];
|
||||
|
||||
const [ score, setScore ] = useState( NaN );
|
||||
const [ score, setScore ] = useState( defaultScore || NaN );
|
||||
const [ comments, setComments ] = useState( '' );
|
||||
const [ showNoScoreMessage, setShowNoScoreMessage ] = useState( false );
|
||||
const [ isOpen, setOpen ] = useState( true );
|
||||
|
@ -152,6 +154,7 @@ function CustomerFeedbackModal( {
|
|||
CustomerFeedbackModal.propTypes = {
|
||||
recordScoreCallback: PropTypes.func.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
score: PropTypes.number,
|
||||
};
|
||||
|
||||
export default CustomerFeedbackModal;
|
||||
export { CustomerFeedbackModal };
|
||||
|
|
|
@ -15,6 +15,7 @@ import { __ } from '@wordpress/i18n';
|
|||
type CustomerFeedbackSimpleProps = {
|
||||
recordScoreCallback: ( score: number ) => void;
|
||||
label: string;
|
||||
showFeedback?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,10 +32,12 @@ type CustomerFeedbackSimpleProps = {
|
|||
* @param {Object} props Component props.
|
||||
* @param {Function} props.recordScoreCallback Function to call when the results are sent.
|
||||
* @param {string} props.label Question to ask the customer.
|
||||
* @param {string} props.showFeedback To show feedback message.
|
||||
*/
|
||||
const CustomerFeedbackSimple: React.FC< CustomerFeedbackSimpleProps > = ( {
|
||||
recordScoreCallback,
|
||||
label,
|
||||
showFeedback = false,
|
||||
} ) => {
|
||||
const options = [
|
||||
{
|
||||
|
@ -67,14 +70,14 @@ const CustomerFeedbackSimple: React.FC< CustomerFeedbackSimpleProps > = ( {
|
|||
const [ score, setScore ] = useState( NaN );
|
||||
|
||||
useEffect( () => {
|
||||
if ( score !== NaN ) {
|
||||
if ( ! isNaN( score ) ) {
|
||||
recordScoreCallback( score );
|
||||
}
|
||||
}, [ score ] );
|
||||
|
||||
return (
|
||||
<div className="customer-feedback-simple__container">
|
||||
{ isNaN( score ) ? (
|
||||
{ isNaN( score ) && ! showFeedback ? (
|
||||
<Fragment>
|
||||
<Text
|
||||
variant="subtitle.small"
|
||||
|
@ -101,9 +104,7 @@ const CustomerFeedbackSimple: React.FC< CustomerFeedbackSimpleProps > = ( {
|
|||
) ) }
|
||||
</div>
|
||||
</Fragment>
|
||||
) : null }
|
||||
|
||||
{ score >= 3 && (
|
||||
) : (
|
||||
<div className="woocommerce-customer-effort-score__comments">
|
||||
<Text
|
||||
variant="subtitle.small"
|
||||
|
@ -123,6 +124,7 @@ const CustomerFeedbackSimple: React.FC< CustomerFeedbackSimpleProps > = ( {
|
|||
CustomerFeedbackSimple.propTypes = {
|
||||
recordScoreCallback: PropTypes.func.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
showFeedback: PropTypes.bool,
|
||||
};
|
||||
|
||||
export { CustomerFeedbackSimple };
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './customer-effort-score';
|
||||
export * from './customer-feedback-simple';
|
||||
export * from './customer-feedback-modal';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import { useState } from '@wordpress/element';
|
||||
import PropTypes from 'prop-types';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import CustomerEffortScore from '@woocommerce/customer-effort-score';
|
||||
import { CustomerEffortScore } from '@woocommerce/customer-effort-score';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { withSelect, withDispatch } from '@wordpress/data';
|
||||
import { OPTIONS_STORE_NAME, WEEK } from '@woocommerce/data';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.wooocommerce-task-card__header-subtitle {
|
||||
.wooocommerce-task-card__header .wooocommerce-task-card__header-subtitle {
|
||||
color: $gray-700;
|
||||
margin-bottom: $gap-large;
|
||||
}
|
||||
|
|
|
@ -2,9 +2,17 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import classnames from 'classnames';
|
||||
import { useState } from '@wordpress/element';
|
||||
import { EllipsisMenu } from '@woocommerce/components';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { OPTIONS_STORE_NAME, WEEK } from '@woocommerce/data';
|
||||
import { Button, Card, CardHeader } from '@wordpress/components';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { CustomerFeedbackSimple } from '@woocommerce/customer-effort-score';
|
||||
import {
|
||||
CustomerFeedbackModal,
|
||||
CustomerFeedbackSimple,
|
||||
} from '@woocommerce/customer-effort-score';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
|
@ -12,21 +20,87 @@ import { __ } from '@wordpress/i18n';
|
|||
*/
|
||||
import './completed-header-with-ces.scss';
|
||||
import HeaderImage from './completed-celebration-header.svg';
|
||||
import React from 'react';
|
||||
import { EllipsisMenu } from '@woocommerce/components';
|
||||
|
||||
type TaskListCompletedHeaderProps = {
|
||||
hideTasks: ( event: string ) => void;
|
||||
hideTasks: () => void;
|
||||
keepTasks: () => void;
|
||||
allowTracking: boolean;
|
||||
};
|
||||
|
||||
const ADMIN_INSTALL_TIMESTAMP_OPTION_NAME =
|
||||
'woocommerce_admin_install_timestamp';
|
||||
const SHOWN_FOR_ACTIONS_OPTION_NAME = 'woocommerce_ces_shown_for_actions';
|
||||
const CES_ACTION = 'store_setup';
|
||||
|
||||
function getStoreAgeInWeeks( adminInstallTimestamp: number ) {
|
||||
if ( adminInstallTimestamp === 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Date.now() is ms since Unix epoch, adminInstallTimestamp is in
|
||||
// seconds since Unix epoch.
|
||||
const storeAgeInMs = Date.now() - adminInstallTimestamp * 1000;
|
||||
const storeAgeInWeeks = Math.round( storeAgeInMs / WEEK );
|
||||
|
||||
return storeAgeInWeeks;
|
||||
}
|
||||
|
||||
export const TaskListCompletedHeaderWithCES: React.FC< TaskListCompletedHeaderProps > = ( {
|
||||
hideTasks,
|
||||
keepTasks,
|
||||
allowTracking,
|
||||
} ) => {
|
||||
const recordScoreCallback = ( score: number ) => {};
|
||||
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
||||
const [ showCesModal, setShowCesModal ] = useState( false );
|
||||
const [ score, setScore ] = useState( NaN );
|
||||
const [ showFeedback, setShowFeedback ] = useState( false );
|
||||
const { storeAgeInWeeks, cesShownForActions } = useSelect( ( select ) => {
|
||||
const { getOption } = select( OPTIONS_STORE_NAME );
|
||||
|
||||
const adminInstallTimestamp: number =
|
||||
getOption( ADMIN_INSTALL_TIMESTAMP_OPTION_NAME ) || 0;
|
||||
return {
|
||||
storeAgeInWeeks: getStoreAgeInWeeks( adminInstallTimestamp ),
|
||||
cesShownForActions:
|
||||
getOption( SHOWN_FOR_ACTIONS_OPTION_NAME ) || [],
|
||||
};
|
||||
} );
|
||||
|
||||
const recordScore = ( score: number ) => {
|
||||
if ( score > 2 ) {
|
||||
recordEvent( 'ces_feedback', {
|
||||
action: CES_ACTION,
|
||||
score,
|
||||
store_age: storeAgeInWeeks,
|
||||
} );
|
||||
updateOptions( {
|
||||
[ SHOWN_FOR_ACTIONS_OPTION_NAME ]: [
|
||||
CES_ACTION,
|
||||
...cesShownForActions,
|
||||
],
|
||||
} );
|
||||
} else {
|
||||
setScore( score );
|
||||
setShowCesModal( true );
|
||||
}
|
||||
};
|
||||
|
||||
const recordModalScore = ( score: number, comments: string ) => {
|
||||
setShowCesModal( false );
|
||||
recordEvent( 'ces_feedback', {
|
||||
action: 'store_setup',
|
||||
score,
|
||||
comments: comments || '',
|
||||
store_age: storeAgeInWeeks,
|
||||
} );
|
||||
updateOptions( {
|
||||
[ SHOWN_FOR_ACTIONS_OPTION_NAME ]: [
|
||||
CES_ACTION,
|
||||
...cesShownForActions,
|
||||
],
|
||||
} );
|
||||
setShowFeedback( true );
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -97,11 +171,19 @@ export const TaskListCompletedHeaderWithCES: React.FC< TaskListCompletedHeaderPr
|
|||
'How was your experience?',
|
||||
'woocommerce'
|
||||
) }
|
||||
recordScoreCallback={ recordScoreCallback }
|
||||
recordScoreCallback={ recordScore }
|
||||
showFeedback={ showFeedback }
|
||||
/>
|
||||
) }
|
||||
</Card>
|
||||
</div>
|
||||
{ showCesModal ? (
|
||||
<CustomerFeedbackModal
|
||||
label={ __( 'How was your experience?', 'woocommerce' ) }
|
||||
defaultScore={ score }
|
||||
recordScoreCallback={ recordModalScore }
|
||||
/>
|
||||
) : null }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue