Skip to content

Commit

Permalink
Merge pull request #2604 from 10up/feature/2506
Browse files Browse the repository at this point in the history
Add history and shareable URLs support to Instant Results
  • Loading branch information
felipeelia authored Feb 25, 2022
2 parents 06935b7 + 339e520 commit ec9e96a
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 195 deletions.
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

0 comments on commit ec9e96a

Please sign in to comment.