Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Convert product tag control to functional component (#10529)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikejolley authored Aug 15, 2023
1 parent 8ca9369 commit 911056a
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 219 deletions.
12 changes: 8 additions & 4 deletions assets/js/blocks/product-tag/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ const ProductsByTagBlock = ( {
) }
initialOpen={ ! attributes.tags.length && ! isEditing }
>
{ /* @ts-expect-error ProductTagControl is yet to be converted to tsx*/ }
<ProductTagControl
selected={ attributes.tags }
onChange={ ( value = [] ) => {
Expand Down Expand Up @@ -203,16 +202,21 @@ const ProductsByTagBlock = ( {
'woo-gutenberg-products-block'
) }
<div className="wc-block-product-tag__selection">
{ /* @ts-expect-error ProductTagControl is yet to be converted to tsx*/ }
<ProductTagControl
selected={ currentAttributes.tags }
onChange={ ( value = [] ) => {
const ids = value.map( ( { id } ) => id );
setChangedAttributes( { tags: ids } );
setChangedAttributes( {
...changedAttributes,
tags: ids,
} );
} }
operator={ currentAttributes.tagOperator }
onOperatorChange={ ( value = 'any' ) =>
setChangedAttributes( { tagOperator: value } )
setChangedAttributes( {
...changedAttributes,
tagOperator: value,
} )
}
/>
<Button isPrimary onClick={ onDone }>
Expand Down
2 changes: 1 addition & 1 deletion assets/js/blocks/product-tag/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface ProductsByTagBlockProps {
attributes: {
tags: number[];
tags: ( number | string )[];
tagOperator: string;
columns: number;
rows: number;
Expand Down
213 changes: 0 additions & 213 deletions assets/js/editor-components/product-tag-control/index.js

This file was deleted.

142 changes: 142 additions & 0 deletions assets/js/editor-components/product-tag-control/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { useState, useEffect, useCallback, useMemo } from '@wordpress/element';
import { SearchListControl } from '@woocommerce/editor-components/search-list-control';
import { SelectControl } from '@wordpress/components';
import { getSetting } from '@woocommerce/settings';
import { useDebouncedCallback } from 'use-debounce';

/**
* Internal dependencies
*/
import type { SearchListItem as SearchListItemProps } from '../search-list-control/types';
import ProductTagItem from './product-tag-item';
import type { ProductTagControlProps } from './types';
import { getProductTags } from '../utils';
import './style.scss';

/**
* Component to handle searching and selecting product tags.
*/
const ProductTagControl = ( {
isCompact = false,
onChange,
onOperatorChange,
operator = 'any',
selected,
}: ProductTagControlProps ): JSX.Element => {
const [ list, setList ] = useState< SearchListItemProps[] >( [] );
const [ loading, setLoading ] = useState( true );
const [ isMounted, setIsMounted ] = useState( false );
const limitTags = getSetting( 'limitTags', false );

const selectedTags = useMemo< SearchListItemProps[] >( () => {
return list.filter( ( item ) => selected.includes( item.id ) );
}, [ list, selected ] );

const onSearch = useCallback(
( search: string ) => {
setLoading( true );
getProductTags( { selected, search } )
.then( ( newList ) => {
setList( newList );
setLoading( false );
} )
.catch( () => {
setLoading( false );
} );
},
[ selected ]
);

// Load on mount.
useEffect( () => {
if ( isMounted ) {
return;
}
onSearch( '' );
setIsMounted( true );
}, [ onSearch, isMounted ] );

const debouncedOnSearch = useDebouncedCallback( onSearch, 400 );

const messages = {
clear: __( 'Clear all product tags', 'woo-gutenberg-products-block' ),
list: __( 'Product Tags', 'woo-gutenberg-products-block' ),
noItems: __(
'You have not set up any product tags on your store.',
'woo-gutenberg-products-block'
),
search: __( 'Search for product tags', 'woo-gutenberg-products-block' ),
selected: ( n: number ) =>
sprintf(
/* translators: %d is the count of selected tags. */
_n(
'%d tag selected',
'%d tags selected',
n,
'woo-gutenberg-products-block'
),
n
),
updated: __(
'Tag search results updated.',
'woo-gutenberg-products-block'
),
};

return (
<>
<SearchListControl
className="woocommerce-product-tags"
list={ list }
isLoading={ loading }
selected={ selectedTags }
onChange={ onChange }
onSearch={ limitTags ? debouncedOnSearch : undefined }
renderItem={ ProductTagItem }
messages={ messages }
isCompact={ isCompact }
isHierarchical
isSingle={ false }
/>
{ !! onOperatorChange && (
<div hidden={ selected.length < 2 }>
<SelectControl
className="woocommerce-product-tags__operator"
label={ __(
'Display products matching',
'woo-gutenberg-products-block'
) }
help={ __(
'Pick at least two tags to use this setting.',
'woo-gutenberg-products-block'
) }
value={ operator }
onChange={ onOperatorChange }
options={ [
{
label: __(
'Any selected tags',
'woo-gutenberg-products-block'
),
value: 'any',
},
{
label: __(
'All selected tags',
'woo-gutenberg-products-block'
),
value: 'all',
},
] }
/>
</div>
) }
</>
);
};

export default ProductTagControl;
Loading

0 comments on commit 911056a

Please sign in to comment.