Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add history and shareable URLs support to Instant Results #2604

Merged
merged 15 commits into from
Feb 25, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 3 additions & 4 deletions assets/js/blocks/related-posts/Edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ class Edit extends Component {
// Use 0 if in the Widgets Screen
const postId = wp.data.select('core/editor').getCurrentPostId() ?? 0;

this.fetchRequest = wp
.apiFetch({
path: addQueryArgs(`/wp/v2/posts/${postId}/related`, urlArgs),
})
wp.apiFetch({
path: addQueryArgs(`/wp/v2/posts/${postId}/related`, urlArgs),
})
.then((posts) => {
this.setState({ posts });
})
Expand Down
41 changes: 17 additions & 24 deletions assets/js/instant-results/components/common/checkbox-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,29 +199,6 @@ export default ({ disabled, label, options, onChange, selected, sortBy }) => {
listEl.current.focus();
};

/**
* Show all button component.
*
* @return {WPElement} Element.
*/
const ShowAllButton = () =>
options.length > optionsLimit && (
<SmallButton aria-expanded={showAll} disabled={disabled} onClick={onToggleShowAll}>
{showAll
? __('Show fewer options', 'elasticpress')
: sprintf(
/* translators: %d: Number of additional options available. */
_n(
'Show %d more option',
'Show %d more options',
options.length - optionsLimit,
'elasticpress',
),
options.length - optionsLimit,
)}
</SmallButton>
);

return (
<>
{options.length > 0 && (
Expand All @@ -241,7 +218,23 @@ export default ({ disabled, label, options, onChange, selected, sortBy }) => {
}
</ul>
)}
<ShowAllButton />

{options.length > optionsLimit && (
<SmallButton aria-expanded={showAll} disabled={disabled} onClick={onToggleShowAll}>
{showAll
? __('Show fewer options', 'elasticpress')
: sprintf(
/* translators: %d: Number of additional options available. */
_n(
'Show %d more option',
'Show %d more options',
options.length - optionsLimit,
'elasticpress',
),
options.length - optionsLimit,
)}
</SmallButton>
)}
</>
);
};
4 changes: 2 additions & 2 deletions assets/js/instant-results/components/facets/facet.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ export default ({ index, label, name, postTypes, type }) => {
<TaxonomyTermsFacet
defaultIsOpen={defaultIsOpen}
label={label}
name={name}
postTypes={postTypes}
taxonomy={name}
/>
);
default:
return <></>;
return null;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import { ActiveContraint } from '../tools/active-constraints';
export default ({ defaultIsOpen, label }) => {
const {
state: {
aggregations: { post_type: { post_type: { buckets = [] } = {} } = {} },
args: { post_type: selectedPostTypes = [] },
isLoading,
filters: { post_type: selectedPostTypes = [] },
postTypesAggregation: { post_types: { buckets = [] } = {} } = {},
},
dispatch,
} = useContext(Context);
Expand Down Expand Up @@ -71,7 +71,7 @@ export default ({ defaultIsOpen, label }) => {
* @param {string[]} postTypes Selected post types.
*/
const onChange = (postTypes) => {
dispatch({ type: 'APPLY_FILTERS', payload: { post_type: postTypes } });
dispatch({ type: 'APPLY_ARGS', payload: { post_type: postTypes } });
};

/**
Expand All @@ -85,7 +85,7 @@ export default ({ defaultIsOpen, label }) => {

postTypes.splice(index, 1);

dispatch({ type: 'APPLY_FILTERS', payload: { post_type: postTypes } });
dispatch({ type: 'APPLY_ARGS', payload: { post_type: postTypes } });
};

return (
Expand Down
18 changes: 11 additions & 7 deletions assets/js/instant-results/components/facets/price-range-facet.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ import { ActiveContraint } from '../tools/active-constraints';
export default ({ defaultIsOpen, label }) => {
const {
state: {
aggregations: {
price_range: {
max_price: { value: maxAgg = null } = {},
min_price: { value: minAgg = null } = {},
} = {},
},
args: { max_price: maxArg = null, min_price: minArg = null },
isLoading,
priceRangeAggregations: {
max_price: { value: maxAgg = null } = {},
min_price: { value: minAgg = null } = {},
} = {},
filters: { price_range: [minArg = null, maxArg = null] = [] },
},
dispatch,
} = useContext(Context);
Expand Down Expand Up @@ -70,7 +72,9 @@ export default ({ defaultIsOpen, label }) => {
* @param {number[]} values Lowest and highest values.
*/
const onAfterChange = (values) => {
dispatch({ type: 'APPLY_FILTER', payload: { price_range: values } });
const [min_price, max_price] = values;

dispatch({ type: 'APPLY_ARGS', payload: { min_price, max_price } });
};

/**
Expand All @@ -87,7 +91,7 @@ export default ({ defaultIsOpen, label }) => {
* Handle clearing the filter.
*/
const onClear = () => {
dispatch({ type: 'APPLY_FILTER', payload: { price_range: [] } });
dispatch({ type: 'APPLY_ARGS', payload: { max_price: null, min_price: null } });
};

/**
Expand Down
33 changes: 28 additions & 5 deletions assets/js/instant-results/components/facets/search-term-facet.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/**
* WordPress dependencies.
*/
import { useContext, WPElement } from '@wordpress/element';
import { useContext, useEffect, useState, WPElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';

/**
* Internal dependencies.
*/
import Context from '../../context';
import { useDebounce } from '../../hooks';
import { ActiveContraint } from '../tools/active-constraints';

/**
Expand All @@ -24,30 +25,52 @@ export default () => {
dispatch,
} = useContext(Context);

const [value, setValue] = useState(search);

/**
* Dispatch the change, with debouncing.
*/
const dispatchChange = useDebounce((value) => {
dispatch({ type: 'NEW_SEARCH_TERM', payload: value });
}, 300);

/**
* Handle input changes.
*
* @param {Event} event Change event.
*/
const onChange = (event) => {
dispatch({ type: 'SET_SEARCH_TERM', payload: event.target.value });
dispatch({ type: 'CLEAR_FILTERS' });
setValue(event.target.value);
dispatchChange(event.target.value);
};

/**
* Handle clearing.
*/
const onClear = () => {
dispatch({ type: 'SET_SEARCH_TERM', payload: '' });
dispatch({ type: 'NEW_SEARCH_TERM', payload: '' });
};

/**
* Handle an external change to the search value, such as from popping
* state.
*/
const handleSearch = () => {
setValue(search);
};

/**
* Effects.
*/
useEffect(handleSearch, [search]);

return (
<>
<input
className="ep-search-input"
placeholder={__('Search…', 'elasticpress')}
type="search"
value={search}
value={value}
onChange={onChange}
/>
{searchedTerm && (
Expand Down
31 changes: 13 additions & 18 deletions assets/js/instant-results/components/facets/taxonomy-terms-facet.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,26 @@ import { ActiveContraint } from '../tools/active-constraints';
* @param {Object} props Components props.
* @param {boolean} props.defaultIsOpen Whether the panel is open by default.
* @param {string} props.label Facet label.
* @param {string} props.name Facet name.
* @param {Array} props.postTypes Facet post types.
* @param {string} props.taxonomy Facet taxonomy.
* @return {WPElement} Component element.
*/
export default ({ defaultIsOpen, label, postTypes, taxonomy }) => {
export default ({ defaultIsOpen, label, postTypes, name }) => {
const {
state: {
isLoading,
filters: { [taxonomy]: selectedTerms = [] },
taxonomyTermsAggregations: {
[taxonomy]: { taxonomy_terms: { buckets = [] } = {} } = {},
} = {},
args: { [name]: selectedTerms = [] },
aggregations: { [name]: { [name]: { buckets = [] } = {} } = {} } = {},
},
dispatch,
} = useContext(Context);

/**
* A unique label for the facet. Adds additional context to the label if
* another taxonomy with the same label is being used as a facet.
* another facet with the same label is being used.
*/
const uniqueLabel = useMemo(() => {
const isNotUnique = facets.some(
(facet) => facet.label === label && facet.name !== taxonomy,
);

const isNotUnique = facets.some((facet) => facet.label === label && facet.name !== name);
const typeLabels = postTypes.map((postType) => postTypeLabels[postType].plural);
const typeSeparator = __(', ', 'elasticpress');

Expand All @@ -55,7 +50,7 @@ export default ({ defaultIsOpen, label, postTypes, taxonomy }) => {
typeLabels.join(typeSeparator),
)
: label;
}, [label, postTypes, taxonomy]);
}, [label, postTypes, name]);

/**
* Create list of filter options from aggregation buckets.
Expand All @@ -67,21 +62,21 @@ export default ({ defaultIsOpen, label, postTypes, taxonomy }) => {
*/
const reduceOptions = useCallback(
(options, { doc_count, key }) => {
const { name, parent, term_id, term_order } = JSON.parse(key);
const { name: label, parent, term_id, term_order } = JSON.parse(key);

options.push({
checked: selectedTerms.includes(term_id),
count: doc_count,
id: `ep-search-${taxonomy}-${term_id}`,
label: name,
id: `ep-search-${name}-${term_id}`,
label,
parent: parent.toString(),
order: term_order,
value: term_id.toString(),
});

return options;
},
[selectedTerms, taxonomy],
[selectedTerms, name],
);

/**
Expand Down Expand Up @@ -114,7 +109,7 @@ export default ({ defaultIsOpen, label, postTypes, taxonomy }) => {
* @param {string[]} terms Selected terms.
*/
const onChange = (terms) => {
dispatch({ type: 'APPLY_FILTERS', payload: { [taxonomy]: terms } });
dispatch({ type: 'APPLY_ARGS', payload: { [name]: terms } });
};

/**
Expand All @@ -127,7 +122,7 @@ export default ({ defaultIsOpen, label, postTypes, taxonomy }) => {

terms.splice(terms.indexOf(term), 1);

dispatch({ type: 'APPLY_FILTERS', payload: { [taxonomy]: terms } });
dispatch({ type: 'APPLY_ARGS', payload: { [name]: terms } });
};

return (
Expand Down
15 changes: 11 additions & 4 deletions assets/js/instant-results/components/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Sort from './tools/sort';
*/
export default () => {
const {
state: { isLoading, isSidebarOpen },
state: { isLoading },
} = useContext(Context);

return (
Expand All @@ -41,10 +41,17 @@ export default () => {
</div>

<div className="ep-search-page__body">
<Sidebar isOpen={isSidebarOpen}>
<Sidebar>
<Sort />
{facets.map((facet, index) => (
<Facet {...facet} index={index} />
{facets.map(({ label, name, postTypes, type }, index) => (
<Facet
index={index}
key={name}
label={label}
name={name}
postTypes={postTypes}
type={type}
/>
))}
</Sidebar>

Expand Down
18 changes: 14 additions & 4 deletions assets/js/instant-results/components/tools/clear-constraints.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import SmallButton from '../common/small-button';
*/
export default () => {
const {
state: { filters },
state: { args },
dispatch,
} = useContext(Context);

Expand All @@ -32,16 +32,26 @@ export default () => {
* @return {boolean} Whether there are active filters.
*/
const hasFilters = useMemo(() => {
return facets.some(({ name }) => filters[name]?.length > 0);
}, [filters]);
return facets.some(({ name, type }) => {
switch (type) {
case 'post_type':
case 'taxonomy':
return args[name]?.length > 0;
case 'price_range':
return args.max_price || args.min_price;
default:
return args[name];
}
});
}, [args]);

/**
* Handle clicking button.
*
* @return {void}
*/
const onClick = () => {
dispatch({ type: 'CLEAR_FILTERS' });
dispatch({ type: 'CLEAR_FACETS' });
};

return (
Expand Down
2 changes: 1 addition & 1 deletion assets/js/instant-results/components/tools/sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default () => {
const onChange = (event) => {
const { orderby, order } = sortOptions[event.target.value];

dispatch({ type: 'SORT_RESULTS', payload: { orderby, order } });
dispatch({ type: 'APPLY_ARGS', payload: { orderby, order } });
};

return (
Expand Down
Loading