content: import React from 'react';
  import PropTypes from 'prop-types';
  import { withStyles } from '@material-ui/core/styles';
  import Stepper from '@material-ui/core/Stepper';
  import Step from '@material-ui/core/Step';
  import StepButton from '@material-ui/core/StepButton';
  import Button from '@material-ui/core/Button';
  import Typography from '@material-ui/core/Typography';
  
  const styles = theme => ({
    root: {
      width: '90%',
    },
    button: {
      marginRight: theme.spacing.unit,
    },
    backButton: {
      marginRight: theme.spacing.unit,
    },
    completed: {
      display: 'inline-block',
    },
    instructions: {
      marginTop: theme.spacing.unit,
      marginBottom: theme.spacing.unit,
    },
  });
  
  function getSteps() {
    return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
  }
  
  function getStepContent(step) {
    switch (step) {
      case 0:
        return 'Step 1: Select campaign settings...';
      case 1:
        return 'Step 2: What is an ad group anyways?';
      case 2:
        return 'Step 3: This is the bit I really care about!';
      default:
        return 'Unknown step';
    }
  }
  
  class HorizontalNonLinearAlternativeLabelStepper extends React.Component {
    state = {
      activeStep: 0,
      completed: new Set(),
      skipped: new Set(),
    };
  
    totalSteps = () => {
      return getSteps().length;
    };
  
    isStepOptional = step => {
      return step === 1;
    };
  
    handleSkip = () => {
      const { activeStep } = this.state;
      if (!this.isStepOptional(activeStep)) {
        // You probably want to guard against something like this
        // it should never occur unless someone's actively trying to break something.
        throw new Error("You can't skip a step that isn't optional.");
      }
  
      this.setState(state => {
        const skipped = new Set(state.skipped.values());
        skipped.add(activeStep);
        return {
          activeStep: state.activeStep + 1,
          skipped,
        };
      });
    };
  
    handleNext = () => {
      let activeStep;
  
      if (this.isLastStep() && !this.allStepsCompleted()) {
        // It's the last step, but not all steps have been completed
        // find the first step that has been completed
        const steps = getSteps();
        activeStep = steps.findIndex((step, i) => !this.state.completed.has(i));
      } else {
        activeStep = this.state.activeStep + 1;
      }
      this.setState({
        activeStep,
      });
    };
  
    handleBack = () => {
      this.setState(state => ({
        activeStep: state.activeStep - 1,
      }));
    };
  
    handleStep = step => () => {
      this.setState({
        activeStep: step,
      });
    };
  
    handleComplete = () => {
      // eslint-disable-next-line react/no-access-state-in-setstate
      const completed = new Set(this.state.completed);
      completed.add(this.state.activeStep);
      this.setState({
        completed,
      });
  
      /**
       * Sigh... it would be much nicer to replace the following if conditional with
       * `if (!this.allStepsComplete())` however state is not set when we do this,
       * thus we have to resort to not being very DRY.
       */
      if (completed.size !== this.totalSteps() - this.skippedSteps()) {
        this.handleNext();
      }
    };
  
    handleReset = () => {
      this.setState({
        activeStep: 0,
        completed: new Set(),
        skipped: new Set(),
      });
    };
  
    skippedSteps() {
      return this.state.skipped.size;
    }
  
    isStepSkipped(step) {
      return this.state.skipped.has(step);
    }
  
    isStepComplete(step) {
      return this.state.completed.has(step);
    }
  
    completedSteps() {
      return this.state.completed.size;
    }
  
    allStepsCompleted() {
      return this.completedSteps() === this.totalSteps() - this.skippedSteps();
    }
  
    isLastStep() {
      return this.state.activeStep === this.totalSteps() - 1;
    }
  
    render() {
      const { classes } = this.props;
      const steps = getSteps();
      const { activeStep } = this.state;
  
      return (
        <div className={classes.root}>
          <Stepper alternativeLabel nonLinear activeStep={activeStep}>
            {steps.map((label, index) => {
              const props = {};
              const buttonProps = {};
              if (this.isStepOptional(index)) {
                buttonProps.optional = <Typography variant="caption">Optional</Typography>;
              }
              if (this.isStepSkipped(index)) {
                props.completed = false;
              }
              return (
                <Step key={label} {...props}>
                  <StepButton
                    onClick={this.handleStep(index)}
                    completed={this.isStepComplete(index)}
                    {...buttonProps}
                  >
                    {label}
                  </StepButton>
                </Step>
              );
            })}
          </Stepper>
          <div>
            {this.allStepsCompleted() ? (
              <div>
                <Typography className={classes.instructions}>
                  All steps completed - you&apos;re finished
                </Typography>
                <Button onClick={this.handleReset}>Reset</Button>
              </div>
            ) : (
              <div>
                <Typography className={classes.instructions}>{getStepContent(activeStep)}</Typography>
                <div>
                  <Button
                    disabled={activeStep === 0}
                    onClick={this.handleBack}
                    className={classes.button}
                  >
                    Back
                  </Button>
                  <Button
                    variant="contained"
                    color="primary"
                    onClick={this.handleNext}
                    className={classes.button}
                  >
                    Next
                  </Button>
                  {this.isStepOptional(activeStep) &&
                    !this.state.completed.has(this.state.activeStep) && (
                      <Button
                        variant="contained"
                        color="primary"
                        onClick={this.handleSkip}
                        className={classes.button}
                      >
                        Skip
                      </Button>
                    )}
                  {activeStep !== steps.length &&
                    (this.state.completed.has(this.state.activeStep) ? (
                      <Typography variant="caption" className={classes.completed}>
                        Step {activeStep + 1} already completed
                      </Typography>
                    ) : (
                      <Button variant="contained" color="primary" onClick={this.handleComplete}>
                        {this.completedSteps() === this.totalSteps() - 1 ? 'Finish' : 'Complete Step'}
                      </Button>
                    ))}
                </div>
              </div>
            )}
          </div>
        </div>
      );
    }
  }
  
  HorizontalNonLinearAlternativeLabelStepper.propTypes = {
    classes: PropTypes.object,
  };
  
  export default withStyles(styles)(HorizontalNonLinearAlternativeLabelStepper);
  