InstitutePicker.tsx 5.58 KB
Newer Older
1
import * as React from 'react';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
2 3
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
4
import { translate } from 'react-i18next';
Oleksii Savran's avatar
Oleksii Savran committed
5
import { debounce } from 'debounce';
6

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
7 8
import {autocompleteWiewsTerm, loadWiewsTerm} from 'vocabulary/actions/public';

9 10 11 12 13 14 15 16 17 18 19 20
import { Field } from 'redux-form';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import Input from '@material-ui/core/Input';
import TextField from '@material-ui/core/TextField';
import FormControl from 'ui/common/forms/FormControl';
import Select from '@material-ui/core/Select';
import Markdown from 'ui/common/markdown';

interface ISelectFaoInstituteInternal extends React.ClassAttributes<any> {
  input: any;
  label: string;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
21 22
  loadWiewsTerm: (code) => Promise<any>;
  autocompleteWiewsTerm: (code) => Promise<any>;
23 24 25 26 27
  meta?: any;
  t: any;
}

class SelectFaoInstituteInternal extends React.Component<ISelectFaoInstituteInternal, any> {
Oleksii Savran's avatar
Oleksii Savran committed
28
  public updateMenuPosition = null;
29 30 31 32

  protected handleInputChange = (event) => {
    this.setState({searchText: event.target.value});
    if (event.target.value) {
Oleksii Savran's avatar
Oleksii Savran committed
33
      this.doAutocomplete(event.target.value);
34 35
    }
  }
Oleksii Savran's avatar
Oleksii Savran committed
36 37
  private doAutocomplete = debounce((value) => {
    this.props.autocompleteWiewsTerm(value).then((suggestions) => {
Oleksii Savran's avatar
Oleksii Savran committed
38
      this.updateMenuPosition();
Oleksii Savran's avatar
Oleksii Savran committed
39 40 41
      this.setState({suggestions});
    });
  }, 1000);
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  protected handleClick = (event) => {
    this.setState({open: true, anchorEl: event.currentTarget});
  }
  protected handleRequestClose = () => {
    this.setState({open: false});
  }
  protected select = (value) => (event) => {
    const {input} = this.props;
    const institute = this.state.suggestions.find((inst) => inst.code === value);
    if (institute) {
      input.onChange({code: institute.code});
      this.setState({
        open: false,
        pickerList: {code: institute.code, title: institute.title},
      });
    } else {
      input.onChange('');
      this.setState({
        open: false,
        pickerList: null,
      });
    }
  }

  private constructor(props, context) {
    super(props, context);
    this.state = {
      disabled: false,
      pickerList: null,
      open: false,
      anchorEl: null,
      searchText: '',
      suggestions: [],
    };
  }

  public componentWillMount() {
    const {input: {value}} = this.props;

    if (value) {
      this.setState({
        pickerList: {
          code:  value.code,
          title: value.fullName || value.code,
        },
        disabled: true,
      });
    }
  }

  public componentWillReceiveProps(nextProps) {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
93
    const { loadWiewsTerm } = this.props;
94 95 96 97 98 99 100 101 102
    if (! nextProps.input.value) {
      return this.setState({pickerList: null});
    }
    if (nextProps.input.value !== this.props.input.value) {
      const code = nextProps.input.value.code;
      const institute = this.state.suggestions.find((inst) => inst.code === code);
      if (institute) {
        this.setState({pickerList: {code: institute.code, title: institute.title}});
      } else {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
103
        loadWiewsTerm(code).then((inst) => {
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
          this.setState({pickerList: {code: inst.code, title: inst.title}});
        });
      }
    }
  }

  public render() {
    const {label, meta, t} = this.props;
    const {pickerList: inputValue, disabled} = this.state;
    return (
      <FormControl fullWidth meta={ meta } label={ label } disabled={ disabled }>
        <Select
          onClick={ !disabled ? this.handleClick : null }
          value={ inputValue }
          input={ <Input/> }
          MenuProps={ {
            open: false,
          } }
Oleksii Savran's avatar
Oleksii Savran committed
122
          classes={ { select: 'mui-select-rtl', icon: 'mui-select-icon-rtl' } }
123 124 125 126 127 128 129 130 131 132 133 134
        >
          {
            this.state.pickerList ? (
              <MenuItem value={ inputValue }>
                <Markdown basic source={ this.state.pickerList.title }/>
              </MenuItem>) : null
          }
        </Select>
        <Menu
          anchorEl={ this.state.anchorEl }
          open={ this.state.open }
          onClose={ this.handleRequestClose }
Oleksii Savran's avatar
Oleksii Savran committed
135
          action={ (actions) => this.updateMenuPosition = actions.updatePosition }
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
        >
          <MenuItem>
            <TextField
              fullWidth
              value={ this.state.searchText }
              label={ t('partners.admin.c.institutePicker.search') }
              onChange={ this.handleInputChange }
            />
          </MenuItem>
          {
            this.state.suggestions.map((inst, index) => (
              <MenuItem onClick={ this.select(inst.code) } key={ `fao-institute-${index}` }>
                <Markdown basic source={ `${inst.code} - ${inst.title}` }/>
              </MenuItem>
            ))
          }
        </Menu>
      </FormControl>
    );
  }
}

interface IFaoInstitutePicker extends React.ClassAttributes<any> {
  name: string;
  label: string;
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
161 162
  loadWiewsTerm: (code) => Promise<any>;
  autocompleteWiewsTerm: (code) => Promise<any>;
163 164 165 166 167 168 169
  className?: string;
  t: any;
}

class FaoInstitutePicker extends React.Component<IFaoInstitutePicker, any> {

  public render() {
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
170
    const {name, label, className, loadWiewsTerm, autocompleteWiewsTerm, t} = this.props;
171 172 173 174 175 176 177

    return (
      <div className={ className }>
        <Field
          name={ name }
          component={ SelectFaoInstituteInternal }
          label={ label }
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
178 179
          loadWiewsTerm={ loadWiewsTerm }
          autocompleteWiewsTerm={ autocompleteWiewsTerm }
180 181 182 183 184 185 186
          t={ t }
        />
      </div>
    );
  }
}

Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
187 188 189 190 191 192
const mapDispatchToProps = (dispatch) => bindActionCreators({
  loadWiewsTerm,
  autocompleteWiewsTerm,
}, dispatch);

export default translate()(connect(null, mapDispatchToProps)(FaoInstitutePicker));