diff --git a/plugins/woocommerce-admin/client/components/search/autocompleters/index.js b/plugins/woocommerce-admin/client/components/search/autocompleters/index.js index f6f56b13ccf..26cbd6cf7f8 100644 --- a/plugins/woocommerce-admin/client/components/search/autocompleters/index.js +++ b/plugins/woocommerce-admin/client/components/search/autocompleters/index.js @@ -3,3 +3,4 @@ * Export all autocompleters */ export { default as product } from './product'; +export { default as productCategory } from './product-cat'; diff --git a/plugins/woocommerce-admin/client/components/search/autocompleters/product-cat.js b/plugins/woocommerce-admin/client/components/search/autocompleters/product-cat.js new file mode 100644 index 00000000000..704115b77e1 --- /dev/null +++ b/plugins/woocommerce-admin/client/components/search/autocompleters/product-cat.js @@ -0,0 +1,60 @@ +/** @format */ +/** + * External dependencies + */ +import apiFetch from '@wordpress/api-fetch'; + +/** + * Internal dependencies + */ +import { computeSuggestionMatch } from './utils'; +import { stringifyQuery } from 'lib/nav-utils'; + +/** + * A product categories completer. + * See https://github.com/WordPress/gutenberg/tree/master/packages/components/src/autocomplete#the-completer-interface + * + * @type {Completer} + */ +export default { + name: 'product_cats', + className: 'woocommerce-search__product-result', + options( search ) { + let payload = ''; + if ( search ) { + const query = { + search: encodeURIComponent( search ), + per_page: 10, + orderby: 'count', + }; + payload = stringifyQuery( query ); + } + return apiFetch( { path: '/wc/v3/products/categories' + payload } ); + }, + isDebounced: true, + getOptionKeywords( cat ) { + return [ cat.name ]; + }, + getOptionLabel( cat, query ) { + const match = computeSuggestionMatch( cat.name, query ) || {}; + // @todo bring back ProductImage, but allow for product category image + return [ + + { match.suggestionBeforeMatch } + + { match.suggestionMatch } + + { match.suggestionAfterMatch } + , + ]; + }, + // This is slightly different than gutenberg/Autocomplete, we don't support different methods + // of replace/insertion, so we can just return the value. + getOptionCompletion( cat ) { + const value = { + id: cat.id, + label: cat.name, + }; + return value; + }, +}; diff --git a/plugins/woocommerce-admin/client/components/search/autocompleters/product.js b/plugins/woocommerce-admin/client/components/search/autocompleters/product.js index bafa9fb0207..7d688e8c7e1 100644 --- a/plugins/woocommerce-admin/client/components/search/autocompleters/product.js +++ b/plugins/woocommerce-admin/client/components/search/autocompleters/product.js @@ -7,22 +7,10 @@ import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ +import { computeSuggestionMatch } from './utils'; import ProductImage from 'components/product-image'; import { stringifyQuery } from 'lib/nav-utils'; -const computeSuggestionMatch = ( suggestion, query ) => { - if ( ! query ) { - return null; - } - const indexOfMatch = suggestion.toLocaleLowerCase().indexOf( query.toLocaleLowerCase() ); - - return { - suggestionBeforeMatch: suggestion.substring( 0, indexOfMatch ), - suggestionMatch: suggestion.substring( indexOfMatch, indexOfMatch + query.length ), - suggestionAfterMatch: suggestion.substring( indexOfMatch + query.length ), - }; -}; - /** * A products completer. * See https://github.com/WordPress/gutenberg/tree/master/packages/components/src/autocomplete#the-completer-interface diff --git a/plugins/woocommerce-admin/client/components/search/autocompleters/utils.js b/plugins/woocommerce-admin/client/components/search/autocompleters/utils.js new file mode 100644 index 00000000000..23d9becb214 --- /dev/null +++ b/plugins/woocommerce-admin/client/components/search/autocompleters/utils.js @@ -0,0 +1,21 @@ +/** @format */ +/** + * Parse a string suggestion, split apart by where the first matching query is. + * Used to display matched partial in bold. + * + * @param {string} suggestion The item's label as returned from the API. + * @param {string} query The search term to match in the string. + * @return {object} A list in three parts: before, match, and after. + */ +export function computeSuggestionMatch( suggestion, query ) { + if ( ! query ) { + return null; + } + const indexOfMatch = suggestion.toLocaleLowerCase().indexOf( query.toLocaleLowerCase() ); + + return { + suggestionBeforeMatch: suggestion.substring( 0, indexOfMatch ), + suggestionMatch: suggestion.substring( indexOfMatch, indexOfMatch + query.length ), + suggestionAfterMatch: suggestion.substring( indexOfMatch + query.length ), + }; +} diff --git a/plugins/woocommerce-admin/client/components/search/index.js b/plugins/woocommerce-admin/client/components/search/index.js index 4abd2869335..935192de415 100644 --- a/plugins/woocommerce-admin/client/components/search/index.js +++ b/plugins/woocommerce-admin/client/components/search/index.js @@ -11,7 +11,7 @@ import PropTypes from 'prop-types'; * Internal dependencies */ import Autocomplete from './autocomplete'; -import { product } from './autocompleters'; +import { product, productCategory } from './autocompleters'; import Tag from 'components/tag'; import './style.scss'; @@ -61,6 +61,8 @@ class Search extends Component { switch ( this.props.type ) { case 'products': return product; + case 'product_cats': + return productCategory; default: return {}; } @@ -119,7 +121,7 @@ Search.propTypes = { /** * The object type to be used in searching. */ - type: PropTypes.oneOf( [ 'products', 'orders', 'customers' ] ).isRequired, + type: PropTypes.oneOf( [ 'products', 'product_cats', 'orders', 'customers' ] ).isRequired, /** * An array of objects describing selected values */