From 24898d007d5f8d35dae8a917d08d8e9d0a724fcb Mon Sep 17 00:00:00 2001 From: claudiulodro Date: Wed, 4 Apr 2018 12:26:23 -0700 Subject: [PATCH] Refactor main products block for better maintainability --- .../assets/js/products-block.js | 278 ++++++++++---- .../assets/js/products-block.jsx | 360 +++++++++++------- 2 files changed, 410 insertions(+), 228 deletions(-) diff --git a/plugins/woocommerce-blocks/assets/js/products-block.js b/plugins/woocommerce-blocks/assets/js/products-block.js index 74b56bb0326..204728df9ad 100644 --- a/plugins/woocommerce-blocks/assets/js/products-block.js +++ b/plugins/woocommerce-blocks/assets/js/products-block.js @@ -647,87 +647,48 @@ var ProductsBlockPreview = withAPIData(function (_ref) { }); /** - * Register and run the products block. + * The main products block UI. */ -registerBlockType('woocommerce/products', { - title: __('Products'), - icon: 'screenoptions', - category: 'widgets', - attributes: { - - /** - * Number of columns. - */ - columns: { - type: 'number', - default: wc_product_block_data.default_columns - }, - - /** - * Number of rows. - */ - rows: { - type: 'number', - default: wc_product_block_data.default_rows - }, - - /** - * What types of products to display. 'all', 'specific', or 'category'. - */ - display: { - type: 'string', - default: '' - }, - - /** - * Which products to display if 'display' is 'specific' or 'category'. Array of product ids or category slugs depending on setting. - */ - display_setting: { - type: 'array', - default: [] - }, - - /** - * How to order the products: 'date', 'popularity', 'price_asc', 'price_desc' 'rating', 'title'. - */ - orderby: { - type: 'string', - default: 'date' - }, - - /** - * Whether the block is in edit or preview mode. - */ - edit_mode: { - type: 'boolean', - default: true - } - }, +var ProductsBlock = function (_React$Component5) { + _inherits(ProductsBlock, _React$Component5); /** - * Renders and manages the block. + * Constructor. */ - edit: function edit(props) { - var attributes = props.attributes, - className = props.className, - focus = props.focus, - setAttributes = props.setAttributes, - setFocus = props.setFocus; - var rows = attributes.rows, - columns = attributes.columns, - display = attributes.display, - display_setting = attributes.display_setting, - orderby = attributes.orderby, - edit_mode = attributes.edit_mode; + function ProductsBlock(props) { + _classCallCheck(this, ProductsBlock); - /** - * Get the components for the sidebar settings area that is rendered while focused on a Products block. - * - * @return Component - */ + var _this7 = _possibleConstructorReturn(this, (ProductsBlock.__proto__ || Object.getPrototypeOf(ProductsBlock)).call(this, props)); + + _this7.getInspectorControls = _this7.getInspectorControls.bind(_this7); + _this7.getToolbarControls = _this7.getToolbarControls.bind(_this7); + _this7.getBlockDescription = _this7.getBlockDescription.bind(_this7); + _this7.getPreview = _this7.getPreview.bind(_this7); + _this7.getSettingsEditor = _this7.getSettingsEditor.bind(_this7); + return _this7; + } + + /** + * Get the components for the sidebar settings area that is rendered while focused on a Products block. + * + * @return Component + */ + + + _createClass(ProductsBlock, [{ + key: 'getInspectorControls', + value: function getInspectorControls() { + var _props2 = this.props, + attributes = _props2.attributes, + setAttributes = _props2.setAttributes; + var rows = attributes.rows, + columns = attributes.columns, + display = attributes.display, + display_setting = attributes.display_setting, + orderby = attributes.orderby, + edit_mode = attributes.edit_mode; - function getInspectorControls() { var columnControl = wp.element.createElement(RangeControl, { label: __('Columns'), @@ -791,16 +752,26 @@ registerBlockType('woocommerce/products', { }), orderControl ); - }; + } /** * Get the components for the toolbar area that appears on top of the block when focused. * * @return Component */ - function getToolbarControls() { + + }, { + key: 'getToolbarControls', + value: function getToolbarControls() { + var props = this.props; + var attributes = props.attributes, + setAttributes = props.setAttributes; + var display = attributes.display, + display_setting = attributes.display_setting, + edit_mode = attributes.edit_mode; // Edit button should not do anything if valid product selection has not been made. + var shouldDisableEditButton = ['', 'specific', 'category', 'attribute'].includes(display) && !display_setting.length; var editButton = [{ @@ -819,13 +790,70 @@ registerBlockType('woocommerce/products', { ); } + /** + * Get a description of the current block settings. + * + * @return Component + */ + + }, { + key: 'getBlockDescription', + value: function getBlockDescription() { + var _props3 = this.props, + attributes = _props3.attributes, + setAttributes = _props3.setAttributes; + var display = attributes.display, + display_setting = attributes.display_setting, + edit_mode = attributes.edit_mode; + + + if (!display.length) { + return null; + } + + var editLink = null; + if (!edit_mode) { + // @todo needs to center in view also + editLink = wp.element.createElement( + 'a', + { className: 'change-quicklink', onClick: function onClick() { + setAttributes({ edit_mode: true }); + } }, + __('Edit') + ); + } + + return wp.element.createElement( + InspectorControls, + { key: 'description-inspector' }, + wp.element.createElement( + 'h3', + null, + __('Current Source') + ), + wp.element.createElement( + 'div', + { className: 'wc-products-selected-scope-description' }, + wp.element.createElement( + 'span', + { className: 'selected-scope' }, + PRODUCTS_BLOCK_DISPLAY_SETTINGS[display].title + ), + editLink + ) + ); + } + /** * Get the block preview component for preview mode. * * @return Component */ - function getPreview() { - return wp.element.createElement(ProductsBlockPreview, { attributes: attributes }); + + }, { + key: 'getPreview', + value: function getPreview() { + return wp.element.createElement(ProductsBlockPreview, { attributes: this.props.attributes }); } /** @@ -833,7 +861,16 @@ registerBlockType('woocommerce/products', { * * @return Component */ - function getSettingsEditor() { + + }, { + key: 'getSettingsEditor', + value: function getSettingsEditor() { + var _props4 = this.props, + attributes = _props4.attributes, + setAttributes = _props4.setAttributes; + var display = attributes.display, + display_setting = attributes.display_setting; + var update_display_callback = function update_display_callback(value) { @@ -861,8 +898,89 @@ registerBlockType('woocommerce/products', { } }); } + }, { + key: 'render', + value: function render() { + var _props5 = this.props, + attributes = _props5.attributes, + focus = _props5.focus; + var edit_mode = attributes.edit_mode; - return [!!focus ? getInspectorControls() : null, !!focus ? getToolbarControls() : null, edit_mode ? getSettingsEditor() : getPreview()]; + + return [!!focus ? this.getBlockDescription() : null, !!focus ? this.getInspectorControls() : null, !!focus ? this.getToolbarControls() : null, edit_mode ? this.getSettingsEditor() : this.getPreview()]; + } + }]); + + return ProductsBlock; +}(React.Component); + +/** + * Register and run the products block. + */ + + +registerBlockType('woocommerce/products', { + title: __('Products'), + icon: 'screenoptions', + category: 'widgets', + description: __('Display a grid of products from a variety of sources.'), + + attributes: { + + /** + * Number of columns. + */ + columns: { + type: 'number', + default: wc_product_block_data.default_columns + }, + + /** + * Number of rows. + */ + rows: { + type: 'number', + default: wc_product_block_data.default_rows + }, + + /** + * What types of products to display. 'all', 'specific', or 'category'. + */ + display: { + type: 'string', + default: '' + }, + + /** + * Which products to display if 'display' is 'specific' or 'category'. Array of product ids or category slugs depending on setting. + */ + display_setting: { + type: 'array', + default: [] + }, + + /** + * How to order the products: 'date', 'popularity', 'price_asc', 'price_desc' 'rating', 'title'. + */ + orderby: { + type: 'string', + default: 'date' + }, + + /** + * Whether the block is in edit or preview mode. + */ + edit_mode: { + type: 'boolean', + default: true + } + }, + + /** + * Renders and manages the block. + */ + edit: function edit(props) { + return wp.element.createElement(ProductsBlock, props); }, diff --git a/plugins/woocommerce-blocks/assets/js/products-block.jsx b/plugins/woocommerce-blocks/assets/js/products-block.jsx index 8182fb7ab05..c77ac750018 100644 --- a/plugins/woocommerce-blocks/assets/js/products-block.jsx +++ b/plugins/woocommerce-blocks/assets/js/products-block.jsx @@ -227,7 +227,7 @@ class ProductsBlockSettingsEditor extends React.Component { closeMenu() { this.setState( { - menu_visible: false + menu_visible: false, } ); } @@ -391,6 +391,215 @@ const ProductsBlockPreview = withAPIData( ( { attributes } ) => { ); } ); +/** + * The main products block UI. + */ +class ProductsBlock extends React.Component { + + /** + * Constructor. + */ + constructor( props ) { + super( props ); + + this.getInspectorControls = this.getInspectorControls.bind( this ); + this.getToolbarControls = this.getToolbarControls.bind( this ); + this.getBlockDescription = this.getBlockDescription.bind( this ); + this.getPreview = this.getPreview.bind( this ); + this.getSettingsEditor = this.getSettingsEditor.bind( this ); + } + + /** + * Get the components for the sidebar settings area that is rendered while focused on a Products block. + * + * @return Component + */ + getInspectorControls() { + const { attributes, setAttributes } = this.props; + const { rows, columns, display, display_setting, orderby, edit_mode } = attributes; + + let columnControl = ( + setAttributes( { columns: value } ) } + min={ wc_product_block_data.min_columns } + max={ wc_product_block_data.max_columns } + /> + ); + + // Orderby settings don't make sense for specific-selected products display. + let orderControl = null; + if ( 'specific' !== display ) { + orderControl = ( + setAttributes( { orderby: value } ) } + /> + ); + } + + return ( + +

{ __( 'Layout' ) }

+ { columnControl } + setAttributes( { rows: value } ) } + min={ wc_product_block_data.min_rows } + max={ wc_product_block_data.max_rows } + /> + { orderControl } +
+ ); + } + + /** + * Get the components for the toolbar area that appears on top of the block when focused. + * + * @return Component + */ + getToolbarControls() { + let props = this.props; + const { attributes, setAttributes } = props; + const { display, display_setting, edit_mode } = attributes; + + // Edit button should not do anything if valid product selection has not been made. + const shouldDisableEditButton = ['', 'specific', 'category', 'attribute'].includes( display ) && ! display_setting.length; + + const editButton = [ + { + icon: 'edit', + title: __( 'Edit' ), + onClick: shouldDisableEditButton ? function(){} : () => setAttributes( { edit_mode: ! edit_mode } ), + isActive: edit_mode, + }, + ]; + + return ( + + + + ); + } + + /** + * Get a description of the current block settings. + * + * @return Component + */ + getBlockDescription() { + const { attributes, setAttributes } = this.props; + const { display, display_setting, edit_mode } = attributes; + + if ( ! display.length ) { + return null; + } + + let editLink = null; + if ( ! edit_mode ) { + // @todo needs to center in view also + editLink = { setAttributes( { edit_mode: true } ); } } >{ __( 'Edit' ) }; + } + + return ( + +

{ __( 'Current Source' ) }

+
+ + { PRODUCTS_BLOCK_DISPLAY_SETTINGS[ display ].title } + + { editLink } +
+
+ ); + } + + /** + * Get the block preview component for preview mode. + * + * @return Component + */ + getPreview() { + return ; + } + + /** + * Get the block edit component for edit mode. + * + * @return Component + */ + getSettingsEditor() { + const { attributes, setAttributes } = this.props; + const { display, display_setting } = attributes; + + const update_display_callback = ( value ) => { + + // These options have setting screens that need further input from the user, so keep edit mode open. + const needsFurtherSettings = [ 'specific', 'attribute', 'category' ]; + + if ( display !== value ) { + setAttributes( { + display: value, + display_setting: [], + edit_mode: needsFurtherSettings.includes( value ), + } ); + } + }; + + return ( + setAttributes( { display_setting: value } ) } + done_callback={ () => setAttributes( { edit_mode: false } ) } + /> + ); + } + + render() { + const { attributes, focus } = this.props; + const { edit_mode } = attributes; + + return [ + ( !! focus ) ? this.getBlockDescription() : null, + ( !! focus ) ? this.getInspectorControls() : null, + ( !! focus ) ? this.getToolbarControls() : null, + edit_mode ? this.getSettingsEditor() : this.getPreview(), + ]; + } +} + /** * Register and run the products block. */ @@ -398,6 +607,7 @@ registerBlockType( 'woocommerce/products', { title: __( 'Products' ), icon: 'screenoptions', category: 'widgets', + description: __( 'Display a grid of products from a variety of sources.' ), attributes: { @@ -454,153 +664,7 @@ registerBlockType( 'woocommerce/products', { * Renders and manages the block. */ edit( props ) { - const { attributes, className, focus, setAttributes, setFocus } = props; - const { rows, columns, display, display_setting, orderby, edit_mode } = attributes; - - /** - * Get the components for the sidebar settings area that is rendered while focused on a Products block. - * - * @return Component - */ - function getInspectorControls() { - - let columnControl = ( - setAttributes( { columns: value } ) } - min={ wc_product_block_data.min_columns } - max={ wc_product_block_data.max_columns } - /> - ); - - // Orderby settings don't make sense for specific-selected products display. - let orderControl = null; - if ( 'specific' !== display ) { - orderControl = ( - setAttributes( { orderby: value } ) } - /> - ); - } - - return ( - -

{ __( 'Layout' ) }

- { columnControl } - setAttributes( { rows: value } ) } - min={ wc_product_block_data.min_rows } - max={ wc_product_block_data.max_rows } - /> - { orderControl } -
- ); - }; - - /** - * Get the components for the toolbar area that appears on top of the block when focused. - * - * @return Component - */ - function getToolbarControls() { - - // Edit button should not do anything if valid product selection has not been made. - const shouldDisableEditButton = ['', 'specific', 'category', 'attribute'].includes( display ) && ! display_setting.length; - - const editButton = [ - { - icon: 'edit', - title: __( 'Edit' ), - onClick: shouldDisableEditButton ? function(){} : () => setAttributes( { edit_mode: ! edit_mode } ), - isActive: edit_mode, - }, - ]; - - return ( - - - - ); - } - - /** - * Get the block preview component for preview mode. - * - * @return Component - */ - function getPreview() { - return ; - } - - /** - * Get the block edit component for edit mode. - * - * @return Component - */ - function getSettingsEditor() { - - const update_display_callback = ( value ) => { - - // These options have setting screens that need further input from the user, so keep edit mode open. - const needsFurtherSettings = [ 'specific', 'attribute', 'category' ]; - - if ( display !== value ) { - setAttributes( { - display: value, - display_setting: [], - edit_mode: needsFurtherSettings.includes( value ), - } ); - } - }; - - return ( - setAttributes( { display_setting: value } ) } - done_callback={ () => setAttributes( { edit_mode: false } ) } - /> - ); - } - - return [ - ( !! focus ) ? getInspectorControls() : null, - ( !! focus ) ? getToolbarControls() : null, - edit_mode ? getSettingsEditor() : getPreview(), - ]; + return }, /**