github.com/replicatedhq/ship@v0.55.0/web/init/src/components/shared/StepNumbers.jsx (about)

     1  import * as React from "react";
     2  import { withRouter } from "react-router-dom";
     3  import isEmpty from "lodash/isEmpty";
     4  import find from "lodash/find";
     5  import indexOf from "lodash/indexOf";
     6  
     7  class StepNumbers extends React.Component {
     8    constructor() {
     9      super();
    10      this.state = {
    11        currentStep: 0,
    12        progressLength: 0,
    13        steps: [],
    14      }
    15    }
    16  
    17    getPositionAtCenter = (element) => {
    18      const data = element.getBoundingClientRect();
    19      return {
    20        x: data.left + data.width / 2,
    21        y: data.top + data.height / 2
    22      };
    23    }
    24  
    25    getDistanceBetweenElements = (a, b) => {
    26      var aPosition = this.getPositionAtCenter(a);
    27      var bPosition = this.getPositionAtCenter(b);
    28      return Math.sqrt(Math.pow(aPosition.x - bPosition.x, 2) + Math.pow(aPosition.y - bPosition.y, 2));
    29    }
    30  
    31    setStepsToState = () => {
    32      const { steps } = this.props;
    33      const stateSteps = steps.map((step) => {
    34        const cleanedPath = this.props.location.pathname.split("/").pop();
    35        const newStep = {
    36          ...step,
    37          isComplete: false,
    38          isActive: cleanedPath === step.id,
    39        };
    40        return newStep;
    41      });
    42      const currIdx = find(stateSteps, ["isActive", true]);
    43      const currStep = indexOf(stateSteps, currIdx);
    44      this.setState({ steps: stateSteps, currentStep: currStep });
    45      this.setCompleteSteps(currStep, stateSteps);
    46    }
    47  
    48    setCompleteSteps = (currentStep, steps) => {
    49      for (let i = 0; i < currentStep; i++) {
    50        let currStep = steps[i];
    51        currStep.isComplete = true;
    52      }
    53      this.setState({ steps });
    54    }
    55  
    56    determineCurrentStep = (id) => {
    57      let stateStep = find(this.state.steps, ["id", id]);
    58      const stateStepIndex = indexOf(this.state.steps, stateStep);
    59      const { currentStep } = this.state;
    60      stateStep.isActive = currentStep === stateStepIndex ? true : false;
    61    }
    62  
    63    goToStep = (idx) => {
    64      const { basePath } = this.props;
    65      const step = this.state.steps[idx];
    66      this.props.history.push(`${basePath}/${step.id}`);
    67    }
    68  
    69    componentDidUpdate(lastProps, lastState) {
    70      if (
    71        (this.props.location.pathname !== lastProps.location.pathname) ||
    72        (this.props.steps !== lastProps.steps && !isEmpty(this.props.steps))
    73      ) {
    74        this.setStepsToState();
    75      }
    76      if (this.state.currentStep !== lastState.currentStep) {
    77        const elOne = find(this.state.steps, ["isComplete", true]);
    78        const elTwo = find(this.state.steps, ["isActive", true]);
    79        if (elOne && elTwo) {
    80          const length = this.getDistanceBetweenElements(document.getElementById(elOne.id), document.getElementById(elTwo.id));
    81          this.setState({ progressLength: length });
    82        }
    83      }
    84    }
    85  
    86    componentDidMount() {
    87      if (!isEmpty(this.props.steps)) {
    88        this.setStepsToState();
    89      }
    90    }
    91  
    92    renderSteps = () => {
    93      const { steps } = this.state;
    94      if (!steps.length) return;
    95      const renderedSteps = this.state.steps.map((step, i) => {
    96        this.determineCurrentStep(step.id); // Is this the current step, if so set to active
    97        return (
    98          <div key={`${step.id}-${i}`} id={step.id} className={`flex-auto u-cursor--pointer flex step-number ${step.isActive ? "is-active" : ""} ${step.isComplete ? "is-complete" : ""}`} onClick={() => this.goToStep(i)}>
    99            <span className="number flex-column flex-verticalCenter alignItems--center">{step.isComplete ? <span className="icon clickable u-smallCheckWhite"></span> : i + 1}</span>
   100          </div>
   101        )
   102      });
   103      return renderedSteps;
   104    }
   105  
   106    render() {
   107      const { inNav } = this.props;
   108      const { currentStep, progressLength } = this.state;
   109      return (
   110        <div className={`flex-column justifyContent--center ${inNav ? "navbar-steps flex1" : "flex-auto"}`}>
   111          {!isEmpty(this.state.steps) ? <div className="steps-numbers-wrapper">
   112            <div className="numbers-wrapper flex flex1 justifyContent--spaceBetween">
   113              {this.renderSteps()}
   114              {currentStep > 0 && <span className="completed-progress-bar" style={{ width: `${progressLength}px` }}></span>}
   115              <span className="progress-base"></span>
   116            </div>
   117          </div>
   118            : null}
   119        </div>
   120      );
   121    }
   122  }
   123  
   124  export default withRouter(StepNumbers);