Skip to content

Commit

Permalink
Add survey when disabling new experience (#36544)
Browse files Browse the repository at this point in the history
* Add customer-score-tracks data

* Add callback after disabling new exp

* Add TransientNotice after filling out the survey

# Conflicts:
#	plugins/woocommerce/src/Admin/Features/NewProductManagementExperience.php

* Remove comments

* Remove NEW_PRODUCT_MANAGEMENT_FEEDBACK

* Add changelog

* Rename const

* Remove queryParam after showing notice

* Fix lint

* Fix lint 2.0

* Remove empty line

* Refactor `maybe_show_disabled_notice`

* Fix lint 3.0

Co-authored-by: Fernando Marichal <contacto@fernandomarichal.com>
  • Loading branch information
2 people authored and vedanshujain committed Jan 25, 2023
1 parent 1d8ba9f commit 8dde8f3
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 9 deletions.
Expand Up @@ -3,6 +3,8 @@ const TYPES = {
ADD_CES_SURVEY: 'ADD_CES_SURVEY',
SHOW_CES_MODAL: 'SHOW_CES_MODAL',
HIDE_CES_MODAL: 'HIDE_CES_MODAL',
SHOW_PRODUCT_MVP_FEEDBACK_MODAL: 'SHOW_PRODUCT_MVP_FEEDBACK_MODAL',
HIDE_PRODUCT_MVP_FEEDBACK_MODAL: 'HIDE_PRODUCT_MVP_FEEDBACK_MODAL',
};

export default TYPES;
Expand Up @@ -141,3 +141,21 @@ export function addCesSurveyForCustomerSearch() {
},
} );
}

/**
* Add show product MVP Feedback modal.
*/
export function showProductMVPFeedbackModal() {
return {
type: TYPES.SHOW_PRODUCT_MVP_FEEDBACK_MODAL,
};
}

/**
* Hide product MVP Feedback modal.
*/
export function hideProductMVPFeedbackModal() {
return {
type: TYPES.HIDE_PRODUCT_MVP_FEEDBACK_MODAL,
};
}
Expand Up @@ -7,6 +7,7 @@ const DEFAULT_STATE = {
queue: [],
cesModalData: undefined,
showCESModal: false,
showProductMVPFeedbackModal: false,
};

const reducer = ( state = DEFAULT_STATE, action ) => {
Expand Down Expand Up @@ -62,6 +63,16 @@ const reducer = ( state = DEFAULT_STATE, action ) => {
...state,
queue: [ ...state.queue, newTrack ],
};
case TYPES.SHOW_PRODUCT_MVP_FEEDBACK_MODAL:
return {
...state,
showProductMVPFeedbackModal: true,
};
case TYPES.HIDE_PRODUCT_MVP_FEEDBACK_MODAL:
return {
...state,
showProductMVPFeedbackModal: false,
};

default:
return state;
Expand Down
Expand Up @@ -5,3 +5,7 @@ export function getCesSurveyQueue( state ) {
export function getVisibleCESModalData( state ) {
return state.showCESModal ? state.cesModalData : undefined;
}

export function isProductMVPFeedbackModalVisible( state ) {
return state.showProductMVPFeedbackModal;
}
Expand Up @@ -21,9 +21,12 @@ import { STORE_KEY } from './data/constants';

export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
'woocommerce_ces_product_mvp_ces_action';
export const NEW_PRODUCT_MANAGEMENT =
'woocommerce_new_product_management_enabled';

export const ProductMVPCESFooter: React.FC = () => {
const { showCesModal } = useDispatch( STORE_KEY );
const { showCesModal, showProductMVPFeedbackModal } =
useDispatch( STORE_KEY );
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
const {
cesAction,
Expand Down Expand Up @@ -99,6 +102,16 @@ export const ProductMVPCESFooter: React.FC = () => {
} );
};

const onDisablingNewProductExperience = () => {
updateOptions( {
[ PRODUCT_MVP_CES_ACTION_OPTION_NAME ]: 'hide',
} );
updateOptions( {
[ NEW_PRODUCT_MANAGEMENT ]: 'no',
} );
showProductMVPFeedbackModal();
};

const onDisablingCES = () => {
updateOptions( {
[ PRODUCT_MVP_CES_ACTION_OPTION_NAME ]: 'hide',
Expand Down Expand Up @@ -126,7 +139,7 @@ export const ProductMVPCESFooter: React.FC = () => {
{ __( 'Share feedback', 'woocommerce' ) }
</Button>
<Button
onClick={ onDisablingCES }
onClick={ onDisablingNewProductExperience }
variant="tertiary"
>
{ __( 'Turn it off', 'woocommerce' ) }
Expand Down
@@ -0,0 +1,61 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { ProductMVPFeedbackModal } from '@woocommerce/customer-effort-score';
import { recordEvent } from '@woocommerce/tracks';
import { getAdminLink } from '@woocommerce/settings';
import { useFormContext } from '@woocommerce/components';
import { Product } from '@woocommerce/data';

/**
* Internal dependencies
*/
import { STORE_KEY } from './data/constants';

export const ProductMVPFeedbackModalContainer: React.FC = () => {
const { values } = useFormContext< Product >();
const { hideProductMVPFeedbackModal } = useDispatch( STORE_KEY );
const { isProductMVPModalVisible } = useSelect( ( select ) => {
const { isProductMVPFeedbackModalVisible } = select( STORE_KEY );
return {
isProductMVPModalVisible: isProductMVPFeedbackModalVisible(),
};
} );

const classicEditorUrl = values.id
? getAdminLink( `post.php?post=${ values.id }&action=edit` )
: getAdminLink( 'post-new.php?post_type=product' );

const recordScore = ( checked: string[], comments: string ) => {
recordEvent( 'product_mvp_feedback', {
action: 'disable',
checked,
comments: comments || '',
} );
hideProductMVPFeedbackModal();
window.location.href = `${ classicEditorUrl }&new-product-experience-disabled=true`;
};

const onCloseModal = () => {
recordEvent( 'product_mvp_feedback', {
action: 'disable',
checked: '',
comments: '',
} );
hideProductMVPFeedbackModal();
window.location.href = classicEditorUrl;
};

if ( ! isProductMVPModalVisible ) {
return null;
}

return (
<ProductMVPFeedbackModal
recordScoreCallback={ recordScore }
onCloseModal={ onCloseModal }
/>
);
};
Expand Up @@ -2,11 +2,13 @@
* Internal dependencies
*/
import { ProductMVPCESFooter } from '~/customer-effort-score-tracks/product-mvp-ces-footer';
import { ProductMVPFeedbackModalContainer } from '~/customer-effort-score-tracks/product-mvp-feedback-modal-container';

export const ProductFormFooter: React.FC = () => {
return (
<>
<ProductMVPCESFooter />
<ProductMVPFeedbackModalContainer />
</>
);
};
45 changes: 38 additions & 7 deletions plugins/woocommerce-admin/client/products/product-more-menu.tsx
Expand Up @@ -3,10 +3,10 @@
*/
import { __ } from '@wordpress/i18n';
import { DropdownMenu, MenuItem } from '@wordpress/components';
import { useDispatch } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { getAdminLink } from '@woocommerce/settings';
import { moreVertical } from '@wordpress/icons';
import { Product } from '@woocommerce/data';
import { OPTIONS_STORE_NAME, Product } from '@woocommerce/data';
import { useFormContext } from '@woocommerce/components';

/**
Expand All @@ -16,16 +16,41 @@ import { ClassicEditorIcon } from './images/classic-editor-icon';
import { FeedbackIcon } from './images/feedback-icon';
import { WooHeaderItem } from '~/header/utils';
import { STORE_KEY as CES_STORE_KEY } from '~/customer-effort-score-tracks/data/constants';
import { NEW_PRODUCT_MANAGEMENT } from '~/customer-effort-score-tracks/product-mvp-ces-footer';
import { ALLOW_TRACKING_OPTION_NAME } from '~/customer-effort-score-tracks/constants';
import './product-more-menu.scss';

export const ProductMoreMenu = () => {
const { values } = useFormContext< Product >();
const { showCesModal } = useDispatch( CES_STORE_KEY );
const { showCesModal, showProductMVPFeedbackModal } =
useDispatch( CES_STORE_KEY );
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );

const { allowTracking, resolving: isLoading } = useSelect( ( select ) => {
const { getOption, hasFinishedResolution } =
select( OPTIONS_STORE_NAME );

const allowTrackingOption =
getOption( ALLOW_TRACKING_OPTION_NAME ) || 'no';

const resolving = ! hasFinishedResolution( 'getOption', [
ALLOW_TRACKING_OPTION_NAME,
] );

return {
allowTracking: allowTrackingOption === 'yes',
resolving,
};
} );

const classEditorUrl = values.id
? getAdminLink( `post.php?post=${ values.id }&action=edit` )
: getAdminLink( 'post-new.php?post_type=product' );

if ( isLoading ) {
return null;
}

return (
<WooHeaderItem>
<DropdownMenu
Expand Down Expand Up @@ -69,11 +94,17 @@ export const ProductMoreMenu = () => {
</MenuItem>
<MenuItem
onClick={ () => {
onClose();
if ( allowTracking ) {
updateOptions( {
[ NEW_PRODUCT_MANAGEMENT ]: 'no',
} );
showProductMVPFeedbackModal();
onClose();
} else {
window.location.href = classEditorUrl;
onClose();
}
} }
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore The href prop exists as buttonProps.
href={ classEditorUrl }
icon={ <ClassicEditorIcon /> }
iconPosition="right"
>
Expand Down
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Add survey after disabling new experience
Expand Up @@ -5,6 +5,7 @@

namespace Automattic\WooCommerce\Admin\Features;

use \Automattic\WooCommerce\Admin\Features\TransientNotices;
use \Automattic\WooCommerce\Admin\PageController;
use \Automattic\WooCommerce\Internal\Admin\Loader;

Expand All @@ -22,6 +23,7 @@ class NewProductManagementExperience {
* Constructor
*/
public function __construct() {
$this->maybe_show_disabled_notice();
if ( ! Features::is_enabled( 'new-product-management-experience' ) ) {
return;
}
Expand All @@ -30,6 +32,28 @@ public function __construct() {
add_action( 'get_edit_post_link', array( $this, 'update_edit_product_link' ), 10, 2 );
}

/**
* Maybe show disabled notice.
*/
public function maybe_show_disabled_notice() {
$new_product_experience_param = 'new-product-experience-disabled';
if ( isset( $_GET[ $new_product_experience_param ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
TransientNotices::add(
array(
'user_id' => get_current_user_id(),
'id' => 'new-product-experience-disbled',
'status' => 'success',
'content' => __( '🌟‎ ‎ Thanks for the feedback. We’ll put it to good use!', 'woocommerce' ),
)
);

$url = isset( $_SERVER['REQUEST_URI'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
$url = remove_query_arg( 'new-product-experience-disabled', $url );
wp_safe_redirect( $url );
exit;
}
}

/**
* Enqueue styles needed for the rich text editor.
*/
Expand Down

0 comments on commit 8dde8f3

Please sign in to comment.