<commit_before>import React from 'react';
import domOnlyProps from 'form/domOnlyProps';
import fieldIsInvalid from 'form/fieldIsInvalid';
import Autosuggest from 'react-autosuggest';
import styles from './autocomplete.scss';

const MIN_QUERY_LENGTH = 2;

const getClassname = (element, error) => {
  return [
    styles[element || 'input'],
    styles[error ? 'invalid' : 'valid']
  ].join(' ');
};

// We handle the query length validation here as we don‘t want to do it in the
// (throttled) typeahead search. If we did, the first input after
// MIN_QUERY_LENGTH would be delayed.
const handleFetchRequest = (endpoint, e, typeaheadSearch, clearSuggestions) => {
  let query = e.value;

  if (query) {
    query = query.trim().toLowerCase();

    if (query.length > MIN_QUERY_LENGTH) {
      return typeaheadSearch(endpoint, query);
    }
  }

  return clearSuggestions();
};

const handleBlur = (displayedValue, displaySuggestion, updateSuggestionInputValue, helper) => {
  const savedValue = helper.value && displaySuggestion(helper.value.data);

  // If the saved value in the redux-form matches the displayed value in the
  // auto-suggest input, we know that the user hasn‘t changed his choice.
  // If it did, we must reset both values as they aren‘t valid anymore.
  if (savedValue !== displayedValue) {
    updateSuggestionInputValue('');
    helper.onChange('');
  }
};

const handleChange = (newValue, updateSuggestionInputValue, helper) => {
  // We have to manually update the displayed value in the auto-suggest.
  // This has nothing to do with the actual redux-form value.
  updateSuggestionInputValue(newValue);

  // If there is no more value, then we know the user has deleted his choice,
  // and we can update the redux-form store.
  if (!newValue) {
    helper.onChange('');
  }
};

const handleSelection = (e, { suggestion }, helper) => {
  // Disable form submitting when selecting option with ENTER
  e.preventDefault();

  // Update redux-form store manually to reflect the selection
  helper.onChange({
    data: suggestion,
    id: suggestion.id,
    class: 'City'
  });
};

const Autocomplete = ({
  endpoint,
  suggestionFormatter,
  typeaheadSearch,
  clearSuggestions,
  updateSuggestionInputValue,
  suggestions,
  value,
  helper,
  name,
  html
}) => (
  <Autosuggest
    theme={{
      containerOpen: styles.open,
      input: getClassname('input', fieldIsInvalid(helper)),
      suggestionsList: styles.list,
      suggestion: styles.suggestion,
      suggestionFocused: styles.focused
    }}
    id={name}

    suggestions={suggestions}
    renderSuggestion={suggestionFormatter}
    getSuggestionValue={suggestionFormatter}
    focusFirstSuggestion

    onSuggestionsFetchRequested={(e) => (
      handleFetchRequest(endpoint, e, typeaheadSearch, clearSuggestions)
    )}
    onSuggestionsClearRequested={clearSuggestions}
    onSuggestionSelected={(e, option) => (
      handleSelection(e, option, helper)
    )}

    inputProps={{
      name: name,
      id: name,
      required: html.required,
      placeholder: html.placeholder,
      autoComplete: html.autocomplete || 'off',

      ...domOnlyProps(helper),

      value: value,
      onBlur: () => (
        handleBlur(value, suggestionFormatter, updateSuggestionInputValue, helper)
      ),
      onChange: (e, { newValue }) => (
        handleChange(newValue, updateSuggestionInputValue, helper)
      )
    }}
  />
);

export default Autocomplete;<commit_msg>Refactored autocomplete component to use React class<commit_after>import React from 'react';
import domOnlyProps from 'form/domOnlyProps';
import fieldIsInvalid from 'form/fieldIsInvalid';
import Autosuggest from 'react-autosuggest';
import styles from './autocomplete.scss';

const MIN_QUERY_LENGTH = 2;

const Autocomplete = React.createClass({
  getClassname (element, error) {
    return [
      styles[element || 'input'],
      styles[error ? 'invalid' : 'valid']
    ].join(' ');
  },

  handleFetchRequest (e, { endpoint, typeaheadSearch, clearSuggestions }) {
    // We handle the query length validation here as we don‘t want to do it in
    // the (throttled) typeahead search. If we did, the first input after
    // MIN_QUERY_LENGTH would be delayed.
    let query = e.value;

    if (query) {
      query = query.trim().toLowerCase();

      if (query.length >= MIN_QUERY_LENGTH) {
        return typeaheadSearch(endpoint, query);
      }
    }

    return clearSuggestions();
  },

  handleBlur ({
    value,
    suggestionFormatter,
    updateSuggestionInputValue,
    helper
  }) {
    const savedValue = helper.value && suggestionFormatter(helper.value.data);

    // If the saved value in the redux-form matches the displayed value in the
    // auto-suggest input, we know that the user hasn‘t changed his choice.
    // If it did, we must reset both values as they aren‘t valid anymore.
    if (savedValue !== value) {
      updateSuggestionInputValue('');
      helper.onChange('');
    }
  },

  handleChange (newValue, { updateSuggestionInputValue, helper }) {
    // We have to manually update the displayed value in the auto-suggest.
    // This has nothing to do with the actual redux-form value.
    updateSuggestionInputValue(newValue);

    // If there is no more value, then we know the user has deleted his choice,
    // and we can update the redux-form store.
    if (!newValue) {
      helper.onChange('');
    }
  },

  handleSelection (e, { suggestion }, helper) {
    // Disable form submitting when selecting option with ENTER
    e.preventDefault();

    // Update redux-form store manually to reflect the selection
    helper.onChange({
      data: suggestion,
      id: suggestion.id,
      class: 'City'
    });
  },

  render () {
    return (
      <Autosuggest
        theme={{
          containerOpen: styles.open,
          input: this.getClassname('input', fieldIsInvalid(this.props.helper)),
          suggestionsList: styles.list,
          suggestion: styles.suggestion,
          suggestionFocused: styles.focused
        }}
        id={this.props.name}

        suggestions={this.props.suggestions}
        renderSuggestion={this.props.suggestionFormatter}
        getSuggestionValue={this.props.suggestionFormatter}
        focusFirstSuggestion

        onSuggestionsFetchRequested={(e) => (
          this.handleFetchRequest(e, {...this.props})
        )}
        onSuggestionsClearRequested={this.props.clearSuggestions}
        onSuggestionSelected={(e, suggestion) => (
          this.handleSelection(e, suggestion, this.props.helper)
        )}

        inputProps={{
          name: this.props.name,
          id: this.props.name,
          required: this.props.html.required,
          placeholder: this.props.html.placeholder,
          autoComplete: this.props.html.autocomplete || 'off',

          ...domOnlyProps(this.props.helper),

          value: this.props.value,
          onBlur: () => (
            this.handleBlur({...this.props})
          ),
          onChange: (e, { newValue }) => (
            this.handleChange(newValue, {...this.props})
          )
        }}
      />
    );
  }
});

export default Autocomplete;
{'fraction_non_alphanumeric': 0.11180992313067785, 'fraction_numerical': 0.0002795248078266946, 'mean_word_length': 2.9755555555555557, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2216022', 'n_tokens_mistral': 2097, 'n_tokens_neox': 2020, 'n_words': 563}