/** * External dependencies */ import { __, sprintf, _n } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; import { InspectorControls, BlockControls } from '@wordpress/block-editor'; import { Placeholder, Disabled, PanelBody, ToggleControl, Button, ToolbarGroup, withSpokenMessages, } from '@wordpress/components'; import { Icon, server, external } from '@woocommerce/icons'; import { SearchListControl } from '@woocommerce/components'; import { mapValues, toArray, sortBy, find } from 'lodash'; import { getAdminLink, getSetting } from '@woocommerce/settings'; import HeadingToolbar from '@woocommerce/editor-components/heading-toolbar'; import BlockTitle from '@woocommerce/editor-components/block-title'; import ToggleButtonControl from '@woocommerce/editor-components/toggle-button-control'; /** * Internal dependencies */ import Block from './block.js'; import './editor.scss'; const ATTRIBUTES = getSetting( 'attributes', [] ); const Edit = ( { attributes, setAttributes, debouncedSpeak } ) => { const { attributeId, className, displayStyle, heading, headingLevel, isPreview, queryType, showCounts, showFilterButton, } = attributes; const [ isEditing, setIsEditing ] = useState( ! attributeId && ! isPreview ); const getBlockControls = () => { return ( <BlockControls> <ToolbarGroup controls={ [ { icon: 'edit', title: __( 'Edit', 'woocommerce' ), onClick: () => setIsEditing( ! isEditing ), isActive: isEditing, }, ] } /> </BlockControls> ); }; const getInspectorControls = () => { return ( <InspectorControls key="inspector"> <PanelBody title={ __( 'Content', 'woocommerce' ) } > <ToggleControl label={ __( 'Product count', 'woocommerce' ) } help={ showCounts ? __( 'Product count is visible.', 'woocommerce' ) : __( 'Product count is hidden.', 'woocommerce' ) } checked={ showCounts } onChange={ () => setAttributes( { showCounts: ! showCounts, } ) } /> <p> { __( 'Heading Level', 'woocommerce' ) } </p> <HeadingToolbar isCollapsed={ false } minLevel={ 2 } maxLevel={ 7 } selectedLevel={ headingLevel } onChange={ ( newLevel ) => setAttributes( { headingLevel: newLevel } ) } /> </PanelBody> <PanelBody title={ __( 'Block Settings', 'woocommerce' ) } > <ToggleButtonControl label={ __( 'Query Type', 'woocommerce' ) } help={ queryType === 'and' ? __( 'Products that have all of the selected attributes will be shown.', 'woocommerce' ) : __( 'Products that have any of the selected attributes will be shown.', 'woocommerce' ) } value={ queryType } options={ [ { label: __( 'And', 'woocommerce' ), value: 'and', }, { label: __( 'Or', 'woocommerce' ), value: 'or', }, ] } onChange={ ( value ) => setAttributes( { queryType: value, } ) } /> <ToggleButtonControl label={ __( 'Display Style', 'woocommerce' ) } value={ displayStyle } options={ [ { label: __( 'List', 'woocommerce' ), value: 'list', }, { label: __( 'Dropdown', 'woocommerce' ), value: 'dropdown', }, ] } onChange={ ( value ) => setAttributes( { displayStyle: value, } ) } /> <ToggleControl label={ __( 'Filter button', 'woocommerce' ) } help={ showFilterButton ? __( 'Products will only update when the button is pressed.', 'woocommerce' ) : __( 'Products will update as options are selected.', 'woocommerce' ) } checked={ showFilterButton } onChange={ ( value ) => setAttributes( { showFilterButton: value, } ) } /> </PanelBody> <PanelBody title={ __( 'Filter Products by Attribute', 'woocommerce' ) } initialOpen={ false } > { renderAttributeControl() } </PanelBody> </InspectorControls> ); }; const noAttributesPlaceholder = () => ( <Placeholder className="wc-block-attribute-filter" icon={ <Icon srcElement={ server } /> } label={ __( 'Filter Products by Attribute', 'woocommerce' ) } instructions={ __( 'Display a list of filters based on a chosen attribute.', 'woocommerce' ) } > <p> { __( "Attributes are needed for filtering your products. You haven't created any attributes yet.", 'woocommerce' ) } </p> <Button className="wc-block-attribute-filter__add-attribute-button" isSecondary href={ getAdminLink( 'edit.php?post_type=product&page=product_attributes' ) } > { __( 'Add new attribute', 'woocommerce' ) + ' ' } <Icon srcElement={ external } /> </Button> <Button className="wc-block-attribute-filter__read_more_button" isTertiary href="https://docs.woocommerce.com/document/managing-product-taxonomies/" > { __( 'Learn more', 'woocommerce' ) } </Button> </Placeholder> ); const onDone = () => { setIsEditing( false ); debouncedSpeak( __( 'Showing Filter Products by Attribute block preview.', 'woocommerce' ) ); }; const onChange = ( selected ) => { if ( ! selected || ! selected.length ) { return; } const selectedId = selected[ 0 ].id; const productAttribute = find( ATTRIBUTES, [ 'attribute_id', selectedId.toString(), ] ); if ( ! productAttribute || attributeId === selectedId ) { return; } const attributeName = productAttribute.attribute_label; setAttributes( { attributeId: selectedId, heading: sprintf( /* translators: %s attribute name. */ __( 'Filter by %s', 'woocommerce' ), attributeName ), } ); }; const renderAttributeControl = () => { const messages = { clear: __( 'Clear selected attribute', 'woocommerce' ), list: __( 'Product Attributes', 'woocommerce' ), noItems: __( "Your store doesn't have any product attributes.", 'woocommerce' ), search: __( 'Search for a product attribute:', 'woocommerce' ), selected: ( n ) => sprintf( /* translators: %d is the number of attributes selected. */ _n( '%d attribute selected', '%d attributes selected', n, 'woocommerce' ), n ), updated: __( 'Product attribute search results updated.', 'woocommerce' ), }; const list = sortBy( toArray( mapValues( ATTRIBUTES, ( item ) => { return { id: parseInt( item.attribute_id, 10 ), name: item.attribute_label, }; } ) ), 'name' ); return ( <SearchListControl className="woocommerce-product-attributes" list={ list } selected={ list.filter( ( { id } ) => id === attributeId ) } onChange={ onChange } messages={ messages } isSingle /> ); }; const renderEditMode = () => { return ( <Placeholder className="wc-block-attribute-filter" icon={ <Icon srcElement={ server } /> } label={ __( 'Filter Products by Attribute', 'woocommerce' ) } instructions={ __( 'Display a list of filters based on a chosen attribute.', 'woocommerce' ) } > <div className="wc-block-attribute-filter__selection"> { renderAttributeControl() } <Button isPrimary onClick={ onDone }> { __( 'Done', 'woocommerce' ) } </Button> </div> </Placeholder> ); }; return Object.keys( ATTRIBUTES ).length === 0 ? ( noAttributesPlaceholder() ) : ( <> { getBlockControls() } { getInspectorControls() } { isEditing ? ( renderEditMode() ) : ( <div className={ className }> <BlockTitle headingLevel={ headingLevel } heading={ heading } onChange={ ( value ) => setAttributes( { heading: value } ) } /> <Disabled> <Block attributes={ attributes } isEditor /> </Disabled> </div> ) } </> ); }; export default withSpokenMessages( Edit );