Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 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
8 changes: 6 additions & 2 deletions assets/js/base/components/label/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ const Label = ( {
} ) => {
let Wrapper;

if ( ! label && screenReaderLabel ) {
const hasLabel = typeof label !== 'undefined' && label !== null;
const hasScreenReaderLabel =
typeof screenReaderLabel !== 'undefined' && screenReaderLabel !== null;

if ( ! hasLabel && hasScreenReaderLabel ) {
Wrapper = wrapperElement || 'span';
wrapperProps = {
...wrapperProps,
Expand All @@ -33,7 +37,7 @@ const Label = ( {

Wrapper = wrapperElement || Fragment;

if ( label && screenReaderLabel && label !== screenReaderLabel ) {
if ( hasLabel && hasScreenReaderLabel && label !== screenReaderLabel ) {
return (
<Wrapper { ...wrapperProps }>
<span aria-hidden="true">{ label }</span>
Expand Down
3 changes: 2 additions & 1 deletion assets/js/base/components/price-slider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import classnames from 'classnames';
import './style.scss';
import { constrainRangeSliderValues } from './utils';
import { formatPrice } from '../../utils/price';
import SubmitButton from './submit-button';
import SubmitButton from '../submit-button';
import PriceLabel from './price-label';
import PriceInput from './price-input';

Expand Down Expand Up @@ -307,6 +307,7 @@ const PriceSlider = ( {
) }
{ showFilterButton && (
<SubmitButton
className="wc-block-price-filter__button"
disabled={ isLoading || ! hasValidConstraints }
onClick={ onSubmit }
/>
Expand Down
5 changes: 0 additions & 5 deletions assets/js/base/components/price-slider/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,6 @@
margin-left: 0;
margin-right: 10px;
}

.wc-block-price-filter__button {
margin-left: auto;
white-space: nowrap;
}
}
}
.wc-block-price-filter__range-input {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@
*/
import { __ } from '@wordpress/i18n';
import PropTypes from 'prop-types';
import classNames from 'classnames';

const SubmitButton = ( { disabled, onClick } ) => {
/**
* Internal dependencies
*/
import './style.scss';

const SubmitButton = ( { className, disabled, onClick } ) => {
return (
<button
type="submit"
className="wc-block-price-filter__button wc-block-form-button"
className={ classNames( 'wc-block-submit-button', className ) }
disabled={ disabled }
onClick={ onClick }
>
{ // translators: Submit button text for the price filter.
{ // translators: Submit button text for filters.
__( 'Go', 'woo-gutenberg-products-block' ) }
</button>
);
Expand Down
5 changes: 5 additions & 0 deletions assets/js/base/components/submit-button/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.wc-block-submit-button {
display: block;
margin-left: auto;
white-space: nowrap;
}
194 changes: 99 additions & 95 deletions assets/js/blocks/attribute-filter/block.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/**
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { speak } from '@wordpress/a11y';
import {
useCollection,
useQueryStateByKey,
useQueryStateByContext,
useCollectionData,
useShallowEqual,
} from '@woocommerce/base-hooks';
import {
useCallback,
Expand All @@ -18,14 +19,17 @@ import {
} from '@wordpress/element';
import CheckboxList from '@woocommerce/base-components/checkbox-list';
import DropdownSelector from '@woocommerce/base-components/dropdown-selector';
import Label from '@woocommerce/base-components/label';
import SubmitButton from '@woocommerce/base-components/submit-button';
import isShallowEqual from '@wordpress/is-shallow-equal';

/**
* Internal dependencies
*/
import './style.scss';
import { getAttributeFromID } from '../../utils/attributes';
import { updateAttributeFilter } from '../../utils/attributes-query';
import Label from './label';
import { previewAttributeObject, previewOptions } from './preview';
import './style.scss';

/**
* Component displaying an attribute filter.
Expand All @@ -34,68 +38,15 @@ const AttributeFilterBlock = ( {
attributes: blockAttributes,
isEditor = false,
} ) => {
/**
* Get the label for an attribute term filter.
*/
const getLabel = useCallback(
( name, count ) => {
return (
<Fragment>
{ name }
{ blockAttributes.showCounts && count !== null && (
<Label
label={ count }
screenReaderLabel={ sprintf(
// translators: %s number of products.
_n(
'%s product',
'%s products',
count,
'woo-gutenberg-products-block'
),
count
) }
wrapperElement="span"
wrapperProps={ {
className:
'wc-block-attribute-filter-list-count',
} }
/>
) }
</Fragment>
);
},
[ blockAttributes ]
);

const attributeObject =
blockAttributes.isPreview && ! blockAttributes.attributeId
? {
id: 0,
name: 'preview',
taxonomy: 'preview',
label: 'Preview',
}
? previewAttributeObject
: getAttributeFromID( blockAttributes.attributeId );

const [ checked, setChecked ] = useState( [] );
const [ displayedOptions, setDisplayedOptions ] = useState(
blockAttributes.isPreview && ! blockAttributes.attributeId
? [
{
value: 'preview-1',
name: 'Blue',
label: getLabel( 'Blue', 3 ),
},
{
value: 'preview-2',
name: 'Green',
label: getLabel( 'Green', 3 ),
},
{
value: 'preview-3',
name: 'Red',
label: getLabel( 'Red', 2 ),
},
]
? previewOptions
: []
);

Expand All @@ -105,15 +56,6 @@ const AttributeFilterBlock = ( {
setProductAttributesQuery,
] = useQueryStateByKey( 'attributes', [] );

const checked = useMemo( () => {
return productAttributesQuery
.filter(
( attribute ) =>
attribute.attribute === attributeObject.taxonomy
)
.flatMap( ( attribute ) => attribute.slug );
}, [ productAttributesQuery, attributeObject ] );

const {
results: attributeTerms,
isLoading: attributeTermsLoading,
Expand Down Expand Up @@ -157,39 +99,84 @@ const AttributeFilterBlock = ( {
* Compare intersection of all terms and filtered counts to get a list of options to display.
*/
useEffect( () => {
/**
* Checks if a term slug is in the query state.
*/
const isTermInQueryState = ( termSlug ) => {
if ( ! queryState || ! queryState.attributes ) {
return false;
}
return queryState.attributes.some(
( { attribute, slug = [] } ) =>
attribute === attributeObject.taxonomy &&
slug.includes( termSlug )
);
};

if ( attributeTermsLoading || filteredCountsLoading ) {
return;
}

const newOptions = [];
const newOptions = attributeTerms
.map( ( term ) => {
const filteredTerm = getFilteredTerm( term.id );

attributeTerms.forEach( ( term ) => {
const filteredTerm = getFilteredTerm( term.id );
const isChecked = checked.includes( term.slug );
const count = filteredTerm ? filteredTerm.count : null;
// If there is no match this term doesn't match the current product collection - only render if checked.
if (
! filteredTerm &&
! checked.includes( term.slug ) &&
! isTermInQueryState( term.slug )
) {
return null;
}

// If there is no match this term doesn't match the current product collection - only render if checked.
if ( ! filteredTerm && ! isChecked ) {
return;
}
const count = filteredTerm ? filteredTerm.count : 0;

newOptions.push( {
value: term.slug,
name: term.name,
label: getLabel( term.name, count ),
} );
} );
return {
value: term.slug,
name: term.name,
label: (
<Label
name={ term.name }
count={ blockAttributes.showCounts ? count : null }
/>
),
};
} )
.filter( Boolean );

setDisplayedOptions( newOptions );
}, [
attributeObject.taxonomy,
attributeTerms,
attributeTermsLoading,
blockAttributes.showCounts,
filteredCountsLoading,
getFilteredTerm,
getLabel,
checked,
queryState.attributes,
] );

// Track checked STATE changes - if state changes, update the query.
useEffect( () => {
if ( ! blockAttributes.showFilterButton ) {
onSubmit();
}
}, [ checked, onSubmit ] );
Copy link
Member

Choose a reason for hiding this comment

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

Does blockAttributes.showFilterButton need to be a dependency here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! I think it's not needed because blockAttributes.showFilterButton can only change in the editor and onSubmit should only be triggered in the frontend.

But that makes me thing that when eluding dependencies we must always explain it in a comment so it doesn't look like a bug. Added in 909a4f9.


const curentCheckedQuery = useShallowEqual( checkedQuery );

// Track ATTRIBUTES QUERY changes so the block reflects current filters.
useEffect(
() => {
if ( ! isShallowEqual( checked, checkedQuery ) ) {
setChecked( checkedQuery );
}
},
// We only want to apply this effect when the query changes, so we are intentionally leaving `checked` out of the dependencies.
[ curentCheckedQuery ]
);

/**
* Returns an array of term objects that have been chosen via the checkboxes.
*/
Expand All @@ -205,6 +192,24 @@ const AttributeFilterBlock = ( {
[ attributeTerms ]
);

const onSubmit = () => {
updateAttributeFilter(
productAttributesQuery,
setProductAttributesQuery,
attributeObject,
getSelectedTerms( checked ),
blockAttributes.queryType === 'or' ? 'in' : 'and'
);
};

const checkedQuery = useMemo( () => {
return productAttributesQuery
.filter(
( { attribute } ) => attribute === attributeObject.taxonomy
)
.flatMap( ( { slug } ) => slug );
}, [ productAttributesQuery, attributeObject.taxonomy ] );

const multiple =
blockAttributes.displayStyle !== 'dropdown' ||
blockAttributes.queryType === 'or';
Expand Down Expand Up @@ -289,17 +294,9 @@ const AttributeFilterBlock = ( {
}
}

const newSelectedTerms = getSelectedTerms( newChecked );

updateAttributeFilter(
productAttributesQuery,
setProductAttributesQuery,
attributeObject,
newSelectedTerms,
blockAttributes.queryType === 'or' ? 'in' : 'and'
);
setChecked( newChecked );
},
[ displayedOptions, multiple ]
[ checked, displayedOptions, multiple ]
);

if ( displayedOptions.length === 0 && ! attributeTermsLoading ) {
Expand Down Expand Up @@ -337,6 +334,13 @@ const AttributeFilterBlock = ( {
isDisabled={ isDisabled }
/>
) }
{ blockAttributes.showFilterButton && (
<SubmitButton
className="wc-block-attribute-filter__button"
disabled={ isLoading || isDisabled }
onClick={ onSubmit }
/>
) }
</div>
</Fragment>
);
Expand Down
Loading