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
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
47a36b2
Block setup
mikejolley Nov 4, 2019
dd1fe39
Working filtering and intersection of arrays
mikejolley Nov 4, 2019
7f36fdf
Implement block settings and no attribute placeholder
mikejolley Nov 4, 2019
63c3489
Correctly toggle counts
mikejolley Nov 4, 2019
2a4bf48
Implement filtering
mikejolley Nov 4, 2019
3f2e1df
Fix price slider constraints
mikejolley Nov 4, 2019
378d861
Fix price slider constraints
mikejolley Nov 4, 2019
8941166
Edit mode
mikejolley Nov 5, 2019
d1695c5
Rename ProductAttributeControl to ProductAttributeTermControl
mikejolley Nov 5, 2019
b92b99d
Attribute ID saving
mikejolley Nov 5, 2019
7d90236
fix incorrect test fixtures
nerrad Nov 4, 2019
98fae73
fix incorrect regex for parsing model (or resource names) from the ro…
nerrad Nov 4, 2019
4aeaed1
Fix query classes for some endpoints
mikejolley Nov 5, 2019
dcb704c
Style improvements
mikejolley Nov 5, 2019
7c26a00
Update inline comments
mikejolley Nov 6, 2019
2792bac
use previous tests
mikejolley Nov 6, 2019
9e3ef5d
Show attribute control in sidebar
mikejolley Nov 6, 2019
56f8d95
Remove displayStyle option
mikejolley Nov 6, 2019
62711cf
Sort attributes by name
mikejolley Nov 6, 2019
505ce96
Merge branch 'master' into update/price-slider-constraints
mikejolley Nov 6, 2019
b02150c
Merge branch 'master' into experiment/filter-by-attribute
mikejolley Nov 6, 2019
b8a7780
Merge branch 'update/price-slider-constraints' into experiment/filter…
mikejolley Nov 6, 2019
e95e19c
Show more/less toggle
mikejolley Nov 6, 2019
d11aa29
Merge branch 'master' into experiment/filter-by-attribute
mikejolley Nov 7, 2019
18562a0
Use renderFrontend
mikejolley Nov 7, 2019
c5dfef4
Only sort when adding values
mikejolley Nov 7, 2019
9b955e8
Rename memo placeholder
mikejolley Nov 7, 2019
21c244d
More specific CSS for pointer
mikejolley Nov 7, 2019
df96edb
Update assets/js/base/hooks/use-query-state.js
mikejolley Nov 7, 2019
8aa6811
Remove always true taxonomy check
mikejolley Nov 7, 2019
0109336
Update assets/js/blocks/attribute-filter/block.js
mikejolley Nov 7, 2019
24bba5c
Merge branch 'experiment/filter-by-attribute' of https://github.com/w…
mikejolley Nov 7, 2019
0af54f9
Remove lodash join
mikejolley Nov 7, 2019
e830631
native js for string casting
mikejolley Nov 7, 2019
a0dc217
Move internal deps
mikejolley Nov 7, 2019
97561a6
hyphenate attributes
mikejolley Nov 7, 2019
171fb41
Correct data set names
mikejolley Nov 7, 2019
18cb5d8
Remove unwanted dependency
mikejolley Nov 7, 2019
81b8abb
Moving imports
mikejolley Nov 7, 2019
0ba0591
Missing deps
mikejolley Nov 7, 2019
ae21f20
replace yoda conditonal
mikejolley Nov 7, 2019
d9a691c
Missing deps
mikejolley Nov 7, 2019
1a8e4af
Missing deps
mikejolley Nov 7, 2019
b1a24d6
Check value exists
mikejolley Nov 7, 2019
b4bcd39
Remove undefined filter
mikejolley Nov 7, 2019
9c14ae7
renderedOptions usememo
mikejolley Nov 7, 2019
2270310
Set defaults in checkbox list
mikejolley Nov 7, 2019
bc8dbfd
Show more/less refactor
mikejolley Nov 7, 2019
ca426f4
Use getAdminLink
mikejolley Nov 7, 2019
4a02e64
Fix object length check
mikejolley Nov 7, 2019
cdb3f09
Correct AND query handling for counts
mikejolley Nov 7, 2019
0867c94
Merge branch 'master' into experiment/filter-by-attribute
mikejolley Nov 7, 2019
1d53d56
useQueryStateByContext
mikejolley Nov 7, 2019
e250eba
Add store rest endpoints
mikejolley Nov 7, 2019
fba12a2
Update assets/js/base/components/checkbox-list/index.js
mikejolley Nov 7, 2019
7631fb8
Update assets/js/base/components/checkbox-list/index.js
mikejolley Nov 7, 2019
4e1f250
Update assets/js/base/components/checkbox-list/index.js
mikejolley Nov 7, 2019
dc492a2
Update assets/js/blocks/attribute-filter/block.js
mikejolley Nov 7, 2019
7785207
Feedback
mikejolley Nov 7, 2019
53ba361
Merge branch 'master' into experiment/filter-by-attribute
mikejolley Nov 7, 2019
8c22ba0
Merge conflict
mikejolley Nov 7, 2019
129aebe
feedback
mikejolley Nov 8, 2019
4a77711
API readme
mikejolley Nov 8, 2019
0432ef7
Fix API relation queries for multiple attributes
mikejolley Nov 8, 2019
607aeee
Prevent all options flashing visible during loads
mikejolley Nov 8, 2019
ab2351f
null check
mikejolley Nov 8, 2019
ded36b6
Improve loading state
mikejolley Nov 8, 2019
e87da8c
Remove null options change - it's no longer needed
mikejolley Nov 8, 2019
bbcebcb
update from master
mikejolley Nov 11, 2019
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
110 changes: 110 additions & 0 deletions assets/js/base/components/checkbox-list/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* External dependencies
*/
import PropTypes from 'prop-types';
import {
Fragment,
useCallback,
useMemo,
useState,
useEffect,
} from '@wordpress/element';
import classNames from 'classnames';

/**
* Internal dependencies
*/
import './style.scss';

/**
* Component used to show a list of checkboxes in a group.
*/
const CheckboxList = ( { className, onChange, options, isLoading } ) => {
// Holds all checked options.
const [ checked, setChecked ] = useState( [] );

useEffect( () => {
onChange( checked );
}, [ checked ] );

const renderPlaceholder = useMemo( () => {
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
return (
<Fragment>
{ [ ...Array( 5 ) ].map( ( x, i ) => (
<li
key={ i }
style={ {
/* stylelint-disable */
width: Math.floor( Math.random() * 75 ) + 25 + '%',
} }
/>
) ) }
</Fragment>
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
);
}, [] );

const onCheckboxChange = useCallback(
( event ) => {
const isChecked = event.target.checked;
const checkedValue = event.target.value;
const newChecked = checked.filter(
( value ) => value !== checkedValue
);

if ( isChecked ) {
newChecked.push( checkedValue );
}

newChecked.sort();
mikejolley marked this conversation as resolved.
Show resolved Hide resolved

setChecked( newChecked );
},
[ options, checked ]
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
);

const renderOptions = useCallback( () => {
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
return (
<Fragment>
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
{ options.map( ( option ) => (
<li key={ option.key }>
<input
type="checkbox"
id={ option.key }
value={ option.key }
onChange={ onCheckboxChange }
checked={ checked.includes( option.key ) }
/>
<label htmlFor={ option.key }>{ option.label }</label>
</li>
) ) }
</Fragment>
);
}, [ options, checked ] );

const listClass = classNames(
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
'wc-block-checkbox-list',
isLoading && 'is-loading',
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
className
);

return (
<ul className={ listClass }>
{ isLoading ? renderPlaceholder : renderOptions() }
</ul>
);
};

CheckboxList.propTypes = {
onChange: PropTypes.func,
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
options: PropTypes.arrayOf(
PropTypes.shape( {
key: PropTypes.string.isRequired,
label: PropTypes.node.isRequired,
checked: PropTypes.bool,
} )
),
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
className: PropTypes.string,
isLoading: PropTypes.bool,
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
};

export default CheckboxList;
17 changes: 17 additions & 0 deletions assets/js/base/components/checkbox-list/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.editor-styles-wrapper .wc-block-checkbox-list,
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
.wc-block-checkbox-list {
margin: 0;
padding: 0;
list-style: none outside;

li {
margin: 0 0 $gap-smallest;
padding: 0;
list-style: none outside;
}
&.is-loading {
li {
@include placeholder();
}
}
}
30 changes: 26 additions & 4 deletions assets/js/base/components/price-slider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from '@wordpress/element';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useDebounce } from '@woocommerce/base-hooks';
import { useDebounce, usePrevious } from '@woocommerce/base-hooks';

/**
* Internal dependencies
Expand Down Expand Up @@ -47,15 +47,25 @@ const PriceSlider = ( {
formatCurrencyForInput( maxPrice, priceFormat, currencySymbol )
);
const debouncedChangeValue = useDebounce( [ minPrice, maxPrice ], 500 );
const prevMinConstraint = usePrevious( minConstraint );
const prevMaxConstraint = usePrevious( maxConstraint );

useEffect( () => {
if ( minPrice === undefined || minConstraint > minPrice ) {
if (
minPrice === undefined ||
minConstraint > minPrice ||
minPrice === prevMinConstraint
) {
setMinPrice( minConstraint );
}
}, [ minConstraint ] );

useEffect( () => {
if ( maxPrice === undefined || maxConstraint < maxPrice ) {
if (
maxPrice === undefined ||
maxConstraint < maxPrice ||
maxPrice === prevMaxConstraint
) {
setMaxPrice( maxConstraint );
}
}, [ maxConstraint ] );
Expand All @@ -82,6 +92,18 @@ const PriceSlider = ( {
* Handles styles for the shaded area of the range slider.
*/
const getProgressStyle = useMemo( () => {
if (
! isFinite( minPrice ) ||
! isFinite( maxPrice ) ||
! isFinite( minConstraint ) ||
! isFinite( maxConstraint )
) {
return {
'--low': '0%',
'--high': '100%',
};
}

const low =
Math.round(
100 *
Expand All @@ -99,7 +121,7 @@ const PriceSlider = ( {
'--low': low + '%',
'--high': high + '%',
};
}, [ minPrice, minConstraint, maxPrice, maxConstraint ] );
}, [ minPrice, maxPrice, minConstraint, maxConstraint ] );

/**
* Trigger the onChange prop callback with new values.
Expand Down
1 change: 1 addition & 0 deletions assets/js/base/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './use-store-products';
export * from './use-collection';
export * from './use-collection-header';
export * from './use-debounce';
export * from './use-previous';
7 changes: 6 additions & 1 deletion assets/js/base/hooks/use-collection-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ import { useShallowEqual } from './use-shallow-equal';
* loading (true) or not.
*/
export const useCollectionHeader = ( headerKey, options ) => {
const { namespace, resourceName, resourceValues, query } = options;
const {
namespace,
resourceName,
resourceValues = [],
query = {},
} = options;
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
if ( ! namespace || ! resourceName ) {
throw new Error(
'The options object must have valid values for the namespace and ' +
Expand Down
7 changes: 6 additions & 1 deletion assets/js/base/hooks/use-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ import { useShallowEqual } from './use-shallow-equal';
* loading (true) or not.
*/
export const useCollection = ( options ) => {
const { namespace, resourceName, resourceValues, query } = options;
const {
namespace,
resourceName,
resourceValues = [],
query = {},
} = options;
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
if ( ! namespace || ! resourceName ) {
throw new Error(
'The options object must have valid values for the namespace and ' +
Expand Down
15 changes: 15 additions & 0 deletions assets/js/base/hooks/use-previous.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useRef, useEffect } from 'react';

/**
* Use Previous from https://usehooks.com/usePrevious/.
* @param {mixed} value
*/
export const usePrevious = ( value ) => {
const ref = useRef();

useEffect( () => {
ref.current = value;
}, [ value ] );

return ref.current;
};
9 changes: 7 additions & 2 deletions assets/js/base/hooks/use-query-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,20 @@ export const useQueryStateContext = ( context ) => {
*
* @param {string} context What context to retrieve the query state for.
* @param {*} queryKey The specific query key to retrieve the value for.
* @param {*} defaultValue Default value if query does not exist.
*
* @return {*} Whatever value is set at the query state index using the
* provided context and query key.
*/
export const useQueryStateByKey = ( context, queryKey ) => {
export const useQueryStateByKey = (
context,
queryKey,
defaultValue = undefined
mikejolley marked this conversation as resolved.
Show resolved Hide resolved
) => {
const queryValue = useSelect(
( select ) => {
const store = select( storeKey );
return store.getValueForQueryKey( context, queryKey, undefined );
return store.getValueForQueryKey( context, queryKey, defaultValue );
},
[ context, queryKey ]
);
Expand Down
Loading