mahaplatform/reframe

View on GitHub
src/controls/lookup/options.js

Summary

Maintainability
B
6 hrs
Test Coverage
import React from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash'
import Searchbox from '../../components/searchbox'
import Infinite from '../../components/infinite'
import Format from '../../utils/format'

class Options extends React.Component {

  static contextTypes = {
    form: PropTypes.object
  }

  static propTypes = {
    format: PropTypes.oneOfType([
      PropTypes.element,
      PropTypes.func,
      PropTypes.string
    ]),
    options: PropTypes.array,
    selected: PropTypes.array,
    text: PropTypes.string,
    value: PropTypes.string,
    onChange: PropTypes.func,
    onChoose: PropTypes.func
  }

  render() {
    const { format, options, selected, text } = this.props
    return (
      <div className="reframe-lookup-panel-results">
        { options.map((option, index) => (
          <div key={`result_${option.id || index}`} className="reframe-lookup-panel-result" onClick={ this._handleChoose.bind(this, option) }>
            <div className="reframe-lookup-panel-result-label">
              <Format { ...option } format={ format } value={ _.get(option, text) } />
            </div>
            <div className="reframe-lookup-panel-result-icon">
              { index === selected ? <i className="fa fa-fw fa-check" /> : null }
            </div>
          </div>
        ))}
      </div>
    )
  }

  _handleChoose(chosen) {
    const { onChoose, onChange, value } = this.props
    onChoose(chosen)
    onChange(_.get(chosen, value))
    this.context.form.pop()
  }

}

class Dynamic extends React.Component {

  static propTypes = {
    format: PropTypes.oneOfType([
      PropTypes.element,
      PropTypes.func,
      PropTypes.string
    ]),
    records: PropTypes.array,
    text: PropTypes.string,
    value: PropTypes.string,
    selected: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.number
    ]),
    onChange: PropTypes.func,
    onChoose: PropTypes.func
  }

  render() {
    const { records } = this.props
    return (records) ? <Options { ...this._getOptions() } /> : null
  }

  _getOptions() {
    const { format, selected, records, text, value, onChoose, onChange } = this.props
    return {
      format,
      selected,
      options: records,
      text,
      value,
      onChoose,
      onChange
    }
  }

}

class Container extends React.Component {

  static contextTypes = {
    modal: PropTypes.object
  }

  static propTypes = {
    cacheKey: PropTypes.string,
    endpoint: PropTypes.string,
    form: PropTypes.object,
    label: PropTypes.string,
    options: PropTypes.array,
    q: PropTypes.string,
    search: PropTypes.bool,
    sort: PropTypes.string,
    text: PropTypes.string,
    value: PropTypes.string,
    onChange: PropTypes.func,
    onChoose: PropTypes.func,
    onQuery: PropTypes.func,
    onShowForm: PropTypes.func
  }

  render() {
    const { endpoint, label, form, search } = this.props
    return (
      <div className="reframe-lookup-panel">
        { search &&
          <div className="reframe-lookup-panel-search">
            <Searchbox { ...this._getSearchbox() } />
          </div>
        }
        { endpoint && <Infinite { ...this._getInfinite() } /> }
        { !endpoint && <Options { ...this._getStaticOptions() } /> }
        { form &&
          <div className="reframe-lookup-panel-add">
            <div className="ui fluid red button" onClick={ this._handleAdd.bind(this)}>
              Add {label}
            </div>
          </div>
        }
      </div>
    )
  }

  _getSearchbox() {
    const { label, onQuery } = this.props
    return {
      prompt: `Find a ${label}`,
      onChange: onQuery
    }
  }

  _getInfinite() {
    const { cacheKey, endpoint, q, sort, text, value } = this.props
    return {
      cacheKey,
      endpoint,
      filter: { q },
      layout: (props) => <Dynamic { ...this.props } { ...props } />,
      sort,
      text,
      value
    }
  }

  _handleAdd() {
    this.props.onShowForm()
  }

  _getStaticOptions() {
    const { options, q } = this.props
    return {
      ...this.props,
      options: options.filter(options => q === null || options.text.search(q) >= 0)
    }
  }

}

export default Container