2019-01-31 01:04:11 +00:00
|
|
|
/** @format */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2019-03-06 05:32:05 +00:00
|
|
|
import { Button } from '@wordpress/components';
|
2019-01-31 01:04:11 +00:00
|
|
|
import { Component } from '@wordpress/element';
|
2019-03-06 05:32:05 +00:00
|
|
|
import { compose } from '@wordpress/compose';
|
2019-01-31 01:04:11 +00:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { uniqueId } from 'lodash';
|
2019-03-06 05:32:05 +00:00
|
|
|
import { withDispatch } from '@wordpress/data';
|
2019-01-31 01:04:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import './setting.scss';
|
|
|
|
|
|
|
|
class Setting extends Component {
|
2019-03-06 05:32:05 +00:00
|
|
|
constructor( props ) {
|
|
|
|
super( props );
|
|
|
|
this.state = {
|
|
|
|
disabled: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-01-31 01:04:11 +00:00
|
|
|
renderInput = () => {
|
2019-05-22 21:43:04 +00:00
|
|
|
const { handleChange, name, inputText, inputType, options, value, component } = this.props;
|
2019-03-06 05:32:05 +00:00
|
|
|
const { disabled } = this.state;
|
2019-01-31 01:04:11 +00:00
|
|
|
const id = uniqueId( name );
|
|
|
|
|
|
|
|
switch ( inputType ) {
|
|
|
|
case 'checkboxGroup':
|
|
|
|
return options.map(
|
|
|
|
optionGroup =>
|
|
|
|
optionGroup.options.length > 0 && (
|
|
|
|
<div
|
|
|
|
className="woocommerce-setting__options-group"
|
|
|
|
key={ optionGroup.key }
|
|
|
|
aria-labelledby={ name + '-label' }
|
|
|
|
>
|
|
|
|
{ optionGroup.label && (
|
|
|
|
<span className="woocommerce-setting__options-group-label">
|
|
|
|
{ optionGroup.label }
|
|
|
|
</span>
|
|
|
|
) }
|
|
|
|
{ this.renderCheckboxOptions( optionGroup.options ) }
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
);
|
|
|
|
case 'checkbox':
|
|
|
|
return this.renderCheckboxOptions( options );
|
2019-03-06 05:32:05 +00:00
|
|
|
case 'button':
|
|
|
|
return (
|
|
|
|
<Button isDefault onClick={ this.handleInputCallback } disabled={ disabled }>
|
|
|
|
{ inputText }
|
|
|
|
</Button>
|
|
|
|
);
|
2019-05-22 21:43:04 +00:00
|
|
|
case 'component':
|
|
|
|
const SettingComponent = component;
|
|
|
|
return <SettingComponent value={ value } onChange={ handleChange } { ...this.props } />;
|
2019-01-31 01:04:11 +00:00
|
|
|
case 'text':
|
|
|
|
default:
|
|
|
|
return (
|
2019-03-06 05:32:05 +00:00
|
|
|
<input
|
|
|
|
id={ id }
|
|
|
|
type="text"
|
|
|
|
name={ name }
|
|
|
|
onChange={ handleChange }
|
|
|
|
value={ value }
|
|
|
|
placeholder={ inputText }
|
|
|
|
disabled={ disabled }
|
|
|
|
/>
|
2019-01-31 01:04:11 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-06 05:32:05 +00:00
|
|
|
handleInputCallback = () => {
|
2019-07-23 03:26:46 +00:00
|
|
|
const { createNotice, callback } = this.props;
|
2019-03-06 05:32:05 +00:00
|
|
|
|
|
|
|
if ( 'function' !== typeof callback ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Promise( ( resolve, reject ) => {
|
|
|
|
this.setState( { disabled: true } );
|
2019-07-23 03:26:46 +00:00
|
|
|
callback( resolve, reject, createNotice );
|
2019-03-06 05:32:05 +00:00
|
|
|
} )
|
|
|
|
.then( () => {
|
|
|
|
this.setState( { disabled: false } );
|
|
|
|
} )
|
|
|
|
.catch( () => {
|
|
|
|
this.setState( { disabled: false } );
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2019-01-31 01:04:11 +00:00
|
|
|
renderCheckboxOptions( options ) {
|
|
|
|
const { handleChange, name, value } = this.props;
|
2019-03-06 05:32:05 +00:00
|
|
|
const { disabled } = this.state;
|
2019-01-31 01:04:11 +00:00
|
|
|
|
|
|
|
return options.map( option => {
|
|
|
|
const id = uniqueId( name + '-' + option.value );
|
|
|
|
return (
|
|
|
|
<label htmlFor={ id } key={ option.value }>
|
|
|
|
<input
|
|
|
|
id={ id }
|
|
|
|
type="checkbox"
|
|
|
|
name={ name }
|
|
|
|
onChange={ handleChange }
|
|
|
|
aria-label={ option.description }
|
|
|
|
checked={ value && value.includes( option.value ) }
|
|
|
|
value={ option.value }
|
2019-03-06 05:32:05 +00:00
|
|
|
disabled={ disabled }
|
2019-01-31 01:04:11 +00:00
|
|
|
/>
|
|
|
|
{ option.label }
|
|
|
|
</label>
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { helpText, label, name } = this.props;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="woocommerce-setting">
|
|
|
|
<div className="woocommerce-setting__label" id={ name + '-label' }>
|
|
|
|
{ label }
|
|
|
|
</div>
|
2019-03-06 05:32:05 +00:00
|
|
|
<div className="woocommerce-setting__input">
|
2019-01-31 01:04:11 +00:00
|
|
|
{ this.renderInput() }
|
|
|
|
{ helpText && <span className="woocommerce-setting__help">{ helpText }</span> }
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Setting.propTypes = {
|
2019-03-06 05:32:05 +00:00
|
|
|
/**
|
|
|
|
* A callback that is fired after actionable items, such as buttons.
|
|
|
|
*/
|
|
|
|
callback: PropTypes.func,
|
2019-01-31 01:04:11 +00:00
|
|
|
/**
|
|
|
|
* Function assigned to the onChange of all inputs.
|
|
|
|
*/
|
|
|
|
handleChange: PropTypes.func.isRequired,
|
|
|
|
/**
|
|
|
|
* Optional help text displayed underneath the setting.
|
|
|
|
*/
|
|
|
|
helpText: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array ] ),
|
2019-03-06 05:32:05 +00:00
|
|
|
/**
|
|
|
|
* Text used as placeholder or button text in the input area.
|
|
|
|
*/
|
|
|
|
inputText: PropTypes.string,
|
2019-01-31 01:04:11 +00:00
|
|
|
/**
|
|
|
|
* Type of input to use; defaults to a text input.
|
|
|
|
*/
|
2019-05-22 21:43:04 +00:00
|
|
|
inputType: PropTypes.oneOf( [ 'button', 'checkbox', 'checkboxGroup', 'text', 'component' ] ),
|
2019-01-31 01:04:11 +00:00
|
|
|
/**
|
|
|
|
* Label used for describing the setting.
|
|
|
|
*/
|
|
|
|
label: PropTypes.string.isRequired,
|
|
|
|
/**
|
|
|
|
* Setting slug applied to input names.
|
|
|
|
*/
|
|
|
|
name: PropTypes.string.isRequired,
|
|
|
|
/**
|
|
|
|
* Array of options used for when the `inputType` allows multiple selections.
|
|
|
|
*/
|
|
|
|
options: PropTypes.arrayOf(
|
|
|
|
PropTypes.shape( {
|
|
|
|
/**
|
|
|
|
* Input value for this option.
|
|
|
|
*/
|
|
|
|
value: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Label for this option or above a group for a group `inputType`.
|
|
|
|
*/
|
|
|
|
label: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Description used for screen readers.
|
|
|
|
*/
|
|
|
|
description: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Key used for a group `inputType`.
|
|
|
|
*/
|
|
|
|
key: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Nested options for a group `inputType`.
|
|
|
|
*/
|
|
|
|
options: PropTypes.array,
|
|
|
|
} )
|
|
|
|
),
|
|
|
|
/**
|
|
|
|
* The string value used for the input or array of items if the input allows multiselection.
|
|
|
|
*/
|
|
|
|
value: PropTypes.oneOfType( [ PropTypes.string, PropTypes.array ] ),
|
|
|
|
};
|
|
|
|
|
2019-03-06 05:32:05 +00:00
|
|
|
export default compose(
|
|
|
|
withDispatch( dispatch => {
|
2019-07-23 03:26:46 +00:00
|
|
|
const { createNotice } = dispatch( 'core/notices' );
|
|
|
|
return { createNotice };
|
2019-03-06 05:32:05 +00:00
|
|
|
} )
|
|
|
|
)( Setting );
|