'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Typeahead = undefined;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _bind = require('classnames/bind');

var _bind2 = _interopRequireDefault(_bind);

var _reactClickOutside = require('react-click-outside');

var _reactClickOutside2 = _interopRequireDefault(_reactClickOutside);

var _fuzzy = require('fuzzy');

var _fuzzy2 = _interopRequireDefault(_fuzzy);

var _debounce = require('lodash/debounce');

var _debounce2 = _interopRequireDefault(_debounce);

var _reactLoader = require('react-loader');

var _reactLoader2 = _interopRequireDefault(_reactLoader);

var _Input = require('../Input');

var _Input2 = _interopRequireDefault(_Input);

var _Icon = require('../Icon');

var _Icon2 = _interopRequireDefault(_Icon);

var _style = require('./style.scss');

var _style2 = _interopRequireDefault(_style);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Typeahead = exports.Typeahead = function (_React$Component) {
  _inherits(Typeahead, _React$Component);

  function Typeahead(props) {
    _classCallCheck(this, Typeahead);

    var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Typeahead).call(this, props));

    _this.state = {
      isActive: false,
      value: _this.props.value || '',
      results: [],
      selected: '',
      searchStr: ''
    };

    _this.componentWillMount = function () {
      if (typeof _this.state.value !== 'undefined' && _this.state.value !== '' && _this.getIndex(_this.state.value, _this.props.options) > -1) {
        _this.selectItem(_this.state.value, _this.props.options);
      } else {
        _this.setState({ selected: '' });
      }
    };

    _this.componentWillReceiveProps = function (nextProps) {
      if (nextProps.value && nextProps.value !== _this.state.value && _this.getIndex(nextProps.value, nextProps.options) > -1) {
        _this.setState({ value: nextProps.value }, function () {
          _this.selectItem(nextProps.value, nextProps.options);
        });
      }
    };

    _this.selectOption = function (option) {
      var normalizedOption = option.original ? option.original : option;

      var newState = {
        selected: normalizedOption,
        searchStr: normalizedOption[_this.props.displayProp],
        value: normalizedOption[_this.props.valueProp],
        isActive: false
      };

      if (_this.props.resetAfterSelection) {
        newState.searchStr = '';
        newState.value = '';

        // Focus the input field
        _this._inputField.focus();
      }

      _this.setState(newState, function () {
        if (typeof _this.props.changeCallback === 'function') {
          _this.props.changeCallback({
            target: {
              name: _this.props.name,
              value: normalizedOption[_this.props.valueProp],
              option: normalizedOption
            }
          });
        }
      });
    };

    _this.selectItem = function (value, options) {
      var index = _this.getIndex(value, options);
      if (index >= 0) {
        _this.selectOption(options[index], false);
      }
    };

    _this.getIndex = function (value, options) {
      var optionIndex = -1;
      options.map(function (option, index) {
        if (option[_this.props.valueProp] === value) {
          optionIndex = index;
        }
      });
      return optionIndex;
    };

    _this.handleChange = function (event) {
      if (!event.target.value.length) {
        _this.clearSearch();
        return;
      }

      _this.setState({ searchStr: event.target.value });
      if (typeof _this.props.searchCallback === 'function') {
        _this.props.searchCallback(event.target.value).then(function (options) {
          _this.updateResults(event, options);
        });
      } else {
        _this.updateResults(event, _this.props.options);
      }
    };

    _this.handleClickOutside = function () {
      _this.setState({ isActive: false });
    };

    _this.updateResults = function (event, options) {
      var str = {
        pre: '<b>',
        post: '</b>',
        extract: function extract(el) {
          return el[_this.props.displayProp];
        }
      };

      var results = _fuzzy2.default.filter(event.target.value, options, str);
      _this.setState({ results: results, isActive: true });
    };

    _this.getDynamicList = function (str) {
      return {
        __html: str
      };
    };

    _this.clearSearch = function () {
      _this.setState({ isActive: false, searchStr: '', selected: '', value: '' }, function () {
        if (typeof _this.props.changeCallback === 'function') {
          _this.props.changeCallback({
            target: {
              name: '',
              value: '',
              option: ''
            }
          });
        }
      });
    };

    _this.onChange = typeof _this.props.searchCallback === 'function' && props.searchDebounceTime > 0 ? (0, _debounce2.default)(_this.handleChange, props.searchDebounceTime) : _this.handleChange;
    return _this;
  }

  _createClass(Typeahead, [{
    key: 'render',
    value: function render() {
      var _this2 = this;

      var cx = _bind2.default.bind(_style2.default);
      var loaderClass = this.props.loading ? 'loading' : null;
      var typeaheadClass = cx(_style2.default['typeahead-component'], loaderClass, this.props.optClass);

      var spinnerOptions = {
        color: '#9198A0',
        length: 4,
        lines: 10,
        radius: 5,
        left: 'calc(100% - 21px)',
        width: 3
      };

      var options = this.state.results.map(function (option, index) {
        return _react2.default.createElement('li', {
          key: index,
          onClick: _this2.selectOption.bind(null, option, true),
          dangerouslySetInnerHTML: _this2.getDynamicList(option.string) });
      });

      return _react2.default.createElement(
        'div',
        { className: typeaheadClass },
        _react2.default.createElement(_Input2.default, { ref: function ref(c) {
            return _this2._inputField = c;
          }, changeCallback: this.onChange, value: this.state.searchStr, placeholder: this.props.placeholder, disabled: this.props.disabled }),
        this.state.searchStr !== '' && !this.props.loading && !this.props.disabled ? _react2.default.createElement(
          _Icon2.default,
          { name: 'icon-delete-1-1', onClick: this.clearSearch, className: _style2.default['reset-button'] },
          'Reset'
        ) : null,
        this.props.loading ? _react2.default.createElement(_reactLoader2.default, { loaded: false, options: spinnerOptions }) : null,
        this.state.isActive ? _react2.default.createElement(
          'ul',
          { className: _style2.default['typeahead-list'] },
          options
        ) : null
      );
    }
  }]);

  return Typeahead;
}(_react2.default.Component);

Typeahead.defaultProps = {
  disabled: false,
  options: [],
  valueProp: '',
  displayProp: '',
  resetAfterSelection: false,
  searchDebounceTime: 0
};
Typeahead.propTypes = {
  /**
   * A string to display as the placeholder text.
   */
  placeholder: _react2.default.PropTypes.string,
  /**
   * An array of objects which will be used as the options for the select field.
   */
  options: _react2.default.PropTypes.array.isRequired,
  /**
   * Value of the typeahead.
   */
  value: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.number, _react2.default.PropTypes.string]),
  /**
   * Which field in the option object will be used as the value of the select field.
   */
  valueProp: _react2.default.PropTypes.string.isRequired,
  /**
   * Which field in the option object will be used as the display of the select field.
   */
  displayProp: _react2.default.PropTypes.string.isRequired,
  /**
   * Whether the select field is disabled.
   */
  disabled: _react2.default.PropTypes.bool,
  /**
   * Optional styles to add to the select field.
   */
  optClass: _react2.default.PropTypes.string,
  /**
   * A callback function to be called when an option is selected.
   */
  changeCallback: _react2.default.PropTypes.func,
  /**
   * A callback for updating options when typeahead search value is changed.
   */
  searchCallback: _react2.default.PropTypes.func,
  /**
   * A loading state to be set to true when asynchronous searching is in progress.
   */
  loading: _react2.default.PropTypes.bool,
  /**
   * Clear search string after selection.
   */
  resetAfterSelection: _react2.default.PropTypes.bool,
  /**
   * Search debounce time.
   */
  searchDebounceTime: _react2.default.PropTypes.number
};
exports.default = (0, _reactClickOutside2.default)(Typeahead);