"use strict";

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

var _preact = require("preact");

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

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

var _timeString = require("../utils/time-string");

var _date = require("../utils/date");

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

var _msToTimeString = require("../utils/ms-to-time-string");

var _isToday = _interopRequireDefault(require("date-fns/isToday"));

var _button = require("../button");

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

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

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

class TimeIncrementorButtons extends _preact.Component {
  constructor(props) {
    super(props);
    this.handleTextInput = this.handleTextInput.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.getError = this.getError.bind(this);
    this.realUpdateValue = this.realUpdateValue.bind(this);
    this.startEditingDate = this.startEditingDate.bind(this);
    this.stopEditingDate = this.stopEditingDate.bind(this);
    this.handleDateInput = this.handleDateInput.bind(this);
    this.state = _objectSpread({
      editingDate: false
    }, this.getUpdatedStateForValue(this.getValueToShow()));
  }

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

    return value;
  }

  getUpdatedStateForValue(rawValue, updatedText, updateDateText) {
    const error = this.getError(rawValue);
    return {
      error,
      asNumber: rawValue,
      internalTextValue: updatedText || (0, _msToTimeString.msToTimeString)(rawValue),
      internalDateString: updateDateText || (0, _date.toSimpleISODateString)(rawValue),
      isValid: !error && rawValue
    };
  }

  handleTextInput(e) {
    const newText = e.target.value;
    const newValue = (0, _timeString.timeStringToMs)(newText, {
      timestampFromDay: this.props.value,
      strict: true
    });

    if (newValue) {
      this.realUpdateValue(newValue, newText);
    } else {
      this.setState({
        error: 'Invalid time input use HH:MM',
        internalTextValue: newText
      });
    }
  }

  handleBlur() {
    this.resetFromValue();
  }

  getValueToShow() {
    const {
      displayValue,
      value
    } = this.props;
    return displayValue != null ? displayValue : value;
  }

  startEditingDate() {
    this.setState({
      editingDate: true
    });
    setTimeout(() => {
      const input = this.base && this.base.querySelector('input[type=date]');

      if (input) {
        input.focus();
      }
    }, 300);
  }

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

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

    if (val > max) {
      return "max is ".concat((0, _date.toDateString)(max, true));
    }

    if (val < min) {
      return "min is ".concat((0, _date.toDateString)(min, true));
    }

    return null;
  }

  realUpdateValue(newValue, updatedText) {
    const realValueError = this.getError(this.getValueToShow());
    const {
      updateValue
    } = this.props;
    const changedState = this.getUpdatedStateForValue(newValue, updatedText);
    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);
      }
    }
  }

  handleDateInput(e) {
    const value = e.target.value;

    if (value) {
      const wrongTZDate = new Date(value);
      const asDate = new Date(wrongTZDate.setMinutes(wrongTZDate.getMinutes() + wrongTZDate.getTimezoneOffset()));
      const updatedMs = (0, _timeString.timeStringToMs)(this.state.internalTextValue, {
        timestampFromDay: asDate,
        strict: true
      });
      this.realUpdateValue(updatedMs);
    }
  }

  stopEditingDate() {
    this.setState({
      editingDate: false
    });
  }

  resetFromValue() {
    const newTextValue = (0, _msToTimeString.msToTimeString)(this.props.value);

    if (newTextValue !== this.state.internalTextValue) {
      this.realUpdateValue(this.props.value, newTextValue);
    }
  } // 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) {
      this.resetFromValue();
    }
  }

  render(_ref) {
    let {
      step = 60000,
      max = Infinity,
      min = 0,
      className = '',
      value,
      startingValue,
      name,
      style,
      wrap = true,
      showDate = 'always'
    } = _ref,
        rest = _objectWithoutProperties(_ref, ["step", "max", "min", "className", "value", "startingValue", "name", "style", "wrap", "showDate"]);

    const shouldShowDate = showDate === 'never' ? false : showDate === 'always' || showDate === 'notToday' && !(0, _isToday.default)(value);
    const {
      internalTextValue,
      internalDateString,
      editingDate,
      error
    } = this.state;
    const effectiveValue = value != null ? value : startingValue;
    return (0, _preact.h)("div", _extends({
      className: (0, _classnames.default)('dib', error && _shared.errorClasses, className),
      style: _objectSpread({}, style)
    }, rest), (0, _preact.h)("div", {
      className: (0, _classnames.default)('flex items-center', wrap && 'flex-wrap')
    }, shouldShowDate && (editingDate ? (0, _preact.h)(_inputs.Input, {
      type: "date",
      "data-e2e": "incrementorDateInput",
      onBlur: this.stopEditingDate,
      value: internalDateString,
      onInput: this.handleDateInput,
      className: "mr2"
    }) : (0, _preact.h)(_button.IconButton, {
      type: "button",
      icon: "edit",
      "data-e2e": "incrementorEditDate",
      href: "#",
      className: "mid-gray mr2",
      onClick: this.startEditingDate
    }, (0, _date.toDateString)(effectiveValue))), (0, _preact.h)(_inputs.Input, {
      type: "text",
      name: "time",
      style: {
        width: '60px'
      },
      "data-e2e": "".concat(name, "Value"),
      className: 'mr2 f5' + (error ? 'bg-washed-red' : ''),
      value: internalTextValue,
      onInput: this.handleTextInput,
      onBlur: this.handleBlur
    }), (0, _preact.h)(_plusMinus.MinusButton, {
      name: name,
      disabled: effectiveValue - step < min,
      onClick: () => this.realUpdateValue(effectiveValue - step)
    }), (0, _preact.h)(_plusMinus.PlusButton, {
      name: name,
      disabled: effectiveValue + step > max,
      onClick: () => this.realUpdateValue(effectiveValue + step)
    })), error && (0, _preact.h)(_shared.IncrementorError, null, error));
  }

}

exports.TimeIncrementorButtons = TimeIncrementorButtons;