huridocs/uwazi

View on GitHub
app/react/Forms/components/NestedMultiselect.js

Summary

Maintainability
A
0 mins
Test Coverage
D
66%
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import ShowIf from 'app/App/ShowIf';
import { Field, Control } from 'react-redux-form';
import { t } from 'app/I18N';
import { advancedSort } from 'app/utils/advancedSort';
import nestedProperties from 'app/Templates/components/ViolatedArticlesNestedProperties';
import { store } from 'app/store';
import { Icon } from 'UI';
import { MultiSelect } from './MultiSelect';

export default class NestedMultiselect extends Component {
  constructor(props) {
    super(props);
    const values = this.props.value || {};
    this.state = { values, filter: '' };
    if (!Object.keys(this.state.values).length) {
      this.state.values = props.property.nestedProperties.reduce((result, prop) => {
        result[prop.key] = [];
        return result;
      }, {});
    }
  }

  onChange(key, optionsSelected) {
    const values = { ...this.state.values, [key]: optionsSelected };

    this.setState({ values });
    this.props.onChange(values);
  }

  getOptions(prop, aggregations) {
    if (this.props.options) {
      return this.props.options;
    }

    if (!aggregations.all[this.props.property.name][prop]) {
      return [];
    }
    let options = aggregations.all[this.props.property.name][prop].buckets;
    if (options.length === 1 && options[0].key === 'missing') {
      return [];
    }
    options = options
      .map(item => ({
        label: item.key,
        value: item.key,
        results: item.filtered.total.filtered.doc_count,
      }))
      .filter(option => option.results);
    return advancedSort(options, {
      property: 'value',
      treatAs: 'dottedList',
      listTypes: [Number, Number, String],
    });
  }

  resetFilter() {
    this.setState({ filter: '' });
  }

  filter(e) {
    this.setState({ filter: e.target.value });
  }

  selectAnyChange(key, e) {
    const values = { ...this.state.values, [key]: [], [`${key}any`]: e.target.checked };
    this.setState({ values });
    this.props.onChange(values);
  }

  toggleOptions(key, e) {
    e.preventDefault();
    const state = {};
    state[key] = !this.state[key];
    this.setState(state);
  }

  render() {
    const { property } = this.props;
    const { locale } = store.getState();
    const aggregations = this.props.aggregations ? this.props.aggregations.toJS() : {};
    return (
      <ul className="multiselect is-active">
        <li className="multiselectActions">
          <div className="form-group">
            <Icon
              icon={this.state.filter ? 'times-circle' : 'search'}
              onClick={this.resetFilter.bind(this)}
            />
            <input
              className="form-control"
              type="text"
              placeholder={t('System', 'Search item', null, false)}
              value={this.state.filter}
              onChange={this.filter.bind(this)}
            />
          </div>
        </li>
        {(() =>
          property.nestedProperties.map((prop, index) => {
            const options = this.getOptions(prop, aggregations);
            if (!options.length) {
              return false;
            }
            const label = nestedProperties[prop.toLowerCase()]
              ? nestedProperties[prop.toLowerCase()][`label_${locale}`]
              : prop;
            return (
              <li key={index}>
                <Field model={`.filters.${property.name}.properties.${prop}.any`}>
                  <div className="multiselectItem">
                    <input
                      type="checkbox"
                      className="form-control multiselectItem-input"
                      id={prop.key}
                      onChange={this.selectAnyChange.bind(this, prop)}
                    />
                    <label htmlFor={prop} className="multiselectItem-label">
                      <span className="multiselectItem-icon" />
                      <span className="multiselectItem-name" title={label}>
                        <b>{label}</b>
                      </span>
                    </label>
                    <span className="multiselectItem-results">
                      <span
                        className="multiselectItem-action"
                        onClick={this.toggleOptions.bind(this, prop)}
                      >
                        <Icon icon={this.state[prop] ? 'caret-up' : 'caret-down'} />
                      </span>
                    </span>
                  </div>
                </Field>
                <ShowIf if={this.state[prop]}>
                  <Control
                    component={MultiSelect}
                    model={`.filters.${property.name}.properties.${prop}.values`}
                    prefix={property.name + prop}
                    options={options}
                    onChange={this.onChange.bind(this, prop)}
                    showAll
                    hideSearch
                    sortbyLabel
                    filter={this.state.filter}
                  />
                </ShowIf>
              </li>
            );
          }))()}
      </ul>
    );
  }
}

NestedMultiselect.defaultProps = {
  value: {},
  options: undefined,
};

NestedMultiselect.propTypes = {
  onChange: PropTypes.func.isRequired,
  value: PropTypes.instanceOf(Object),
  property: PropTypes.instanceOf(Object).isRequired,
  options: PropTypes.instanceOf(Array),
  aggregations: PropTypes.instanceOf(Object).isRequired,
};