Add confirmation dialog before loading the sample products
This commit is contained in:
parent
86553fbe1f
commit
e2cc91dd60
|
@ -12,17 +12,16 @@ import './load-sample-product-confirm-modal.scss';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onOK: () => void;
|
onImport: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LoadSampleProductConfirmModal: React.VFC< Props > = ( {
|
export const LoadSampleProductConfirmModal: React.VFC< Props > = ( {
|
||||||
onCancel,
|
onCancel,
|
||||||
onOK,
|
onImport,
|
||||||
} ) => {
|
} ) => {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="woocommerce-products-load-sample-product-confirm-modal"
|
className="woocommerce-products-load-sample-product-confirm-modal"
|
||||||
overlayClassName="woocommerce-products-load-sample-product-confirm-modal-overlay"
|
|
||||||
title="Load sample products"
|
title="Load sample products"
|
||||||
onRequestClose={ onCancel }
|
onRequestClose={ onCancel }
|
||||||
>
|
>
|
||||||
|
@ -35,7 +34,7 @@ export const LoadSampleProductConfirmModal: React.VFC< Props > = ( {
|
||||||
<Button isSecondary onClick={ onCancel }>
|
<Button isSecondary onClick={ onCancel }>
|
||||||
{ __( 'Cancel' ) }
|
{ __( 'Cancel' ) }
|
||||||
</Button>
|
</Button>
|
||||||
<Button isPrimary onClick={ onOK }>
|
<Button isPrimary onClick={ onImport }>
|
||||||
{ __( 'Import sample products' ) }
|
{ __( 'Import sample products' ) }
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,11 +21,16 @@ import useProductTypeListItems from '../experimental-products/use-product-types-
|
||||||
import { getProductTypes } from '../experimental-products/utils';
|
import { getProductTypes } from '../experimental-products/utils';
|
||||||
import LoadSampleProductModal from '../components/load-sample-product-modal';
|
import LoadSampleProductModal from '../components/load-sample-product-modal';
|
||||||
import useLoadSampleProducts from '../components/use-load-sample-products';
|
import useLoadSampleProducts from '../components/use-load-sample-products';
|
||||||
|
import LoadSampleProductConfirmModal from '../components/load-sample-product-confirm-modal';
|
||||||
import useRecordCompletionTime from '../use-record-completion-time';
|
import useRecordCompletionTime from '../use-record-completion-time';
|
||||||
|
|
||||||
export const Products = () => {
|
export const Products = () => {
|
||||||
const [ showStacks, setStackVisibility ] = useState< boolean >( false );
|
const [ showStacks, setStackVisibility ] = useState< boolean >( false );
|
||||||
const { recordCompletionTime } = useRecordCompletionTime( 'products' );
|
const { recordCompletionTime } = useRecordCompletionTime( 'products' );
|
||||||
|
const [
|
||||||
|
isConfirmingLoadSampleProducts,
|
||||||
|
setIsConfirmingLoadSampleProducts,
|
||||||
|
] = useState( false );
|
||||||
|
|
||||||
const importTypesWithTimeRecord = useMemo(
|
const importTypesWithTimeRecord = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -61,7 +66,9 @@ export const Products = () => {
|
||||||
const StacksComponent = (
|
const StacksComponent = (
|
||||||
<Stacks
|
<Stacks
|
||||||
items={ productTypeListItems }
|
items={ productTypeListItems }
|
||||||
onClickLoadSampleProduct={ loadSampleProduct }
|
onClickLoadSampleProduct={ () =>
|
||||||
|
setIsConfirmingLoadSampleProducts( true )
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -83,7 +90,21 @@ export const Products = () => {
|
||||||
</Button>
|
</Button>
|
||||||
{ showStacks && StacksComponent }
|
{ showStacks && StacksComponent }
|
||||||
</div>
|
</div>
|
||||||
{ isLoadingSampleProducts && <LoadSampleProductModal /> }
|
{ isLoadingSampleProducts ? (
|
||||||
|
<LoadSampleProductModal />
|
||||||
|
) : (
|
||||||
|
isConfirmingLoadSampleProducts && (
|
||||||
|
<LoadSampleProductConfirmModal
|
||||||
|
onCancel={ () =>
|
||||||
|
setIsConfirmingLoadSampleProducts( false )
|
||||||
|
}
|
||||||
|
onImport={ () => {
|
||||||
|
setIsConfirmingLoadSampleProducts( false );
|
||||||
|
loadSampleProduct();
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,16 @@ import { Products } from '../';
|
||||||
|
|
||||||
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
||||||
|
|
||||||
|
global.fetch = jest.fn().mockImplementation( () =>
|
||||||
|
Promise.resolve( {
|
||||||
|
json: () => Promise.resolve( {} ),
|
||||||
|
status: 200,
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
|
||||||
|
const confirmModalText =
|
||||||
|
"We'll import images from woocommerce.com to set up your sample products.";
|
||||||
|
|
||||||
describe( 'Products', () => {
|
describe( 'Products', () => {
|
||||||
beforeEach( () => {
|
beforeEach( () => {
|
||||||
( recordEvent as jest.Mock ).mockClear();
|
( recordEvent as jest.Mock ).mockClear();
|
||||||
|
@ -103,4 +113,57 @@ describe( 'Products', () => {
|
||||||
);
|
);
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should send a request to load sample products when the "Import sample products" button is clicked', async () => {
|
||||||
|
const fetchMock = jest.spyOn( global, 'fetch' );
|
||||||
|
const { queryByText, getByRole } = render( <Products /> );
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'button', { name: 'Or add your products from scratch' } )
|
||||||
|
);
|
||||||
|
expect( queryByText( 'Load Sample Products' ) ).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'link', { name: 'Load Sample Products' } )
|
||||||
|
);
|
||||||
|
await waitFor( () =>
|
||||||
|
expect( queryByText( confirmModalText ) ).toBeInTheDocument()
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'button', { name: 'Import sample products' } )
|
||||||
|
);
|
||||||
|
await waitFor( () =>
|
||||||
|
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( fetchMock ).toHaveBeenCalledWith(
|
||||||
|
'/wc-admin/onboarding/tasks/import_sample_products?_locale=user',
|
||||||
|
{
|
||||||
|
body: undefined,
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { Accept: 'application/json, */*;q=0.1' },
|
||||||
|
method: 'POST',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should close the confirmation modal when the cancel button is clicked', async () => {
|
||||||
|
const { queryByText, getByRole } = render( <Products /> );
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'button', { name: 'Or add your products from scratch' } )
|
||||||
|
);
|
||||||
|
expect( queryByText( 'Load Sample Products' ) ).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'link', { name: 'Load Sample Products' } )
|
||||||
|
);
|
||||||
|
await waitFor( () =>
|
||||||
|
expect( queryByText( confirmModalText ) ).toBeInTheDocument()
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click( getByRole( 'button', { name: 'Cancel' } ) );
|
||||||
|
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument();
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -25,6 +25,7 @@ import CardLayout from './card-layout';
|
||||||
import { LoadSampleProductType } from './constants';
|
import { LoadSampleProductType } from './constants';
|
||||||
import LoadSampleProductModal from '../components/load-sample-product-modal';
|
import LoadSampleProductModal from '../components/load-sample-product-modal';
|
||||||
import useLoadSampleProducts from '../components/use-load-sample-products';
|
import useLoadSampleProducts from '../components/use-load-sample-products';
|
||||||
|
import LoadSampleProductConfirmModal from '../components/load-sample-product-confirm-modal';
|
||||||
import useRecordCompletionTime from '../use-record-completion-time';
|
import useRecordCompletionTime from '../use-record-completion-time';
|
||||||
import { getCountryCode } from '~/dashboard/utils';
|
import { getCountryCode } from '~/dashboard/utils';
|
||||||
import { useProductTaskExperiment } from './use-product-layout-experiment';
|
import { useProductTaskExperiment } from './use-product-layout-experiment';
|
||||||
|
@ -54,6 +55,10 @@ const ViewControlButton: React.FC< {
|
||||||
|
|
||||||
export const Products = () => {
|
export const Products = () => {
|
||||||
const [ isExpanded, setIsExpanded ] = useState< boolean >( false );
|
const [ isExpanded, setIsExpanded ] = useState< boolean >( false );
|
||||||
|
const [
|
||||||
|
isConfirmingLoadSampleProducts,
|
||||||
|
setIsConfirmingLoadSampleProducts,
|
||||||
|
] = useState( false );
|
||||||
const {
|
const {
|
||||||
isLoading: isLoadingExperiment,
|
isLoading: isLoadingExperiment,
|
||||||
experimentLayout,
|
experimentLayout,
|
||||||
|
@ -125,7 +130,7 @@ export const Products = () => {
|
||||||
if ( experimentLayout === 'card' ) {
|
if ( experimentLayout === 'card' ) {
|
||||||
surfacedProductTypes.push( {
|
surfacedProductTypes.push( {
|
||||||
...LoadSampleProductType,
|
...LoadSampleProductType,
|
||||||
onClick: loadSampleProduct,
|
onClick: () => setIsConfirmingLoadSampleProducts( true ),
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +140,6 @@ export const Products = () => {
|
||||||
isExpanded,
|
isExpanded,
|
||||||
productTypesWithTimeRecord,
|
productTypesWithTimeRecord,
|
||||||
experimentLayout,
|
experimentLayout,
|
||||||
loadSampleProduct,
|
|
||||||
] );
|
] );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -159,7 +163,9 @@ export const Products = () => {
|
||||||
{ experimentLayout === 'stacked' ? (
|
{ experimentLayout === 'stacked' ? (
|
||||||
<Stack
|
<Stack
|
||||||
items={ visibleProductTypes }
|
items={ visibleProductTypes }
|
||||||
onClickLoadSampleProduct={ loadSampleProduct }
|
onClickLoadSampleProduct={ () =>
|
||||||
|
setIsConfirmingLoadSampleProducts( true )
|
||||||
|
}
|
||||||
showOtherOptions={ isExpanded }
|
showOtherOptions={ isExpanded }
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
@ -178,7 +184,21 @@ export const Products = () => {
|
||||||
/>
|
/>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
{ isLoadingSampleProducts && <LoadSampleProductModal /> }
|
{ isLoadingSampleProducts ? (
|
||||||
|
<LoadSampleProductModal />
|
||||||
|
) : (
|
||||||
|
isConfirmingLoadSampleProducts && (
|
||||||
|
<LoadSampleProductConfirmModal
|
||||||
|
onCancel={ () =>
|
||||||
|
setIsConfirmingLoadSampleProducts( false )
|
||||||
|
}
|
||||||
|
onImport={ () => {
|
||||||
|
setIsConfirmingLoadSampleProducts( false );
|
||||||
|
loadSampleProduct();
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
) }
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -45,6 +45,9 @@ global.fetch = jest.fn().mockImplementation( () =>
|
||||||
|
|
||||||
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
|
||||||
|
|
||||||
|
const confirmModalText =
|
||||||
|
"We'll import images from woocommerce.com to set up your sample products.";
|
||||||
|
|
||||||
describe( 'Products', () => {
|
describe( 'Products', () => {
|
||||||
beforeEach( () => {
|
beforeEach( () => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
@ -238,31 +241,57 @@ describe( 'Products', () => {
|
||||||
expect( queryByText( 'View less product types' ) ).toBeInTheDocument();
|
expect( queryByText( 'View less product types' ) ).toBeInTheDocument();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should send a request to load sample products when the link is clicked', async () => {
|
it( 'should send a request to load sample products when the "Import sample products" button is clicked', async () => {
|
||||||
const fetchMock = jest.spyOn( global, 'fetch' );
|
const fetchMock = jest.spyOn( global, 'fetch' );
|
||||||
const { queryByText, getByRole } = render( <Products /> );
|
const { queryByText, getByRole } = render( <Products /> );
|
||||||
|
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
getByRole( 'button', { name: 'View more product types' } )
|
getByRole( 'button', { name: 'View more product types' } )
|
||||||
);
|
);
|
||||||
|
|
||||||
expect( queryByText( 'Load Sample Products' ) ).toBeInTheDocument();
|
expect( queryByText( 'Load Sample Products' ) ).toBeInTheDocument();
|
||||||
|
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
getByRole( 'link', { name: 'Load Sample Products' } )
|
getByRole( 'link', { name: 'Load Sample Products' } )
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor( () =>
|
await waitFor( () =>
|
||||||
expect( fetchMock ).toHaveBeenCalledWith(
|
expect( queryByText( confirmModalText ) ).toBeInTheDocument()
|
||||||
'/wc-admin/onboarding/tasks/import_sample_products?_locale=user',
|
|
||||||
{
|
|
||||||
body: undefined,
|
|
||||||
credentials: 'include',
|
|
||||||
headers: { Accept: 'application/json, */*;q=0.1' },
|
|
||||||
method: 'POST',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'button', { name: 'Import sample products' } )
|
||||||
|
);
|
||||||
|
await waitFor( () =>
|
||||||
|
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( fetchMock ).toHaveBeenCalledWith(
|
||||||
|
'/wc-admin/onboarding/tasks/import_sample_products?_locale=user',
|
||||||
|
{
|
||||||
|
body: undefined,
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { Accept: 'application/json, */*;q=0.1' },
|
||||||
|
method: 'POST',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should close the confirmation modal when the cancel button is clicked', async () => {
|
||||||
|
const { queryByText, getByRole } = render( <Products /> );
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'button', { name: 'View more product types' } )
|
||||||
|
);
|
||||||
|
expect( queryByText( 'Load Sample Products' ) ).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(
|
||||||
|
getByRole( 'link', { name: 'Load Sample Products' } )
|
||||||
|
);
|
||||||
|
await waitFor( () =>
|
||||||
|
expect( queryByText( confirmModalText ) ).toBeInTheDocument()
|
||||||
|
);
|
||||||
|
|
||||||
|
userEvent.click( getByRole( 'button', { name: 'Cancel' } ) );
|
||||||
|
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should show spinner when layout experiment is loading', async () => {
|
it( 'should show spinner when layout experiment is loading', async () => {
|
||||||
|
|
Loading…
Reference in New Issue