From 826029ca7b39a0447f8a8972b7e0c0c29675e49d Mon Sep 17 00:00:00 2001 From: Ilyas Foo Date: Tue, 10 May 2022 16:58:02 +0800 Subject: [PATCH] Add ExPlat call for product task experiment --- .../fills/experimental-products/index.tsx | 65 +++++++++++-------- .../experimental-products/test/index.tsx | 5 ++ .../client/tasks/fills/index.js | 12 +++- .../fills/use-product-layout-experiment.ts | 44 +++++++++++++ 4 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts 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 34ab388d276..1c5dadde5f8 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx +++ b/plugins/woocommerce-admin/client/tasks/fills/experimental-products/index.tsx @@ -6,7 +6,7 @@ import { WooOnboardingTask } from '@woocommerce/onboarding'; import { Text } from '@woocommerce/experimental'; import { registerPlugin } from '@wordpress/plugins'; import { useMemo, useState } from '@wordpress/element'; -import { Button } from '@wordpress/components'; +import { Button, Spinner } from '@wordpress/components'; import { getAdminLink } from '@woocommerce/settings'; import { Icon, chevronDown, chevronUp } from '@wordpress/icons'; @@ -17,6 +17,7 @@ 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'; @@ -24,9 +25,6 @@ import { LoadSampleProductType } from './constants'; import LoadSampleProductModal from '../components/load-sample-product-modal'; import useLoadSampleProducts from '../components/use-load-sample-products'; -// TODO: Use experiment data from the API, not hardcoded. -const SHOW_STACK_LAYOUT = true; - const getOnboardingProductType = (): string[] => { const onboardingData = getAdminSetting( 'onboarding' ); return ( @@ -52,6 +50,7 @@ const ViewControlButton: React.FC< { export const Products = () => { const [ isExpanded, setIsExpanded ] = useState< boolean >( false ); + const [ isLoadingExperiment, experimentLayout ] = useLayoutExperiment(); const productTypes = useProductTypeListItems( getProductTypes() ); const surfacedProductTypeKeys = getSurfacedProductTypeKeys( @@ -79,7 +78,7 @@ export const Products = () => { surfacedProductTypes.push( productType ) ); - if ( ! SHOW_STACK_LAYOUT ) { + if ( experimentLayout === 'card' ) { surfacedProductTypes.push( { ...LoadSampleProductType, onClick: loadSampleProduct, @@ -91,35 +90,45 @@ export const Products = () => { surfacedProductTypeKeys, isExpanded, productTypes, + experimentLayout, loadSampleProduct, ] ); return (
- - { __( 'What product do you want to add?', 'woocommerce' ) } - + { isLoadingExperiment ? ( + + ) : ( + <> + + { __( + 'What product do you want to add?', + 'woocommerce' + ) } + -
- { SHOW_STACK_LAYOUT ? ( - - ) : ( - - ) } - setIsExpanded( ! isExpanded ) } - /> -
-
- { isLoadingSampleProducts && } +
+ { experimentLayout === 'stacked' ? ( + + ) : ( + + ) } + setIsExpanded( ! isExpanded ) } + /> +
+
+ { isLoadingSampleProducts && } + + ) }
); }; 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 a1e44f684e8..2edf943462f 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 @@ -20,6 +20,11 @@ jest.mock( '~/utils/admin-settings', () => ( { getAdminSetting: jest.fn(), } ) ); +jest.mock( '../../use-product-layout-experiment', () => ( { + default: () => [ false, 'stacked' ], + __esModule: true, +} ) ); + global.fetch = jest.fn().mockImplementation( () => Promise.resolve( { json: () => Promise.resolve( {} ), diff --git a/plugins/woocommerce-admin/client/tasks/fills/index.js b/plugins/woocommerce-admin/client/tasks/fills/index.js index bfb0521f95e..6abd22a44b1 100644 --- a/plugins/woocommerce-admin/client/tasks/fills/index.js +++ b/plugins/woocommerce-admin/client/tasks/fills/index.js @@ -2,6 +2,7 @@ * Internal dependencies */ import { getAdminSetting } from '~/utils/admin-settings'; +import { isExperimentProductTask } from './use-product-layout-experiment'; import './PaymentGatewaySuggestions'; import './shipping'; @@ -14,6 +15,15 @@ import './purchase'; const onboardingData = getAdminSetting( 'onboarding' ); +const importProductTask = async () => { + const isExperiment = await isExperimentProductTask(); + if ( isExperiment ) { + import( './experimental-products' ); + } else { + import( './products' ); + } +}; + if ( window.wcAdminFeatures && window.wcAdminFeatures[ 'experimental-import-products-task' ] && @@ -25,7 +35,7 @@ if ( window.wcAdminFeatures && window.wcAdminFeatures[ 'experimental-products-task' ] ) { - import( './experimental-products' ); + importProductTask(); } else { import( './products' ); } diff --git a/plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts b/plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts new file mode 100644 index 00000000000..31212677aa4 --- /dev/null +++ b/plugins/woocommerce-admin/client/tasks/fills/use-product-layout-experiment.ts @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +import { useState, useEffect } from '@wordpress/element'; +import { loadExperimentAssignment } from '@woocommerce/explat'; + +type Layout = 'control' | 'card' | 'stacked'; + +export const getProductLayoutExperiment = async (): Promise< Layout > => { + const [ cardAssignment, stackedAssignment ] = await Promise.all( [ + loadExperimentAssignment( `woocommerce_products_task_layout_card` ), + loadExperimentAssignment( `woocommerce_products_task_layout_stacked` ), + ] ); + // This logic may look flawed as in both looks like they can be assigned treatment at the same time, + // but in backend we segment the experiments by store country, so it will never be. + if ( cardAssignment?.variationName === 'treatment' ) { + return 'card'; + } else if ( stackedAssignment?.variationName === 'treatment' ) { + return 'stacked'; + } + return 'control'; +}; + +export const isExperimentProductTask = async (): Promise< boolean > => { + return ( await getProductLayoutExperiment() ) !== 'control'; +}; + +export const useLayoutExperiment = () => { + const [ isLoading, setIsLoading ] = useState< boolean >( true ); + const [ experimentLayout, setExperimentLayout ] = useState< Layout >( + 'control' + ); + + useEffect( () => { + getProductLayoutExperiment().then( ( layout ) => { + setExperimentLayout( layout ); + setIsLoading( false ); + } ); + }, [ setExperimentLayout ] ); + + return [ isLoading, experimentLayout ]; +}; + +export default useLayoutExperiment;