20250105 - 에어비앤비와 유사한 기능으로 변경 Date Picker2

처리조건 :

1. 기본 로드될 때 이미 예약되어 선택 불가능한 날짜들 17, 18일, 24,25일 비활성화처리


2. 체크인 날짜 선택시 그 이후 기예약 시작일 찾아서 거기까지만 예약 가능하도록 나머지 일자 비활성화 처리



3. 체크아웃 날짜 선택시 처음에 로드했던 예약 불가능한 날짜들 17, 18일, 24,25일 비활성화처리 (단, 기예약 시작일과 현재 선택하는 체크아웃 날짜는 같을 수 있도록 처리 보완 필요, 추가 이미지 확인)





Page Load


window.checkInCheckOutDateRangePicker = new DateRangePicker({
   picker: {
       name: "P6_CHECKIN_CHECKOUT_PICKER",
       format: "YYYY-MM-DD",
       allowSingleDay: false
   },
   start: {
       name: "P6_CHECKIN",  
       label: "Check In"
   },
   end: {
       name: "P6_CHECKOUT",
       label:"Check Out"
   },
   reset: {
       id:"Reset_CheckIn_CheckOut"
   }
});

const testDates = ['2025-01-17', '2025-01-18', '2025-01-24', '2025-01-25', '2025-01-26'];
window.checkInCheckOutDateRangePicker.setDisabledDates(testDates);


$(document).on('daterangepicker-reset', function(event, data) {
    apex.item('P6_MAX').setValue(null);

    window.checkInCheckOutDateRangePicker.setMaxDate(null);

    const testDates = ['2025-01-17', '2025-01-18', '2025-01-24', '2025-01-25', '2025-01-26'];
    window.checkInCheckOutDateRangePicker.setDisabledDates(testDates);
});

// 참고 : 예약된 날짜 데이터 가져오기
/*
apex.server.process(
   'GET_RESERVED_DATES',
   {},
   {
       success: function(data) {
           // data는 ['2024-01-01', '2024-01-02', '2024-01-03'] 형식으로 받음
           window.checkInCheckOutDateRangePicker.setDisabledDates(data);
           window.eventStartEndDateRangePicker.setDisabledDates(data);  // 두 번째 데이트피커에도 적용
       },
       error: function(jqXHR, textStatus, errorThrown) {
           apex.message.showErrors([{
               type: "error",
               location: ["page"],
               message: "Failed to load reserved dates",
               unsafe: false
           }]);
       }
   }
);
*/


P6_CHECKIN 선택시(변경시), Max 예약일 구한 후 :

PL/SQL


:P6_MAX := '2025-01-17'; --to_date('2025-01-17', 'YYYY-MM-DD');


JS 


const maxDate = apex.item('P6_MAX').getValue();
window.checkInCheckOutDateRangePicker.setDisabledDates(null);
window.checkInCheckOutDateRangePicker.setMaxDate(maxDate);


P6_CHECKOUT 선택시(변경시)


window.checkInCheckOutDateRangePicker.setMaxDate(null);

//나중에 종료일 선택 날짜와 P6_MAX와 같으면 비활성화 날짜 리스트에서 제외, 예를 들어 '2025-01-17' 종료일 선택일 경우
const testDates = ['2025-01-18', '2025-01-24', '2025-01-25', '2025-01-26'];
window.checkInCheckOutDateRangePicker.setDisabledDates(testDates);


P6_CHECKIN_CHECKOUT_PICKER :



Reset_CheckIn_CheckOut 버튼 (SID 및 DA 로 셋팅) :




CSS : 


a-date-picker.date-range-picker .a-DatePicker-calendar td.is-current {
    --a-datepicker-calendar-day-current-background-color: var(--a-datepicker-calendar-background-color);
    --a-datepicker-calendar-day-current-text-color: var(--a-datepicker-calendar-day-text-color);
    --a-datepicker-calendar-day-current-border-color: var(--a-datepicker-calendar-background-color);
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.is-current > span,
a-date-picker.date-range-picker .a-DatePicker-calendar td.is-selected > span {
    font-weight: var(--a-datepicker-calendar-day-font-weight, var(--a-base-font-weight-semibold,500));
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.is-current.dateRangeStart > span,
a-date-picker.date-range-picker .a-DatePicker-calendar td.is-current.dateRangeEnd > span {
     border-radius: var(--a-datepicker-calendar-day-border-radius);
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeStart,
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeEnd,
a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeSingleDay {
     --a-datepicker-calendar-day-border-radius: calc(var(--a-datepicker-calendar-day-font-size, 1rem) * 2);
     --a-datepicker-calendar-day-text-color: var(--a-palette-primary-contrast);                        
}

a-date-picker.date-range-picker .a-DatePicker-calendar td {
    height: 44px !important;
    position: relative;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td > span {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 44px !important;
    height: 44px !important;
    margin: auto !important;
    border-radius: 50% !important;
    position: relative;
    z-index: 2;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeStart {
    background: none;
    position: relative;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeStart:not(.dateRangeSingleDay)::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    right: 0;
    height: 44px;
    transform: translateY(-22px);
    background-color: #F7F7F7;
    z-index: 1;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeStart > span {
    background-color: #222222 !important;
    color: #FFFFFF !important;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeMiddle {
    background: none;
    position: relative;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeMiddle::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    right: 0;
    height: 44px;
    transform: translateY(-22px);
    background-color: #F7F7F7;
    z-index: 1;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeEnd {
    background: none;
    position: relative;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeEnd::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    right: 50%;
    height: 44px;
    transform: translateY(-22px);
    background-color: #F7F7F7;
    z-index: 1;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeEnd > span {
    background-color: #222222 !important;
    color: #FFFFFF !important;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.dateRangeSingleDay > span {
    background-color: #222222 !important;
    color: #FFFFFF !important;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.is-disabled > span {
    text-decoration: line-through;
}

a-date-picker.date-range-picker .a-DatePicker-calendar td.is-selected > span {
    background-color: #222222 !important;
    color: #FFFFFF !important;
}


JS :


window.DateRangePicker = class DateRangePicker {
    constructor(pConfig) {
        this.#config = pConfig;
        this.#disabledDates = new Set();
        this.#maxDate = null;
        this.#pickerItem().element.addClass("date-range-picker");
        this.#assignInitialValueFromStartDate();
        this.#assignDayFormatter();
        this.#pickerItem().element.on("change", () => {
            this.#onChanged();
        });
        document.getElementById(this.#resetId()).addEventListener("click", () => {
            this.#reset();
        });
    }

    #config;
    #disabledDates;
    #maxDate;

    setDisabledDates(dates) {
        this.#disabledDates = new Set(dates);
        this.#pickerItem().refresh();
    }

    setMaxDate(date) {
        this.#maxDate = date;
        this.#pickerItem().refresh();
    }

    #pickerItem() {
        return apex.items[this.#config.picker.name];
    }

    #pickerFormat() {
        return this.#config.picker.format;
    }

    #pickerSingleDay() {
        return this.#config.picker.allowSingleDay;
    }

    #startItem() {
        return apex.items[this.#config.start.name];
    }

    #startItemLabel() {
        return this.#config.start.label;
    }

    #endItem() {
        return apex.items[this.#config.end.name];
    }

    #resetId() {
        return this.#config.reset.id;
    }

    #endItemLabel() {
        return this.#config.end.label;
    }

    #assignInitialValueFromStartDate() {
        const startItemValue = this.#startItem().getValue();
        if (startItemValue) {
            this.#pickerItem().setValue(startItemValue,null,true);
        }
    }

    #assignDayFormatter() {
        const pickerItem = this.#pickerItem();
        const startItemLabel = this.#startItemLabel();
        const endItemLabel = this.#endItemLabel();
        const pickerFormat = this.#pickerFormat();
        const startItem = this.#startItem();
        const endItem = this.#endItem();
        const getDisabledDates = () => this.#disabledDates;
        const getMaxDate = () => this.#maxDate;

        pickerItem.dayFormatter = function(iso8860DateString) {
            const disabledDates = getDisabledDates();
            const maxDate = getMaxDate();
            const currentDate = apex.date.parse(iso8860DateString, "YYYY-MM-DD");
            const isDisabledByDate = disabledDates.has(iso8860DateString);
            const isAfterMax = maxDate ?
                apex.date.isAfter(currentDate, apex.date.parse(maxDate, pickerFormat)) :
                false;
            const isDisabled = isDisabledByDate || isAfterMax;
            const startDateValue = startItem.getValue();
            const startDate = startDateValue ? apex.date.parse(startDateValue, pickerFormat) : null;
            const endDateValue = endItem.getValue();
            const endDate = endDateValue ? apex.date.parse(endDateValue, pickerFormat) : null;
            var tooltipText = "";
            var dateRangeClass = "";

            if (!startDateValue) {
                tooltipText = "Choose " + (startItemLabel ? startItemLabel : "Start") + " Date";
            } else {
                if (apex.date.isSame(startDate, currentDate)) {
                    tooltipText = startItemLabel;
                } else {
                    if (!endDateValue) {
                        tooltipText = "Choose " + (endItemLabel ? endItemLabel : "End") + " Date";
                    } else {
                        if (apex.date.isSame(endDate, currentDate)) {
                            tooltipText = endItemLabel;
                        }
                    }
                }
            }

            if (startDateValue) {
                if (apex.date.isSame(currentDate, startDate)) {
                    if (endDateValue && apex.date.isSame(currentDate, endDate)) {
                        dateRangeClass = "dateRangeSingleDay";
                    } else if (endDateValue) {
                        dateRangeClass = "dateRangeStart";
                    } else {
                        dateRangeClass = "dateRangeSingleDay";
                    }
                } else if (endDateValue) {
                    if (apex.date.isSame(currentDate, endDate)) {
                        dateRangeClass = "dateRangeEnd";
                    } else if (apex.date.isBetween(currentDate, startDate, endDate)) {
                        dateRangeClass = "dateRangeMiddle";
                    }
                }
            }

            return {
                disabled: isDisabled,
                class: dateRangeClass,
                tooltip: isDisabled ? 'Not Available' : tooltipText
            };
        };

        pickerItem.refresh();
    }

    #onChanged() {
        const startItem = this.#startItem();
        const endItem = this.#endItem();
        const pickerItem = this.#pickerItem();
        const pickerFormat = this.#pickerFormat();

        if (!pickerItem.getValue()) {
            this.#reset();
            return;
        }

        const datepicked = pickerItem.getNativeValue();
        const startDateValue = startItem.getValue();
        const endDateValue = endItem.getValue();

        if (startDateValue === "" || (endDateValue !== "")) {
            startItem.setValue(pickerItem.getValue());
            endItem.setValue(null);
        } else {
            const startDate = apex.date.parse(startDateValue, pickerFormat);
            if (apex.date.isBefore(datepicked, startDate)) {
                startItem.setValue(pickerItem.getValue());
                endItem.setValue(null);
            } else if (!apex.date.isSame(datepicked, startDate)) {
                endItem.setValue(pickerItem.getValue());
            }
        }

        pickerItem.refresh();
    }

    #reset() {
        const startItem = this.#startItem();
        const endItem = this.#endItem();
        const pickerItem = this.#pickerItem();
       
        startItem.setValue(null,null,true);
        endItem.setValue(null,null,true);
        pickerItem.setValue(null,null,true);
       
        pickerItem.element.find('.dateRangeStart, .dateRangeEnd, .dateRangeSingleDay').removeClass('dateRangeStart dateRangeEnd dateRangeSingleDay');
        pickerItem.element.find('.is-selected').removeClass('is-selected');
       
        pickerItem.refresh();
       
        $(document).trigger('daterangepicker-reset', {
            picker: this.#config.picker.name,
            start: this.#config.start.name,
            end: this.#config.end.name
        });
    }
};



참고




댓글 없음:

댓글 쓰기

20250202 - IG 다운로드 버튼 바로 보이기

JS initialization Code : function (config) {     var $ = apex.jQuery,         toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),  ...