diff --git a/packages/js/onboarding/changelog/dev-follow-up-product-task-experiment b/packages/js/onboarding/changelog/dev-follow-up-product-task-experiment new file mode 100644 index 00000000000..e55863c5a53 --- /dev/null +++ b/packages/js/onboarding/changelog/dev-follow-up-product-task-experiment @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Add ExPlat dependency and product task experiment logic diff --git a/packages/js/onboarding/package.json b/packages/js/onboarding/package.json index f38ad112585..0e8e1ebc083 100644 --- a/packages/js/onboarding/package.json +++ b/packages/js/onboarding/package.json @@ -29,6 +29,7 @@ "@woocommerce/components": "workspace:*", "@woocommerce/experimental": "workspace:*", "@woocommerce/tracks": "workspace:*", + "@woocommerce/explat": "workspace:*", "@wordpress/components": "^19.5.0", "@wordpress/element": "^4.1.1", "@wordpress/i18n": "^4.3.1", diff --git a/packages/js/onboarding/src/components/WooOnboardingTask/WooOnboardingTask.js b/packages/js/onboarding/src/components/WooOnboardingTask/WooOnboardingTask.js index dfe6851caa5..4598319b4ee 100644 --- a/packages/js/onboarding/src/components/WooOnboardingTask/WooOnboardingTask.js +++ b/packages/js/onboarding/src/components/WooOnboardingTask/WooOnboardingTask.js @@ -5,7 +5,12 @@ import { createElement, useEffect } from '@wordpress/element'; import { recordEvent } from '@woocommerce/tracks'; import { Slot, Fill } from '@wordpress/components'; -export const trackView = ( taskId ) => { +/** + * Internal dependencies + */ +import { isProductTaskExperimentTreatment } from './use-product-layout-experiment'; + +export const trackView = async ( taskId ) => { const activePlugins = wp.data .select( 'wc/admin/plugins' ) .getActivePlugins(); @@ -21,7 +26,8 @@ export const trackView = ( taskId ) => { recordEvent( 'task_view', { task_name: taskId, experimental_products: - window.wcAdminFeatures[ 'experimental-products-task' ], + window.wcAdminFeatures[ 'experimental-products-task' ] && + ( await isProductTaskExperimentTreatment() ), wcs_installed: installedPlugins.includes( 'woocommerce-services' ), wcs_active: activePlugins.includes( 'woocommerce-services' ), jetpack_installed: installedPlugins.includes( 'jetpack' ), diff --git a/packages/js/onboarding/src/components/WooOnboardingTask/index.js b/packages/js/onboarding/src/components/WooOnboardingTask/index.js index 06482c0ab9e..88c38d69e77 100644 --- a/packages/js/onboarding/src/components/WooOnboardingTask/index.js +++ b/packages/js/onboarding/src/components/WooOnboardingTask/index.js @@ -1 +1,2 @@ export * from './WooOnboardingTask'; +export * from './use-product-layout-experiment'; diff --git a/plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts b/packages/js/onboarding/src/components/WooOnboardingTask/use-product-layout-experiment.ts similarity index 88% rename from plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts rename to packages/js/onboarding/src/components/WooOnboardingTask/use-product-layout-experiment.ts index 31212677aa4..bf227588b29 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts +++ b/packages/js/onboarding/src/components/WooOnboardingTask/use-product-layout-experiment.ts @@ -21,11 +21,11 @@ export const getProductLayoutExperiment = async (): Promise< Layout > => { return 'control'; }; -export const isExperimentProductTask = async (): Promise< boolean > => { +export const isProductTaskExperimentTreatment = async (): Promise< boolean > => { return ( await getProductLayoutExperiment() ) !== 'control'; }; -export const useLayoutExperiment = () => { +export const useProductTaskExperiment = () => { const [ isLoading, setIsLoading ] = useState< boolean >( true ); const [ experimentLayout, setExperimentLayout ] = useState< Layout >( 'control' @@ -41,4 +41,4 @@ export const useLayoutExperiment = () => { return [ isLoading, experimentLayout ]; }; -export default useLayoutExperiment; +export default useProductTaskExperiment; diff --git a/packages/js/onboarding/src/index.js b/packages/js/onboarding/src/index.js index c2e7dddf91d..b3f44d4261f 100644 --- a/packages/js/onboarding/src/index.js +++ b/packages/js/onboarding/src/index.js @@ -10,5 +10,9 @@ export { default as GooglePay } from './images/cards/googlepay'; export { default as WCPayLogo } from './images/wcpay-logo'; export { WooPaymentGatewaySetup } from './components/WooPaymentGatewaySetup'; export { WooPaymentGatewayConfigure } from './components/WooPaymentGatewayConfigure'; -export { WooOnboardingTask } from './components/WooOnboardingTask'; export { WooOnboardingTaskListItem } from './components/WooOnboardingTaskListItem'; +export { + WooOnboardingTask, + useProductTaskExperiment, + isProductTaskExperimentTreatment, +} from './components/WooOnboardingTask'; diff --git a/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx b/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx index 1c5dadde5f8..73a62b1a06b 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx +++ b/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx @@ -2,7 +2,10 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; -import { WooOnboardingTask } from '@woocommerce/onboarding'; +import { + WooOnboardingTask, + useProductTaskExperiment, +} from '@woocommerce/onboarding'; import { Text } from '@woocommerce/experimental'; import { registerPlugin } from '@wordpress/plugins'; import { useMemo, useState } from '@wordpress/element'; @@ -17,7 +20,6 @@ import './index.scss'; import { getAdminSetting } from '~/utils/admin-settings'; import { getSurfacedProductTypeKeys, getProductTypes } from './utils'; import useProductTypeListItems from './use-product-types-list-items'; -import useLayoutExperiment from '../use-product-layout-experiment'; import Stack from './stack'; import Footer from './footer'; import CardLayout from './card-layout'; @@ -50,7 +52,10 @@ const ViewControlButton: React.FC< { export const Products = () => { const [ isExpanded, setIsExpanded ] = useState< boolean >( false ); - const [ isLoadingExperiment, experimentLayout ] = useLayoutExperiment(); + const [ + isLoadingExperiment, + experimentLayout, + ] = useProductTaskExperiment(); const productTypes = useProductTypeListItems( getProductTypes() ); const surfacedProductTypeKeys = getSurfacedProductTypeKeys( diff --git a/plugins/woocommerce-admin/client/tasks/fills/experimental-products/test/index.tsx b/plugins/woocommerce-admin/client/tasks/fills/experimental-products/test/index.tsx index 933aa0abb2c..1fcec27fa68 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/experimental-products/test/index.tsx +++ b/plugins/woocommerce-admin/client/tasks/fills/experimental-products/test/index.tsx @@ -3,6 +3,7 @@ */ import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { useProductTaskExperiment } from '@woocommerce/onboarding'; /** * Internal dependencies @@ -10,7 +11,6 @@ import userEvent from '@testing-library/user-event'; import { Products } from '../'; import { defaultSurfacedProductTypes, productTypes } from '../constants'; import { getAdminSetting } from '~/utils/admin-settings'; -import useLayoutExperiment from '../../use-product-layout-experiment'; jest.mock( '@wordpress/data', () => ( { ...jest.requireActual( '@wordpress/data' ), @@ -21,9 +21,8 @@ jest.mock( '~/utils/admin-settings', () => ( { getAdminSetting: jest.fn(), } ) ); -jest.mock( '../../use-product-layout-experiment', () => ( { - default: jest.fn().mockReturnValue( [ false, 'stacked' ] ), - __esModule: true, +jest.mock( '@woocommerce/onboarding', () => ( { + useProductTaskExperiment: jest.fn().mockReturnValue( [ false, 'stacked' ] ), } ) ); global.fetch = jest.fn().mockImplementation( () => @@ -113,7 +112,7 @@ describe( 'Products', () => { } ); it( 'should show spinner when layout experiment is loading', async () => { - ( useLayoutExperiment as jest.Mock ).mockImplementation( () => [ + ( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [ true, 'card', ] ); @@ -124,7 +123,7 @@ describe( 'Products', () => { } ); it( 'should render card layout when experiment is assigned', async () => { - ( useLayoutExperiment as jest.Mock ).mockImplementation( () => [ + ( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [ false, 'card', ] ); @@ -137,7 +136,7 @@ describe( 'Products', () => { } ); it( 'should render stacked layout when experiment is assigned', async () => { - ( useLayoutExperiment as jest.Mock ).mockImplementation( () => [ + ( useProductTaskExperiment as jest.Mock ).mockImplementation( () => [ false, 'stacked', ] ); diff --git a/plugins/woocommerce-admin/client/tasks/fills/index.js b/plugins/woocommerce-admin/client/tasks/fills/index.js index 1d04f492a50..70b6d4ff64d 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/index.js +++ b/plugins/woocommerce-admin/client/tasks/fills/index.js @@ -1,8 +1,12 @@ +/** + * External dependencies + */ +import { isProductTaskExperimentTreatment } from '@woocommerce/onboarding'; + /** * Internal dependencies */ import { getAdminSetting } from '~/utils/admin-settings'; -import { isExperimentProductTask } from './use-product-layout-experiment'; import './PaymentGatewaySuggestions'; import './shipping'; @@ -16,7 +20,7 @@ import './purchase'; const onboardingData = getAdminSetting( 'onboarding' ); const possiblyImportProductTaskExperiment = async () => { - const isExperiment = await isExperimentProductTask(); + const isExperiment = await isProductTaskExperimentTreatment(); if ( isExperiment ) { import( './experimental-products' ); } else { diff --git a/plugins/woocommerce/changelog/dev-follow-up-product-task-experiment b/plugins/woocommerce/changelog/dev-follow-up-product-task-experiment new file mode 100644 index 00000000000..271b4cbb1ee --- /dev/null +++ b/plugins/woocommerce/changelog/dev-follow-up-product-task-experiment @@ -0,0 +1,4 @@ +Significance: minor +Type: update + +Moved out product task experiment hook to onboarding package, added ExPlat logic to backend calls diff --git a/plugins/woocommerce/src/Admin/API/OnboardingTasks.php b/plugins/woocommerce/src/Admin/API/OnboardingTasks.php index 3f54f1d68a3..dff22c92ab1 100644 --- a/plugins/woocommerce/src/Admin/API/OnboardingTasks.php +++ b/plugins/woocommerce/src/Admin/API/OnboardingTasks.php @@ -340,7 +340,10 @@ class OnboardingTasks extends \WC_REST_Data_Controller { * @return WP_Error|WP_REST_Response */ public static function import_sample_products() { - if ( Features::is_enabled( 'experimental-products-task' ) || Features::is_enabled( 'experimental-import-products-task' ) ) { + if ( + ( Features::is_enabled( 'experimental-import-products-task' ) || Features::is_enabled( 'experimental-products-task' ) ) + && static::is_experiment_product_task() + ) { $sample_csv_file = WC_ABSPATH . 'sample-data/experimental_sample_9_products.csv'; } else { $sample_csv_file = WC_ABSPATH . 'sample-data/sample_products.csv'; @@ -350,6 +353,22 @@ class OnboardingTasks extends \WC_REST_Data_Controller { return rest_ensure_response( $import ); } + /** + * Check if product task experiment is treatment. + * + * @return bool + */ + public static function is_experiment_product_task() { + $anon_id = isset( $_COOKIE['tk_ai'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) ) : ''; + $allow_tracking = 'yes' === get_option( 'woocommerce_allow_tracking' ); + $abtest = new \WooCommerce\Admin\Experimental_Abtest( + $anon_id, + 'woocommerce', + $allow_tracking + ); + return $abtest->get_variation( 'woocommerce_products_task_layout_stacked' ) === 'treatment' || + $abtest->get_variation( 'woocommerce_products_task_layout_card' ) === 'treatment'; + } /** * Creates a product from a template name passed in through the template_name param. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98c38cfb1b3..053d3888eef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1062,6 +1062,7 @@ importers: '@woocommerce/components': workspace:* '@woocommerce/eslint-plugin': workspace:* '@woocommerce/experimental': workspace:* + '@woocommerce/explat': workspace:* '@woocommerce/style-build': workspace:* '@woocommerce/tracks': workspace:* '@wordpress/browserslist-config': ^4.1.1 @@ -1085,6 +1086,7 @@ importers: '@automattic/interpolate-components': 1.2.1 '@woocommerce/components': link:../components '@woocommerce/experimental': link:../experimental + '@woocommerce/explat': link:../explat '@woocommerce/tracks': link:../tracks '@wordpress/components': 19.6.1_@babel+core@7.17.8 '@wordpress/element': 4.2.1