Fix incorrect product data displayed in Product Collection in context of Single Product block (#44123)
* Initial approach to fix incorrect product data displayed in Product Collection in context of Single Product block * Remove the BlockCOntextProvider * Add Block context for title and summary * Add changelog * Improve typing * Add E2E test with Product Collection inside Single Product block * Improve insertBLock function description * Make productPrices selector in Product Collectionmore specific * Extract components props into a types
This commit is contained in:
parent
402b9bf096
commit
84f2de633d
|
@ -15,10 +15,12 @@ import {
|
|||
} from '@wordpress/block-editor';
|
||||
import { Spinner } from '@wordpress/components';
|
||||
import { store as coreStore } from '@wordpress/core-data';
|
||||
import type { BlockEditProps } from '@wordpress/blocks';
|
||||
import { ProductCollectionAttributes } from '@woocommerce/blocks/product-collection/types';
|
||||
import { getSettingWithCoercion } from '@woocommerce/settings';
|
||||
import { isNumber } from '@woocommerce/types';
|
||||
import { isNumber, ProductResponseItem } from '@woocommerce/types';
|
||||
import { ProductDataContextProvider } from '@woocommerce/shared-context';
|
||||
import { withProduct } from '@woocommerce/block-hocs';
|
||||
import type { BlockEditProps, BlockInstance } from '@wordpress/blocks';
|
||||
|
||||
const ProductTemplateInnerBlocks = () => {
|
||||
const innerBlocksProps = useInnerBlocksProps(
|
||||
|
@ -28,17 +30,19 @@ const ProductTemplateInnerBlocks = () => {
|
|||
return <li { ...innerBlocksProps } />;
|
||||
};
|
||||
|
||||
type ProductTemplateBlockPreviewProps = {
|
||||
blocks: object[];
|
||||
blockContextId: string;
|
||||
isHidden: boolean;
|
||||
setActiveBlockContextId: ( blockContextId: string ) => void;
|
||||
};
|
||||
|
||||
const ProductTemplateBlockPreview = ( {
|
||||
blocks,
|
||||
blockContextId,
|
||||
isHidden,
|
||||
setActiveBlockContextId,
|
||||
}: {
|
||||
blocks: object[];
|
||||
blockContextId: string;
|
||||
isHidden: boolean;
|
||||
setActiveBlockContextId: ( blockContextId: string ) => void;
|
||||
} ) => {
|
||||
}: ProductTemplateBlockPreviewProps ) => {
|
||||
const blockPreviewProps = useBlockPreview( {
|
||||
blocks,
|
||||
props: {
|
||||
|
@ -69,6 +73,50 @@ const ProductTemplateBlockPreview = ( {
|
|||
|
||||
const MemoizedProductTemplateBlockPreview = memo( ProductTemplateBlockPreview );
|
||||
|
||||
type ProductContentProps = {
|
||||
attributes: { productId: string };
|
||||
isLoading: boolean;
|
||||
product: ProductResponseItem;
|
||||
displayTemplate: boolean;
|
||||
blocks: BlockInstance[];
|
||||
blockContext: {
|
||||
postType: string;
|
||||
postId: string;
|
||||
};
|
||||
setActiveBlockContextId: ( id: string ) => void;
|
||||
};
|
||||
|
||||
const ProductContent = withProduct(
|
||||
( {
|
||||
isLoading,
|
||||
product,
|
||||
displayTemplate,
|
||||
blocks,
|
||||
blockContext,
|
||||
setActiveBlockContextId,
|
||||
}: ProductContentProps ) => {
|
||||
return (
|
||||
<BlockContextProvider
|
||||
key={ blockContext.postId }
|
||||
value={ blockContext }
|
||||
>
|
||||
<ProductDataContextProvider
|
||||
product={ product }
|
||||
isLoading={ isLoading }
|
||||
>
|
||||
{ displayTemplate ? <ProductTemplateInnerBlocks /> : null }
|
||||
<MemoizedProductTemplateBlockPreview
|
||||
blocks={ blocks }
|
||||
blockContextId={ blockContext.postId }
|
||||
setActiveBlockContextId={ setActiveBlockContextId }
|
||||
isHidden={ displayTemplate }
|
||||
/>
|
||||
</ProductDataContextProvider>
|
||||
</BlockContextProvider>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const ProductTemplateEdit = ( {
|
||||
clientId,
|
||||
context: {
|
||||
|
@ -100,7 +148,8 @@ const ProductTemplateEdit = ( {
|
|||
__unstableLayoutClassNames: string;
|
||||
} ) => {
|
||||
const [ { page } ] = queryContext;
|
||||
const [ activeBlockContextId, setActiveBlockContextId ] = useState();
|
||||
const [ activeBlockContextId, setActiveBlockContextId ] =
|
||||
useState< string >();
|
||||
const postType = 'product';
|
||||
const loopShopPerPage = getSettingWithCoercion(
|
||||
'loopShopPerPage',
|
||||
|
@ -241,28 +290,26 @@ const ProductTemplateEdit = ( {
|
|||
return (
|
||||
<ul { ...blockProps }>
|
||||
{ blockContexts &&
|
||||
blockContexts.map( ( blockContext ) => (
|
||||
<BlockContextProvider
|
||||
key={ blockContext.postId }
|
||||
value={ blockContext }
|
||||
>
|
||||
{ blockContext.postId ===
|
||||
( activeBlockContextId ||
|
||||
blockContexts[ 0 ]?.postId ) ? (
|
||||
<ProductTemplateInnerBlocks />
|
||||
) : null }
|
||||
<MemoizedProductTemplateBlockPreview
|
||||
blockContexts.map( ( blockContext ) => {
|
||||
const displayTemplate =
|
||||
blockContext.postId ===
|
||||
( activeBlockContextId || blockContexts[ 0 ]?.postId );
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore isLoading and product props are missing as they're coming from untyped withProduct HOC.
|
||||
<ProductContent
|
||||
key={ blockContext.postId }
|
||||
attributes={ {
|
||||
productId: blockContext.postId,
|
||||
} }
|
||||
blocks={ blocks }
|
||||
blockContextId={ blockContext.postId }
|
||||
displayTemplate={ displayTemplate }
|
||||
blockContext={ blockContext }
|
||||
setActiveBlockContextId={ setActiveBlockContextId }
|
||||
isHidden={
|
||||
blockContext.postId ===
|
||||
( activeBlockContextId ||
|
||||
blockContexts[ 0 ]?.postId )
|
||||
}
|
||||
/>
|
||||
</BlockContextProvider>
|
||||
) ) }
|
||||
);
|
||||
} ) }
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -674,4 +674,71 @@ test.describe( 'Product Collection', () => {
|
|||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
test.describe( 'With other blocks', () => {
|
||||
test( 'In Single Product block', async ( {
|
||||
admin,
|
||||
editor,
|
||||
page,
|
||||
editorUtils,
|
||||
pageObject,
|
||||
} ) => {
|
||||
await admin.createNewPost();
|
||||
await editorUtils.closeWelcomeGuideModal();
|
||||
|
||||
// Prepare Single Product block
|
||||
await editor.insertBlock( { name: 'woocommerce/single-product' } );
|
||||
await page.waitForResponse(
|
||||
( response ) =>
|
||||
response.url().includes( 'wc/store/v1/products' ) &&
|
||||
response.status() === 200
|
||||
);
|
||||
const singleProductBlock = await editorUtils.getBlockByName(
|
||||
'woocommerce/single-product'
|
||||
);
|
||||
await singleProductBlock
|
||||
.locator( 'input[type="radio"]' )
|
||||
.nth( 0 )
|
||||
.click();
|
||||
await singleProductBlock.getByText( 'Done' ).click();
|
||||
|
||||
await page.getByLabel( 'Block: Product Title' ).press( 'Enter' );
|
||||
await page
|
||||
.getByLabel(
|
||||
'Empty block; start writing or type forward slash to choose a block'
|
||||
)
|
||||
.pressSequentially( '/Product Collection (Beta)' );
|
||||
await page
|
||||
.getByRole( 'option', {
|
||||
name: 'Product Collection (Beta)',
|
||||
exact: true,
|
||||
} )
|
||||
.first()
|
||||
.click();
|
||||
await pageObject.chooseCollectionInPost( 'featured' );
|
||||
|
||||
const featuredProducts = [
|
||||
'Cap',
|
||||
'Hoodie with Zipper',
|
||||
'Sunglasses',
|
||||
'V-Neck T-Shirt',
|
||||
];
|
||||
const featuredProductsPrices = [
|
||||
'Previous price:$18.00Discounted price:$16.00',
|
||||
'$45.00',
|
||||
'$90.00',
|
||||
'Price between $15.00 and $20.00$15.00 — $20.00',
|
||||
];
|
||||
|
||||
await expect( pageObject.products ).toHaveCount( 4 );
|
||||
// This verifies if Core's block context is provided
|
||||
await expect( pageObject.productTitles ).toHaveText(
|
||||
featuredProducts
|
||||
);
|
||||
// This verifies if Blocks's product context is provided
|
||||
await expect( pageObject.productPrices ).toHaveText(
|
||||
featuredProductsPrices
|
||||
);
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -526,7 +526,7 @@ class ProductCollectionPage {
|
|||
this.productTitles = this.productTemplate
|
||||
.locator( SELECTORS.productTitle )
|
||||
.locator( 'visible=true' );
|
||||
this.productPrices = this.page
|
||||
this.productPrices = this.productTemplate
|
||||
.locator( SELECTORS.productPrice.inEditor )
|
||||
.locator( 'visible=true' );
|
||||
this.addToCartButtons = this.page
|
||||
|
|
|
@ -47,7 +47,7 @@ export class EditorUtils {
|
|||
|
||||
// todo: Make a PR to @wordpress/e2e-test-utils-playwright to add this method.
|
||||
/**
|
||||
* Inserts a block after a given client ID.
|
||||
* Inserts a block inside a given client ID.
|
||||
*
|
||||
*/
|
||||
async insertBlock(
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Product Collection: fix incorrect product data being displayed when Product Collection is placed in Single Product block
|
Loading…
Reference in New Issue