Product Collection - refactor inspector controls props (https://github.com/woocommerce/woocommerce-blocks/pull/10154)

* Refactor Columns Control inspector controls in Product Collection

* Refactor Order By inspector controls in Product Collection

* Reorder imports in Product Collection Inspector Controls

* Refactor On Sale inspector controls in Product Collection

* Refactor Stock Status inspector controls in Product Collection

* Refactor Keyword inspector controls in Product Collection

* Unify interface of query controlling Inspector Controls

* Unify interfaces of Inspector Controls that modify Query in Product Collection

* Unify other Query modifying Controls

* Simplify types
This commit is contained in:
Karol Manijak 2023-07-11 13:05:49 +02:00 committed by GitHub
parent d4c3d43f9d
commit c55343b736
12 changed files with 99 additions and 140 deletions

View File

@ -61,17 +61,23 @@ export const DEFAULT_ATTRIBUTES: Partial< ProductCollectionAttributes > = {
}, },
}; };
export const getDefaultQuery = (
currentQuery: ProductCollectionQuery
): ProductCollectionQuery => ( {
...currentQuery,
orderBy: DEFAULT_QUERY.orderBy as TProductCollectionOrderBy,
order: DEFAULT_QUERY.order as TProductCollectionOrder,
inherit: DEFAULT_QUERY.inherit,
} );
export const getDefaultDisplayLayout = () =>
DEFAULT_ATTRIBUTES.displayLayout as ProductCollectionDisplayLayout;
export const getDefaultSettings = ( export const getDefaultSettings = (
currentAttributes: ProductCollectionAttributes currentAttributes: ProductCollectionAttributes
): Partial< ProductCollectionAttributes > => ( { ): Partial< ProductCollectionAttributes > => ( {
displayLayout: displayLayout: getDefaultDisplayLayout(),
DEFAULT_ATTRIBUTES.displayLayout as ProductCollectionDisplayLayout, query: getDefaultQuery( currentAttributes.query ),
query: {
...currentAttributes.query,
orderBy: DEFAULT_QUERY.orderBy as TProductCollectionOrderBy,
order: DEFAULT_QUERY.order as TProductCollectionOrder,
inherit: DEFAULT_QUERY.inherit,
},
} ); } );
export const DEFAULT_FILTERS: Partial< ProductCollectionQuery > = { export const DEFAULT_FILTERS: Partial< ProductCollectionQuery > = {

View File

@ -3,7 +3,6 @@
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import ProductAttributeTermControl from '@woocommerce/editor-components/product-attribute-term-control'; import ProductAttributeTermControl from '@woocommerce/editor-components/product-attribute-term-control';
import { AttributeMetadata } from '@woocommerce/types';
import { SearchListItem } from '@woocommerce/editor-components/search-list-control/types'; import { SearchListItem } from '@woocommerce/editor-components/search-list-control/types';
import { ADMIN_URL } from '@woocommerce/settings'; import { ADMIN_URL } from '@woocommerce/settings';
import { import {
@ -16,19 +15,15 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionQuery } from '../types'; import { QueryControlProps } from '../types';
const EDIT_ATTRIBUTES_URL = `${ ADMIN_URL }edit.php?post_type=product&page=product_attributes`; const EDIT_ATTRIBUTES_URL = `${ ADMIN_URL }edit.php?post_type=product&page=product_attributes`;
interface AttributesControlProps {
woocommerceAttributes?: AttributeMetadata[];
setQueryAttribute: ( value: Partial< ProductCollectionQuery > ) => void;
}
const AttributesControl = ( { const AttributesControl = ( {
woocommerceAttributes, query,
setQueryAttribute, setQueryAttribute,
}: AttributesControlProps ) => { }: QueryControlProps ) => {
const woocommerceAttributes = query.woocommerceAttributes || [];
const selectedAttributes = woocommerceAttributes?.map( const selectedAttributes = woocommerceAttributes?.map(
( { termId: id } ) => ( { ( { termId: id } ) => ( {
id, id,

View File

@ -13,7 +13,7 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionQuery } from '../types'; import { QueryControlProps } from '../types';
interface Author { interface Author {
id: string; id: string;
@ -27,11 +27,6 @@ interface AuthorsInfo {
names: string[]; names: string[];
} }
interface AuthorControlProps {
value: string;
setQueryAttribute: ( value: Partial< ProductCollectionQuery > ) => void;
}
const AUTHORS_QUERY = { const AUTHORS_QUERY = {
who: 'authors', who: 'authors',
per_page: -1, per_page: -1,
@ -68,7 +63,8 @@ const getIdByValue = (
if ( id ) return id; if ( id ) return id;
}; };
function AuthorControl( { value, setQueryAttribute }: AuthorControlProps ) { function AuthorControl( { query, setQueryAttribute }: QueryControlProps ) {
const value = query.author;
const { records: authorsList, error } = useEntityRecords< Author[] >( const { records: authorsList, error } = useEntityRecords< Author[] >(
'root', 'root',
'user', 'user',

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import { import {
RangeControl, RangeControl,
// @ts-expect-error Using experimental features // @ts-expect-error Using experimental features
@ -13,32 +12,26 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { import { DisplayLayoutControlProps } from '../types';
ProductCollectionAttributes, import { getDefaultDisplayLayout } from '../constants';
ProductCollectionDisplayLayout,
} from '../types';
import { getDefaultSettings } from '../constants';
const ColumnsControl = ( const ColumnsControl = ( props: DisplayLayoutControlProps ) => {
props: BlockEditProps< ProductCollectionAttributes > const { type, columns } = props.displayLayout;
) => {
const { type, columns } = props.attributes.displayLayout;
const showColumnsControl = type === 'flex'; const showColumnsControl = type === 'flex';
const defaultSettings = getDefaultSettings( props.attributes ); const defaultLayout = getDefaultDisplayLayout();
return showColumnsControl ? ( return showColumnsControl ? (
<ToolsPanelItem <ToolsPanelItem
label={ __( 'Columns', 'woo-gutenberg-products-block' ) } label={ __( 'Columns', 'woo-gutenberg-products-block' ) }
hasValue={ () => hasValue={ () =>
defaultSettings.displayLayout?.columns !== columns || defaultLayout?.columns !== columns ||
defaultSettings.displayLayout?.type !== type defaultLayout?.type !== type
} }
isShownByDefault isShownByDefault
onDeselect={ () => { onDeselect={ () => {
props.setAttributes( { props.setAttributes( {
displayLayout: displayLayout: defaultLayout,
defaultSettings.displayLayout as ProductCollectionDisplayLayout,
} ); } );
} } } }
> >
@ -48,7 +41,7 @@ const ColumnsControl = (
onChange={ ( value: number ) => onChange={ ( value: number ) =>
props.setAttributes( { props.setAttributes( {
displayLayout: { displayLayout: {
...props.attributes.displayLayout, ...props.displayLayout,
columns: value, columns: value,
}, },
} ) } )

View File

@ -8,15 +8,10 @@ import { list, grid } from '@wordpress/icons';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionDisplayLayout } from '../types'; import {
DisplayLayoutControlProps,
type DisplayLayoutObject = { ProductCollectionDisplayLayout,
displayLayout: ProductCollectionDisplayLayout; } from '../types';
};
type DisplayLayoutControlProps = DisplayLayoutObject & {
setAttributes: ( attrs: DisplayLayoutObject ) => void;
};
const DisplayLayoutControl = ( props: DisplayLayoutControlProps ) => { const DisplayLayoutControl = ( props: DisplayLayoutControlProps ) => {
const { type, columns } = props.displayLayout; const { type, columns } = props.displayLayout;

View File

@ -15,12 +15,7 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionQuery } from '../types'; import { QueryControlProps } from '../types';
interface HandPickedProductsControlProps {
setQueryAttribute: ( value: Partial< ProductCollectionQuery > ) => void;
selectedProductIds?: string[] | undefined;
}
/** /**
* Returns: * Returns:
@ -55,9 +50,10 @@ function useProducts() {
} }
const HandPickedProductsControl = ( { const HandPickedProductsControl = ( {
selectedProductIds, query,
setQueryAttribute, setQueryAttribute,
}: HandPickedProductsControlProps ) => { }: QueryControlProps ) => {
const selectedProductIds = query.woocommerceHandPickedProducts;
const { productsMap, productsList } = useProducts(); const { productsMap, productsList } = useProducts();
const onTokenChange = useCallback( const onTokenChange = useCallback(

View File

@ -16,12 +16,12 @@ import {
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionAttributes } from '../types'; import { ProductCollectionAttributes } from '../types';
import { setQueryAttribute } from '../utils';
import { DEFAULT_FILTERS, getDefaultSettings } from '../constants';
import ColumnsControl from './columns-control'; import ColumnsControl from './columns-control';
import InheritQueryControl from './inherit-query-control'; import InheritQueryControl from './inherit-query-control';
import OrderByControl from './order-by-control'; import OrderByControl from './order-by-control';
import OnSaleControl from './on-sale-control'; import OnSaleControl from './on-sale-control';
import { setQueryAttribute } from '../utils';
import { DEFAULT_FILTERS, getDefaultSettings } from '../constants';
import StockStatusControl from './stock-status-control'; import StockStatusControl from './stock-status-control';
import KeywordControl from './keyword-control'; import KeywordControl from './keyword-control';
import AttributesControl from './attributes-control'; import AttributesControl from './attributes-control';
@ -42,13 +42,20 @@ const ProductCollectionInspectorControls = (
[ props ] [ props ]
); );
const displayControlProps = {
setAttributes: props.setAttributes,
displayLayout: props.attributes.displayLayout,
};
const queryControlProps = {
setQueryAttribute: setQueryAttributeBind,
query,
};
return ( return (
<InspectorControls> <InspectorControls>
<BlockControls> <BlockControls>
<DisplayLayoutControl <DisplayLayoutControl { ...displayControlProps } />
displayLayout={ props.attributes.displayLayout }
setAttributes={ props.setAttributes }
/>
</BlockControls> </BlockControls>
<ToolsPanel <ToolsPanel
label={ __( 'Settings', 'woo-gutenberg-products-block' ) } label={ __( 'Settings', 'woo-gutenberg-products-block' ) }
@ -59,13 +66,10 @@ const ProductCollectionInspectorControls = (
props.setAttributes( defaultSettings ); props.setAttributes( defaultSettings );
} } } }
> >
<ColumnsControl { ...props } /> <ColumnsControl { ...displayControlProps } />
<InheritQueryControl <InheritQueryControl { ...queryControlProps } />
setQueryAttribute={ setQueryAttributeBind }
query={ query }
/>
{ displayQueryControls ? ( { displayQueryControls ? (
<OrderByControl { ...props } /> <OrderByControl { ...queryControlProps } />
) : null } ) : null }
</ToolsPanel> </ToolsPanel>
@ -80,29 +84,13 @@ const ProductCollectionInspectorControls = (
} } } }
className="wc-block-editor-product-collection-inspector-toolspanel__filters" className="wc-block-editor-product-collection-inspector-toolspanel__filters"
> >
<OnSaleControl { ...props } /> <OnSaleControl { ...queryControlProps } />
<StockStatusControl { ...props } /> <StockStatusControl { ...queryControlProps } />
<HandPickedProductsControl <HandPickedProductsControl { ...queryControlProps } />
setQueryAttribute={ setQueryAttributeBind } <KeywordControl { ...queryControlProps } />
selectedProductIds={ <AttributesControl { ...queryControlProps } />
query.woocommerceHandPickedProducts <TaxonomyControls { ...queryControlProps } />
} <AuthorControl { ...queryControlProps } />
/>
<KeywordControl { ...props } />
<AttributesControl
woocommerceAttributes={
query.woocommerceAttributes || []
}
setQueryAttribute={ setQueryAttributeBind }
/>
<TaxonomyControls
setQueryAttribute={ setQueryAttributeBind }
query={ query }
/>
<AuthorControl
value={ query.author }
setQueryAttribute={ setQueryAttributeBind }
/>
</ToolsPanel> </ToolsPanel>
) : null } ) : null }
<ProductCollectionFeedbackPrompt /> <ProductCollectionFeedbackPrompt />

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import { useEffect, useState } from '@wordpress/element'; import { useEffect, useState } from '@wordpress/element';
import { useDebounce } from '@wordpress/compose'; import { useDebounce } from '@wordpress/compose';
import { import {
@ -15,18 +14,17 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionAttributes } from '../types'; import { QueryControlProps } from '../types';
import { setQueryAttribute } from '../utils';
const KeywordControl = ( const KeywordControl = ( props: QueryControlProps ) => {
props: BlockEditProps< ProductCollectionAttributes > const { query, setQueryAttribute } = props;
) => {
const { query } = props.attributes;
const [ querySearch, setQuerySearch ] = useState( query.search ); const [ querySearch, setQuerySearch ] = useState( query.search );
const onChangeDebounced = useDebounce( () => { const onChangeDebounced = useDebounce( () => {
if ( query.search !== querySearch ) { if ( query.search !== querySearch ) {
setQueryAttribute( props, { search: querySearch } ); setQueryAttribute( {
search: querySearch,
} );
} }
}, 250 ); }, 250 );

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import { import {
ToggleControl, ToggleControl,
// @ts-expect-error Using experimental features // @ts-expect-error Using experimental features
@ -13,13 +12,10 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionAttributes } from '../types'; import { QueryControlProps } from '../types';
import { setQueryAttribute } from '../utils';
const OnSaleControl = ( const OnSaleControl = ( props: QueryControlProps ) => {
props: BlockEditProps< ProductCollectionAttributes > const { query, setQueryAttribute } = props;
) => {
const { query } = props.attributes;
return ( return (
<ToolsPanelItem <ToolsPanelItem
@ -27,7 +23,7 @@ const OnSaleControl = (
hasValue={ () => query.woocommerceOnSale === true } hasValue={ () => query.woocommerceOnSale === true }
isShownByDefault isShownByDefault
onDeselect={ () => { onDeselect={ () => {
setQueryAttribute( props, { setQueryAttribute( {
woocommerceOnSale: false, woocommerceOnSale: false,
} ); } );
} } } }
@ -39,7 +35,7 @@ const OnSaleControl = (
) } ) }
checked={ query.woocommerceOnSale || false } checked={ query.woocommerceOnSale || false }
onChange={ ( woocommerceOnSale ) => { onChange={ ( woocommerceOnSale ) => {
setQueryAttribute( props, { setQueryAttribute( {
woocommerceOnSale, woocommerceOnSale,
} ); } );
} } } }

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import { import {
SelectControl, SelectControl,
// @ts-expect-error Using experimental features // @ts-expect-error Using experimental features
@ -14,11 +13,11 @@ import {
* Internal dependencies * Internal dependencies
*/ */
import { import {
ProductCollectionAttributes,
TProductCollectionOrder, TProductCollectionOrder,
TProductCollectionOrderBy, TProductCollectionOrderBy,
QueryControlProps,
} from '../types'; } from '../types';
import { getDefaultSettings } from '../constants'; import { getDefaultQuery } from '../constants';
const orderOptions = [ const orderOptions = [
{ {
@ -47,27 +46,21 @@ const orderOptions = [
}, },
]; ];
const OrderByControl = ( const OrderByControl = ( props: QueryControlProps ) => {
props: BlockEditProps< ProductCollectionAttributes > const { query, setQueryAttribute } = props;
) => { const { order, orderBy } = query;
const { order, orderBy } = props.attributes.query; const defaultQuery = getDefaultQuery( query );
const defaultSettings = getDefaultSettings( props.attributes );
return ( return (
<ToolsPanelItem <ToolsPanelItem
label={ __( 'Order by', 'woo-gutenberg-products-block' ) } label={ __( 'Order by', 'woo-gutenberg-products-block' ) }
hasValue={ () => hasValue={ () =>
order !== defaultSettings.query?.order || order !== defaultQuery?.order ||
orderBy !== defaultSettings.query?.orderBy orderBy !== defaultQuery?.orderBy
} }
isShownByDefault isShownByDefault
onDeselect={ () => { onDeselect={ () => {
props.setAttributes( { setQueryAttribute( defaultQuery );
query: {
...props.attributes.query,
...defaultSettings.query,
},
} );
} } } }
> >
<SelectControl <SelectControl
@ -76,12 +69,9 @@ const OrderByControl = (
label={ __( 'Order by', 'woo-gutenberg-products-block' ) } label={ __( 'Order by', 'woo-gutenberg-products-block' ) }
onChange={ ( value ) => { onChange={ ( value ) => {
const [ newOrderBy, newOrder ] = value.split( '/' ); const [ newOrderBy, newOrder ] = value.split( '/' );
props.setAttributes( { setQueryAttribute( {
query: { order: newOrder as TProductCollectionOrder,
...props.attributes.query, orderBy: newOrderBy as TProductCollectionOrderBy,
order: newOrder as TProductCollectionOrder,
orderBy: newOrderBy as TProductCollectionOrderBy,
},
} ); } );
} } } }
/> />

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import fastDeepEqual from 'fast-deep-equal/es6'; import fastDeepEqual from 'fast-deep-equal/es6';
import { import {
FormTokenField, FormTokenField,
@ -14,8 +13,7 @@ import {
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { ProductCollectionAttributes } from '../types'; import { QueryControlProps } from '../types';
import { setQueryAttribute } from '../utils';
import { STOCK_STATUS_OPTIONS, getDefaultStockStatuses } from '../constants'; import { STOCK_STATUS_OPTIONS, getDefaultStockStatuses } from '../constants';
/** /**
@ -35,10 +33,9 @@ function getStockStatusIdByLabel( statusLabel: FormTokenField.Value ) {
)?.[ 0 ]; )?.[ 0 ];
} }
const StockStatusControl = ( const StockStatusControl = ( props: QueryControlProps ) => {
props: BlockEditProps< ProductCollectionAttributes > const { query, setQueryAttribute } = props;
) => {
const { query } = props.attributes;
return ( return (
<ToolsPanelItem <ToolsPanelItem
label={ __( 'Stock status', 'woo-gutenberg-products-block' ) } label={ __( 'Stock status', 'woo-gutenberg-products-block' ) }
@ -49,7 +46,7 @@ const StockStatusControl = (
) )
} }
onDeselect={ () => { onDeselect={ () => {
setQueryAttribute( props, { setQueryAttribute( {
woocommerceStockStatus: getDefaultStockStatuses(), woocommerceStockStatus: getDefaultStockStatuses(),
} ); } );
} } } }
@ -62,7 +59,7 @@ const StockStatusControl = (
.map( getStockStatusIdByLabel ) .map( getStockStatusIdByLabel )
.filter( Boolean ) as string[]; .filter( Boolean ) as string[];
setQueryAttribute( props, { setQueryAttribute( {
woocommerceStockStatus, woocommerceStockStatus,
} ); } );
} } } }

View File

@ -61,3 +61,12 @@ export type TProductCollectionOrderBy =
| 'title' | 'title'
| 'popularity' | 'popularity'
| 'rating'; | 'rating';
export type DisplayLayoutControlProps = {
displayLayout: ProductCollectionDisplayLayout;
setAttributes: ( attrs: Partial< ProductCollectionAttributes > ) => void;
};
export type QueryControlProps = {
query: ProductCollectionQuery;
setQueryAttribute: ( attrs: Partial< ProductCollectionQuery > ) => void;
};