Update interactivity price filter block to use latest Interactivity Store API (https://github.com/woocommerce/woocommerce-blocks/pull/11943)

This commit is contained in:
Sam Seay 2023-11-29 12:04:35 +08:00 committed by GitHub
parent a652fa18f8
commit 58c6339ac9
3 changed files with 97 additions and 91 deletions

View File

@ -3,14 +3,15 @@
*/
import { store, navigate } from '@woocommerce/interactivity';
import { formatPrice, getCurrency } from '@woocommerce/price-format';
import { HTMLElementEvent } from '@woocommerce/types';
/**
* Internal dependencies
*/
import { ActionProps, StateProps } from './types';
import { PriceFilterState } from './types';
const getHrefWithFilters = ( { state }: StateProps ) => {
const { minPrice, maxPrice } = state.filters;
const getHrefWithFilters = ( state: PriceFilterState ) => {
const { minPrice = 0, maxPrice = 0, maxRange = 0 } = state;
const url = new URL( window.location.href );
const { searchParams } = url;
@ -20,7 +21,7 @@ const getHrefWithFilters = ( { state }: StateProps ) => {
searchParams.delete( 'min_price' );
}
if ( maxPrice < state.filters.maxRange ) {
if ( maxPrice < maxRange ) {
searchParams.set( 'max_price', maxPrice.toString() );
} else {
searchParams.delete( 'max_price' );
@ -33,12 +34,27 @@ const getHrefWithFilters = ( { state }: StateProps ) => {
return url.href;
};
store( {
state: {
filters: {
rangeStyle: ( { state }: StateProps ) => {
const { minPrice, maxPrice, minRange, maxRange } =
state.filters;
interface PriceFilterStore {
state: PriceFilterState;
actions: {
setMinPrice: ( event: HTMLElementEvent< HTMLInputElement > ) => void;
setMaxPrice: ( event: HTMLElementEvent< HTMLInputElement > ) => void;
updateProducts: () => void;
reset: () => void;
};
}
const { state } = store< PriceFilterStore >(
'woocommerce/collection-price-filter',
{
state: {
get rangeStyle(): string {
const {
minPrice = 0,
maxPrice = 0,
minRange = 0,
maxRange = 0,
} = state;
return [
`--low: ${
( 100 * ( minPrice - minRange ) ) /
@ -50,48 +66,48 @@ store( {
}%`,
].join( ';' );
},
formattedMinPrice: ( { state }: StateProps ) => {
const { minPrice } = state.filters;
get formattedMinPrice(): string {
const { minPrice = 0 } = state;
return formatPrice( minPrice, getCurrency( { minorUnit: 0 } ) );
},
formattedMaxPrice: ( { state }: StateProps ) => {
const { maxPrice } = state.filters;
get formattedMaxPrice(): string {
const { maxPrice = 0 } = state;
return formatPrice( maxPrice, getCurrency( { minorUnit: 0 } ) );
},
},
},
actions: {
filters: {
setMinPrice: ( { state, event }: ActionProps ) => {
actions: {
setMinPrice: ( event: HTMLElementEvent< HTMLInputElement > ) => {
const { minRange = 0, maxPrice = 0, maxRange = 0 } = state;
const value = parseFloat( event.target.value );
state.filters.minPrice = Math.min(
Number.isNaN( value ) ? state.filters.minRange : value,
state.filters.maxRange - 1
);
state.filters.maxPrice = Math.max(
state.filters.maxPrice,
state.filters.minPrice + 1
state.minPrice = Math.min(
Number.isNaN( value ) ? minRange : value,
maxRange - 1
);
state.maxPrice = Math.max( maxPrice, state.minPrice + 1 );
},
setMaxPrice: ( { state, event }: ActionProps ) => {
setMaxPrice: ( event: HTMLElementEvent< HTMLInputElement > ) => {
const {
minRange = 0,
minPrice = 0,
maxPrice = 0,
maxRange = 0,
} = state;
const value = parseFloat( event.target.value );
state.filters.maxPrice = Math.max(
Number.isNaN( value ) ? state.filters.maxRange : value,
state.filters.minRange + 1
);
state.filters.minPrice = Math.min(
state.filters.minPrice,
state.filters.maxPrice - 1
state.maxPrice = Math.max(
Number.isNaN( value ) ? maxRange : value,
minRange + 1
);
state.minPrice = Math.min( minPrice, maxPrice - 1 );
},
updateProductsWithPriceFilter: ( { state }: ActionProps ) => {
navigate( getHrefWithFilters( { state } ) );
updateProducts: () => {
navigate( getHrefWithFilters( state ) );
},
reset: ( { state }: ActionProps ) => {
state.filters.minPrice = 0;
state.filters.maxPrice = state.filters.maxRange;
navigate( getHrefWithFilters( { state } ) );
reset: () => {
const { maxRange = 0 } = state;
state.minPrice = 0;
state.maxPrice = maxRange;
navigate( getHrefWithFilters( state ) );
},
},
},
} );
}
);

View File

@ -2,7 +2,6 @@
* External dependencies
*/
import { BlockEditProps } from '@wordpress/blocks';
import { HTMLElementEvent } from '@woocommerce/types';
export type BlockAttributes = {
showInputFields: boolean;
@ -16,24 +15,15 @@ export interface EditProps extends BlockEditProps< BlockAttributes > {
}
export type PriceFilterState = {
minPrice: number;
maxPrice: number;
minRange: number;
maxRange: number;
minPrice?: number;
maxPrice?: number;
minRange?: number;
maxRange?: number;
rangeStyle: string;
formattedMinPrice: string;
formattedMaxPrice: string;
};
export type StateProps = {
state: {
filters: PriceFilterState;
};
};
export interface ActionProps extends StateProps {
event: HTMLElementEvent< HTMLInputElement >;
}
export type FilterComponentProps = BlockEditProps< BlockAttributes > & {
collectionData: Partial< PriceFilterState >;
};

View File

@ -44,20 +44,15 @@ final class CollectionPriceFilter extends AbstractBlock {
$formatted_max_price = wc_price( $max_price, array( 'decimals' => 0 ) );
$data = array(
'minPrice' => $min_price,
'maxPrice' => $max_price,
'minRange' => $min_range,
'maxRange' => $max_range,
'formattedMinPrice' => $formatted_min_price,
'formattedMaxPrice' => $formatted_max_price,
'minPrice' => $min_price,
'maxPrice' => $max_price,
'minRange' => $min_range,
'maxRange' => $max_range,
);
wc_store(
array(
'state' => array(
'filters' => $data,
),
)
wc_initial_state(
'woocommerce/collection-price-filter',
$data
);
list (
@ -75,9 +70,12 @@ final class CollectionPriceFilter extends AbstractBlock {
$__high = 100 * ( $max_price - $min_range ) / ( $max_range - $min_range );
$range_style = "--low: $__low%; --high: $__high%";
$data_directive = wp_json_encode( array( 'namespace' => 'woocommerce/collection-price-filter' ) );
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => $show_input_fields && $inline_input ? 'inline-input' : '',
'class' => $show_input_fields && $inline_input ? 'inline-input' : '',
'data-wc-interactive' => $data_directive,
)
);
@ -87,14 +85,15 @@ final class CollectionPriceFilter extends AbstractBlock {
class="min"
type="text"
value="%d"
data-wc-bind--value="state.filters.minPrice"
data-wc-on--input="actions.filters.setMinPrice"
data-wc-on--change="actions.filters.updateProductsWithPriceFilter"
data-wc-bind--value="state.minPrice"
data-wc-on--input="actions.setMinPrice"
data-wc-on--change="actions.updateProducts"
/>',
esc_attr( $min_price )
) : sprintf(
'<span data-wc-text="state.filters.formattedMinPrice">%s</span>',
esc_attr( $formatted_min_price )
'<span data-wc-text="state.formattedMinPrice">%s</span>',
// Not escaped, as this is HTML.
$formatted_min_price
);
$price_max = $show_input_fields ?
@ -103,14 +102,15 @@ final class CollectionPriceFilter extends AbstractBlock {
class="max"
type="text"
value="%d"
data-wc-bind--value="state.filters.maxPrice"
data-wc-on--input="actions.filters.setMaxPrice"
data-wc-on--change="actions.filters.updateProductsWithPriceFilter"
data-wc-bind--value="state.maxPrice"
data-wc-on--input="actions.setMaxPrice"
data-wc-on--change="actions.updateProducts"
/>',
esc_attr( $max_price )
) : sprintf(
'<span data-wc-text="state.filters.formattedMaxPrice">%s</span>',
esc_attr( $formatted_max_price )
'<span data-wc-text="state.formattedMaxPrice">%s</span>',
// Not escaped, as this is HTML.
$formatted_max_price
);
ob_start();
@ -119,7 +119,7 @@ final class CollectionPriceFilter extends AbstractBlock {
<div
class="range"
style="<?php echo esc_attr( $range_style ); ?>"
data-wc-bind--style="state.filters.rangeStyle"
data-wc-bind--style="state.rangeStyle"
>
<div class="range-bar"></div>
<input
@ -128,11 +128,11 @@ final class CollectionPriceFilter extends AbstractBlock {
min="<?php echo esc_attr( $min_range ); ?>"
max="<?php echo esc_attr( $max_range ); ?>"
value="<?php echo esc_attr( $min_price ); ?>"
data-wc-bind--max="state.filters.maxRange"
data-wc-bind--value="state.filters.minPrice"
data-wc-class--active="state.filters.isMinActive"
data-wc-on--input="actions.filters.setMinPrice"
data-wc-on--change="actions.filters.updateProductsWithPriceFilter"
data-wc-bind--max="state.maxRange"
data-wc-bind--value="state.minPrice"
data-wc-class--active="state.isMinActive"
data-wc-on--input="actions.setMinPrice"
data-wc-on--change="actions.updateProducts"
>
<input
type="range"
@ -140,15 +140,15 @@ final class CollectionPriceFilter extends AbstractBlock {
min="<?php echo esc_attr( $min_range ); ?>"
max="<?php echo esc_attr( $max_range ); ?>"
value="<?php echo esc_attr( $max_price ); ?>"
data-wc-bind--max="state.filters.maxRange"
data-wc-bind--value="state.filters.maxPrice"
data-wc-class--active="state.filters.isMaxActive"
data-wc-on--input="actions.filters.setMaxPrice"
data-wc-on--change="actions.filters.updateProductsWithPriceFilter"
data-wc-bind--max="state.maxRange"
data-wc-bind--value="state.maxPrice"
data-wc-class--active="state.isMaxActive"
data-wc-on--input="actions.setMaxPrice"
data-wc-on--change="actions.updateProducts"
>
</div>
<div class="text">
<?php // $price_min and $price_max are escapsed in the sprintf() calls above. ?>
<?php // $price_min and $price_max are escaped in the sprintf() calls above. ?>
<?php echo $price_min; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
<?php echo $price_max; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</div>