<commit_before>// @flow
// MegaWizard - Copyright 2018 Zeroarc Software, LLC
'use strict';

import React from 'react';
import * as Immutable from 'immutable';
import ClassNames from 'classnames';
import Autobind from 'autobind-decorator';

import Buttons from './Buttons';

type Props = {
  // Required
  // steps: Wizard steps config object
  steps: Immutable.List<*>,
  
  // Optional

  // Defaults to true. If false, cancel button is not visible
  cancelAllowed: bool,
  
  // Override for complete button text
  cancelButtonText: string,

  // Override for complete button text
  completeButtonText: string,

  // Optional override for complete button classes
  completeButtonClasses?: string,

  // Optional override for complete button icon classes
  completeButtonIconClasses?: string,

  // If provided, Megazwizard will not automatically advance
  // steps and instead use the provided index to display
  index?: number,

  // Override for next button text
  nextButtonText: string,

  // Optional override for next button classes
  nextButtonClasses?: string,

  // Optional override for next button icon classes
  nextButtonIconClasses?: string,

  // Override for previous button text
  prevButtonText: string,

  // Optional override for previous button classes
  prevButtonClasses?: string,

  // Optional override for previous button icon classes
  prevButtonIconClasses?: string,

  // onCancel: called when the cancel button is clicked. If not provided, cancel will not be allowed
  onCancel?: (Immutable.Map<string,*>) => void,
  
  // onComplete: called when the final wizard complete button is clicked
  onComplete?: (Immutable.Map<string,*>) => void,

  // called when step index wants to change
  onStepShouldChange?: (number) => void,

  // called when any step changes, passes step
  onStepChanged?: (Immutable.Map<string,*>) => void,

  // called when any step changes, passes step
  onNextStepChanged?: (Immutable.Map<string,*>) => void,

  // called when any step changes, passes step
  onPreviousStepChanged?: (Immutable.Map<string,*>) => void,

  // called before any step changes, passes step
  onStepWillChange?: (Immutable.Map<string,*>) => void,

  // called before next step changes, passes step
  onStepWillChangeToNext?: (Immutable.Map<string,*>) => void,

  // called before previous step changes, passes step
  onStepWillChangeToPrevious?: (Immutable.Map<string,*>) => void,
};

type State = {
  currentStepIndex: number,
  steps: Immutable.List<Immutable.Map<string, *>>,
};

@Autobind
export default class MegaWizardContainer extends React.Component<Props,State> {
  static defaultProps: {
    completeButtonText: string,
    nextButtonText: string,
    prevButtonText: string,
  };

  constructor(props: Props) {
    super(props);

    const visibleSteps = props.steps.filter(s => typeof s.get('visible') === 'undefined' || s.get('visible'));

    let index = 0;
    const propsIndex = props.index;
    if (typeof propsIndex === 'number' && propsIndex < 0) {
      index = visibleSteps.count() + propsIndex;
    }
    else if (typeof propsIndex === 'number') {
      index = propsIndex;
    }

    this.state = {
      currentStepIndex: index,
      steps: visibleSteps,
    };
  }

  // Because we have steps in state, we need watch for updates
  // and re-filter
  componentWillReceiveProps(nextProps: Props) {
    if (nextProps.steps !== this.props.steps) {
      const visibleSteps = nextProps.steps.filter(s => typeof s.get('visible') === 'undefined' || s.get('visible'));

      this.setState({
        steps: visibleSteps,
      });
    }

    if (nextProps.index !== this.props.index) {
      const nextIndex = nextProps.index;
      if (typeof nextIndex === 'number') {
        const index = nextIndex < 0 ? nextProps.steps.count() + nextIndex : nextIndex;
        this.setState({ currentStepIndex: index });
      }
    }
  }

  // Check to see if we have an onEnter callback defined on first step
  componentDidMount() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex, Immutable.Map());
    const onEnter =  currentStep.get('onEnter');
    if (typeof onEnter === 'function')
      onEnter();
  }

  // Check to see if we have an onExit callback defined on current step
  // before unmounting
  componentWillUnmount() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex, Immutable.Map());
    const onExit = currentStep.get('onExit');
    if (typeof onExit === 'function')
      onExit();
  }

  // Check for step changes and fire optional callbacks
  componentDidUpdate(prevProps: Props, prevState: State) {
    if (prevState.currentStepIndex !== this.state.currentStepIndex) {
      const currentStepIndex = this.state.currentStepIndex;
      const currentStep = this.state.steps.get(currentStepIndex, Immutable.Map());

      const prevStepIndex = prevState.currentStepIndex;
      const prevStep = this.state.steps.get(prevStepIndex, Immutable.Map());

      // Fire global step change callback if it exists
      currentStep && this.props.onStepChanged && this.props.onStepChanged(currentStep);

      // We went forward, fire next
      if (prevStepIndex > currentStepIndex)
        currentStep && this.props.onNextStepChanged && this.props.onNextStepChanged(currentStep);
      // We went back, fire previous
      else
        currentStep && this.props.onPreviousStepChanged && this.props.onPreviousStepChanged(currentStep);

      // Fire entry/exit steps if they exist for previous and current states
      const onExit = prevStep.get('onExit');
      if (typeof onExit === 'function')
        onExit();

      const onEnter = currentStep.get('onEnter');
      if (typeof onEnter === 'function')
        onEnter();
    }
  }

  render() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex);
    if (!currentStep) throw 'Invalid state, currentStep not found for index ' + this.state.currentStepIndex;

    // If defined, execute validators and check the result to determine if the step can advancex;
    const nextStepAllowed = typeof currentStep.get('nextValidator') === 'undefined' || !!currentStep.get('nextValidator');
    // In addition to the prevValidator, make sure this isn't the first step
    const prevStepAllowed = this.state.currentStepIndex !== 0 &&
      (typeof currentStep.get('prevValidator') === 'undefined' || !!currentStep.get('prevValidator'));

    // Build out summary column of steps
    const stepNames = this.state.steps.map((step,index) => {
      // Current step is highlighted in bold
      const nameClasses = ClassNames('list-group-item', {
        'text-bold': index === this.state.currentStepIndex
      });

      // Current step has success badge, previous steps are primary
      // future steps are default
      const numberClasses = ClassNames('badge', {
        'badge-success': index < this.state.currentStepIndex,
        'badge-primary': index === this.state.currentStepIndex,
        'badge-light': index > this.state.currentStepIndex,
      });

      const jumpButton = currentStep.get('allowJumpFrom', false) && step.get('allowJumpTo', false)
      ? (
        <button className='btn btn-sm btn-secondary pull-right'
          onClick={(e: SyntheticInputEvent<*>) => this.handleJumpStepClick(e, index)}>
          <i className='far fa-fw fa-history'></i> Jump
          </button>
      )
      : null;

      return (
        <li key={'stepName-' + index} className={nameClasses}>
          <span className='mr-2' style={{fontSize: '1.5em'}}><span className={numberClasses}>&nbsp;{index + 1}&nbsp;</span></span> {step.get('text')}
          {jumpButton}
        </li>
      );
    });

    const display = currentStep.get('display');
    const onDisplay = typeof display === 'function' ? display() : null;

    return (
      <div className='megawizard'>
        <div className='row'>
          <div className='col-4'>
            <ul className='list-group'>
              {stepNames}
            </ul>
          </div>
          <div className='col'>
            <div className='row'>
              <div className='col-12 text-center'>
                <h2>{this.state.currentStepIndex + 1}. {currentStep.get('text')}</h2>
              </div>
            </div>
            <div className='row mt-1 mb-4'>
              {onDisplay}<commit_msg>Layout updates<commit_after>// @flow
// MegaWizard - Copyright 2018 Zeroarc Software, LLC
'use strict';

import React from 'react';
import * as Immutable from 'immutable';
import ClassNames from 'classnames';
import Autobind from 'autobind-decorator';

import Buttons from './Buttons';

type Props = {
  // Required
  // steps: Wizard steps config object
  steps: Immutable.List<*>,
  
  // Optional

  // Defaults to true. If false, cancel button is not visible
  cancelAllowed: bool,
  
  // Override for complete button text
  cancelButtonText: string,

  // Override for complete button text
  completeButtonText: string,

  // Optional override for complete button classes
  completeButtonClasses?: string,

  // Optional override for complete button icon classes
  completeButtonIconClasses?: string,

  // If provided, Megazwizard will not automatically advance
  // steps and instead use the provided index to display
  index?: number,

  // Override for next button text
  nextButtonText: string,

  // Optional override for next button classes
  nextButtonClasses?: string,

  // Optional override for next button icon classes
  nextButtonIconClasses?: string,

  // Override for previous button text
  prevButtonText: string,

  // Optional override for previous button classes
  prevButtonClasses?: string,

  // Optional override for previous button icon classes
  prevButtonIconClasses?: string,

  // onCancel: called when the cancel button is clicked. If not provided, cancel will not be allowed
  onCancel?: (Immutable.Map<string,*>) => void,
  
  // onComplete: called when the final wizard complete button is clicked
  onComplete?: (Immutable.Map<string,*>) => void,

  // called when step index wants to change
  onStepShouldChange?: (number) => void,

  // called when any step changes, passes step
  onStepChanged?: (Immutable.Map<string,*>) => void,

  // called when any step changes, passes step
  onNextStepChanged?: (Immutable.Map<string,*>) => void,

  // called when any step changes, passes step
  onPreviousStepChanged?: (Immutable.Map<string,*>) => void,

  // called before any step changes, passes step
  onStepWillChange?: (Immutable.Map<string,*>) => void,

  // called before next step changes, passes step
  onStepWillChangeToNext?: (Immutable.Map<string,*>) => void,

  // called before previous step changes, passes step
  onStepWillChangeToPrevious?: (Immutable.Map<string,*>) => void,
};

type State = {
  currentStepIndex: number,
  steps: Immutable.List<Immutable.Map<string, *>>,
};

@Autobind
export default class MegaWizardContainer extends React.Component<Props,State> {
  static defaultProps: {
    completeButtonText: string,
    nextButtonText: string,
    prevButtonText: string,
  };

  constructor(props: Props) {
    super(props);

    const visibleSteps = props.steps.filter(s => typeof s.get('visible') === 'undefined' || s.get('visible'));

    let index = 0;
    const propsIndex = props.index;
    if (typeof propsIndex === 'number' && propsIndex < 0) {
      index = visibleSteps.count() + propsIndex;
    }
    else if (typeof propsIndex === 'number') {
      index = propsIndex;
    }

    this.state = {
      currentStepIndex: index,
      steps: visibleSteps,
    };
  }

  // Because we have steps in state, we need watch for updates
  // and re-filter
  componentWillReceiveProps(nextProps: Props) {
    if (nextProps.steps !== this.props.steps) {
      const visibleSteps = nextProps.steps.filter(s => typeof s.get('visible') === 'undefined' || s.get('visible'));

      this.setState({
        steps: visibleSteps,
      });
    }

    if (nextProps.index !== this.props.index) {
      const nextIndex = nextProps.index;
      if (typeof nextIndex === 'number') {
        const index = nextIndex < 0 ? nextProps.steps.count() + nextIndex : nextIndex;
        this.setState({ currentStepIndex: index });
      }
    }
  }

  // Check to see if we have an onEnter callback defined on first step
  componentDidMount() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex, Immutable.Map());
    const onEnter =  currentStep.get('onEnter');
    if (typeof onEnter === 'function')
      onEnter();
  }

  // Check to see if we have an onExit callback defined on current step
  // before unmounting
  componentWillUnmount() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex, Immutable.Map());
    const onExit = currentStep.get('onExit');
    if (typeof onExit === 'function')
      onExit();
  }

  // Check for step changes and fire optional callbacks
  componentDidUpdate(prevProps: Props, prevState: State) {
    if (prevState.currentStepIndex !== this.state.currentStepIndex) {
      const currentStepIndex = this.state.currentStepIndex;
      const currentStep = this.state.steps.get(currentStepIndex, Immutable.Map());

      const prevStepIndex = prevState.currentStepIndex;
      const prevStep = this.state.steps.get(prevStepIndex, Immutable.Map());

      // Fire global step change callback if it exists
      currentStep && this.props.onStepChanged && this.props.onStepChanged(currentStep);

      // We went forward, fire next
      if (prevStepIndex > currentStepIndex)
        currentStep && this.props.onNextStepChanged && this.props.onNextStepChanged(currentStep);
      // We went back, fire previous
      else
        currentStep && this.props.onPreviousStepChanged && this.props.onPreviousStepChanged(currentStep);

      // Fire entry/exit steps if they exist for previous and current states
      const onExit = prevStep.get('onExit');
      if (typeof onExit === 'function')
        onExit();

      const onEnter = currentStep.get('onEnter');
      if (typeof onEnter === 'function')
        onEnter();
    }
  }

  render() {
    const currentStep = this.state.steps.get(this.state.currentStepIndex);
    if (!currentStep) throw 'Invalid state, currentStep not found for index ' + this.state.currentStepIndex;

    // If defined, execute validators and check the result to determine if the step can advancex;
    const nextStepAllowed = typeof currentStep.get('nextValidator') === 'undefined' || !!currentStep.get('nextValidator');
    // In addition to the prevValidator, make sure this isn't the first step
    const prevStepAllowed = this.state.currentStepIndex !== 0 &&
      (typeof currentStep.get('prevValidator') === 'undefined' || !!currentStep.get('prevValidator'));

    // Build out summary column of steps
    const stepNames = this.state.steps.map((step,index) => {
      // Current step is highlighted in bold
      const nameClasses = ClassNames('list-group-item', {
        'text-bold': index === this.state.currentStepIndex
      });

      // Current step has success badge, previous steps are primary
      // future steps are default
      const numberClasses = ClassNames('badge', {
        'badge-success': index < this.state.currentStepIndex,
        'badge-primary': index === this.state.currentStepIndex,
        'badge-light': index > this.state.currentStepIndex,
      });

      const jumpButton = currentStep.get('allowJumpFrom', false) && step.get('allowJumpTo', false)
      ? (
        <button className='btn btn-sm btn-secondary pull-right'
          onClick={(e: SyntheticInputEvent<*>) => this.handleJumpStepClick(e, index)}>
          <i className='far fa-fw fa-history'></i> Jump
          </button>
      )
      : null;

      return (
        <li key={'stepName-' + index} className={nameClasses}>
          <span className='mr-2' style={{fontSize: '1.5em'}}><span className={numberClasses}>&nbsp;{index + 1}&nbsp;</span></span> {step.get('text')}
          {jumpButton}
        </li>
      );
    });

    const display = currentStep.get('display');
    const onDisplay = typeof display === 'function' ? display() : null;

    return (
      <div className='megawizard'>
        <div className='row'>
          <div className='col-4'>
            <ul className='list-group'>
              {stepNames}
            </ul>
          </div>
          <div className='col'>
            <div className='row'>
              <div className='col-12 text-center'>
                <h2>{this.state.currentStepIndex + 1}. {currentStep.get('text')}</h2>
              </div>
            </div>
            <div className='row mt-1 mb-4 justify-content-center'>
              {onDisplay}
{'fraction_non_alphanumeric': 0.1222115615255457, 'fraction_numerical': 0.0023986567522187576, 'mean_word_length': 3.13103789943027, 'pattern_counts': {'":': 0, '<': 83, '<?xml version=': 0, '>': 107, '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': '4507787', 'n_tokens_mistral': 4693, 'n_tokens_neox': 4581, 'n_words': 1355}