"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.IncrementorButtons = void 0;

var _preact = require("preact");

var _classnames = _interopRequireDefault(require("classnames"));

var _decimals = require("../utils/decimals");

var _inputs = require("../inputs");

var _plusMinus = require("../plus-minus");

var _shared = require("./shared");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

const roundIfNeeded = (val, step) => (0, _decimals.roundToDecimal)(val, (0, _decimals.getNumberOfDecimals)(step));

class IncrementorButtons extends _preact.Component {
  constructor(props) {
    super(props);
    this.state = this.getUpdatedStateForValue(this.getValueToShow());
  }

  getTargetNumberOfDecimals() {
    const {
      step = 1
    } = this.props;
    return (0, _decimals.getNumberOfDecimals)(step);
  }

  getValueAsNumber(value) {
    if (typeof value === 'string') {
      return Number(value);
    }

    return value;
  }

  getUpdatedStateForValue(rawValue, isTrusted) {
    let {
      max
    } = this.props;

    if (max == null) {
      max = Infinity;
    }

    if (isTrusted) {
      return {
        error: null,
        asNumber: rawValue,
        internalTextValue: rawValue.toString(),
        isValid: true
      };
    }

    const maxLenBefore = max === Infinity ? 20 : max.toString().split('.')[0].length;
    const maxLenAfter = this.getTargetNumberOfDecimals();
    const cleaned = (0, _decimals.getCleanDecimalWithLimits)({
      maxLenBefore,
      maxLenAfter
    })(rawValue);
    const asNumber = this.getValueAsNumber(cleaned);
    const hasValue = !!rawValue;
    const error = hasValue ? this.getError(asNumber) : null;
    const isValid = hasValue && !error;
    return {
      error,
      asNumber: asNumber,
      internalTextValue: cleaned,
      isValid
    };
  }

  getValueToShow() {
    const {
      displayValue,
      value
    } = this.props;
    const targetNumberOfDecimals = this.getTargetNumberOfDecimals();
    let valueToShow = displayValue != null ? displayValue : value;

    if (!valueToShow) {
      valueToShow = targetNumberOfDecimals === 0 ? value : (0, _decimals.ensureDecimals)(value, targetNumberOfDecimals);
    }

    return valueToShow && valueToShow.toString ? valueToShow.toString() : '';
  }

  getError(val) {
    const {
      max,
      min
    } = this.props;

    if (isNaN(val)) {
      return "invalid value";
    }

    if (val > max) {
      return "max is ".concat(max);
    }

    if (val < min) {
      return "min is ".concat(min);
    }

    return;
  }

  realUpdateValue(newValue, isTrusted) {
    const realValueError = this.getError(this.getValueToShow());
    const {
      updateValue
    } = this.props;
    const changedState = this.getUpdatedStateForValue(newValue, isTrusted);
    this.setState(changedState); // if we're already in an error state, we can allow the update.
    // this is important if we are fixing a scenario where the real-underlying
    // value is already out of range and people want to use the + and - buttons
    // to get it *into* range.

    if (!changedState.error || realValueError) {
      // we only want to report it if it's different
      if (changedState.asNumber !== this.props.value) {
        updateValue(changedState.asNumber);
      }
    }
  } // this handles changes to underlying value that need to be
  // reflected in the text


  componentDidUpdate(prevProps) {
    const valueChanged = prevProps.value !== this.props.value;

    if (valueChanged) {
      const newTextValue = this.getUpdatedStateForValue(this.props.value, true).internalTextValue;

      if (newTextValue !== this.state.internalTextValue) {
        this.realUpdateValue(this.props.value);
      }
    }
  }

  render() {
    const {
      step = 1,
      max = Infinity,
      min = 0,
      className = '',
      showStep = true,
      unit = '',
      value,
      startingValue,
      name
    } = this.props;
    const {
      internalTextValue,
      error
    } = this.state;
    const effectiveValue = value != null ? value : startingValue;
    const stepDown = roundIfNeeded(effectiveValue - step, step);
    const stepUp = roundIfNeeded(effectiveValue + step, step);
    return (0, _preact.h)("div", {
      className: (0, _classnames.default)('dib', error && _shared.errorClasses, className)
    }, (0, _preact.h)("div", {
      className: "flex items-center ".concat(className)
    }, (0, _preact.h)(_inputs.Input, {
      type: "text",
      "data-e2e": "".concat(name, "Value"),
      style: {
        width: '60px'
      },
      className: 'mr2 f5' + (error ? 'bg-washed-red' : ''),
      value: internalTextValue,
      onInput: e => {
        const value = e.target.value;
        this.realUpdateValue(value);
      }
    }), unit && (0, _preact.h)("span", {
      className: "mr2 f5 fw6"
    }, unit), (0, _preact.h)(_plusMinus.MinusButton, {
      name: name,
      disabled: stepDown < min,
      onClick: () => this.realUpdateValue(stepDown, true)
    }, showStep ? step : null), (0, _preact.h)(_plusMinus.PlusButton, {
      name: name,
      disabled: stepUp > max,
      onClick: () => this.realUpdateValue(stepUp, true)
    }, showStep ? step : null)), error && (0, _preact.h)(_shared.IncrementorError, null, error));
  }

}

exports.IncrementorButtons = IncrementorButtons;