swagger-api/swagger-editor

View on GitHub
src/standalone/topbar-insert/forms/components/FormDropdown.jsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { Component } from "react"
import PropTypes from "prop-types"
import classNames from "classnames"

class FormDropdown extends Component {
  constructor(props) {
    super(props)
    this.state = {
      addedOptions: [],
      toBeAdded: "",
      showAddOption: false,
      isValidAddition: true
    }

    this.updateToBeAdded = this.updateToBeAdded.bind(this)
    this.showAddField = this.showAddField.bind(this)
    this.onEnterKeyPress = this.onEnterKeyPress.bind(this)
    this.submitAdded = this.submitAdded.bind(this)
    this.onChangeWrapper = this.onChangeWrapper.bind(this)
  }

  onEnterKeyPress = (event) => {
    if (event.key === "Enter") {
      this.submitAdded()
    }
  }

  submitAdded = () => {
    if (this.props.isValidAddition(this.state.toBeAdded)) {
      this.setState((prevState) => {
        prevState.addedOptions.push(prevState.toBeAdded)
        return {
          addedOptions: prevState.addedOptions,
          toBeAdded: "",
          showAddOption: false
        }
      })
    } else {
      this.setState({
        isValidAddition: false
      })
    }
  }

  updateToBeAdded = (event) => {
    this.setState({
      toBeAdded: event.target.value,
      isValidAddition: this.props.isValidAddition(event.target.value)
    })

    this.props.onChange(event)
  }

  showAddField = () => {
    this.setState({
      showAddOption: true
    })

    if (this.state.toBeAdded) {
      this.submitAdded()
    }
  }

  onChangeWrapper = (event) => {
    if (event.target.value === "Please Select" || event.target.value === this.props.placeholderText) {
      const updated = event
      updated.target.value = null
      this.props.onChange(updated)
    }

    this.props.onChange(event)
  }

  render() { 
    let addedOption = <span />
    const addButton = <a role="button" className="d-inline-block float-right" onClick={this.showAddField} onKeyDown={this.onEnterKeyPress} tabIndex={0}>Add</a>
    if (this.props.isValidAddition) {
      if (this.state.showAddOption) {
        addedOption = ( 
          <div>
            <input 
              className="form-control" 
              type="text"
              onChange={this.updateToBeAdded} 
              value={this.state.toBeAdded} 
              placeholder="Add Option" 
              onKeyDown={this.addField} 
            />
            {addButton}
            {!this.state.isValidAddition &&
              this.props.isValidAdditionMessage && 
              <div className="invalid-feedback">
                {this.props.isValidAdditionMessage}
              </div>
            }
          </div>)
      } else {
        addedOption = addButton
      }
    }
    
    return (
      <div>
        {!this.state.showAddOption &&
          <select 
            value={this.props.selected || this.props.placeholderText || "Please Select"} 
            onChange={this.onChangeWrapper}
            className={classNames("custom-select", {"border-danger": !this.props.isValid})} 
          >
            <option value={this.props.placeholderText || "Please Select"}>
              {this.props.placeholderText || "Please Select"}
            </option>
            {(this.props.options || []).map((option, i) => 
              <option key={option + i} value={option}>{option}</option>)}
            {this.state.addedOptions.length && 
              this.state.addedOptions.map((option, i) =>
                <option key={option + i} value={option}>{option}</option>)
            }
          </select>
        }
        {addedOption}
        {!this.props.isValid && 
          <div className="invalid-feedback d-block">
            {this.props.validationMessage}
          </div> 
        }
      </div>
    )
  }
}

FormDropdown.propTypes = {
  isValid: PropTypes.bool.isRequired,
  placeholderText: PropTypes.string,
  validationMessage: PropTypes.string,
  options: PropTypes.oneOfType([
    PropTypes.array,
    PropTypes.object 
  ]),
  onChange: PropTypes.func.isRequired,
  selected: PropTypes.string,
  isValidAddition: PropTypes.func,
  isValidAdditionMessage: PropTypes.string
}

export default FormDropdown