1const getFirstDayOfMonth = (year, month) => { 2 return new Date(year, month, 1); 3} 4 5/** 6 * It adds a click event listener to each link in the tabs, and when clicked, it removes the active 7 * class from all tabs and tab content, and then adds the active class to the clicked tab and its 8 * corresponding tab content 9 */ 10const MetaboxRoomTabs = () => { 11 const roomID = hotel_settings.room_id; 12 if ( roomID == 0 ) return; 13 14 const url = new URL(document.URL); 15 const linkTabs = document.querySelectorAll('.wphb-meta-box__room-tab__tabs li a'); 16 const elemTabs = document.querySelectorAll('.wphb-meta-box__room-tab__tabs li'); 17 const elemContent = document.querySelectorAll('.wphb-meta-box-room-panels'); 18 19 20 // show tab active when update post; 21 const tabActive = window.localStorage.getItem('tabActive'); 22 url.searchParams.set('tab', tabActive); 23 window.history.pushState( '', '', url.href ); 24 // end show tab active when update post; 25 26 if ( linkTabs.length == 0 || elemTabs.length == 0 || elemContent.length == 0 ) return ; 27 //hide first load 28 elemTabs[0].classList.add('active'); 29 elemContent[0].classList.add('active'); 30 31 linkTabs.forEach( function( link ) { 32 const tabID = link.getAttribute('href'); 33 const tabContent = document.querySelector( '#' + tabID ); 34 //active tab when reload page 35 36 if ( url.searchParams.get('tab') == tabActive ) { 37 tabContent.classList.remove('active'); 38 link.parentNode.classList.remove('active'); 39 if ( tabContent.getAttribute('id') == tabActive ) { 40 tabContent.classList.add('active'); 41 link.parentNode.classList.add('active'); 42 if( tabContent.getAttribute('id') == 'block_room_data' ) { 43 roomBlockDate(); 44 } 45 } 46 } 47 48 link.addEventListener('click', function (e) { 49 e.preventDefault(); 50 clear(); 51 url.searchParams.set('tab', tabID); 52 link.parentNode.classList.add('active'); 53 window.history.pushState( '', '', url.href ); 54 window.localStorage.setItem('tabActive', tabID ); 55 if ( tabContent !== null || url.searchParams.get('tab') == tabContent.getAttribute('id') ) { 56 tabContent.classList.add('active'); 57 if( tabContent.getAttribute('id') == 'block_room_data' ) { 58 roomBlockDate(); 59 } 60 } 61 }) 62 }) 63 const clear = () => { 64 linkTabs.forEach( function( link ) { 65 link.parentNode.classList.remove('active'); 66 const tabID = link.getAttribute('href'); 67 const tabContent = document.querySelector( '#' + tabID ); 68 if ( tabContent !== null ) { 69 tabContent.classList.remove('active'); 70 } 71 }) 72 } 73}; 74 75/** 76 * It fetches the pricing plans for the current month and renders them on the calendar 77 */ 78const viewAllPlanSingleRoom = () => { 79 80 const getPrices = async ( dayElem ) => { 81 const events = []; 82 const roomID = hotel_settings.room_id; 83 84 if ( roomID == null ) return events; 85 86 try { 87 const response = await wp.apiFetch( { 88 path: 'wphb/v1/admin/rooms/pricing-plans', 89 method: 'POST', 90 data: { date:dayElem , roomID }, 91 } ); 92 93 const {status , data } = response; 94 if ( 'success' === status ) { 95 const bookings = JSON.parse(data) 96 for (var i = 0; i < bookings.length; ++i) { 97 const booking = bookings[i], 98 day = new Date(booking.d), 99 today = new Date(); 100 const MyDateString = (day.getFullYear() + '-' + ('0' + (day.getMonth() + 1 )).slice(-2) + '-' + ('0' + day.getDate()).slice(-2)); 101 if ( booking.price > 0 ) { 102 events.push({ 103 title: booking.price + '$', 104 start: MyDateString, 105 textColor: '#d04a61', 106 backgroundColor: '#FFFFFF', 107 borderColor: '#FFFFFF', 108 classNames: ['wphb-pricing-plan-event'], 109 }); 110 } 111 } 112 return events; 113 } 114 115 } catch ( error ) { 116 alert( error.message && error.message ); 117 } 118 } 119 120 const calendarEl = document.getElementById('calendar_room_pricing'); 121 if ( calendarEl == null ) return; 122 const calendar = new FullCalendar.Calendar(calendarEl, { 123 events: function(info, successCallback, failureCallback) { 124 const date = new Date(info.end); 125 const firstDayCurrentMonth = getFirstDayOfMonth( 126 date.getFullYear(), 127 date.getMonth(), 128 ); 129 130 const events = getPrices( firstDayCurrentMonth ); 131 132 (async () => { 133 successCallback( await events ) 134 })() 135 }, 136 selectable: true, 137 height: 500, 138 }); 139 140 const btn = document.querySelector('button.show-all-plan'); 141 142 if( btn == null ) return; 143 144 btn.addEventListener('click', function (e) { 145 e.preventDefault(); 146 if ( calendarEl.hasChildNodes() ) { 147 btn.textContent = btn.dataset.textView; 148 calendar.destroy(); 149 } else { 150 btn.textContent = btn.dataset.textClose; 151 calendar.render(); 152 } 153 154 }); 155} 156 157/** 158 * It creates a calendar that allows you to select dates and then save them to the database 159 * @returns A function. 160 */ 161const roomBlockDate = () => { 162 //submit block room 163 const roomID = hotel_settings.room_id; 164 let removeMonth = false;
165 let argsBlock = hotel_settings.block_dates ?? []; 166 167 if ( roomID == null ) return; 168 169 const submit = async () => { 170 171 try { 172 const response = await wp.apiFetch( { 173 path: 'wphb/v1/admin/rooms/block-date', 174 method: 'POST', 175 data: { argsBlock , roomID , removeMonth }, 176 } ); 177 178 const {status , message } = response; 179 if ( 'success' === status ) { 180 alert( message ); 181 } 182 removeMonth = false; 183 } catch ( error ) { 184 alert( error.message && error.message ); 185 } 186 } 187 188 /** 189 * It checks if the date is already selected, if it is, it removes the selected class and removes 190 * the date from the array, if it isn't, it adds the selected class and adds the date to the array 191 * @param date - The date of the day you clicked on. 192 * @param ele - The element that was clicked. 193 * @param args - an array of dates that have been selected. 194 * @returns the array of dates that have been selected. 195 */ 196 const checkedBlock = ( date, ele , args ) => { 197 const eleHighLight = ele.querySelector('.fc-highlight'); 198 if ( ele.classList.contains( 'selected') ) { 199 ele.classList.remove('selected'); 200 ele.style.backgroundColor = '#fff'; 201 const childNodeEvent = ele.querySelector('._hb_event_selected'); 202 if ( childNodeEvent != null ) { 203 childNodeEvent.style.background = '#fff'; 204 childNodeEvent.classList.remove('_hb_event_selected'); 205 if ( eleHighLight != null) { 206 eleHighLight.style.background = '#fff'; 207 } 208 } 209 const index = args.indexOf( String( date.valueOf() / 1000) ); 210 if ( index != -1 ) { 211 args.splice( index, 1 ); 212 } 213 } else { 214 if ( eleHighLight != null) { 215 eleHighLight.style.backgroundColor = '#27262240'; 216 } 217 ele.style.backgroundColor = '#27262240'; 218 ele.className += ' selected'; 219 const index = args.indexOf( String( date.valueOf() / 1000) ); 220 if ( index == -1 ) { 221 args.push( String( date.valueOf() / 1000 ) ); 222 } 223 } 224 argsBlock = args; 225 return argsBlock; 226 } 227 228 229 /** 230 * It removes all the block dates from the calendar. 231 * @param ele - The element that is clicked 232 * @param date - The date you want to check 233 * @param argsBlock - an array of dates that are blocked 234 */ 235 const removeAllBlockDate = async ( ele , date, argsBlock ) => { 236 if ( ele === null ) return; 237 const yearCurrent = date.getFullYear(); 238 const monthCurrent = date.getMonth() + 1; 239 const daysOfMonth = document.querySelectorAll('#calender_block .fc-daygri
239d-day:not(.fc-day-other)'); 240 241 for ( var i = 0; i < daysOfMonth.length; ++i ) { 242 const elem = daysOfMonth[i]; 243 const dateEle = new Date(elem.dataset.date); 244 const index = ( dateEle.valueOf() / 1000).toString(); 245 if ( argsBlock.includes( index ) ) { 246 const bgBanner = elem.querySelector('.fc-daygrid-bg-harness'); 247 if( bgBanner != null){ 248 bgBanner.remove(); 249 } 250 if ( dateEle.getFullYear() == yearCurrent && ( dateEle.getMonth() + 1 ) == monthCurrent ) { 251 checkedBlock( dateEle, elem, argsBlock ); 252 } 253 } 254 } 255 256 removeMonth = true; 257 } 258 259 /** 260 * It takes a date, and checks if it's in the block list. If it is, it adds a class to the date 261 * element 262 * @param ele - The element that was clicked. 263 * @param argsBlock - an object that contains the following properties: 264 */ 265 const addAllMonthBlockDate = async ( ele , argsBlock ) => { 266 if ( ele === null ) return; 267 const daysOfMonth = document.querySelectorAll('#calender_block .fc-daygri
267d-day:not(.fc-day-other):not(.selected)'); 268 if ( daysOfMonth.length == 0 ) return; 269 270 for ( var i = 0; i < daysOfMonth.length; ++i ) { 271 const elem = daysOfMonth[i]; 272 const date = new Date(elem.getAttribute('data-date')); 273 checkedBlock( date, elem, argsBlock ); 274 } 275 276 } 277 278 /* The above code is a function that is used to sync the calendar with the selected dates. */ 279 syncCalendar = () => { 280 const daysOfMonth = document.querySelectorAll('#calender_block .fc-daygrid-day:not(.fc-day-other):not(.selected)'); 281 if ( daysOfMonth.length > 0 ) { 282 daysOfMonth.forEach( function( el ) { 283 el.classList.remove('selected'); 284 const eleBg = el.querySelector('.fc-daygrid-bg-harness'); 285 if( eleBg != null){ 286 eleBg.remove(); 287 } 288 }); 289 } 290 argsBlock.forEach( function( date ) { 291 const day = new Date( date * 1000 ); 292 const MyDateString = (day.getFullYear() + '-' + ('0' + (day.getMonth() + 1 )).slice(-2) + '-' + ('0' + day.getDate()).slice(-2)); 293 const daySelected = document.querySelector('.fc-daygrid-day[data-date="'+MyDateString+'"]'); 294 if(daySelected != null){ 295 daySelected.classList.add('selected'); 296 daySelected.style.backgroundColor = '#27262261'; 297 } 298 }); 299 const selectedEvents = document.querySelectorAll('._hb_event_selected'); 300 if ( selectedEvents.length > 0 ) { 301 selectedEvents.forEach( function( el ) { 302 const parentBg = el.closest('.fc-daygrid-day'); 303 parentBg.classList.add('selected'); 304 }); 305 }; 306 const daysOther = document.querySelectorAll('#calender_block .fc-daygri
306d-day.fc-day-other'); 307 if ( daysOther.length > 0 ) { 308 daysOther.forEach( function( el ) { 309 el.classList.remove('selected'); 310 const eleBg = el.querySelector('.fc-daygrid-bg-harness'); 311 if( eleBg != null){ 312 eleBg.remove(); 313 } 314 }); 315 } 316 } 317 318 const events = []; 319 argsBlock.map( function( date ) { 320 const day = new Date( date * 1000 ); 321 const MyDateString = (day.getFullYear() + '-' + ('0' + (day.getMonth() + 1 )).slice(-2) + '-' + ('0' + day.getDate()).slice(-2)); 322 events.push({ 323 start: MyDateString, 324 backgroundColor : '#ffdc2926', 325 display: 'background', 326 classNames:['_hb_event_selected'], 327 }); 328 }); 329 330 const eleShowBlock = document.getElementById('calender_block'); 331 if ( eleShowBlock == null ) return; 332 333 const calendarBlock = new FullCalendar.Calendar(eleShowBlock, { 334 headerToolbar: { 335 right: 'add_month disable_all prev,next' 336 }, 337 initialView: 'dayGridMonth', 338 selectable: true, 339 height: 500, 340 events: events, 341 dateClick: function(info) { 342 const date = new Date(info.dateStr); 343 checkedBlock( date, info.dayEl, argsBlock ); 344 }, 345 customButtons: { 346 prev: { 347 click: function(e) { 348 calendarBlock.prev(); 349 syncCalendar(); 350 }, 351 }, 352 next: { 353 click: function() { 354 calendarBlock.next(); 355 syncCalendar(); 356 }, 357 }, 358 disable_all: { 359 text: 'Open This Month', 360 click: function() { 361 const date = calendarBlock.getDate(); 362 removeAllBlockDate( this , date, argsBlock ); 363 } 364 }, 365 add_month: { 366 text: 'Block This Month', 367 click: function() { 368 addAllMonthBlockDate( this , argsBlock ); 369 } 370 } 371 } 372 }); 373 374 const btnUpdate = document.querySelector('#tp_hotel_booking_block_date button.update_block'); 375 376 if( btnUpdate === null ) return; 377 btnUpdate.addEventListener('click', function (e) { 378 e.preventDefault(); 379 submit( argsBlock ); 380 }); 381 382 // render when active tab; 383 calendarBlock.render(); 384 const selectedEvents = document.querySelectorAll('._hb_event_selected'); 385 if ( selectedEvents.length > 0 ) { 386 selectedEvents.forEach( function( el ) { 387 const parentBg = el.closest('.fc-daygrid-day'); 388 parentBg.classList.add('selected'); 389 }); 390 }; 391} 392/** 393 * It creates a new FullCalendar instance, and then renders it 394 * @returns A function that returns a function. 395 */ 396const CalendarManager = () => { 397 const getBookings = async ( info ) => { 398 const start = new Date( info.start ); 399 const timeStart = (start.getFullYear() + '-' + ('0' + (start.getMonth() + 1 )).slice(-2) + '-' + ('0' + start.getDate()).slice(-2)); 400 const end = new Date( info.end ); 401 const timeEnd = (end.getFullYear() + '-' + ('0' + (end.getMonth() + 1 )).slice(-2) + '-' + ('0' + end.getDate()).slice(-2)); 402 403 try { 404 const response = await wp.apiFetch( { 405 path: 'wphb/v1/admin/rooms/manager-bookings?startDay=' + timeStart + '&endDay=' + timeEnd, 406 method: 'GET', 407 } ); 408 409 const {status , data } = response; 410 if ( 'success' === status ) { 411 return data; 412 } else { 413 return []; 414 } 415 } catch ( error ) { 416 alert( error.message && error.message ); 417 } 418 } 419 const eleBooking = document.getElementById('manager_booking'); 420 if( eleBooking == null ) return; 421 const calendarBooking = new FullCalendar.Calendar(eleBooking, { 422 423 height: 700, 424 events: function(info, successCallback, failureCallback) { 425 const bookings = getBookings( info ); 426 427 (async () => { 428 successCallback( await bookings ) 429 })() 430 }, 431 dayMaxEvents: true, 432 eventDidMount: function(info) { 433 434 info.el.addEventListener('click',function(e){ 435 const parent = this.closest('body.wp-hotel-booking_page_tp_hotel_booking_c
435alender_manager'); 436 if( parent == null ) return; 437 if( parent.classList.contains('active') ) { 438 return; 439 } 440 parent.classList.add('active'); 441 parent.insertAdjacentHTML("afterbegin", htmlShow( info )); 442 const popup = document.getElementById("popup-events"); 443 if ( popup == null ) return; 444 popup.style.display = 'block'; 445 clickOutside( popup , parent); 446 closePopup( parent ); 447 448 }); 449 450 const htmlShow = (info) => { 451 const html = 452 '<div id="popup-events">' + 453 '<div id="popup-container">' + 454 '<div class="popup">' + 455 '<div class="popup-header">' + 456 '<h2>Booking Info</h2>' + 457 '<div class="close-popup">X</div>' + 458 '</div>' + 459 '<div class="info">' + 460 '<div class="info_detail">' + 461 '<div class="info_detail_left">' + 462 '<span id="heading">Order Created Date: </span><br>' + 463 '<span id="details">'+ info.event.extendedProps?.data_order?.order_date +'</span>' + 464 '</div>'+ 465 '<div class="info_detail_right">' + 466 '<span id="heading">Order No.</span><br>' + 467 '<span id="details"><a href="'+info.event.extendedProps?.data_order?.link_edit +'" target="_blank">' + 468 '#' + info.event.extendedProps?.data_order?.id +'</a></span>' + 469 '</div>'+ 470 '<div class="info_detail_left">' + 471 '<span id="heading">Check in date: </span><br>' + 472 '<span id="details">'+ info.event.extendedProps?.data_order?.start_date_popup +'</span>' + 473 '</div>'+ 474 '<div class="info_detail_right">' + 475 '<span id="heading">Check out date: </span><br>' + 476 '<span id="details">'+ info.event.extendedProps?.data_order?.end_date_popup +'</span>' + 477 '</div>'+ 478 '</div>'+ 479 '<div class="pricing">' + 480 '<div class="pricing_detail">' + 481 '<div class="pricing_detail_left">' + 482 '<span id="name">'+ info.event.extendedProps?.data_order?.title +'</span>' + 483 '</div>'+ 484 '<div class="pricing_detail_right">' + 485 '<span id="price">'+ info.event.extendedProps?.data_order?.total +'</span>' + 486 '</div>'+ 487 '</div>'+ 488 '</div>'+ 489 '</div>' + 490 '</div>' + 491 '</div>' + 492 '</div>'; 493 return html; 494 } 495 const clickOutside = ( popup , parent) => { 496 document.addEventListener('click', function(e) { 497 if( e.target.id == 'popup-container' ) { 498 popup.style.display = 'none'; 499 parent.classList.remove('active'); 500 } 501 }); 502 } 503 504 const closePopup = ( parent ) => { 505 const btn = document.querySelector('#popup-events .close-popup'); 506 if ( btn == null ) return; 507 btn.addEventListener('click', function(e) { 508 const popup = document.getElementById("popup-events"); 509 popup.style.display = 'none'; 510 parent.classList.remove('active'); 511 }); 512 } 513 }, 514 }); 515 calendarBooking.render(); 516} 517 518/** 519 * It adds an event listener to the checkbox with the id of `_hb_room_preview` and when the checkbox is 520 * checked, it removes the class `hidden` from the element with the class `room_preview_url` 521 */ 522const RoomPreview = () => { 523 524 const enablePreview = document.getElementById('_hb_room_preview'); 525 if( enablePreview == null ) return; 526 527 enablePreview.addEventListener('change', function (e) { 528 const contentPreview = document.querySelector('.room_preview_url'); 529 if ( contentPreview == null ) return; 530 if ( enablePreview.checked ) { 531 contentPreview.classList.remove('hidden'); 532 } else{ 533 contentPreview.classList.add('hidden'); 534 } 535 }); 536} 537 538const adminUpdateField = () => { 539 const btn = document.querySelector('._wphb_update_field'); 540 if ( btn == null ) return; 541 542 const submit = async () => { 543 try { 544 const response = await wp.apiFetch( { 545 path: 'wphb/v1/admin/rooms/update-field', 546 method: 'POST', 547 } ); 548 549 const {status , message } = response; 550 if ( 'success' === status ) { 551 alert( message ); 552 window.location.reload(true); 553 } else { 554 throw new Error( message ); 555 } 556 } catch ( error ) { 557 alert( error.message && error.message ); 558 } 559 } 560 btn.addEventListener('click', function(e) { 561 e.preventDefault(); 562 btn.classList.add('wphb_loading'); 563 submit(); 564 }); 565} 566 567const toggleDeposit = () => { 568 const ele = document.querySelector('#deposit_room'); 569 if ( ele == null ) return; 570 571 const checked = ele.querySelector('#_hb_enable_deposit'); 572 if ( checked.checked ) { 573 ele.classList.remove('blocked'); 574 } 575 checked.addEventListener('change',function(e) { 576 if ( checked.checked ) { 577 ele.classList.remove('blocked'); 578 } else{ 579 ele.classList.add('blocked'); 580 } 581 }); 582} 583 584document.addEventListener( 'DOMContentLoaded', () => { 585 MetaboxRoomTabs(); 586 viewAllPlanSingleRoom(); 587 CalendarManager(); 588 RoomPreview(); 589 adminUpdateField(); 590 toggleDeposit(); 591} );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.