Home Reference Source

src/components/actions/ButtonContainer.js

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { DropdownMenu, Button } from 'reactstrap';
import { createStructuredSelector } from 'reselect';
import cx from 'classnames';

import { registerButton } from '../../actions/toolbar';
import {
  isDisabledSelector,
  isInitSelector,
  isVisibleSelector,
  titleSelector,
  countSelector,
  sizeSelector,
  colorSelector,
  iconSelector,
  classSelector,
  hintSelector,
  hintPositionSelector,
  styleSelector,
} from '../../selectors/toolbar';
import withTooltip from '../../utils/withTooltip';
import { id } from '../../utils/id';
import Dropdown from './Dropdowns/Dropdown';

/**
 * кнопка-контейнер
 */
class ButtonContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.buttonId = id();
  }

  /**
   * Диспатч экшена регистрации виджета
   */
  static initIfNeeded(props) {
    const {
      isInit,
      dispatch,
      id,
      parentId,
      containerKey,
      initialProps: {
        visible = true,
        disabled = false,
        size,
        color,
        count,
        title,
        icon,
        hint,
        className,
        style,
        conditions,
        resolveEnabled,
        hintPosition,
      },
    } = props;
    !isInit &&
      dispatch(
        registerButton(containerKey, id, {
          id,
          visible,
          disabled,
          size,
          parentId,
          color,
          icon,
          count,
          title,
          hint,
          className,
          style,
          conditions,
          containerKey,
          resolveEnabled,
          hintPosition,
        })
      );
  }

  static getDerivedStateFromProps(props, state) {
    ButtonContainer.initIfNeeded(props);
    return null;
  }

  /**
   * рендер кнопки или элемента списка
   * @returns {*}
   */
  renderButton() {
    const {
      onClick,
      count,
      icon,
      className,
      disabled,
      size,
      color,
      visible,
      title,
      hint,
      btnKey,
      component,
    } = this.props;

    const style = title ? { marginRight: 3 } : null;
    const counter =
      (count || '') && count > 0 ? (
        <span
          className={cx('badge', {
            'badge-light': color !== 'secondary',
            'badge-dark': color === 'secondary',
          })}
        >
          {count}
        </span>
      ) : (
        ''
      );

    return React.createElement(
      component,
      {
        key: this.buttonId,
        id: this.buttonId,
        onClick,
        disabled,
        size,
        color,
        className,
      },
      <React.Fragment>
        <span style={style}>
          <i className={icon} />
        </span>
        {title} {counter}
      </React.Fragment>
    );
  }

  /**
   * рендер кнопки дропдауна
   * @returns {*}
   */
  renderDropdown() {
    const { children, icon, color, title, disabled } = this.props;
    return (
      <Dropdown
        id={this.buttonId}
        disabled={disabled}
        color={color}
        title={
          <span>
            <i className={icon} /> {title}
          </span>
        }
      >
        {children}
      </Dropdown>
    );
  }

  /**
   *Базовый рендер
   */
  render() {
    const {
      visible,
      disabled,
      size,
      title,
      count,
      color,
      icon,
      hint,
      hintPosition,
      component,
    } = this.props;
    const isDropdown = component === DropdownMenu;

    return isDropdown ? (
      <div className={cx(visible ? 'd-block' : 'd-none')}>
        {withTooltip(this.renderDropdown(), hint, hintPosition, this.buttonId)}
      </div>
    ) : visible ? (
      withTooltip(this.renderButton(), hint, hintPosition, this.buttonId)
    ) : null;
  }
}

const mapStateToProps = createStructuredSelector({
  isInit: (state, ownProps) =>
    isInitSelector(ownProps.containerKey, ownProps.id)(state),
  visible: (state, ownProps) =>
    isVisibleSelector(ownProps.containerKey, ownProps.id)(state),
  disabled: (state, ownProps) =>
    isDisabledSelector(ownProps.containerKey, ownProps.id)(state),
  color: (state, ownProps) =>
    colorSelector(ownProps.containerKey, ownProps.id)(state),
  size: (state, ownProps) =>
    sizeSelector(ownProps.containerKey, ownProps.id)(state),
  title: (state, ownProps) =>
    titleSelector(ownProps.containerKey, ownProps.id)(state),
  count: (state, ownProps) =>
    countSelector(ownProps.containerKey, ownProps.id)(state),
  icon: (state, ownProps) =>
    iconSelector(ownProps.containerKey, ownProps.id)(state),
  hint: (state, ownProps) =>
    hintSelector(ownProps.containerKey, ownProps.id)(state),
  hintPosition: (state, ownProps) =>
    hintPositionSelector(ownProps.containerKey, ownProps.id)(state),
  className: (state, ownProps) =>
    classSelector(ownProps.containerKey, ownProps.id)(state),
  style: (state, ownProps) =>
    styleSelector(ownProps.containerKey, ownProps.id)(state),
});

ButtonContainer.propTypes = {
  isInit: PropTypes.bool,
  visible: PropTypes.bool,
  disabled: PropTypes.bool,
  color: PropTypes.string,
  size: PropTypes.string,
  title: PropTypes.string,
  count: PropTypes.number,
  icon: PropTypes.string,
  hint: PropTypes.string,
  hintPosition: PropTypes.string,
  className: PropTypes.string,
  style: PropTypes.object,
};

ButtonContainer.defaultProps = {
  visible: true,
  disabled: false,
};

export default connect(mapStateToProps)(ButtonContainer);