Refactor main products block for better maintainability

This commit is contained in:
claudiulodro 2018-04-04 12:26:23 -07:00
parent c8dfecdf9a
commit 24898d007d
2 changed files with 410 additions and 228 deletions

View File

@ -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);
},

View File

@ -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 = (
<RangeControl
label={ __( 'Columns' ) }
value={ columns }
onChange={ ( value ) => 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 = (
<SelectControl
key="query-panel-select"
label={ __( 'Order Products By' ) }
value={ orderby }
options={ [
{
label: __( 'Newness - newest first' ),
value: 'date',
},
{
label: __( 'Price - low to high' ),
value: 'price_asc',
},
{
label: __( 'Price - high to low' ),
value: 'price_desc',
},
{
label: __( 'Rating - highest first' ),
value: 'rating',
},
{
label: __( 'Sales - most first' ),
value: 'popularity',
},
{
label: __( 'Title - alphabetical' ),
value: 'title',
},
] }
onChange={ ( value ) => setAttributes( { orderby: value } ) }
/>
);
}
return (
<InspectorControls key="inspector">
<h3>{ __( 'Layout' ) }</h3>
{ columnControl }
<RangeControl
label={ __( 'Rows' ) }
value={ rows }
onChange={ ( value ) => setAttributes( { rows: value } ) }
min={ wc_product_block_data.min_rows }
max={ wc_product_block_data.max_rows }
/>
{ orderControl }
</InspectorControls>
);
}
/**
* 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 (
<BlockControls key="controls">
<Toolbar controls={ editButton } />
</BlockControls>
);
}
/**
* 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 = <a className="change-quicklink" onClick={ () => { setAttributes( { edit_mode: true } ); } } >{ __( 'Edit' ) }</a>;
}
return (
<InspectorControls key="description-inspector">
<h3>{ __( 'Current Source' ) }</h3>
<div className="wc-products-selected-scope-description">
<span className="selected-scope">
{ PRODUCTS_BLOCK_DISPLAY_SETTINGS[ display ].title }
</span>
{ editLink }
</div>
</InspectorControls>
);
}
/**
* Get the block preview component for preview mode.
*
* @return Component
*/
getPreview() {
return <ProductsBlockPreview attributes={ this.props.attributes } />;
}
/**
* 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 (
<ProductsBlockSettingsEditor
selected_display={ display }
selected_display_setting={ display_setting }
update_display_callback={ update_display_callback }
update_display_setting_callback={ ( value ) => 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 = (
<RangeControl
label={ __( 'Columns' ) }
value={ columns }
onChange={ ( value ) => 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 = (
<SelectControl
key="query-panel-select"
label={ __( 'Order Products By' ) }
value={ orderby }
options={ [
{
label: __( 'Newness - newest first' ),
value: 'date',
},
{
label: __( 'Price - low to high' ),
value: 'price_asc',
},
{
label: __( 'Price - high to low' ),
value: 'price_desc',
},
{
label: __( 'Rating - highest first' ),
value: 'rating',
},
{
label: __( 'Sales - most first' ),
value: 'popularity',
},
{
label: __( 'Title - alphabetical' ),
value: 'title',
},
] }
onChange={ ( value ) => setAttributes( { orderby: value } ) }
/>
);
}
return (
<InspectorControls key="inspector">
<h3>{ __( 'Layout' ) }</h3>
{ columnControl }
<RangeControl
label={ __( 'Rows' ) }
value={ rows }
onChange={ ( value ) => setAttributes( { rows: value } ) }
min={ wc_product_block_data.min_rows }
max={ wc_product_block_data.max_rows }
/>
{ orderControl }
</InspectorControls>
);
};
/**
* 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 (
<BlockControls key="controls">
<Toolbar controls={ editButton } />
</BlockControls>
);
}
/**
* Get the block preview component for preview mode.
*
* @return Component
*/
function getPreview() {
return <ProductsBlockPreview attributes={ attributes } />;
}
/**
* 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 (
<ProductsBlockSettingsEditor
selected_display={ display }
selected_display_setting={ display_setting }
update_display_callback={ update_display_callback }
update_display_setting_callback={ ( value ) => setAttributes( { display_setting: value } ) }
done_callback={ () => setAttributes( { edit_mode: false } ) }
/>
);
}
return [
( !! focus ) ? getInspectorControls() : null,
( !! focus ) ? getToolbarControls() : null,
edit_mode ? getSettingsEditor() : getPreview(),
];
return <ProductsBlock { ...props } />
},
/**