lightpick 기본 사용법은 https://truthz-z.tistory.com/30
[API] lightpick 달력 라이브러리(1)
lightpick은 달력에서 날짜를 선택할 수 있는 라이브러리입니다. 보통은 달력 라이브러리로 datepicker를 많이 사용하는데 저는 많은 기능이 필요하지 않아서 lightpick을 사용했습니다. 현재는 lightpick
truthz-z.tistory.com
이번에는 lightpick으로 이미 예약된 날짜를 선택 하지 못하게 하는 기능입니다.
제가 첫 프로젝트를 끝낼 때 구현하지 못했던 부분인데 이제 아주 약간 짬이 차서 그런지 결국 해결을 하긴했습니다.
lightpick을 구글링해도 정보가 잘 나오지 않아서 힘들었는데 저와 같은 고민을 겪고 있으신 분들을 위해 작성해봅니당. (easypick을 사용하시는 분들도 도움이 될지도,,,,?)
ReservController.java : 예약된 날짜를 가져오는 메서드
@ResponseBody
@GetMapping(value = "/reservDate/{hotel_no}", produces=MediaType.APPLICATION_JSON_VALUE)
public List<ReservVO> reservDate(@PathVariable("hotel_no") @ModelAttribute("data") int hotel_no){
List<ReservVO> date = null;
date = reservService.reservDate(hotel_no);
return date;
}
reservForm.jsp
$(function(){
// 현재 예약하려는 호텔
let hotel_no = ${hotelVO.hotel_no};
// 이미 예약되어있는 날짜 배열
let res_day = [];
listAll(hotel_no);
function listAll(hotel_no){
// 호텔의 예약된 날짜를 가져옴
let url = "/reserv/reservDate/"+hotel_no;
$.getJSON(url,function(data){
$(data).each(function(){
checkin = this.checkin;
checkout = this.checkout;
// 배열에 값 넣음
res_day.push([checkin,checkout]);
});
// 달력 불러옴
pickerData(res_day);
}).fail(function(){
alert("오류가 발생했습니다. 잠시 후 다시 시도해주세요.");
})
}
페이지를 불러오면서 getJSON으로 이미 예약 된 날짜를 가져옵니다.
저의 db에는 checkin날짜와 checkout날짜로 예약일이 저장되어 있습니다.
// 사용자가 결제할 가격
let price = "";
// 사용자가 예약할 일 수
let days = "";
function pickerData(res_day) {
var picker = new Lightpick({
field: document.getElementById('date'),
inline : true,
lang: 'ko',
singleDate: false,
minDate: moment().startOf('day'),
minDays : 2,
disableDates: getReservedDates(res_day), // 이미 예약된 날짜를 선택하지 못하게 함.
format: 'YYYY-MM-DD',
onSelect: function(start, end){
// 사용자가 달력에서 날짜를 한 개만 선택하면 다음 코드가 실행될 필요가 없기때문에 end가 없으면 return 합니다.
if(end == null) return;
// 사용자가 선택한 날짜가 이미 예약된 날짜를 포함하는지 확인
if(isDateInRange(start, end, res_day)){
alert("이미 예약 완료된 날짜입니다. 다시 선택해 주세요.");
// 선택된 날짜 초기화
picker.setDate(null);
return;
}
let startDate = start.format('YYYY-MM-DD');
let endDate = end.format('YYYY-MM-DD');
/* diff는 endDate와 startDate의 일 수 차이를 구할 수 있는 moment의 함수 입니다.
'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds' 등의 단위를 사용할 수 있습니다. */
days = moment(endDate).diff(startDate, 'days');
// 호텔 하루 가격 * 일 수
price = ${hotelVO.hotel_price} * days;
}
});
pickerData함수에는 lightpick을 실행하고 설정하는 코드와 날짜가 선택된 뒤 어떤 행동을 할지 작성했습니다.
// 이미 예약 된 날짜 범위 지정
function getReservedDates(res_day) {
// 예약 된 날이 없으면 빈 배열 return
if (res_day.length === 0) {
return [];
}
var reservedDates = [];
// dateRange = res_day 배열의 각 요소
res_day.forEach(function(dateRange) {
var startDate = moment(dateRange[0]);
var endDate = moment(dateRange[1]);
// startDate가 endDate보다 이전이거나 같은 날짜인 경우 true
while (startDate.isBefore(endDate) || startDate.isSame(endDate, 'day')) {
reservedDates.push(moment(startDate));
startDate.add(1, 'day'); // 하루씩 추가
}
});
return reservedDates;
}
예약 시작일부터 예약 마지막날까지 하루씩 reservedDates 배열에 추가합니다.
예를 들어 예약 시작일이 1월1일이고 예약 마지막날이 1월3일이라면 reservedDates라는 배열에 1월 1일, 1월 2일, 1월 3일을 추가합니다.
이렇게 하면 달력에서 이미 예약된 날짜가 선택되지 않습니다. 하지만 이미 예약된 날짜들의 이전과 이후를 선택하면 예약이 가능해져버리는 오류가 발생하더라구요...
그래서 isDateInRange라는 함수를 만들어서 이미 예약된 날짜라면 달력을 초기화하기로 했습니다.
// start , end : 사용자가 예약하고자 하는 날
function isDateInRange(start, end, res_day) {
if (res_day.length !== 0) {
let isInRange = false;
res_day.forEach(function (dateRange) {
// 이미 예약된 날짜 (startDate : 예약 시작일)
var startDate = moment(dateRange[0]);
// 사용자가 선택한 날짜가 이미 예약된 날을 포함하면 true
if (startDate.isBetween(start, end)) {
isInRange = true;
}
});
return isInRange;
} else {
return false;
}
}
이렇게 하면
예약 불가능하다는 경고가 뜨고 선택한 날짜가 초기화 됩니다.
처음에 구현에 실패할 때 대차게 오류가 나고 헤맸던 부분이 moment인데 지금도 잘 안다고 할 수는 없지만 그래도 나름,,,?알게 된 것 같고 다른 라이브러리들을 다룰 때도 moment를 찬찬히 뜯어봤던 때를 생각하며 라이브러리를 이해 할 경험치가 조금 적립됐다고 생각합니다.ㅎㅎ 무엇보다 해결하지 못했던 문제를 드디어 풀었다는게 너무나도 뿌듯하답니다~~~~
'코딩 > 개발' 카테고리의 다른 글
[API] lightpick 달력 라이브러리(1) (1) | 2023.11.28 |
---|---|
[웹에디터 API] 썸머노트 사용법 / Summernote (0) | 2023.08.13 |
[CSS] media query 반응형 웹 만들기 (0) | 2022.11.10 |
[아임포트 결제 API] 자바스크립트 / 카카오페이, 카드 결제 / 테스트 결제 (1) | 2022.10.06 |