"use strict";
/*
 * Copyright 2023 Palantir Technologies, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContiguousDayRangePicker = void 0;
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var react_day_picker_1 = require("react-day-picker");
var core_1 = require("@blueprintjs/core");
var datetime_1 = require("@blueprintjs/datetime");
var reactDayPickerUtils_1 = require("../../common/reactDayPickerUtils");
var datePicker3Dropdown_1 = require("../react-day-picker/datePicker3Dropdown");
var datePickerNavIcons_1 = require("../react-day-picker/datePickerNavIcons");
/**
 * Render a standard day range picker where props.contiguousCalendarMonths is expected to be `true`.
 */
var ContiguousDayRangePicker = function (_a) {
    var allowSingleDayRange = _a.allowSingleDayRange, boundaryToModify = _a.boundaryToModify, dayPickerEventHandlers = _a.dayPickerEventHandlers, dayPickerProps = _a.dayPickerProps, initialMonthAndYear = _a.initialMonthAndYear, locale = _a.locale, maxDate = _a.maxDate, minDate = _a.minDate, onRangeSelect = _a.onRangeSelect, _b = _a.singleMonthOnly, singleMonthOnly = _b === void 0 ? false : _b, value = _a.value;
    var _c = useContiguousCalendarViews(initialMonthAndYear, singleMonthOnly, value, dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.onMonthChange), displayMonth = _c.displayMonth, handleMonthChange = _c.handleMonthChange;
    var handleRangeSelect = React.useCallback(function (range, selectedDay, activeModifiers, e) {
        var _a;
        (_a = dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.onSelect) === null || _a === void 0 ? void 0 : _a.call(dayPickerProps, range, selectedDay, activeModifiers, e);
        if (activeModifiers.disabled) {
            return;
        }
        var _b = datetime_1.DateRangeSelectionStrategy.getNextState(value, selectedDay, allowSingleDayRange, boundaryToModify), nextValue = _b.dateRange, boundary = _b.boundary;
        onRangeSelect(nextValue, selectedDay, boundary);
    }, [allowSingleDayRange, boundaryToModify, dayPickerProps, onRangeSelect, value]);
    return (React.createElement(react_day_picker_1.DayPicker, tslib_1.__assign({ showOutsideDays: true }, dayPickerEventHandlers, dayPickerProps, { captionLayout: "dropdown-buttons", components: tslib_1.__assign({ Dropdown: datePicker3Dropdown_1.DatePicker3Dropdown, IconLeft: datePickerNavIcons_1.IconLeft, IconRight: datePickerNavIcons_1.IconRight }, dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.components), fromDate: minDate, locale: locale, mode: "range", month: displayMonth.getFullDate(), numberOfMonths: singleMonthOnly ? 1 : 2, onMonthChange: handleMonthChange, onSelect: handleRangeSelect, selected: (0, reactDayPickerUtils_1.dateRangeToDayPickerRange)(value), toDate: maxDate })));
};
exports.ContiguousDayRangePicker = ContiguousDayRangePicker;
exports.ContiguousDayRangePicker.displayName = "".concat(core_1.DISPLAYNAME_PREFIX, ".ContiguousDayRangePicker");
/**
 * State management and navigation event handlers for a single calendar or two contiguous calendar views.
 *
 * @param initialMonthAndYear initial month and year to display in the left calendar
 * @param singleMonthOnly whether we are only displaying a single month instead of two
 * @param selectedRange currently selected date range
 * @param userOnMonthChange custom `dayPickerProps.onMonthChange` handler supplied by users of `DateRangePicker3`
 */
function useContiguousCalendarViews(initialMonthAndYear, singleMonthOnly, selectedRange, userOnMonthChange) {
    var _a = React.useState(initialMonthAndYear), displayMonth = _a[0], setDisplayMonth = _a[1];
    var prevSelectedRange = React.useRef(selectedRange);
    var isInitialRender = React.useRef(true);
    // use an effect to react to external value updates (such as shortcut item selections)
    React.useEffect(function () {
        // upon first render, we shouldn't update the display month; instead just use the initially computed value.
        // this is important in cases where the user sets `initialMonth` and a controlled `value`.
        if (isInitialRender.current) {
            isInitialRender.current = false;
            return;
        }
        if (selectedRange == null) {
            return;
        }
        setDisplayMonth(function (prevDisplayMonth) {
            var _a, _b;
            var newDisplayMonth = prevDisplayMonth.clone();
            if (selectedRange[0] == null || selectedRange[1] == null) {
                // special case: if only one boundary of the range is selected and it is already displayed in one of the
                // months, don't update the display month. this prevents the picker from shifting around when a user is in
                // the middle of a selection.
                if (isDateDisplayed(selectedRange[0], prevDisplayMonth, singleMonthOnly) ||
                    isDateDisplayed(selectedRange[1], prevDisplayMonth, singleMonthOnly)) {
                    return newDisplayMonth;
                }
            }
            var nextRangeStart = datetime_1.MonthAndYear.fromDate(selectedRange[0]);
            var nextRangeEnd = datetime_1.MonthAndYear.fromDate(selectedRange[1]);
            var hasSelectionEndChanged = ((_a = prevSelectedRange.current[0]) === null || _a === void 0 ? void 0 : _a.valueOf()) === ((_b = selectedRange[0]) === null || _b === void 0 ? void 0 : _b.valueOf());
            if (nextRangeStart == null && nextRangeEnd != null) {
                // Only end date selected.
                // If the newly selected end date isn't in either of the displayed months, then
                //   - set the right DayPicker to the month of the selected end date
                //   - ensure the left DayPicker is before the right, changing if needed
                if (!nextRangeEnd.isSame(newDisplayMonth.getNextMonth())) {
                    newDisplayMonth = nextRangeEnd.getPreviousMonth();
                }
            }
            else if (nextRangeStart != null && nextRangeEnd == null) {
                // Only start date selected.
                // If the newly selected start date isn't in either of the displayed months, then
                //   - set the left DayPicker to the month of the selected start date
                //   - ensure the right DayPicker is before the left, changing if needed
                if (!nextRangeStart.isSame(newDisplayMonth)) {
                    newDisplayMonth = nextRangeStart;
                }
            }
            else if (nextRangeStart != null && nextRangeEnd != null) {
                if (nextRangeStart.isSame(nextRangeEnd)) {
                    // Both start and end date months are identical
                    if (newDisplayMonth.isSame(nextRangeStart) ||
                        (!singleMonthOnly && newDisplayMonth.getNextMonth().isSame(nextRangeEnd))) {
                        // do nothing
                    }
                    else {
                        newDisplayMonth = nextRangeStart;
                    }
                }
                else if (hasSelectionEndChanged) {
                    // If the selection end has changed, adjust the view to show the new end date
                    newDisplayMonth = singleMonthOnly ? nextRangeEnd : nextRangeEnd.getPreviousMonth();
                }
                else {
                    // Otherwise, the selection start must have changed, show that
                    newDisplayMonth = nextRangeStart;
                }
            }
            return newDisplayMonth;
        });
    }, [setDisplayMonth, selectedRange, singleMonthOnly]);
    React.useEffect(function () {
        prevSelectedRange.current = selectedRange;
    }, [selectedRange]);
    var handleMonthChange = React.useCallback(function (newMonth) {
        setDisplayMonth(datetime_1.MonthAndYear.fromDate(newMonth));
        userOnMonthChange === null || userOnMonthChange === void 0 ? void 0 : userOnMonthChange(newMonth);
    }, [userOnMonthChange, setDisplayMonth]);
    return {
        displayMonth: displayMonth,
        handleMonthChange: handleMonthChange,
    };
}
/**
 * Determines whether a given date is displayed in a contiguous single- or double-calendar view.
 */
function isDateDisplayed(date, displayMonth, singleMonthOnly) {
    if (date == null) {
        return false;
    }
    var month = datetime_1.MonthAndYear.fromDate(date);
    return singleMonthOnly
        ? displayMonth.isSameMonth(month)
        : displayMonth.isSameMonth(month) || displayMonth.getNextMonth().isSameMonth(month);
}
//# sourceMappingURL=contiguousDayRangePicker.js.map