"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.DATE_RANGE_INPUT_TYPES = exports.DATE_RANGE_ERROR_TYPES = void 0;
var _react = _interopRequireWildcard(require("react"));
var _moment = _interopRequireDefault(require("moment"));
var _isEmpty = _interopRequireDefault(require("lodash-es/isEmpty"));
var _faCalendar = require("@fortawesome/free-regular-svg-icons/faCalendar");
var _button = require("../button");
var _formField = require("../form-field");
var _dateRangeSingleDatePicker = _interopRequireDefault(require("./date-range-single-date-picker"));
var _datetimeRangePicker = require("./datetime-range-picker");
var _dateRangeSingleDatePickerInput = _interopRequireDefault(require("./date-range-single-date-picker-input"));
var _helpers = require("./helpers");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
let DATE_RANGE_ERROR_TYPES = exports.DATE_RANGE_ERROR_TYPES = /*#__PURE__*/function (DATE_RANGE_ERROR_TYPES) {
  DATE_RANGE_ERROR_TYPES["INVALID_DATETIME"] = "INVALID_DATETIME";
  DATE_RANGE_ERROR_TYPES["START_AFTER_END"] = "START_AFTER_END";
  DATE_RANGE_ERROR_TYPES["END_BEFORE_START"] = "END_BEFORE_START";
  DATE_RANGE_ERROR_TYPES["START_BEFORE_MIN"] = "START_BEFORE_MIN";
  DATE_RANGE_ERROR_TYPES["END_AFTER_MAX"] = "END_AFTER_MAX";
  DATE_RANGE_ERROR_TYPES["END_AFTER_MIN"] = "END_AFTER_MIN";
  DATE_RANGE_ERROR_TYPES["START_AFTER_MAX"] = "START_AFTER_MAX";
  DATE_RANGE_ERROR_TYPES["INVALID_START_DATE"] = "INVALID_START_DATE";
  DATE_RANGE_ERROR_TYPES["INVALID_END_DATE"] = "INVALID_END_DATE";
  DATE_RANGE_ERROR_TYPES["START_END_SAME"] = "START_END_SAME";
  return DATE_RANGE_ERROR_TYPES;
}({});
const DATE_RANGE_INPUT_TYPES = exports.DATE_RANGE_INPUT_TYPES = {
  START: 'START',
  END: 'END'
};
const INITIAL_MODE = {
  days: 'months',
  months: 'years'
};
const DATA_MONTH_PROP = 'data-month';
function getNextState({
  state,
  selectedValue
}) {
  // if we know which date the user wants to change (because they explicitly highlighted the field)
  // then we can just update that part of state
  if (state.targetInput === DATE_RANGE_INPUT_TYPES.START) {
    return {
      start: selectedValue,
      end: selectedValue.isAfter(state.end) ? null : state.end,
      // being careful to clear the other date if the range would be invalid
      targetInput: DATE_RANGE_INPUT_TYPES.END
    };
  }

  // same as the block above, but in reverse
  if (state.targetInput === DATE_RANGE_INPUT_TYPES.END) {
    // with one exception - setting the end to before the start moves the start instead
    if (selectedValue.isBefore(state.start)) {
      return {
        start: selectedValue,
        end: state.end,
        targetInput: DATE_RANGE_INPUT_TYPES.END
      };
    }
    return {
      start: selectedValue.isBefore(state.start) ? null : state.start,
      end: selectedValue,
      targetInput: DATE_RANGE_INPUT_TYPES.START
    };
  }

  // if we don't have an explicit selection from the user then we start a new selection flow
  // this is a fallback, as in most cases we should have an explicitly desired input
  return {
    start: selectedValue,
    end: null,
    targetInput: DATE_RANGE_INPUT_TYPES.END
  };
}
/** Represents the panel used to select two datetimes that make up a range. */
function DateRangePickerPanel({
  buttonText,
  cancelButtonText,
  dateFormat = '',
  defaultEnd,
  defaultStart,
  initialDirection,
  initialViewMode = _datetimeRangePicker.VIEW_MODE_TYPE.DAYS,
  initialTargetInput,
  maxEnd,
  minStart,
  sameDateError,
  onSubmit,
  onDismiss,
  resetText,
  timeFormat,
  utcSuffix,
  validateOnClick: propValidateOnClick,
  validateOnChange: propValidateOnChange,
  dateStartInputAriaLabel,
  dateEndInputAriaLabel
}) {
  const defaultValidateOnClick = (0, _helpers.useValidateOnClick)();
  const defaultValidateOnChange = (0, _helpers.useGetDateTimeValidityError)();
  const validateOnClick = propValidateOnClick || defaultValidateOnClick;
  const validateOnChange = propValidateOnChange || defaultValidateOnChange;
  const dateTimeFormat = (0, _helpers.getDateTimeFormat)(dateFormat, timeFormat);

  // Developer-provided datetimes might not always follow the exact date and time format they want to use.
  // For convenience, we format the provided times.
  const [defaultStartTrimmed, defaultEndTrimmed] = [defaultStart, defaultEnd].map(datetime => (0, _helpers.truncateDateTimeToFormat)(datetime, dateTimeFormat));
  const [minStartTrimmed, maxEndTrimmed] = [minStart, maxEnd].map(datetime => datetime ? (0, _helpers.truncateDateTimeToFormat)(datetime, dateTimeFormat) : null);
  const [state, setState] = (0, _react.useState)({
    start: defaultStartTrimmed,
    end: defaultEndTrimmed,
    startErrors: {},
    endErrors: {},
    targetInput: null
  });
  const initialLeftCalendarStart = (0, _helpers.getLeftCalendarInitialView)(initialDirection, state.start, state.end, INITIAL_MODE[initialViewMode]);
  const initialRightCalendarStart = (0, _helpers.getRightCalendarInitialView)(initialDirection, state.start, state.end, INITIAL_MODE[initialViewMode]);
  const leftPickerRef = (0, _react.useRef)(null);
  const rightPickerRef = (0, _react.useRef)(null);
  const startValidity = (0, _helpers.getValidityFromErrors)(state.startErrors);
  const endValidity = (0, _helpers.getValidityFromErrors)(state.endErrors);
  const datePicker = document.getElementsByClassName('single-datetime-picker');
  function handleSubmit() {
    if (state.start && state.end) {
      onSubmit(state.start, state.end);
    }
  }
  function hasUpdatedStart() {
    return state.start?.toISOString() !== defaultStartTrimmed?.toISOString();
  }
  function hasUpdatedEnd() {
    return state.end?.toISOString() !== defaultEndTrimmed?.toISOString();
  }
  function hasUpdatedValues() {
    return hasUpdatedStart() || hasUpdatedEnd();
  }
  function hasStartErrors() {
    return !(0, _isEmpty.default)(state.startErrors);
  }
  function hasEndErrors() {
    return !(0, _isEmpty.default)(state.endErrors);
  }
  function submitIsDisabled() {
    return hasStartErrors() || hasEndErrors() || !hasUpdatedValues();
  }
  function handleOnChange(selectedValue) {
    if (!_moment.default.isMoment(selectedValue)) {
      return;
    }

    // left time update
    if ((0, _helpers.isMonthRelatedToTimePicker)(leftPickerRef, selectedValue) && state.start && state.end) {
      const updatedTime = (0, _moment.default)(state.start).set({
        hour: selectedValue.hours(),
        minute: selectedValue.minutes()
      });
      return setState({
        ...state,
        start: updatedTime,
        ...validateOnClick({
          start: updatedTime,
          end: state.end,
          viewMode: initialViewMode,
          dateTimeFormat,
          minStart,
          maxEnd,
          sameDateError
        })
      });
    }

    // right time update
    if ((0, _helpers.isMonthRelatedToTimePicker)(rightPickerRef, selectedValue) && state.start && state.end) {
      const updatedTime = (0, _moment.default)(state.end).set({
        hour: selectedValue.hours(),
        minute: selectedValue.minutes()
      });
      return setState({
        ...state,
        end: updatedTime,
        ...validateOnClick({
          start: state.start,
          end: updatedTime,
          viewMode: initialViewMode,
          dateTimeFormat,
          minStart,
          maxEnd,
          sameDateError
        })
      });
    }
    const {
      start,
      end,
      targetInput
    } = getNextState({
      state,
      selectedValue
    });
    setState({
      start,
      end,
      targetInput,
      ...validateOnClick({
        start,
        end,
        viewMode: initialViewMode,
        dateTimeFormat,
        minStart,
        maxEnd,
        sameDateError
      })
    });
  }
  function handleStartReset() {
    setState({
      ...state,
      start: defaultStartTrimmed,
      startErrors: {}
    });
  }
  function handleEndReset() {
    setState({
      ...state,
      end: defaultEndTrimmed,
      endErrors: {}
    });
  }
  function startDayEnabled(startDay) {
    if (minStartTrimmed && startDay.isBefore(minStartTrimmed)) {
      return false;
    }
    if (maxEndTrimmed && startDay.isAfter(maxEndTrimmed)) {
      return false;
    }
    return true;
  }
  function endDayEnabled(endDay) {
    if (minStartTrimmed && endDay.isBefore(minStartTrimmed)) {
      return false;
    }
    if (maxEndTrimmed && endDay.isAfter(maxEndTrimmed)) {
      return false;
    }
    return true;
  }
  function renderLeftDay(props, selectedDate) {
    const {
      start,
      end
    } = state;
    const {
      className,
      ...rest
    } = props;
    let classes = (0, _helpers.customizeCalendarView)(selectedDate, start, end, className, 'day');
    const currentMonthNumber = leftPickerRef.current ? leftPickerRef.current.state.viewDate.month() : initialLeftCalendarStart.month();
    if (currentMonthNumber !== props[DATA_MONTH_PROP]) {
      classes = 'rdtDisabled';
    }
    return /*#__PURE__*/(0, _jsxRuntime.jsx)("td", {
      ...rest,
      className: classes,
      children: selectedDate.date()
    });
  }
  function renderRightDay(props, selectedDate) {
    const {
      start,
      end
    } = state;
    const {
      className,
      ...rest
    } = props;
    let classes = (0, _helpers.customizeCalendarView)(selectedDate, start, end, className, 'day');
    const currentMonthNumber = rightPickerRef.current ? rightPickerRef.current.state.viewDate.month() : initialRightCalendarStart.month();
    if (currentMonthNumber !== props[DATA_MONTH_PROP]) {
      classes = 'rdtDisabled';
    }
    return /*#__PURE__*/(0, _jsxRuntime.jsx)("td", {
      ...rest,
      className: classes,
      children: selectedDate.date()
    });
  }
  function renderMonth(props, month, year) {
    const {
      start,
      end
    } = state;
    const date = (0, _moment.default)().month(month).year(year);
    const formattedDate = (0, _helpers.truncateDateTimeToFormat)(date, dateTimeFormat);
    const {
      className,
      ...rest
    } = props;
    const classes = (0, _helpers.customizeCalendarView)(formattedDate, start, end, className, 'month');
    return /*#__PURE__*/(0, _jsxRuntime.jsx)("td", {
      ...rest,
      className: classes,
      children: (0, _moment.default)().month(month).format('MMM')
    });
  }
  function renderLeftView(mode, renderDefault) {
    return (0, _helpers.customizeRenderCalendarView)(mode, leftPickerRef, state.start, dateTimeFormat, timeFormat, renderDefault);
  }
  function renderRightView(mode, renderDefault) {
    return (0, _helpers.customizeRenderCalendarView)(mode, rightPickerRef, state.end, dateTimeFormat, timeFormat, renderDefault);
  }
  function onNavigateBackLeft() {
    datePicker[1].classList.remove('hide-right-date-picker-prev');
    datePicker[0].classList.remove('hide-left-date-picker-next');
  }
  function onNavigateForwardLeft(_, currentView) {
    datePicker[0].classList.remove('hide-right-date-picker-prev');
    if ((0, _helpers.isNavigationAvailableForMonthsView)(currentView, leftPickerRef, rightPickerRef, 2) || (0, _helpers.isNavigationAvailableForYearsView)(currentView, leftPickerRef, rightPickerRef, 2)) {
      datePicker[1].classList.add('hide-right-date-picker-prev');
      datePicker[0].classList.add('hide-left-date-picker-next');
    }
  }
  function onNavigateBackRight(_, currentView) {
    if ((0, _helpers.isNavigationAvailableForMonthsView)(currentView, leftPickerRef, rightPickerRef, 2) || (0, _helpers.isNavigationAvailableForYearsView)(currentView, leftPickerRef, rightPickerRef, 2)) {
      datePicker[1].classList.add('hide-right-date-picker-prev');
      datePicker[0].classList.add('hide-left-date-picker-next');
    }
  }
  function onNavigateForwardRight(_, currentView) {
    datePicker[1].classList.remove('hide-right-date-picker-prev');
    if ((0, _helpers.isNavigationAvailableForMonthsView)(currentView, leftPickerRef, rightPickerRef, 1) || (0, _helpers.isNavigationAvailableForYearsView)(currentView, leftPickerRef, rightPickerRef, 1)) {
      datePicker[0].classList.remove('hide-left-date-picker-next');
    }
  }
  function handleInputStartChange(e) {
    const startValidityError = validateOnChange(e.target.value, dateTimeFormat);
    if (startValidityError) {
      return setState({
        ...state,
        startErrors: {
          [DATE_RANGE_ERROR_TYPES.INVALID_DATETIME]: startValidityError
        }
      });
    }
    const value = (0, _helpers.convertStringToMoment)(e.target.value, {
      dateTimeFormat
    });
    if (value && value.isAfter(state.end)) {
      return setState({
        ...state,
        start: value,
        end: null,
        ...validateOnClick({
          start: value,
          viewMode: initialViewMode,
          dateTimeFormat,
          minStart,
          maxEnd,
          sameDateError
        })
      });
    }
    return setState({
      ...state,
      start: value,
      ...validateOnClick({
        start: value,
        end: state.end,
        viewMode: initialViewMode,
        dateTimeFormat,
        minStart,
        maxEnd,
        sameDateError
      })
    });
  }
  function handleInputEndChange(e) {
    const endValidityError = validateOnChange(e.target.value, dateTimeFormat);
    if (endValidityError) {
      return setState({
        ...state,
        endErrors: {
          [DATE_RANGE_ERROR_TYPES.INVALID_DATETIME]: endValidityError
        }
      });
    }
    const value = (0, _helpers.convertStringToMoment)(e.target.value, {
      dateTimeFormat
    });
    if (value && value.isBefore(state.start)) {
      return setState({
        ...state,
        start: null,
        end: value,
        ...validateOnClick({
          end: value,
          viewMode: initialViewMode,
          dateTimeFormat,
          minStart,
          maxEnd,
          sameDateError
        })
      });
    }
    return setState({
      ...state,
      end: value,
      ...validateOnClick({
        start: state.start,
        end: value,
        viewMode: initialViewMode,
        dateTimeFormat,
        minStart,
        maxEnd,
        sameDateError
      })
    });
  }
  function handleInputStartFocus() {
    setState({
      ...state,
      targetInput: DATE_RANGE_INPUT_TYPES.START
    });
  }
  function handleInputEndFocus() {
    setState({
      ...state,
      targetInput: DATE_RANGE_INPUT_TYPES.END
    });
  }
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
    children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      className: "datetime-range-picker-panel-inputs",
      "test-id": "datetime-range-picker-panel",
      children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "range-inputs",
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_dateRangeSingleDatePickerInput.default, {
          touched: hasUpdatedStart(),
          onChange: handleInputStartChange,
          resetEnabled: hasUpdatedStart() || hasStartErrors(),
          onReset: handleStartReset,
          validity: startValidity,
          fieldTestId: "datetime-range-start-input",
          resetButtonTestId: "datetime-range-start-reset-button",
          type: "text",
          value: (0, _moment.default)(state.start).format(dateTimeFormat),
          autoFocus: initialTargetInput !== DATE_RANGE_INPUT_TYPES.END,
          rightIcon: _faCalendar.faCalendar,
          resetText: resetText,
          utcSuffix: utcSuffix,
          onFocus: handleInputStartFocus,
          isHighlighted: state.targetInput === DATE_RANGE_INPUT_TYPES.START,
          dateFormat: dateFormat,
          timeFormat: timeFormat,
          ariaLabel: dateStartInputAriaLabel
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_dateRangeSingleDatePickerInput.default, {
          touched: hasUpdatedEnd(),
          onChange: handleInputEndChange,
          resetEnabled: hasUpdatedEnd() || hasEndErrors(),
          onReset: handleEndReset,
          validity: endValidity,
          fieldTestId: "datetime-range-end-input",
          resetButtonTestId: "datetime-range-end-reset-button",
          type: "text",
          value: (0, _moment.default)(state.end).format(dateTimeFormat),
          autoFocus: initialTargetInput === DATE_RANGE_INPUT_TYPES.END,
          rightIcon: _faCalendar.faCalendar,
          resetText: resetText,
          utcSuffix: utcSuffix,
          onFocus: handleInputEndFocus,
          isHighlighted: state.targetInput === DATE_RANGE_INPUT_TYPES.END,
          dateFormat: dateFormat,
          timeFormat: timeFormat,
          ariaLabel: dateEndInputAriaLabel
        })]
      }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "date-pickers",
        "test-id": "date-pickers-container",
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_dateRangeSingleDatePicker.default, {
          ref: leftPickerRef,
          initialViewDate: initialLeftCalendarStart,
          onChange: handleOnChange,
          isValidDate: startDayEnabled,
          dateFormat: dateFormat,
          renderDay: renderLeftDay,
          renderMonth: renderMonth,
          timeFormat: timeFormat,
          initialViewMode: initialViewMode,
          onNavigateForward: onNavigateForwardLeft,
          onNavigateBack: onNavigateBackLeft,
          renderView: renderLeftView,
          className: "hide-left-date-picker-next",
          containerTestId: "datetime-range-left-container"
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_dateRangeSingleDatePicker.default, {
          ref: rightPickerRef,
          initialViewDate: initialRightCalendarStart,
          onChange: handleOnChange,
          isValidDate: endDayEnabled,
          dateFormat: dateFormat,
          timeFormat: timeFormat,
          initialViewMode: initialViewMode,
          renderDay: renderRightDay,
          renderMonth: renderMonth,
          onNavigateForward: onNavigateForwardRight,
          onNavigateBack: onNavigateBackRight,
          renderView: renderRightView,
          className: "hide-right-date-picker-prev",
          containerTestId: "datetime-range-right-container"
        })]
      })]
    }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      className: "datetime-range-picker-panel-controls",
      children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "datetime-range-picker-control-buttons",
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
          className: "button primary",
          onClick: handleSubmit,
          disabled: submitIsDisabled(),
          "test-id": "datetime-range-picker-submit-button",
          type: _button.BUTTON_TYPES.BUTTON,
          children: buttonText
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
          className: "button command",
          onClick: onDismiss,
          type: _button.BUTTON_TYPES.BUTTON,
          children: cancelButtonText
        })]
      }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "datetime-range-picker-validation-messages",
        children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_formField.ValidityMessages, {
          validity: startValidity,
          fieldId: "datetime-range-start-input"
        }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_formField.ValidityMessages, {
          validity: endValidity,
          fieldId: "datetime-range-end-input"
        })]
      })]
    })]
  });
}
var _default = exports.default = DateRangePickerPanel;