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

Filter all products block by attribute #1127

Merged
merged 69 commits into from
Nov 11, 2019

Conversation

mikejolley
Copy link
Member

@mikejolley mikejolley commented Nov 5, 2019

Introduces an attribute filter block for use alongside the all products block.

Ref: #713 Note some acceptance criteria in that issue are not met in this MVP.

TODO:

  • Convert to store namespace
  • The list should be truncated if it contains more than 10 attributes
  • Add attribute selector to inspector sidebar as per the mocks
  • Discuss headings and 'toggle' in acceptance criteria

Screenshots

Screenshot 2019-11-05 at 15 23 06

How to test the changes in this Pull Request:

The best way to test these in conjunction with other filters is as follows:

  1. Create a column block with 2 columns
  2. Add the all products block to one column
  3. Add a price slider, and 2 attribute filter blocks to the other column. Setup one to use attribute 'size' and one to use 'color'. This is assuming you are using woo core sample data. You can use heading blocks to label them if you wish.

Then you can test how the filters work on the frontend.

Changelog

Introduce a filter products by attribute block which works alongside the new "All products" block.

@mikejolley mikejolley added status: needs review type: new block Applied to work that introduces a new block (typically used on an epic issue). labels Nov 5, 2019
@mikejolley mikejolley requested a review from a team November 5, 2019 15:25
Copy link
Contributor

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

This is looking amazing, you did huge progress these last days, congrats! 👏

The behavior is still a bit different from core. Using AND as the Query Type, I can reach a point that the block completely disappears:
Peek 2019-11-06 16-18

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/style.scss Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/style.scss Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/edit.js Outdated Show resolved Hide resolved
Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

Nice work! Have a few comments sprinkled throughout for your perusal 👇

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/index.js Outdated Show resolved Hide resolved
Copy link
Contributor

@Aljullu Aljullu left a comment

Choose a reason for hiding this comment

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

Thanks for applying the feedback @mikejolley! Some minor things I found:

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Show resolved Hide resolved
assets/js/blocks/attribute-filter/edit.js Show resolved Hide resolved
mikejolley and others added 8 commits November 7, 2019 17:07
Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

Almost there! It'd be nice to break up monolith pulls like this if possible, the REST API endpoint could have gone in it's own pull (It should have tests too). However, I reviewed the REST API here so no need to split out now. Comments below 👇

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
return (
<Fragment>
{ options.map( ( option, index ) => (
<Fragment key={ option.key }>
Copy link
Contributor

Choose a reason for hiding this comment

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

Fragment shouldn't be needed here, just put the key on the <li>

Copy link
Member Author

Choose a reason for hiding this comment

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

This fragment wraps 2 sibling <li> elements so is needed here?

Copy link
Contributor

Choose a reason for hiding this comment

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

You're right there is one Fragment that could remain. However there's a couple things:

  1. The inner level fragment should still not be needed.
  2. The key should be on the li items, not the Fragment. The problem with the Fragment having the key is that the "show more options" toggle will get re-rendered everytime the inner list re-renders even if it's not necessary.

The above points might not see important in the context of this particular usage, but it's pattern that could be more problematic in other contexts if it becomes a habit :). So I'm just promoting best practices here.

This code could get changed to:

useMemo( () => {
	// Truncate options if > the limit + 5.
	const optionCount = options.length;
	const shouldTruncateOptions = optionCount > limit + 5;
	return (
		<Fragment>
			{ options.map( ( option, index ) => (
				<li
					key={ option.key }
					{ ...shouldTruncateOptions &&
						! showExpanded &&
						index >= limit && { hidden: true } }
				>
					<input
						type="checkbox"
						id={ option.key }
						value={ option.key }
						onChange={ onCheckboxChange }
						checked={ checked.includes( option.key ) }
					/>
					<label htmlFor={ option.key }>{ option.label }</label>
				</li>
			) ) }
			{ shouldTruncateOptions &&
				options.length > limit &&
				renderedShowMore }
			{ shouldTruncateOptions && renderedShowLess }
		</Fragment>
	);
}, [
	options,
	checked,
	showExpanded,
	limit,
	onCheckboxChange,
	renderedShowLess,
	renderedShowMore,
] );

Even better though, would be to handle the renderedShowMore and renderedShowLess outside of this memoized function. I'd combine the renderedShowMore and renderedShowLess into one memoized function that spits out either of those or null based on the conditions. Then you could get rid of the last unnecessary fragment and end up with something like this:

<ul className={ classes }>
    { isLoading ? placeholder : renderedOptions  }
    { renderedToggleOptions }
</ul>

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm but by having the show more after the list items, if you tab through (with keyboard) when it expands you're at the bottom of the list rather than from the point of expansion.. that was my justification for having it appear inline. Originally I did it similar to you but only rendering visible list items. You were against that particular solution also.

Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 hmm... I see your point. I tried both behaviours and what you have definitely works better from an a11y pov. Let's roll with it.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem with the Fragment having the key is that the "show more options" toggle will get re-rendered everytime the inner list re-renders even if it's not necessary.

Did we work around this by adding a key to the show more/show less li?

Copy link
Contributor

Choose a reason for hiding this comment

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

Did we work around this by adding a key to the show more/show less li?

Hmm... I don't think so (not sure honestly), but regardless I think in this case any accessibility improvements make it worth potential extra rendering for the time being (until we can think of a better pattern).

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/frontend.js Show resolved Hide resolved
);

const filteredCountsQueryState = useMemo( () => {
// If doing an "AND" query, we need to remove current taxonomy query so counts are not affected.
Copy link
Contributor

Choose a reason for hiding this comment

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

should you still do a check here and return a default queryState if taxonomy is null? That will guard against any the lack of any taxonomy for the given attribute id coming into this component.

Copy link
Member Author

Choose a reason for hiding this comment

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

Without a taxonomy this query will be broken... I think the change to the useCollection hook would be good so we can avoid the query altogether if missing (since we cannot add a conditional before the hooks). Follow up?

Copy link
Contributor

@nerrad nerrad Nov 8, 2019

Choose a reason for hiding this comment

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

👍 to follow up.

assets/js/base/components/checkbox-list/index.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

Thanks for handling the feedback 👍 I still see a couple things here that need addressed. Also, should there be tests for the new REST endpoints or are you handling that in a separate pull?

assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
assets/js/blocks/attribute-filter/block.js Outdated Show resolved Hide resolved
@mikejolley
Copy link
Member Author

@nerrad I'll add tests separately if we're happy with the API changes. R/e the useCollection follow-up, are you handling it?

Copy link
Contributor

@nerrad nerrad left a comment

Choose a reason for hiding this comment

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

@nerrad I'll add tests separately if we're happy with the API changes

👍

R/e the useCollection follow-up, are you handling it?

If you mean adding a callback to indicate whether to do the query or not, yup I can. Would you mind doing the issue though? I think you'll be able to describe the problem we're solving by that in the description pretty well. You can just assign to me after?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: new block Applied to work that introduces a new block (typically used on an epic issue).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants