<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import { SELECTION_ALL_PHASES, SELECTION_CUSTOM_PHASE } from 'interface/report/PhaseParser';

import './PhaseSelector.scss';

const INSTANCE_SEPARATOR = '_INSTANCE_';

class PhaseSelector extends React.PureComponent {
  static propTypes = {
    fight: PropTypes.object.isRequired,
    phases: PropTypes.object.isRequired,
    selectedPhase: PropTypes.string.isRequired,
    selectedInstance: PropTypes.number.isRequired,
    handlePhaseSelection: PropTypes.func.isRequired,
    isLoading: PropTypes.bool.isRequired,
  };

  constructor(...args) {
    super(...args);
    this.state = { phases: this.buildPhases() };
    this.phaseRef = React.createRef();
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    const selectedPhase = this.state.phases[e.target.value];
    if (selectedPhase) {
      this.props.handlePhaseSelection(selectedPhase.key, selectedPhase.instance);
    } else {
      this.props.handlePhaseSelection(SELECTION_ALL_PHASES, 0);
    }
  }

  //builds a dictionary of phases / phase instances to keep track of in order to be able to attribute a unique "key" to each phase for the dropdown
  //without losing the actual key (and without having to for example replace an "instance token" like an underscore)
  buildPhases() {
    const phases = [];
    Object.keys(this.props.phases).forEach(key => {
      const phase = this.props.phases[key];
      if (phase.start.length !== phase.end.length) {
        phases.push({ name: phase.name, key: key, start: phases.start[0], instance: 0 });
      } else {
        phases.push(...phase.start.map((start, index) => (
          {
            name: phase.name,
            key: key,
            instance: index,
            start: start,
            multiple: phase.multiple,
          }
        )));
      }
    });
    phases.sort((a, b) => a.start - b.start);
    return phases.reduce((obj, phase) => {
      return {
        ...obj,
        [phase.key + INSTANCE_SEPARATOR + phase.instance]: phase,
      };
    }, {});
  }

  //if phase information changed, build new dictionary of phase selection
  componentDidUpdate(prevProps, prevState, prevContext) {
    if (this.props.phases !== prevProps.phases) {
      this.setState({
        phases: this.buildPhases(),
      });
    }
  }

  render() {
    const { selectedPhase, selectedInstance, fight } = this.props;
    const phases = this.state.phases;
    return (
      <select
        className="form-control phase"
        defaultValue={selectedPhase}
        value={(fight.filtered && !fight.phase) ? SELECTION_CUSTOM_PHASE : (selectedPhase === SELECTION_ALL_PHASES ? SELECTION_ALL_PHASES : selectedPhase + INSTANCE_SEPARATOR + selectedInstance)}
        onChange={this.handleChange}
        ref={this.phaseRef}
        disabled={this.props.isLoading}
      >
        {fight.filtered && !fight.phase && <option key="custom" value={SELECTION_CUSTOM_PHASE}>Custom</option>}
        <option key="all" value={SELECTION_ALL_PHASES}>All Phases</option>
        {Object.keys(phases).map(key =>
          <option key={key} value={key}>{phases[key].name}{phases[key].multiple ? ' ' + (phases[key].instance + 1) : ''}</option>,
        )}
      </select>
    );<commit_msg>Fix React warning<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import { SELECTION_ALL_PHASES, SELECTION_CUSTOM_PHASE } from 'interface/report/PhaseParser';

import './PhaseSelector.scss';

const INSTANCE_SEPARATOR = '_INSTANCE_';

class PhaseSelector extends React.PureComponent {
  static propTypes = {
    fight: PropTypes.object.isRequired,
    phases: PropTypes.object.isRequired,
    selectedPhase: PropTypes.string.isRequired,
    selectedInstance: PropTypes.number.isRequired,
    handlePhaseSelection: PropTypes.func.isRequired,
    isLoading: PropTypes.bool.isRequired,
  };

  constructor(...args) {
    super(...args);
    this.state = { phases: this.buildPhases() };
    this.phaseRef = React.createRef();
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    const selectedPhase = this.state.phases[e.target.value];
    if (selectedPhase) {
      this.props.handlePhaseSelection(selectedPhase.key, selectedPhase.instance);
    } else {
      this.props.handlePhaseSelection(SELECTION_ALL_PHASES, 0);
    }
  }

  //builds a dictionary of phases / phase instances to keep track of in order to be able to attribute a unique "key" to each phase for the dropdown
  //without losing the actual key (and without having to for example replace an "instance token" like an underscore)
  buildPhases() {
    const phases = [];
    Object.keys(this.props.phases).forEach(key => {
      const phase = this.props.phases[key];
      if (phase.start.length !== phase.end.length) {
        phases.push({ name: phase.name, key: key, start: phases.start[0], instance: 0 });
      } else {
        phases.push(...phase.start.map((start, index) => (
          {
            name: phase.name,
            key: key,
            instance: index,
            start: start,
            multiple: phase.multiple,
          }
        )));
      }
    });
    phases.sort((a, b) => a.start - b.start);
    return phases.reduce((obj, phase) => {
      return {
        ...obj,
        [phase.key + INSTANCE_SEPARATOR + phase.instance]: phase,
      };
    }, {});
  }

  //if phase information changed, build new dictionary of phase selection
  componentDidUpdate(prevProps, prevState, prevContext) {
    if (this.props.phases !== prevProps.phases) {
      this.setState({
        phases: this.buildPhases(),
      });
    }
  }

  render() {
    const { selectedPhase, selectedInstance, fight } = this.props;
    const phases = this.state.phases;
    return (
      <select
        className="form-control phase"
        value={(fight.filtered && !fight.phase) ? SELECTION_CUSTOM_PHASE : (selectedPhase === SELECTION_ALL_PHASES ? SELECTION_ALL_PHASES : selectedPhase + INSTANCE_SEPARATOR + selectedInstance)}
        onChange={this.handleChange}
        ref={this.phaseRef}
        disabled={this.props.isLoading}
      >
        {fight.filtered && !fight.phase && <option key="custom" value={SELECTION_CUSTOM_PHASE}>Custom</option>}
        <option key="all" value={SELECTION_ALL_PHASES}>All Phases</option>
        {Object.keys(phases).map(key =>
          <option key={key} value={key}>{phases[key].name}{phases[key].multiple ? ' ' + (phases[key].instance + 1) : ''}</option>,
        )}
      </select>
    );
{'fraction_non_alphanumeric': 0.13234620668600214, 'fraction_numerical': 0.00122118760494581, 'mean_word_length': 2.946987951807229, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 29, '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': '3739747', 'n_tokens_mistral': 1989, 'n_tokens_neox': 1988, 'n_words': 417}