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

Product Collection: Add 'on sale' filter and enhance settings management in product collection block #9549

Merged
merged 14 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/js/blocks/product-collection/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"inherit": false,
"taxQuery": null,
"parents": [],
"isProductCollectionBlock": true
"isProductCollectionBlock": true,
"woocommerceOnSale": false
}
},
"tagName": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,61 @@
/**
* External dependencies
*/
import { RangeControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import {
RangeControl,
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ProductCollectionAttributes } from '../types';
import {
ProductCollectionAttributes,
ProductCollectionDisplayLayout,
} from '../types';
import { getDefaultSettings } from './constants';

const ColumnsControl = (
props: BlockEditProps< ProductCollectionAttributes >
) => {
const { type, columns } = props.attributes.displayLayout;
const showColumnsControl = type === 'flex';

const defaultSettings = getDefaultSettings( props.attributes );

return showColumnsControl ? (
<RangeControl
<ToolsPanelItem
label={ __( 'Columns', 'woo-gutenberg-products-block' ) }
value={ columns }
onChange={ ( value: number ) =>
props.setAttributes( {
displayLayout: {
...props.attributes.displayLayout,
columns: value,
},
} )
hasValue={ () =>
defaultSettings.displayLayout?.columns !== columns ||
defaultSettings.displayLayout?.type !== type
}
min={ 2 }
max={ Math.max( 6, columns ) }
/>
isShownByDefault
onDeselect={ () => {
props.setAttributes( {
displayLayout:
defaultSettings.displayLayout as ProductCollectionDisplayLayout,
} );
} }
>
<RangeControl
value={ columns }
onChange={ ( value: number ) =>
props.setAttributes( {
displayLayout: {
...props.attributes.displayLayout,
columns: value,
},
} )
}
min={ 2 }
max={ Math.max( 6, columns ) }
/>
</ToolsPanelItem>
) : null;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Internal dependencies
*/
import blockJson from '../block.json';
import {
ProductCollectionAttributes,
TProductCollectionOrder,
TProductCollectionOrderBy,
} from '../types';

const defaultQuery = blockJson.attributes.query.default;

export const DEFAULT_FILTERS = {
woocommerceOnSale: defaultQuery.woocommerceOnSale,
};

export const getDefaultSettings = (
currentAttributes: ProductCollectionAttributes
): Partial< ProductCollectionAttributes > => ( {
displayLayout: blockJson.attributes.displayLayout.default,
query: {
...currentAttributes.query,
orderBy: blockJson.attributes.query.default
.orderBy as TProductCollectionOrderBy,
order: blockJson.attributes.query.default
.order as TProductCollectionOrder,
},
} );
30 changes: 26 additions & 4 deletions assets/js/blocks/product-collection/inspector-controls/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,49 @@
*/
import type { BlockEditProps } from '@wordpress/blocks';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanel as ToolsPanel,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ProductCollectionAttributes } from '../types';
import ColumnsControl from './columns-control';
import OrderByControl from './order-by-control';
import OnSaleControl from './on-sale-control';
import { setQueryAttribute } from './utils';
import { DEFAULT_FILTERS, getDefaultSettings } from './constants';

const ProductCollectionInspectorControls = (
props: BlockEditProps< ProductCollectionAttributes >
) => {
return (
<InspectorControls>
<PanelBody
title={ __( 'Settings', 'woo-gutenberg-products-block' ) }
<ToolsPanel
label={ __( 'Settings', 'woo-gutenberg-products-block' ) }
resetAll={ () => {
const defaultSettings = getDefaultSettings(
props.attributes
);
props.setAttributes( defaultSettings );
} }
>
<ColumnsControl { ...props } />
<OrderByControl { ...props } />
</PanelBody>
</ToolsPanel>

<ToolsPanel
label={ __( 'Filters', 'woo-gutenberg-products-block' ) }
resetAll={ () => {
setQueryAttribute( props, DEFAULT_FILTERS );
} }
>
<OnSaleControl { ...props } />
imanish003 marked this conversation as resolved.
Show resolved Hide resolved
</ToolsPanel>
</InspectorControls>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import {
ToggleControl,
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
*/
import { ProductCollectionAttributes } from '../types';

const OnSaleControl = (
props: BlockEditProps< ProductCollectionAttributes >
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A continuation from my comment above, if we are using just the attributes prop and you think we can only pass it to this component, we should probably get rid of the BlockEditProps and create an interface just with the props that are going to be used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your suggestion, @thealexandrelara. You're right, OnSaleControl component is indeed only using the attributes prop currently. Passing only the required props will make our component more explicit and could prevent unnecessary re-renders. I'll make the necessary adjustments in separate PR because I have created a few more PRs which are based on this branch. Appreciate your keen observation. 🙌🏻

) => {
const { query } = props.attributes;

return (
<ToolsPanelItem
label={ __( 'On Sale', 'woo-gutenberg-products-block' ) }
hasValue={ () => query.woocommerceOnSale }
isShownByDefault
onDeselect={ () => {
props.setAttributes( {
query: {
...query,
woocommerceOnSale: false,
},
} );
} }
>
<ToggleControl
label={ __(
'Show only products on sale',
'woo-gutenberg-products-block'
) }
checked={ query.woocommerceOnSale || false }
onChange={ ( woocommerceOnSale ) => {
props.setAttributes( {
query: {
...query,
woocommerceOnSale,
},
} );
} }
/>
</ToolsPanelItem>
);
};

export default OnSaleControl;
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/**
* External dependencies
*/
import { SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { BlockEditProps } from '@wordpress/blocks';
import {
SelectControl,
// @ts-expect-error Using experimental features
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';

/**
* Internal dependencies
Expand All @@ -13,6 +18,7 @@ import {
TProductCollectionOrder,
TProductCollectionOrderBy,
} from '../types';
import { getDefaultSettings } from './constants';

const orderOptions = [
{
Expand Down Expand Up @@ -45,22 +51,40 @@ const OrderByControl = (
props: BlockEditProps< ProductCollectionAttributes >
) => {
const { order, orderBy } = props.attributes.query;
const defaultSettings = getDefaultSettings( props.attributes );

return (
<SelectControl
<ToolsPanelItem
label={ __( 'Order by', 'woo-gutenberg-products-block' ) }
value={ `${ orderBy }/${ order }` }
options={ orderOptions }
onChange={ ( value ) => {
const [ newOrderBy, newOrder ] = value.split( '/' );
hasValue={ () =>
order !== defaultSettings.query?.order ||
orderBy !== defaultSettings.query?.orderBy
}
isShownByDefault
onDeselect={ () => {
props.setAttributes( {
query: {
...props.attributes.query,
order: newOrder as TProductCollectionOrder,
orderBy: newOrderBy as TProductCollectionOrderBy,
...defaultSettings.query,
},
} );
} }
/>
>
<SelectControl
value={ `${ orderBy }/${ order }` }
options={ orderOptions }
onChange={ ( value ) => {
const [ newOrderBy, newOrder ] = value.split( '/' );
props.setAttributes( {
query: {
...props.attributes.query,
order: newOrder as TProductCollectionOrder,
orderBy: newOrderBy as TProductCollectionOrderBy,
},
} );
} }
/>
</ToolsPanelItem>
);
};

Expand Down
28 changes: 28 additions & 0 deletions assets/js/blocks/product-collection/inspector-controls/utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { BlockEditProps } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { ProductCollectionAttributes, ProductCollectionQuery } from '../types';

/**
* Sets the new query arguments of a Product Query block
*
* Shorthand for setting new nested query parameters.
*/
export function setQueryAttribute(
block: BlockEditProps< ProductCollectionAttributes >,
queryParams: Partial< ProductCollectionQuery >
) {
const { query } = block.attributes;

block.setAttributes( {
query: {
...query,
...queryParams,
},
} );
}
11 changes: 7 additions & 4 deletions assets/js/blocks/product-collection/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ export interface ProductCollectionAttributes {
}
];
templateSlug: string;
displayLayout: {
type: string;
columns: number;
};
displayLayout: ProductCollectionDisplayLayout;
}

export interface ProductCollectionDisplayLayout {
type: string;
columns: number;
}

export interface ProductCollectionQuery {
Expand All @@ -27,6 +29,7 @@ export interface ProductCollectionQuery {
search: string;
sticky: string;
taxQuery: string;
woocommerceOnSale: boolean;
}

export type TProductCollectionOrder = 'asc' | 'desc';
Expand Down
Loading