|
2 | 2 | * External dependencies |
3 | 3 | */ |
4 | 4 | import { __ } from '@wordpress/i18n'; |
5 | | -import { noop } from 'lodash'; |
6 | | -import { SelectControl } from '@wordpress/components'; |
| 5 | +import classnames from 'classnames'; |
| 6 | +import { Component, createRef, Fragment } from '@wordpress/element'; |
| 7 | +import { IconButton } from '@wordpress/components'; |
| 8 | +import { repeat } from 'lodash'; |
7 | 9 | import PropTypes from 'prop-types'; |
| 10 | +import { withInstanceId } from '@wordpress/compose'; |
8 | 11 |
|
9 | 12 | /** |
10 | 13 | * Internal dependencies |
11 | 14 | */ |
12 | 15 | import { buildTermsTree } from './hierarchy'; |
13 | 16 |
|
14 | | -function getCategories( { hasEmpty, isDropdown, isHierarchical } ) { |
| 17 | +function getCategories( { hasEmpty, isHierarchical } ) { |
15 | 18 | const categories = wc_product_block_data.productCategories.filter( |
16 | 19 | ( cat ) => hasEmpty || !! cat.count |
17 | 20 | ); |
18 | | - return ! isDropdown && isHierarchical ? |
| 21 | + return isHierarchical ? |
19 | 22 | buildTermsTree( categories ) : |
20 | 23 | categories; |
21 | 24 | } |
22 | 25 |
|
23 | 26 | /** |
24 | 27 | * Component displaying the categories as dropdown or list. |
25 | 28 | */ |
26 | | -const ProductCategoriesBlock = ( { attributes, isPreview = false } ) => { |
27 | | - const { hasCount, isDropdown } = attributes; |
28 | | - const categories = getCategories( attributes ); |
29 | | - const parentKey = 'parent-' + categories[ 0 ].term_id; |
| 29 | +class ProductCategoriesBlock extends Component { |
| 30 | + constructor() { |
| 31 | + super( ...arguments ); |
| 32 | + this.select = createRef(); |
| 33 | + this.onNavigate = this.onNavigate.bind( this ); |
| 34 | + this.renderList = this.renderList.bind( this ); |
| 35 | + this.renderOptions = this.renderOptions.bind( this ); |
| 36 | + } |
30 | 37 |
|
31 | | - const renderList = ( items ) => ( |
32 | | - <ul key={ parentKey }> |
33 | | - { items.map( ( cat ) => { |
34 | | - const count = hasCount ? <span>({ cat.count })</span> : null; |
35 | | - return [ |
36 | | - <li key={ cat.term_id }> |
37 | | - <a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ } |
38 | | - </li>, |
39 | | - !! cat.children && !! cat.children.length && renderList( cat.children ), |
40 | | - ]; |
41 | | - } ) } |
42 | | - </ul> |
43 | | - ); |
| 38 | + onNavigate() { |
| 39 | + const { isPreview = false } = this.props; |
| 40 | + const url = this.select.current.value; |
| 41 | + if ( 'false' === url ) { |
| 42 | + return; |
| 43 | + } |
| 44 | + const home = wc_product_block_data.homeUrl; |
44 | 45 |
|
45 | | - return ( |
46 | | - <div className="wc-block-product-categories"> |
47 | | - { isDropdown ? ( |
48 | | - <SelectControl |
49 | | - label={ __( 'Select a category', 'woo-gutenberg-products-block' ) } |
50 | | - options={ categories.map( ( cat ) => ( { |
51 | | - label: hasCount ? `${ cat.name } (${ cat.count })` : cat.name, |
52 | | - value: cat.term_id, |
53 | | - } ) ) } |
54 | | - onChange={ noop } |
55 | | - /> |
56 | | - ) : ( |
57 | | - renderList( categories ) |
58 | | - ) } |
59 | | - </div> |
60 | | - ); |
61 | | -}; |
| 46 | + if ( ! isPreview && 0 === url.indexOf( home ) ) { |
| 47 | + document.location.href = url; |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + renderList( items, depth = 0 ) { |
| 52 | + const { isPreview = false } = this.props; |
| 53 | + const { hasCount } = this.props.attributes; |
| 54 | + const parentKey = 'parent-' + items[ 0 ].term_id; |
| 55 | + |
| 56 | + return ( |
| 57 | + <ul key={ parentKey }> |
| 58 | + { items.map( ( cat ) => { |
| 59 | + const count = hasCount ? <span>({ cat.count })</span> : null; |
| 60 | + return [ |
| 61 | + <li key={ cat.term_id }> |
| 62 | + <a href={ isPreview ? null : cat.link }>{ cat.name }</a> { count } { /* eslint-disable-line */ } |
| 63 | + </li>, |
| 64 | + !! cat.children && !! cat.children.length && this.renderList( cat.children, depth + 1 ), |
| 65 | + ]; |
| 66 | + } ) } |
| 67 | + </ul> |
| 68 | + ); |
| 69 | + } |
| 70 | + |
| 71 | + renderOptions( items, depth = 0 ) { |
| 72 | + const { hasCount } = this.props.attributes; |
| 73 | + |
| 74 | + return items.map( ( cat ) => { |
| 75 | + const count = hasCount ? `(${ cat.count })` : null; |
| 76 | + return [ |
| 77 | + <option key={ cat.term_id } value={ cat.link }> |
| 78 | + { repeat( '–', depth ) } { cat.name } { count } |
| 79 | + </option>, |
| 80 | + !! cat.children && !! cat.children.length && this.renderOptions( cat.children, depth + 1 ), |
| 81 | + ]; |
| 82 | + } ); |
| 83 | + } |
| 84 | + |
| 85 | + render() { |
| 86 | + const { attributes, instanceId } = this.props; |
| 87 | + const { isDropdown } = attributes; |
| 88 | + const categories = getCategories( attributes ); |
| 89 | + const classes = classnames( { |
| 90 | + 'wc-block-product-categories': true, |
| 91 | + 'is-dropdown': isDropdown, |
| 92 | + 'is-list': ! isDropdown, |
| 93 | + } ); |
| 94 | + |
| 95 | + const selectId = `prod-categories-${ instanceId }`; |
| 96 | + |
| 97 | + return ( |
| 98 | + <div className={ classes }> |
| 99 | + { isDropdown ? ( |
| 100 | + <Fragment> |
| 101 | + <div className="wc-block-product-categories__dropdown"> |
| 102 | + <label className="screen-reader-text" htmlFor={ selectId }> |
| 103 | + { __( 'Select a category', 'woo-gutenberg-products-block' ) } |
| 104 | + </label> |
| 105 | + <select id={ selectId } ref={ this.select }> |
| 106 | + <option value="false" hidden> |
| 107 | + { __( 'Select a category', 'woo-gutenberg-products-block' ) } |
| 108 | + </option> |
| 109 | + { this.renderOptions( categories ) } |
| 110 | + </select> |
| 111 | + </div> |
| 112 | + <IconButton |
| 113 | + icon="arrow-right-alt2" |
| 114 | + label={ __( 'Go to category', 'woo-gutenberg-products-block' ) } |
| 115 | + onClick={ this.onNavigate } |
| 116 | + /> |
| 117 | + </Fragment> |
| 118 | + ) : ( |
| 119 | + this.renderList( categories ) |
| 120 | + ) } |
| 121 | + </div> |
| 122 | + ); |
| 123 | + } |
| 124 | +} |
62 | 125 |
|
63 | 126 | ProductCategoriesBlock.propTypes = { |
64 | 127 | /** |
65 | | - * The attributes for this block |
| 128 | + * The attributes for this block. |
66 | 129 | */ |
67 | 130 | attributes: PropTypes.object.isRequired, |
| 131 | + /** |
| 132 | + * A unique ID for identifying the label for the select dropdown. |
| 133 | + */ |
| 134 | + instanceId: PropTypes.number, |
68 | 135 | /** |
69 | 136 | * Whether this is the block preview or frontend display. |
70 | 137 | */ |
71 | 138 | isPreview: PropTypes.bool, |
72 | 139 | }; |
73 | 140 |
|
74 | | -export default ProductCategoriesBlock; |
| 141 | +export default withInstanceId( ProductCategoriesBlock ); |
0 commit comments