[Product Block Editor]: implement `Choose products for me` button (#43520)

* implement `Choose products for me` button

* clean

* selectSearchedProductDispatcher accepts products array

* rename component with LinkedProductListBlockEdit

* pull and set linked products from choose button

* changelog

* rollback minor changes

* fix typo in fn

* pull the related product from core entities

* minor
This commit is contained in:
Damián Suárez 2024-01-11 17:33:07 -03:00 committed by GitHub
parent 9ce508f47d
commit 47e1f50ae2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 96 additions and 6 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: add
[Product Block Editor]: implement `Choose products for me` button

View File

@ -9,6 +9,13 @@ import {
} from '@wordpress/element';
import { useWooBlockProps } from '@woocommerce/block-templates';
import { Product } from '@woocommerce/data';
import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { reusableBlock } from '@wordpress/icons';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet.
// eslint-disable-next-line @woocommerce/dependency-group
import { useEntityId } from '@wordpress/core-data';
/**
* Internal dependencies
@ -31,6 +38,7 @@ import {
LinkedProductListBlockAttributes,
LinkedProductListBlockEmptyState,
} from './types';
import getRelatedProducts from '../../../utils/get-related-products';
export function EmptyStateImage( {
image,
@ -56,7 +64,7 @@ export function EmptyStateImage( {
}
}
export function Edit( {
export function LinkedProductListBlockEdit( {
attributes,
context: { postType },
}: ProductEditorBlockEditProps< LinkedProductListBlockAttributes > ) {
@ -66,6 +74,9 @@ export function Edit( {
linkedProducts: [],
searchedProducts: [],
} );
const productId = useEntityId( 'postType', postType );
const loadLinkedProductsDispatcher =
getLoadLinkedProductsDispatcher( dispatch );
const searchProductsDispatcher = getSearchProductsDispatcher( dispatch );
@ -100,6 +111,7 @@ export function Edit( {
product,
state.linkedProducts
);
setLinkedProductIds( newLinkedProductIds );
}
@ -112,8 +124,49 @@ export function Edit( {
setLinkedProductIds( newLinkedProductIds );
}
async function chooseProductsForMe() {
dispatch( {
type: 'LOADING_LINKED_PRODUCTS',
payload: {
isLoading: true,
},
} );
const relatedProducts = ( await getRelatedProducts(
productId
) ) as Product[];
dispatch( {
type: 'LOADING_LINKED_PRODUCTS',
payload: {
isLoading: false,
},
} );
if ( ! relatedProducts ) {
return;
}
const newLinkedProducts = selectSearchedProductDispatcher(
relatedProducts,
[]
);
setLinkedProductIds( newLinkedProducts );
}
return (
<div { ...blockProps }>
<div className="wp-block-woocommerce-product-linked-list-field__form-group-header">
<Button
variant="tertiary"
icon={ reusableBlock }
onClick={ chooseProductsForMe }
>
{ __( 'Choose products for me', 'woocommerce' ) }
</Button>
</div>
<div className="wp-block-woocommerce-product-linked-list-field__form-group-content">
<ProductSelect
items={ state.searchedProducts }

View File

@ -3,6 +3,12 @@
flex-direction: column;
gap: $grid-unit-30;
&__form-group-header {
display: flex;
flex-direction: row;
justify-content: right;
}
.woocommerce-advice-card {
min-height: 233px; // min height to cover the min rows rendered in the table on its back

View File

@ -2,7 +2,7 @@
* Internal dependencies
*/
import blockConfiguration from './block.json';
import { Edit } from './edit';
import { LinkedProductListBlockEdit } from './edit';
import { registerProductEditorBlockType } from '../../../utils';
const { name, ...metadata } = blockConfiguration;
@ -11,7 +11,7 @@ export { metadata, name };
export const settings = {
example: {},
edit: Edit,
edit: LinkedProductListBlockEdit,
};
export function init() {

View File

@ -8,7 +8,7 @@ export type State = {
linkedProducts: Product[];
searchedProducts: Product[];
isLoading?: boolean;
selectedProduct?: Product;
selectedProduct?: Product | Product[];
};
export type ActionType =
@ -120,10 +120,14 @@ export function getSelectSearchedProductDispatcher(
dispatch: ( value: Action ) => void
) {
return function selectSearchedProductDispatcher(
selectedProduct: Product,
selectedProduct: Product | Product[],
linkedProducts: Product[]
) {
const newLinkedProducts = [ ...linkedProducts, selectedProduct ];
if ( ! Array.isArray( selectedProduct ) ) {
selectedProduct = [ selectedProduct ];
}
const newLinkedProducts = [ ...linkedProducts, ...selectedProduct ];
dispatch( {
type: 'SELECT_SEARCHED_PRODUCT',

View File

@ -0,0 +1,23 @@
/**
* External dependencies
*/
import { select, resolveSelect } from '@wordpress/data';
import type { Product } from '@woocommerce/data';
export default async function getRelatedProducts( productId: number ) {
const { getEntityRecord } = select( 'core' );
const product = getEntityRecord( 'postType', 'product', productId );
if ( ! product ) {
return;
}
const relatedProductIds = product?.related_ids;
if ( ! relatedProductIds ) {
return;
}
const { getEntityRecords } = resolveSelect( 'core' );
return ( await getEntityRecords( 'postType', 'product', {
include: relatedProductIds,
} ) ) as Product[];
}