1var bookneticPaymentStatus; 2 3(function($) 4{ 5 "use strict"; 6 7 if( typeof window.bookneticInitBookingPage !== 'undefined' ) 8 return; 9 10 window.bookneticHooks = { 11 12 hooks: {}, 13 14 addFilter: function ( key, fn, fn_id ) 15 { 16 key = key.toLowerCase(); 17 18 if ( ! this.hooks.hasOwnProperty( key ) ) 19 { 20 this.hooks[ key ] = {}; 21 } 22 23 if (fn === null && this.hooks[key].hasOwnProperty(fn_id)) { 24 delete this.hooks[key][fn_id]; 25 return 0; 26 } 27 28 if (fn_id === undefined || fn_id === null) { 29 while(true) { 30 fn_id = Math.random().toString(36).substring(2, 15); 31 if (!this.hooks[key].hasOwnProperty(fn_id)) 32 break; 33 } 34 } 35 36 this.hooks[ key ][ fn_id ] = fn; 37 return fn_id; 38 }, 39 40 doFilter: function ( key, params, ...extra ) 41 { 42 key = key.toLowerCase(); 43 44 if (!this.hooks.hasOwnProperty( key ) ) { 45 return params; 46 } 47 48 for (let fn_id in this.hooks[key]) { 49 let fn = this.hooks[key][fn_id]; 50 51 if ( typeof params === 'undefined' ) { 52 params = fn( ...extra ); 53 } else { 54 params = fn( params, ...extra ); 55 } 56 } 57 58 return params; 59 }, 60 61 addAction: function ( key, fn, fn_id ) 62 { 63 return this.addFilter( key, fn, fn_id ); 64 }, 65 66 doAction: function ( key, ...params ) 67 { 68 this.doFilter( key, undefined, ...params ); 69 } 70 }; 71 72 function __( key ) 73 { 74 return key in BookneticData.localization ? BookneticData.localization[ key ] : key; 75 } 76 77 $.fn.handleScrollBooknetic = function() 78 { 79 if ( !this.hasClass('nice-scrollbar-primary') && ! window.matchMedia('(max-width: 1000px)').matches ) 80 { 81 this.addClass( 'nice-scrollbar-primary' ); 82 } 83 84 if( window.matchMedia('(max-width: 1000px)').matches && this.hasClass('nice-scrollbar-primary') ) 85 { 86 booking_panel_js.find(".booknetic_appointment_container_body").removeClass('nice-scrollbar-primary') 87 88 if ( $( '#country-listbox' ).length ) 89 { 90 $( '#country-listbox' ).removeClass('nice-scrollbar-primary') 91 } 92 93 // return; 94 } 95 } 96 97 let index = 0; 98 window.bookneticInitBookingPage = function ( booking_panel_JS_element ) 99 { 100 index++; 101 let booking_panel_js = $(booking_panel_JS_element); 102 103 if( booking_panel_js.data('booknetic_has_been_initiated') === true ) 104 return; 105 106 booking_panel_js.data('booknetic_has_been_initiated', true); 107 108 let booknetic = { 109 110 google_recaptcha_token: null, 111 google_recaptcha_action: 'booknetic_booking_panel_' + index, 112 113 cartArr : [], 114 cartHTMLBody : [], 115 cartHTMLSideBar : [], 116 cartCurrentIndex:0, 117 cartErrors : { 118 a:[], 119 callbacks: [(arr)=>{ 120 if( arr.length > 0 ) 121 { 122 let itemIds = []; 123 124 arr.forEach((value)=>{ 125 if( itemIds.indexOf(value['cart_item']) === -1) 126 itemIds.push(value['cart_item']); 127 }); 128 129 130 booking_panel_js.find('.booknetic-cart-item-error .booknetic-cart-item-error-body').remove(); 131 booking_panel_js.find('.booknetic-cart-item-error').removeClass('show'); 132 133 arr.forEach((value)=>{ 134 if(value['cart_item']!==undefined) 135 { 136 booking_panel_js.find('div.booknetic-cart div[data-index='+ value['cart_item'] +'] .booknetic-cart-item-error').addClass('show'); 137 booking_panel_js.find('div.booknetic-cart div[data-index='+ value['cart_item'] +'] .booknetic-cart-item-error').append(` 138 <div class="booknetic-cart-item-error-body">${value['message']}</div> 139 `); 140 } 141 }) 142 143 144 } 145 else 146 { 147 booking_panel_js.find('.booknetic-cart-item-error .booknetic-cart-item-error-body').remove(); 148 booking_panel_js.find('.booknetic-cart-item-error').removeClass('show'); 149 } 150 }], 151 get error() 152 { 153 return this.a; 154 }, 155 set error(arr) 156 { 157 this.a = arr; 158 for (let i = 0; i < this.callbacks.length; i++) { 159 this.callbacks[i](arr ); 160 } 161 } 162 }, 163 __, 164 165 panel_js : booking_panel_js, 166 167 options: { 168 'templates': { 169 'loader': '<div class="booknetic_loading_layout"></div>' 170 } 171 }, 172 173 localization: { 174 month_names: [ __('January'), __('February'), __('March'), __('April'), __('May'), __('June'), __('July'), __('August'), __('September'), __('October'), __('November'), __('December') ], 175 day_of_week: [ __('Sun'), __('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat'), __('Sun') ] , 176 }, 177 178 calendarDateTimes: {}, 179 time_show_format: 1, 180 calendarYear: null, 181 calendarMonth: null, 182 183 paymentWindow: null, 184 paymentStatus: null, 185 appointmentId: null, // doit: bu failed payment olan appointmenti silmek ucundu, bunu payment_id ederik
186 ajaxResultConfirmStep: null, 187 paymentId: null, 188 dateBasedService: false, 189 serviceData: null, 190 191 globalDayOffs: {}, 192 globalTimesheet: {}, 193 194 195 loading: function ( onOff ) 196 { 197 if( typeof onOff === 'undefined' || onOff ) 198 { 199 booking_panel_js.find('#booknetic_progress').removeClass('booknetic_progress_done').show(); 200 $({property: 0}).animate({property: 100}, { 201 duration: 1000, 202 step: function() 203 { 204 var _percent = Math.round(this.property); 205 if( !booking_panel_js.find('#booknetic_progress').hasClass('booknetic_progress_done') ) 206 { 207 booking_panel_js.find('#booknetic_progress').css('width', _percent+"%"); 208 } 209 } 210 }); 211 212 booking_panel_js.append( this.options.templates.loader ); 213 } 214 else if( ! booking_panel_js.find('#booknetic_progress').hasClass('booknetic_progress_done') ) 215 { 216 booking_panel_js.find('#booknetic_progress').addClass('booknetic_progress_done').css('width', 0); 217 218 // IOS bug... 219 setTimeout(function () 220 { 221 booking_panel_js.find('.booknetic_loading_layout').remove(); 222 }, 0); 223 } 224 }, 225 226 htmlspecialchars_decode: function (string, quote_style) 227 { 228 var optTemp = 0, 229 i = 0, 230 noquotes = false; 231 if(typeof quote_style==='undefined') 232 { 233 quote_style = 2; 234 } 235 string = string.toString().replace(/</g, '<').replace(/>/g, '>'); 236 var OPTS = { 237 'ENT_NOQUOTES': 0, 238 'ENT_HTML_QUOTE_SINGLE': 1, 239 'ENT_HTML_QUOTE_DOUBLE': 2, 240 'ENT_COMPAT': 2, 241 'ENT_QUOTES': 3, 242 'ENT_IGNORE': 4 243 }; 244 if(quote_style===0) 245 { 246 noquotes = true; 247 } 248 if(typeof quote_style !== 'number') 249 { 250 quote_style = [].concat(quote_style); 251 for (i = 0; i < quote_style.length; i++){ 252 if(OPTS[quote_style[i]]===0){ 253 noquotes = true; 254 } else if(OPTS[quote_style[i]]){ 255 optTemp = optTemp | OPTS[quote_style[i]]; 256 } 257 } 258 quote_style = optTemp; 259 } 260 if(quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) 261 { 262 string = string.replace(/�*39;/g, "'"); 263 } 264 if(!noquotes){ 265 string = string.replace(/"/g, '"'); 266 } 267 string = string.replace(/&/g, '&'); 268 return string; 269 }, 270 271 htmlspecialchars: function ( string, quote_style, charset, double_encode ) 272 { 273 var optTemp = 0, 274 i = 0, 275 noquotes = false; 276 if(typeof quote_style==='undefined' || quote_style===null) 277 { 278 quote_style = 2; 279 } 280 string = typeof string != 'string' ? '' : string; 281 282 string = string.toString(); 283 if(double_encode !== false){ 284 string = string.replace(/&/g, '&'); 285 } 286 string = string.replace(/</g, '<').replace(/>/g, '>'); 287 var OPTS = { 288 'ENT_NOQUOTES': 0, 289 'ENT_HTML_QUOTE_SINGLE': 1, 290 'ENT_HTML_QUOTE_DOUBLE': 2, 291 'ENT_COMPAT': 2, 292 'ENT_QUOTES': 3, 293 'ENT_IGNORE': 4 294 }; 295 if(quote_style===0) 296 { 297 noquotes = true; 298 } 299 if(typeof quote_style !== 'number') 300 { 301 quote_style = [].concat(quote_style); 302 for (i = 0; i < quote_style.length; i++) 303 { 304 if(OPTS[quote_style[i]]===0) 305 { 306 noquotes = true; 307 } 308 else if(OPTS[quote_style[i]]) 309 { 310 optTemp = optTemp | OPTS[quote_style[i]]; 311 } 312 } 313 quote_style = optTemp; 314 } 315 if(quote_style & OPTS.ENT_HTML_QUOTE_SINGLE) 316 { 317 string = string.replace(/'/g, '''); 318 } 319 if(!noquotes) 320 { 321 string = string.replace(/"/g, '"'); 322 } 323 return string; 324 }, 325 326 sanitizeHTML: function (node){ 327 node = node.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, '$1'); 328 node = node.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, '$1'); 329 return node; 330 }, 331 332 throttle: function(func, wait = 500) { 333 let processing = false; 334 335 return function (e) { 336 if (processing) return; 337 338 processing = true; 339 340 func.call(this, e); 341 342 setTimeout(() => { 343 processing = false; 344 }, wait); 345 } 346 }, 347 348 getCurrentCartItem: () => { 349 return booknetic.cartArr[booknetic.cartCurrentIndex] 350 }, 351 352 debounce: function(func, wait) { 353 let timeout; 354 355 return function(...args) { 356 clearTimeout(timeout); 357 timeout = setTimeout(() => func.apply(this, args), wait); 358 }; 359 }, 360 361 formDataToObject: function ( formData ) 362 { 363 var object = {}; 364 365 formData.forEach(function(value, key) 366 { 367 object[key] = value; 368 }); 369 370 return object; 371 }, 372 373 ajaxResultCheck: function ( res ) 374 { 375 376 if( typeof res != 'object' ) 377 { 378 try 379 { 380 res = JSON.parse(res); 381 } 382 catch(e) 383 { 384 this.toast( 'Error!' ); 385 return false;
386 } 387 } 388 389 if( typeof res['status'] == 'undefined' ) 390 { 391 this.toast( 'Error!' ); 392 return false; 393 } 394 395 if( res['status'] === 'error' ) 396 { 397 if( typeof res['errors'] != 'undefined' && res['errors'].length > 0) 398 { 399 return false; 400 } 401 this.toast( typeof res['error_msg'] == 'undefined' ? 'Error!' : res['error_msg'] ); 402 return false; 403 } 404 405 if( res['status'] === 'ok' ) 406 return true; 407 408 // else 409 410 this.toast( 'Error!' ); 411 return false; 412 }, 413 414 ajax: function ( action , params , func , loading, fnOnError, async_param ) 415 { 416 // helper: best-effort JSON parse 417 const tryParse = (x) => { try { return JSON.parse(x); } catch { return x; } }; 418 419 // backward-compatible defaults 420 params = typeof params === 'undefined' ? {} : params; 421 func = typeof func === 'function' ? func : function(){}; 422 loading = loading !== false; 423 fnOnError = typeof fnOnError === 'function' ? fnOnError : function(){}; 424 async_param = typeof async_param === 'undefined' ? true : async_param; 425 426 const endLoader = () => { if ( loading ) booknetic.loading( 0 ); }; 427 428 /* ------------------------------------------------------------- 429 Resolve backend / frontend identifiers 430 ------------------------------------------------------------- */ 431 const { backend, frontend } = ( action instanceof Object ) 432 ? { backend: action[ 'backend_action' ], frontend: action[ 'frontend_action' ] } 433 : { backend: action, frontend: action }; 434 435 /* ------------------------------------------------------------- 436 Prepare payload 437 ------------------------------------------------------------- */ 438 const tenantId = BookneticData.tenant_id || booking_panel_js.data( 'tenant_id' ); 439 const isFormData = params instanceof FormData; 440 441 if ( isFormData ) 442 { 443 params.append( 'action', 'bkntc_' + backend ); 444 params.append( 'tenant_id', tenantId ); 445 } 446 else 447 { 448 params = { action: 'bkntc_' + backend, tenant_id: tenantId, ...params }; 449 } 450 451 /* ------------------------------------------------------------- 452 Hooks (before) and loader 453 ------------------------------------------------------------- */ 454 bookneticHooks.doAction( 'ajax_before_' + frontend, params, booknetic ); 455 params = bookneticHooks.doFilter( 'ajax', params, booknetic ); 456 params = bookneticHooks.doFilter( 'ajax_' + frontend, params, booknetic ); 457 458 if ( loading ) 459 { 460 booknetic.loading( true ); 461 } 462 463 /* ------------------------------------------------------------- 464 Execute request 465 ------------------------------------------------------------- */ 466 $.ajax( { 467 url: BookneticData.ajax_url, 468 method: 'POST', 469 data: params, 470 async: async_param, 471 ...( isFormData ? { processData: false, contentType: false } : {} ) 472 } ).done( function ( rawResult ) 473 { 474 endLoader(); 475 476 const result = tryParse( rawResult ); 477 const ok = booknetic.ajaxResultCheck( result, fnOnError ); 478 479 if ( ok ) 480 { 481 func( result ); 482 bookneticHooks.doAction( 'ajax_after_' + frontend + '_success', booknetic, params, result ); 483 } 484 else 485 { 486 fnOnError( result ); 487 bookneticHooks.doAction( 'ajax_after_' + frontend + '_error', booknetic, params, result ); 488 } 489 } ).fail( function ( jqXHR ) 490 { 491 endLoader(); 492 booknetic.toast( jqXHR.status + ' error!' ); 493 fnOnError(); 494 bookneticHooks.doAction( 'ajax_after_' + frontend + '_error', booknetic, params ); 495 } ); 496 }, 497 498 ajaxAsync: function ( action , params , loading, async_param ) 499 { 500 return new Promise( function ( resolve, reject ) 501 { 502 booknetic.ajax( 503 action, 504 params, 505 function( result ) 506 { 507 resolve( result ); 508 }, 509 loading, 510 function ( error ) 511 { 512 reject( error ); 513 }, 514 async_param 515 ); 516 }); 517 }, 518 519 select2Ajax: function ( select, action, parameters ) 520 { 521 var params = {}; 522 params['action'] = 'bkntc_' + action; 523 params['tenant_id'] = BookneticData.tenant_id || booking_panel_js.data('tenant_id'); 524 525 select.select2({ 526 theme: 'bootstrap', 527 placeholder: __('select'), 528 language: { 529 searching: function() { 530 return __('searching'); 531 } 532 }, 533 allowClear: true, 534 ajax: { 535 url: BookneticData.ajax_url, 536 dataType: 'json', 537 type: "POST", 538 data: function ( q ) 539 { 540 var sendParams = params; 541 sendParams['q'] = q['term']; 542 543 if( typeof parameters == 'function' ) 544 { 545 var additionalParameters = parameters( $(this) ); 546 547 for (let key in additionalParameters) 548 { 549 sendParams[key] = additionalParameters[key]; 550 } 551 } 552 else if( typeof parameters == 'object' ) 553 { 554 for (let key in parameters) 555 { 556 sendParams[key] = parameters[key]; 557 } 558 } 559 560 return sendParams; 561 }, 562 processResults: function ( result ) 563 { 564 if( booknetic.ajaxResultCheck( result ) ) 565 { 566 try 567 { 568 result = JSON.parse(result); 569 } 570 catch(e) 571 { 572 573 } 574 575 return result; 576 } 577 } 578 } 579 }); 580 }, 581 582 zeroPad: function(n, p) 583 { 584 p = p > 0 ? p : 2; 585 586 n = String(n); 587 while (n.length < p) 588 n = '0' + n; 589 590 return n; 591 }, 592 593 toast: function( title ) 594 { 595 if( title === false ) 596 { 597 booking_panel_js.find('.booknetic_warning_message').fadeOut(200); 598 return; 599 } 600 601 booking_panel_js.find('.booknetic_warning_message').text( booknetic.htmlspecialchars_decode( title, 'ENT_QUOTES' ) ).fadeIn(300); 602 setTimeout(function () 603 { 604 booking_panel_js.find('.booknetic_warning_message').fadeOut(200); 605 }, 5000); 606 }, 607 608 nonRecurringCalendar: function ( year , month, load_dates_from_backend, load_calendar ) 609 { 610 load_calendar = !!load_calendar; 611 612 const now = new Date(); 613 614 year = year ?? now.getFullYear();
615 month = month ?? now.getMonth(); 616 617 booknetic.loadDefaultDate( year, month, load_calendar ); 618 619 if ( load_dates_from_backend ) 620 booknetic.loadDateFromBackend( year, month, load_calendar ); 621 }, 622 623 loadDefaultDate: function( year, month, load ) 624 { 625 booknetic.calendarYear = year; 626 booknetic.calendarMonth = month; 627 628 booknetic.displayCalendar( load ); 629 booknetic.displayBringPeopleSelect(); 630 }, 631 632 loadDateFromBackend: function( year, month, load ) 633 { 634 booknetic.ajax( 'get_data', booknetic.ajaxParameters( { 635 current_step: 'date_time', 636 year: year, 637 month: month + 1, 638 info: booking_panel_js.data( 'info' ) 639 } ), function ( result ) 640 { 641 booknetic.calendarDateTimes = result[ 'data' ]; 642 booknetic.time_show_format = result[ 'time_show_format' ]; 643 644 booknetic.calendarYear = result[ 'calendar_start_year' ]; 645 booknetic.calendarMonth = result[ 'calendar_start_month' ] - 1; 646 647 booknetic.displayCalendar( load ); 648 booknetic.displayBringPeopleSelect(); 649 650 booknetic.addGroupAppointmentsCounterForBookneticCalendarDays(); 651 } , load ); 652 }, 653 654 displayBringPeopleSelect: function() 655 { 656 var select = booking_panel_js.find('.booknetic_number_of_brought_customers select'); 657 658 var options = ''; 659
660 for(var i = 1; i < booknetic.serviceMaxCapacity; i++ ) 661 { 662 options += '<option value="' + i + '"> + ' + i + '</option>' 663 } 664 665 select.html( options ); 666 667 }, 668 669 displayCalendar: function( loader ) 670 { 671 var _year = booknetic.calendarYear; 672 var _month = booknetic.calendarMonth; 673 674 var htmlContent = "", 675 febNumberOfDays = "", 676 counter = 1, 677 dateNow = new Date(_year , _month ), 678 month = dateNow.getMonth()+1, 679 year = dateNow.getFullYear(), 680 currentDate = new Date(); 681 682 if (month == 2) 683 { 684 febNumberOfDays = ( (year%100!=0) && (year%4==0) || (year%400==0)) ? '29' : '28'; 685 } 686 687 var monthNames = booknetic.localization.month_names; 688 var dayPerMonth = [null, '31', febNumberOfDays ,'31','30','31','30','31','31','30','31','30','31'] 689 690 var nextDate = new Date(month +'/01/'+year); 691 var weekdays = nextDate.getDay(); 692 693 let weekdays2; 694 let week_start_n; 695 let week_end_n; 696 697 if( BookneticData.week_starts_on === 'monday' ) 698 { 699 weekdays2 = weekdays == 0 ? 7 : weekdays; 700 week_start_n = 1; 701 week_end_n = 7; 702 } 703 else 704 { 705 weekdays2 = weekdays; 706 week_start_n = 0; 707 week_end_n = 6; 708 } 709 710 var numOfDays = dayPerMonth[month]; 711 712 for( let w = week_start_n; w < weekdays2; w++ ) 713 { 714 htmlContent += "<div class=\"booknetic_td booknetic_empty_day\"></div>"; 715 } 716 717 while (counter <= numOfDays) 718 { 719 if (weekdays2 > week_end_n) 720 { 721 weekdays2 = week_start_n; 722 htmlContent += "</div><div class=\"booknetic_calendar_rows\">"; 723 } 724 var date_formatted = year + '-' + booknetic.zeroPad(month) + '-' + booknetic.zeroPad(counter); 725 let date_format_view; 726 727 if( BookneticData.date_format === 'Y-m-d' ) 728 { 729 date_format_view = year + '-' + booknetic.zeroPad(month) + '-' + booknetic.zeroPad(counter); 730 } 731 else if( BookneticData.date_format === 'd-m-Y' ) 732 { 733 date_format_view = booknetic.zeroPad(counter) + '-' + booknetic.zeroPad(month) + '-' + year; 734 } 735 else if( BookneticData.date_format === 'm/d/Y' ) 736 { 737 date_format_view = booknetic.zeroPad(month) + '/' + booknetic.zeroPad(counter) + '/' + year; 738 } 739 else if( BookneticData.date_format === 'd/m/Y' ) 740 { 741 date_format_view = booknetic.zeroPad(counter) + '/' + booknetic.zeroPad(month) + '/' + year; 742 } 743 else if( BookneticData.date_format === 'd.m.Y' ) 744 { 745 date_format_view = booknetic.zeroPad(counter) + '.' + booknetic.zeroPad(month) + '.' + year; 746 } 747 748 var addClass = ''; 749 if( !(date_formatted in booknetic.calendarDateTimes['dates']) || booknetic.calendarDateTimes['dates'][ date_formatted ].length == 0 ) 750 { 751 addClass = ' booknetic_calendar_empty_day'; 752 } 753 754 var loadLine = booknetic.drawLoadLine( date_formatted ); 755 756 htmlContent +="<div class=\"booknetic_td booknetic_calendar_days"+addClass+"\" data-date=\"" + date_formatted + "\" data-date-format=\"" + date_format_view + "\"><div>"+counter+"<span>" + loadLine + "</span></div></div>"; 757 758 weekdays2++; 759 counter++; 760 } 761 762 for( let w = weekdays2; w <= week_end_n; w++ ) 763 { 764 htmlContent += "<div class=\"booknetic_td booknetic_empty_day\"></div>"; 765 } 766 767 var calendarBody = "<div class=\"booknetic_calendar\">"; 768 769 calendarBody += "<div class=\"booknetic_calendar_rows booknetic_week_names\">"; 770 771 for( var w = 0; w < booknetic.localization.day_of_week.length; w++ ) 772 { 773 if( w > week_end_n || w < week_start_n ) 774 continue; 775 776 calendarBody += "<div class=\"booknetic_td\">" + booknetic.localization.day_of_week[ w ] + "</div>"; 777 } 778 779 calendarBody += "</div>"; 780 781 calendarBody += "<div class=\"booknetic_calendar_rows\">"; 782 calendarBody += htmlContent; 783 calendarBody += "</div></div>"; 784 785 booking_panel_js.find("#booknetic_calendar_area").html( calendarBody ); 786 787 booking_panel_js.find("#booknetic_calendar_area .days[data-count]:first").trigger('click'); 788 789 booking_panel_js.find(".booknetic_month_name").text( monthNames[ _month ] + ' ' + _year ); 790 booking_panel_js.find('.booknetic_times_list').empty(); 791 booking_panel_js.find('.booknetic_times_title').text(__('Select date')); 792 793 if( !loader ) 794 { 795 booking_panel_js.find(".booknetic_preloader_card3_box").hide(); 796
797 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="date_time"]').fadeIn(200, function() 798 { 799 booking_panel_js.find(".booknetic_appointment_container_body").scrollTop(0); 800 booknetic.handleScroll(); 801 }); 802 } 803 }, 804 805 drawLoadLine: function( date ) 806 { 807 let zoom = function (input, outputSize) { 808 if (input.length === outputSize) { 809 return input; 810 } 811 const ratio = outputSize / input.length; 812 813 const output = new Array(outputSize); 814 815 for (let i = 0; i < outputSize; i++) { 816 let value = false; 817 818 const from = i / ratio; 819 const inc = Math.max(1, 1 / ratio); 820 821 for (let j = Math.floor(from); j < Math.floor(from + inc); j++) { 822 value = value || input[j]; 823 } 824 825 output[i] = value; 826 } 827 828 return output; 829 }; 830 831 var fills = date in booknetic.calendarDateTimes['fills'] ? booknetic.calendarDateTimes['fills'][ date ] : [0]; 832 var data = date in booknetic.calendarDateTimes['dates'] ? booknetic.calendarDateTimes['dates'][ date ] : []; 833 if (data.length === 1 && booknetic.dateBasedService && !( 'hide_available_slots' in booknetic.calendarDateTimes && booknetic.calendarDateTimes['hide_available_slots'] === 'on' )) { 834 fills = []; 835 for (let i = 0; i < data[0].max_capacity; i++) { 836 fills.push(data[0].max_capacity - data[0].weight - i > 0 ? 1 : 0); 837 } 838 } 839 840 var day_schedule = zoom(fills, 17); 841 842 var line = ''; 843 for( var j = 0; j < day_schedule.length; j++ ) 844 { 845 var isFree = day_schedule[j]; 846 line += '<i '+ (isFree?'a':'b') + '></i>'; 847 } 848 849 return line; 850 }, 851 852 timeToMin: function(str) 853 { 854 str = str.split(':'); 855 856 return parseInt(str[0]) * 60 + parseInt(str[1]); 857 }, 858 859 timeZoneOffset: function() 860 { 861 if( BookneticData.client_time_zone === 'off' ) 862 return '-'; 863 864 if ( window.Intl && typeof window.Intl === 'object' ) 865 { 866 return Intl.DateTimeFormat().resolvedOptions().timeZone; 867 } 868 else 869 { 870 return new Date().getTimezoneOffset(); 871 } 872 }, 873 874 datePickerFormat: function() 875 { 876 if( BookneticData.date_format === 'd-m-Y' ) 877 { 878 return 'dd-mm-yyyy'; 879 } 880 else if( BookneticData.date_format === 'm/d/Y' ) 881 { 882 return 'mm/dd/yyyy'; 883 } 884 else if( BookneticData.date_format === 'd/m/Y' ) 885 { 886 return 'dd/mm/yyyy'; 887 } 888 else if( BookneticData.date_format === 'd.m.Y' ) 889 { 890 return 'dd.mm.yyyy'; 891 } 892 893 return 'yyyy-mm-dd'; 894 }, 895 896 convertDate: function( date, from, to ) 897 { 898 if( date == '' ) 899 return date; 900 if( typeof to === 'undefined' ) 901 { 902 to = booknetic.datePickerFormat(); 903 } 904 905 to = to.replace('yyyy', 'Y').replace('dd', 'd').replace('mm', 'm'); 906 from = from.replace('yyyy', 'Y').replace('dd', 'd').replace('mm', 'm'); 907 908 var delimetr = from.indexOf('-') > -1 ? '-' : ( from.indexOf('.') > -1 ? '.' : '/' ); 909 var delimetr_to = to.indexOf('-') > -1 ? '-' : ( to.indexOf('.') > -1 ? '.' : '/' ); 910 var date_split = date.split(delimetr); 911 var date_from_split = from.split(delimetr); 912 var date_to_split = to.split(delimetr_to); 913 914 var parts = {'m':0, 'd':0, 'Y':0}; 915 916 date_from_split.forEach(function( val, i ) 917 { 918 parts[ val ] = i; 919 }); 920 921 var new_date = ''; 922 date_to_split.forEach(function( val, j ) 923 { 924 new_date += (new_date == '' ? '' : delimetr_to) + date_split[ parts[ val ] ]; 925 }); 926 927 return new_date; 928 }, 929 930 getSelected: { 931 932 location: function() 933 { 934 if( booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="location"]').hasClass('booknetic_menu_hidden') ) 935 { 936 var val = booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="location"]').data('value'); 937 } 938 else 939 { 940 val = booking_panel_js.find(".booknetic_appointment_container_body [data-step-id=\"location\"] .booknetic_card_selected").data('id'); 941 } 942 943 return val ? val : ''; 944 }, 945 946 staff: function() 947 { 948 if( booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="staff"]').hasClass('booknetic_menu_hidden') ) 949 { 950 var val = booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="staff"]').data('value'); 951 } 952 else 953 {
954 val = booking_panel_js.find(".booknetic_appointment_container_body [data-step-id=\"staff\"] .booknetic_card_selected").data('id'); 955 } 956 957 return val ? val : ''; 958 }, 959 960 service: function() 961 { 962 const serviceId = booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="service"]').data('value'); 963 964 if( serviceId ) 965 { 966 var val = serviceId; 967 } 968 else 969 { 970 val = booking_panel_js.find(".booknetic_appointment_container_body [data-step-id=\"service\"] .booknetic_service_card_selected").data('id'); 971 } 972 973 return val ? val : ''; 974 }, 975 976 serviceCategory: function() 977 { 978 return booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="service"]').data('service-category'); 979 }, 980 981 serviceIsRecurring: function() 982 { 983 let val; 984 985 if( booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="service"]').hasClass('booknetic_menu_hidden') ) 986 { 987 val = booking_panel_js.find( '.booknetic_appointment_step_element[data-step-id="service"]' ).data( 'is-recurring' ); 988 } 989 else 990 { 991 val = booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="service"] .booknetic_service_card_selected').data('is-recurring'); 992 } 993 994 return val == '1'; 995 }, 996 997 serviceExtras: function() 998 { 999 var extras = []; 1000 1001 booking_panel_js.find(".booknetic_appointment_container_body [data-step-id=\"service_extras\"] .booknetic_service_extra_card_selected").each(function() 1002 { 1003 var extra_id = $(this).data('id'), 1004 quantity = parseInt( $(this).find('.booknetic_service_extra_quantity_input').val() ); 1005 1006 if( quantity > 0 ) 1007 { 1008 extras.push({ 1009 extra: extra_id, 1010 quantity: quantity, 1011 }); 1012 } 1013 }); 1014 1015 return extras; 1016 }, 1017 1018 date: function() 1019 { 1020 if( booknetic.getSelected.serviceIsRecurring() ) 1021 return ''; 1022 1023 var val = booking_panel_js.find(".booknetic_selected_time").data('date-original'); 1024 return val ? val : ''; 1025 }, 1026 1027 date_in_customer_timezone: function() 1028 { 1029 if( booknetic.getSelected.serviceIsRecurring() ) 1030 return ''; 1031 1032 var val = booking_panel_js.find(".booknetic_calendar_selected_day").data('date'); 1033 return val ? val : ''; 1034 }, 1035 1036 time: function() 1037 { 1038 if( booknetic.getSelected.serviceIsRecurring() ) 1039 return booknetic.getSelected.recurringTime(); 1040 1041 var val = booking_panel_js.find(".booknetic_selected_time").data('time'); 1042 return val ? val : ''; 1043 }, 1044 1045 brought_people_count: function() 1046 { 1047 if( ! booking_panel_js.find('#booknetic_bring_someone_checkbox ').is(':checked') ) 1048 return 0; 1049 1050 let broughtPeopleInput = booking_panel_js.find('.booknetic_number_of_brought_customers_quantity_input'); 1051 let val = Number( broughtPeopleInput.val() ); 1052 let max = Number( broughtPeopleInput.data( 'max-quantity' ) ); 1053 1054 val = Number.isInteger( val ) ? val : 0; 1055 1056 return val > max ? max : val; 1057 }, 1058 1059 dateTime: function() 1060 { 1061 if( booknetic.getSelected.serviceIsRecurring() ) 1062 return booknetic.getSelected.recurringTime(); 1063 1064 var val = booking_panel_js.find(".booknetic_selected_time").data('full-date-time-start'); 1065 return val ? val : ''; 1066 }, 1067 1068 formData: function () 1069 { 1070 var data = { data: {email: "", first_name: "", last_name: "", phone: ""} }; 1071 1072 booking_panel_js.find('input[name]#bkntc_input_name, input[name]#bkntc_input_surname, input[name]#bkntc_input_email, input[name]#bkntc_input_phone').each(function() 1073 { 1074 let name = $(this).attr('name'); 1075 let value = $(this).val(); 1076 1077 if(name === 'phone'){ 1078 const itiInstance = booking_panel_js.find('#bkntc_input_phone').data('iti'); 1079 value = itiInstance.getNumber(bookneticIntlTelInput.utils.numberFormat.E164); 1080 } 1081 1082 if ( name === 'email' ) 1083 value = value.trim() 1084 1085 data['data'][name] = value; 1086 }); 1087 1088 return data; 1089 }, 1090 1091 customerId: function () 1092 {
1093 let customerId = booking_panel_js.find('.bkntc_input_identifier_input').data('customer-id'); 1094 1095 return customerId || 0; 1096 }, 1097 1098 paymentMethod: function () 1099 { 1100 if( booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="confirm_details"]').hasClass('booknetic_menu_hidden') ) 1101 return 'local'; 1102 1103 return booking_panel_js.find('.booknetic_payment_method.booknetic_payment_method_selected').attr('data-payment-type'); 1104 }, 1105 1106 paymentDepositFullAmount: function () 1107 { 1108 return booking_panel_js.find('input[name="input_deposit"][type="radio"]:checked').val() == '0' ? true : false; 1109 }, 1110 1111 recurringStartDate: function() 1112 { 1113 var val = booking_panel_js.find("#booknetic_recurring_start").val(); 1114 1115 if( val == '' || val == undefined ) 1116 return ''; 1117 1118 return booknetic.convertDate( val, booknetic.datePickerFormat(), 'Y-m-d' ); 1119 }, 1120 1121 recurringEndDate: function() 1122 { 1123 var val = booking_panel_js.find("#booknetic_recurring_end").val(); 1124 1125 if( val == '' || val == undefined ) 1126 return ''; 1127 1128 return booknetic.convertDate( val, booknetic.datePickerFormat(), 'Y-m-d' ); 1129 }, 1130 1131 recurringTimesArr: function() 1132 { 1133 if( !booknetic.serviceData ) 1134 return JSON.stringify( {} ); 1135 1136 var repeatType = booknetic.serviceData['repeat_type'], 1137 recurringTimes = {}; 1138 1139 if( repeatType == 'weekly' ) 1140 { 1141 booking_panel_js.find(".booknetic_times_days_of_week_area > .booknetic_active_day").each(function() 1142 { 1143 var dayNum = $(this).data('day'); 1144 var time = $(this).find('.booknetic_wd_input_time').val(); 1145 1146 recurringTimes[ dayNum ] = time; 1147 }); 1148 1149 recurringTimes = JSON.stringify( recurringTimes ); 1150 } 1151 else if( repeatType == 'daily' ) 1152 { 1153 recurringTimes = booking_panel_js.find("#booknetic_daily_recurring_frequency").val(); 1154 } 1155 else if( repeatType == 'monthly' ) 1156 { 1157 recurringTimes = booking_panel_js.find("#booknetic_monthly_recurring_type").val(); 1158 if( recurringTimes == 'specific_day' ) 1159 { 1160 recurringTimes += ':' + ( booking_panel_js.find("#booknetic_monthly_recurring_day_of_month").val() == null ? '' : booking_panel_js.find("#booknetic_monthly_recurring_day_of_month").val().join(',') ); 1161 } 1162 else 1163 { 1164 recurringTimes += ':' + booking_panel_js.find("#booknetic_monthly_recurring_day_of_week").val(); 1165 } 1166 } 1167 1168 return recurringTimes; 1169 }, 1170 1171 recurringTimesArrFinish: function() 1172 { 1173 var recurringDates = []; 1174 var hasTimeError = false; 1175 1176 booking_panel_js.find("#booknetic_recurring_dates > tr").each(function() 1177 { 1178 var sDate = $(this).find('[data-date]').attr('data-date'); 1179 var sTime = $(this).find('[data-time]').attr('data-time'); 1180 if($(this).find('[data-service-type]').attr('data-service-type') === 'datebased') 1181 { 1182 sTime = '00:00'; 1183 } 1184 // if tried to change the time 1185 if( $(this).find('.booknetic_time_select').length ) 1186 { 1187 sTime = $(this).find('.booknetic_time_select').val(); 1188 if( sTime == '' ) 1189 { 1190 hasTimeError = true; 1191 } 1192 } 1193 else if( $(this).find('.booknetic_data_has_error').length > 0 ) 1194 { 1195 hasTimeError = ! booknetic.dateBasedService; 1196 } 1197 1198 recurringDates.push([ sDate, sTime ]); 1199 }); 1200 1201 if( hasTimeError ) 1202 { 1203 return false; 1204 } 1205 1206 return JSON.stringify( recurringDates ); 1207 }, 1208 1209 recurringDateValidate: function() 1210 { 1211 let dateError = true; 1212 booking_panel_js.find("#booknetic_recurring_dates > tr").each(function() 1213 { 1214 if( $(this).find('td[data-date] span.booknetic_data_has_error').length > 0 ) 1215 { 1216 dateError = false; 1217 } 1218 }); 1219 return dateError; 1220 }, 1221 1222 recurringTime: function () 1223 { 1224 if( !booknetic.serviceData ) 1225 return ''; 1226 1227 var repeatType = booknetic.serviceData['repeat_type'], 1228 time = ''; 1229 1230 if( repeatType == 'daily' ) 1231 { 1232 time = booking_panel_js.find("#booknetic_daily_time").val(); 1233 } 1234 else if( repeatType == 'monthly' ) 1235 { 1236 time = booking_panel_js.find("#booknetic_monthly_time").val(); 1237 } 1238 1239 return time; 1240 } 1241 1242 }, 1243 1244 ajaxParameters: function ( defaultData = undefined , bool = true ) 1245 { 1246 var data = new FormData(); 1247
1248 data.append( 'payment_method', booknetic.getSelected.paymentMethod() ); 1249 data.append( 'deposit_full_amount', booknetic.getSelected.paymentDepositFullAmount() ? 1 : 0 ); 1250 data.append( 'client_time_zone', booknetic.timeZoneOffset() ); 1251 1252 data.append( 'google_recaptcha_token', booknetic.google_recaptcha_token ); 1253 data.append( 'google_recaptcha_action', booknetic.google_recaptcha_action ); 1254 1255 if( typeof defaultData != 'undefined' ) 1256 { 1257 for ( var key in defaultData ) 1258 { 1259 data.append( key, defaultData[key] ); 1260 } 1261 } 1262 1263 if ( bool ) 1264 { 1265 this.stepManager.saveData(); 1266 } 1267 1268 data.append( 'cart', JSON.stringify(booknetic.cartArr) ); 1269 data.append( 'current', booknetic.cartCurrentIndex ); 1270 data.append( 'query_params', booknetic.getURLQueryParams() ); 1271 1272 return bookneticHooks.doFilter( 'appointment_ajax_data', data, booknetic ); 1273 }, 1274 1275 getURLQueryParams: function() 1276 { 1277 const queryString = window.location.search; 1278 const searchParams = new URLSearchParams( queryString ); 1279 1280 let query_params = {}; 1281 1282 searchParams.forEach( ( value, key ) => { 1283 query_params[ key ] = value; 1284 } ); 1285 1286 return JSON.stringify( query_params ); 1287 }, 1288 1289 calcRecurringTimes: function() 1290 { 1291 booknetic.serviceFixPeriodEndDate(); 1292 1293 var fullPeriod = booknetic.serviceData['full_period_value']; 1294 var repeatType = booknetic.serviceData['repeat_type']; 1295 var startDate = booknetic.getSelected.recurringStartDate(); 1296 var endDate = booknetic.getSelected.recurringEndDate(); 1297 1298 if( startDate == '' || endDate == '' ) 1299 return; 1300 1301 endDate = booknetic.getDateWithUTC( endDate ); 1302 1303 var cursor = booknetic.getDateWithUTC( startDate ), 1304 numberOfAppointments = 0, 1305 frequency = ( repeatType === 'daily' ) ? booking_panel_js.find( '#booknetic_daily_recurring_frequency' ).val() : 1; 1306 1307 if( !( frequency >= 1 ) ) 1308 { 1309 frequency = 1; 1310 if( repeatType === 'daily' ) 1311 { 1312 booking_panel_js.find('#booknetic_daily_recurring_frequency').val('1'); 1313 } 1314 } 1315 1316 var activeDays = {}; 1317 if( repeatType === 'weekly' ) 1318 { 1319 booking_panel_js.find(".booknetic_times_days_of_week_area > .booknetic_active_day").each(function() 1320 { 1321 activeDays[ $(this).data('day') ] = true; 1322 }); 1323 1324 if( $.isEmptyObject( activeDays ) ) 1325 { 1326 return; 1327 } 1328 } 1329 else if( repeatType === 'monthly' ) 1330 { 1331 var monthlyRecurringType = booking_panel_js.find("#booknetic_monthly_recurring_type").val(); 1332 var monthlyDayOfWeek = booking_panel_js.find("#booknetic_monthly_recurring_day_of_week").val(); 1333 1334 var selectedDays = booking_panel_js.find("#booknetic_monthly_recurring_day_of_month").select2('val'); 1335 1336 if( selectedDays ) 1337 { 1338 for( var i = 0; i < selectedDays.length; i++ ) 1339 { 1340 activeDays[ selectedDays[i] ] = true; 1341 } 1342 } 1343 } 1344 1345 while( cursor <= endDate ) 1346 { 1347 var weekNum = cursor.getDay(); 1348 //todo://why did we use parseInt here and on many other places? busy with other tasks rn 1349 // test it out in the future. 1350 var dayNumber = parseInt( cursor.getDate() ); 1351 weekNum = weekNum > 0 ? weekNum : 7;
1352 var dateFormat = cursor.getFullYear() + '-' + booknetic.zeroPad( cursor.getMonth() + 1 ) + '-' + booknetic.zeroPad( cursor.getDate() ); 1353 1354 if( repeatType === 'monthly' ) 1355 { 1356 if( ( monthlyRecurringType === 'specific_day' && typeof activeDays[ dayNumber ] != 'undefined' ) || booknetic.getMonthWeekInfo( cursor, monthlyRecurringType, monthlyDayOfWeek ) ) 1357 { 1358 if( 1359 // if is not off day for staff or service 1360 !( typeof booknetic.globalTimesheet[ weekNum-1 ] != 'undefined' && booknetic.globalTimesheet[ weekNum-1 ]['day_off'] ) && 1361 // if is not holiday for staff or service 1362 typeof booknetic.globalDayOffs[ dateFormat ] == 'undefined' 1363 ) 1364 { 1365 numberOfAppointments++; 1366 } 1367 } 1368 } 1369 else if( 1370 // if weekly repeat type then only selected days of the week... 1371 ( typeof activeDays[ weekNum ] != 'undefined' || repeatType === 'daily' ) && 1372 // if is not off day for staff or service 1373 !( typeof booknetic.globalTimesheet[ weekNum-1 ] != 'undefined' && booknetic.globalTimesheet[ weekNum-1 ]['day_off'] ) && 1374 // if is not holiday for staff or service 1375 typeof booknetic.globalDayOffs[ dateFormat ] == 'undefined' 1376 ) 1377 { 1378 numberOfAppointments++; 1379 } 1380 1381 cursor = new Date( cursor.getTime() + 1000 * 24 * 3600 * frequency ); 1382 } 1383 1384 booking_panel_js.find('#booknetic_recurring_times').val( numberOfAppointments ); 1385 1386 }, 1387 1388 initRecurringElements: function( ) 1389 { 1390 booknetic.select2Ajax( booking_panel_js.find(".booknetic_wd_input_time, #booknetic_daily_time, #booknetic_monthly_time"), 'get_available_times_all', function( select ) 1391 { 1392 var dayNumber = ( select.attr( 'id' ) === 'booknetic_daily_time' || select.attr( 'id' ) === 'booknetic_monthly_time' ) ? -1 : select.attr( 'id' ).replace( 'booknetic_time_wd_', '' ); 1393 1394 return booknetic.formDataToObject( booknetic.ajaxParameters({day_number: dayNumber}) ); 1395 }); 1396 1397 booking_panel_js.find("#booknetic_monthly_recurring_day_of_month").select2({ 1398 theme: 'bootstrap', 1399 placeholder: __('select'), 1400 allowClear: true, 1401 maximumSelectionLength: booknetic.serviceData[ 'repeat_frequency' ], 1402 closeOnSelect: false, 1403 }).on( 'select2:select', function( e ) 1404 { 1405 // https://github.com/select2/select2/issues/3514 1406 1407 if ( 1408 $( this ).select2( "data" ).length >= 1409 $( this ).data( "select2" ).results.data.maximumSelectionLength 1410 ) 1411 { 1412 $( this ).select2( "close" ); 1413 } 1414 }); 1415 1416 booking_panel_js.find("#booknetic_monthly_recurring_type, #booknetic_monthly_recurring_day_of_week").select2({ 1417 theme: 'bootstrap', 1418 placeholder: __('select'), 1419 minimumResultsForSearch: -1 1420 }); 1421 1422 booking_panel_js.find('#booknetic_monthly_recurring_type').trigger('change'); 1423 1424 booknetic.initDatepicker( booking_panel_js.find("#booknetic_recurring_start") ); 1425 booknetic.initDatepicker( booking_panel_js.find("#booknetic_recurring_end") ); 1426 1427 booknetic.serviceFixPeriodEndDate(); 1428 booknetic.serviceFixFrequency(); 1429 booking_panel_js.find("#booknetic_recurring_start").trigger('change'); 1430 }, 1431 1432 loadAvailableDate: function(instance ,data) 1433 { 1434 booknetic.ajax( 'get_recurring_available_dates', data, function ( result ) 1435 { 1436 instance.set('enable',result['available_dates']); 1437 }); 1438 }, 1439 1440 serviceFixPeriodEndDate: function() 1441 { 1442 let startDate, endDate; 1443 let serviceData = booknetic.serviceData; 1444 1445 if( serviceData && serviceData['full_period_value'] > 0 ) 1446 { 1447 booking_panel_js.find("#booknetic_recurring_end").attr('disabled', true); 1448 booking_panel_js.find("#booknetic_recurring_times").attr('disabled', true); 1449 1450 startDate = booknetic.getSelected.recurringStartDate(); 1451 1452 if( serviceData[ 'full_period_type' ] === 'month' ) 1453 { 1454 endDate = new Date( startDate + "T00:00:00" ); 1455 endDate.setMonth( endDate.getMonth() + parseInt( serviceData['full_period_value'] ) ); 1456 endDate.setDate( endDate.getDate() - 1 ); 1457 1458 booking_panel_js.find("#booknetic_recurring_end").val( booknetic.convertDate( endDate.getFullYear() + '-' + booknetic.zeroPad( endDate.getMonth() + 1 ) + '-' + booknetic.zeroPad( endDate.getDate() ), 'Y-m-d' ) ); 1459 } 1460 else if( serviceData[ 'full_period_type' ] === 'week' ) 1461 { 1462 1463 endDate = new Date( startDate + "T00:00:00" ); 1464 endDate.setDate( endDate.getDate() + parseInt( serviceData['full_period_value'] ) * 7 - 1 ); 1465 1466 booking_panel_js.find("#booknetic_recurring_end").val( booknetic.convertDate( endDate.getFullYear() + '-' + booknetic.zeroPad( endDate.getMonth() + 1 ) + '-' + booknetic.zeroPad( endDate.getDate() ), 'Y-m-d' ) ); 1467 } 1468 else if( serviceData[ 'full_period_type' ] === 'day' ) 1469 { 1470 endDate = new Date( startDate + "T00:00:00" ); 1471 endDate.setDate( endDate.getDate() + parseInt( serviceData['full_period_value'] ) - 1 ); 1472 1473 booking_panel_js.find("#booknetic_recurring_end").val( booknetic.convertDate( endDate.getFullYear() + '-' + booknetic.zeroPad( endDate.getMonth() + 1 ) + '-' + booknetic.zeroPad( endDate.getDate() ), 'Y-m-d' ) ); 1474 } 1475 else if( serviceData[ 'full_period_type' ] === 'time' ) 1476 {
1477 if( booknetic.getSelected.recurringEndDate() == '' ) 1478 { 1479 startDate = new Date( booknetic.getSelected.recurringStartDate() ); 1480 endDate = new Date( startDate.setMonth( startDate.getMonth() + 1 ) ); 1481 1482 booking_panel_js.find("#booknetic_recurring_end").val( booknetic.convertDate( endDate.getFullYear() + '-' + booknetic.zeroPad( endDate.getMonth() + 1 ) + '-' + booknetic.zeroPad( endDate.getDate() ), 'Y-m-d' ) ); 1483 } 1484 1485 booking_panel_js.find("#booknetic_recurring_times").val( serviceData['full_period_value'] ).trigger('keyup'); 1486 } 1487 } 1488 else 1489 { 1490 booking_panel_js.find("#booknetic_recurring_end").attr('disabled', false); 1491 booking_panel_js.find("#booknetic_recurring_times").attr('disabled', false); 1492 1493 if( booknetic.getSelected.recurringEndDate() == '' ) 1494 { 1495 startDate = new Date( booknetic.getSelected.recurringStartDate() ); 1496 endDate = new Date( startDate.setMonth( startDate.getMonth() + 1 ) ); 1497 1498 booking_panel_js.find("#booknetic_recurring_end").val( booknetic.convertDate( endDate.getFullYear() + '-' + booknetic.zeroPad( endDate.getMonth() + 1 ) + '-' + booknetic.zeroPad( endDate.getDate() ), 'Y-m-d' ) ); 1499 } 1500 } 1501 }, 1502 1503 serviceFixFrequency: function() 1504 { 1505 var serviceData = booknetic.serviceData; 1506 1507 if( serviceData && serviceData[ 'repeat_frequency' ] > 0 && serviceData[ 'repeat_type' ] === 'daily' ) 1508 { 1509 booking_panel_js.find("#booknetic_daily_recurring_frequency").val( serviceData['repeat_frequency'] ).attr('disabled', true); 1510 } 1511 else 1512 { 1513 booking_panel_js.find("#booknetic_daily_recurring_frequency").attr('disabled', false); 1514 } 1515 }, 1516 1517 getMonthWeekInfo: function( date, type, dayOfWeek ) 1518 { 1519 var jsDate = new Date( date ), 1520 weekd = jsDate.getDay(); 1521 weekd = weekd === 0 ? 7 : weekd; 1522 1523 if( weekd != dayOfWeek ) 1524 { 1525 return false; 1526 } 1527
1528 const month = jsDate.getMonth() + 1, 1529 year = jsDate.getFullYear(); 1530 1531 if( type === 'last' ) 1532 { 1533 var nextWeek = new Date(jsDate.getTime()); 1534 nextWeek.setDate( nextWeek.getDate() + 7 ); 1535 1536 return nextWeek.getMonth() + 1 !== month; 1537 } 1538 1539 const firstDayOfMonth = new Date(year + '-' + booknetic.zeroPad(month) + '-01'), 1540 firstWeekDay = firstDayOfMonth.getDay() === 0 ? 7 : firstDayOfMonth.getDay(); 1541 1542 const dif = (dayOfWeek >= firstWeekDay ? dayOfWeek : parseInt(dayOfWeek) + 7) - firstWeekDay; 1543 const days = jsDate.getDate() - dif, 1544 dNumber = parseInt(days / 7) + 1; 1545 1546 return type == dNumber; 1547 }, 1548 1549 confirmAppointment: async function () 1550 { 1551 let result; 1552 1553 try { 1554 result = await booknetic.ajaxAsync( { backend_action: 'get_data', frontend_action: 'confirm' }, 1555 booknetic.ajaxParameters( { 1556 current_step: 'confirm', 1557 previous_step: booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step").data('step-id'), 1558 info: booking_panel_js.data( 'info' ) 1559 }), true 1560 ); 1561 } catch (e) { 1562 booknetic.refreshGoogleReCaptchaToken(); 1563 if (typeof e['id'] == 'undefined') 1564 return; 1565 1566 booknetic.ajaxResultConfirmStep = e; 1567 booknetic.appointmentId = e['id']; 1568 booknetic.paymentId = typeof e['payment_id'] != 'undefined' ? e['payment_id'] : null; 1569 return; 1570 } 1571 1572 booknetic.refreshGoogleReCaptchaToken(); 1573 1574 booknetic.ajaxResultConfirmStep = result; 1575 booknetic.appointmentId = result['id']; 1576 booknetic.paymentId = result['payment_id']; 1577 1578 if ( booknetic.paymentWindow !== null && result["expires_at"] !== undefined && result["expires_at"] < 24*60*60 ) 1579 setTimeout(() => booknetic.paymentWindow.close, result["expires_at"] * 1000 ) 1580 1581 if( booknetic.getSelected.paymentMethod() === 'local' ) 1582 { 1583 booknetic.paymentFinished( true ); 1584 booknetic.showFinishStep(); 1585 } else { 1586 booknetic.startPolling(result.id) 1587 } 1588 1589 booking_panel_js.find('#booknetic_add_to_google_calendar_btn').data('url', result['google_calendar_url'] ); 1590 booking_panel_js.find('#booknetic_add_to_icalendar_btn').attr('href', encodeURI( result['icalendar_url'] ) ); 1591 }, 1592 1593 waitPaymentFinish: function() 1594 { 1595 if( booknetic.paymentWindow.closed ) 1596 { 1597 if ( booknetic.paymentStatusListener ) 1598 clearInterval( booknetic.paymentStatusListener ); 1599 1600 booknetic.loading(0); 1601 1602 booknetic.showFinishStep(); 1603 1604 return; 1605 } 1606 1607 setTimeout( booknetic.waitPaymentFinish, 1000 ); 1608 }, 1609 1610 paymentFinished: function ( status ) 1611 { 1612 booknetic.paymentStatus = status; 1613 booking_panel_js.find(".booknetic_appointment_finished_code").text( booknetic.zeroPad( booknetic.appointmentId, 4 ) ); 1614 1615 if( booknetic.paymentWindow && !booknetic.paymentWindow.closed ) 1616 { 1617 if ( booknetic.paymentStatusListener ) 1618 clearInterval( booknetic.paymentStatusListener ); 1619 1620 booknetic.paymentWindow.close(); 1621 } 1622 1623 bookneticHooks.doAction( 'payment_completed_deprecated', booknetic ); 1624 booknetic.stopPolling() 1625 }, 1626 1627 showFinishStep: function () 1628 { 1629 if ( BookneticData.settings.redirect_users_on_confirm === true && booknetic.paymentStatus === true ) 1630 { 1631 window.location.href = BookneticData.settings.redirect_users_on_confirm_url; 1632 return; 1633 } 1634 1635 if( booknetic.paymentStatus === true ) 1636 { 1637 booking_panel_js.find('.booknetic_appointment_container').fadeOut(95); 1638 1639 if ( booking_panel_js.find('.booknetic_appointment_steps').css( 'display' ) === 'none' ) 1640 { 1641 booking_panel_js.find('.booknetic_appointment_finished').fadeIn(100).css('display', 'flex'); 1642 } else { 1643 booking_panel_js.find('.booknetic_appointment_steps').fadeOut(100, function () 1644 { 1645 booking_panel_js.find('.booknetic_appointment_finished').fadeIn(100).css('display', 'flex'); 1646 }); 1647 } 1648 1649 bookneticHooks.doAction( 'booking_finished_successfully', booknetic ); 1650 } 1651 else 1652 { 1653 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="confirm_details"]').fadeOut( 150, function() 1654 {
1655 booking_panel_js.find('.booknetic_appointment_container_body > .booknetic_appointment_finished_with_error').removeClass('booknetic_hidden').hide().fadeIn( 150 ); 1656 }); 1657 1658 booking_panel_js.find('.booknetic_next_step.booknetic_confirm_booking_btn').fadeOut( 150, function() 1659 { 1660 booking_panel_js.find('.booknetic_try_again_btn').removeClass('booknetic_hidden').hide().fadeIn( 150 ); 1661 }); 1662 1663 booking_panel_js.find('.booknetic_appointment_container_header_cart').fadeOut( 150 ); 1664 1665 booking_panel_js.find('.booknetic_prev_step').css('opacity', '0').attr('disabled', true); 1666 1667 bookneticHooks.doAction( 'payment_error', booknetic ); 1668 } 1669 1670 if ( booknetic.isMobileView() ) 1671 { 1672 $('html,body').animate({scrollTop: parseInt(booking_panel_js.offset().top) - 100}, 1000); 1673 } 1674 }, 1675 1676 fadeInAnimate: function(el, fn) 1677 { 1678 let sec = 150; 1679 let delay = 50; 1680 let count = booking_panel_js.find(el).length; 1681 1682 if( booking_panel_js.find(el).length === 0 ) 1683 fn(); 1684 1685 booking_panel_js.find(el).hide().each(function (i) 1686 { 1687 (function( i, t, isLast, fn ) 1688 { 1689 setTimeout( function () 1690 { 1691 t.fadeIn( (i > 6 ? 6 : i) * sec, ( isLast ? fn : null )); 1692 }, (i > 6 ? 6 : i) * delay ); 1693 })( i, $(this), (count-1===i), fn ); 1694 }); 1695 }, 1696 1697 fadeOutAnimate: function(el, sec, delay) 1698 { 1699 sec = sec > 0 ? sec : 150; 1700 delay = delay > 0 ? delay : 50; 1701 1702 booking_panel_js.find(el).each(function (i) 1703 { 1704 (function( i, t ) 1705 { 1706 setTimeout( function () 1707 { 1708 t.fadeOut( (i > 6 ? 6 : i) * sec ); 1709 }, (i > 6 ? 6 : i) * delay ); 1710 })( i, $(this) ); 1711 }); 1712 }, 1713 1714 1715 _bookneticScroll: false, 1716 handleScroll: function () 1717 { 1718 if( !booknetic._bookneticScroll && !booknetic.isMobileView() ) 1719 { 1720 booking_panel_js.find(".booknetic_appointment_container_body").addClass('nice-scrollbar-primary'); 1721 1722 booknetic._bookneticScroll = true; 1723 1724 return; 1725 } 1726 1727 if( booknetic.isMobileView() && booknetic._bookneticScroll ) 1728 { 1729 booknetic._bookneticScroll = false; 1730 1731 booking_panel_js.find(".booknetic_appointment_container_body").removeClass('nice-scrollbar-primary'); 1732 1733 if ( $( '#country-listbox' ).length ) 1734 { 1735 $( '#country-listbox' ).removeClass('nice-scrollbar-primary'); 1736 } 1737 } 1738 }, 1739 1740 getDateWithUTC: function ( date )//if the client timezone is negative 1741 { 1742 date = new Date( date ); 1743 let offset = date.getTimezoneOffset(); 1744 1745 if ( offset > 0 ) // if offset a positive number, client's timezone is negative 1746 date.setTime( date.getTime() + ( offset * 60 * 1000 ) ); //get UTC time 1747 1748 return date; 1749 }, 1750 1751 initDatepicker: function ( el ) 1752 { 1753 bookneticdatepicker( el[0], { 1754 formatter: function (input, date, instance) 1755 { 1756 var val = date.getFullYear() + '-' + booknetic.zeroPad( date.getMonth() + 1 ) + '-' + booknetic.zeroPad( date.getDate() ); 1757 input.value = booknetic.convertDate( val, 'Y-m-d' ); 1758 }, 1759 startDay: BookneticData.week_starts_on == 'sunday' ? 0 : 1, 1760 customDays: [__('Sun'), __('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat')], 1761 customMonths: [__('January'), __('February'), __('March'), __('April'), __('May'), __('June'), __('July'), __('August'), __('September'), __('October'), __('November'), __('December')], 1762 onSelect: function( input ) 1763 { 1764 $(input.el).trigger('change'); 1765 }, 1766 minDate: el[0].getAttribute( "data-apply-min" ) ? this.getDateWithUTC( booknetic.convertDate( el[0].value, booknetic.datePickerFormat(), 'Y-m-d' ) ) : undefined 1767 }); 1768 }, 1769 1770 refreshGoogleReCaptchaToken: function () 1771 { 1772 if( 'google_recaptcha_site_key' in BookneticData ) 1773 { 1774 grecaptcha.execute( BookneticData['google_recaptcha_site_key'], { action: booknetic.google_recaptcha_action }).then(function (token) 1775 { 1776 booknetic.google_recaptcha_token = token; 1777 }); 1778 } 1779 }, 1780 1781 isMobileView: function () 1782 { 1783 return window.matchMedia('(max-width: 1000px)').matches; 1784 }, 1785 1786 stepManager: { 1787 1788 stepValidation: function ( step ) 1789 { 1790 let result = bookneticHooks.doFilter( `step_validation_${step}`, { 1791 status: true, 1792 errorMsg: '' 1793 }, booknetic ); 1794 1795 if( result.status ) 1796 bookneticHooks.doAction(`step_end_${step}` , booknetic); 1797 1798 return result; 1799 }, 1800 1801 loadStep: function( step ) 1802 { 1803 if( ! bookneticHooks.doFilter( `load_step_${step}` , booknetic ) ) 1804 return false;
1805 1806 var current_step_el = booking_panel_js.find('.booknetic_appointment_step_element.booknetic_active_step'); 1807 var next_step_el = booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="'+step+'"]'); 1808 1809 while( next_step_el.hasClass('booknetic_menu_hidden') ) 1810 next_step_el = next_step_el.next(); 1811 1812 booknetic.stepManager.disableAction(); 1813 1814 var next_step_id = next_step_el.data('step-id'); 1815 var current_step_id = ''; 1816 1817 if( current_step_el.length > 0 ) 1818 { 1819 current_step_el.removeClass('booknetic_active_step'); 1820 current_step_id = current_step_el.data('step-id'); 1821 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + current_step_id + '"]').hide(); 1822 } 1823 1824 next_step_el.addClass('booknetic_active_step'); 1825 booking_panel_js.find(".booknetic_appointment_container_header_text").text( next_step_el.data('title') ); 1826 1827 booknetic.stepManager.updateGoNextBtn( next_step_el ); 1828 1829 bookneticHooks.doAction('before_step_loading', booknetic, next_step_id, current_step_id); 1830 1831 booknetic.stepManager.saveData(); 1832 1833 booknetic.stepManager.updateBookingPanelFooter(); 1834 1835 return true; 1836 }, 1837 1838 loadStandartSteps: function ( next_step_id, current_step_id ) 1839 { 1840 if( ! booknetic.stepManager.needToReloadCache( next_step_id ) ) 1841 { 1842 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + next_step_id + '"]').show(); 1843 1844 booknetic.fadeInAnimate('.booknetic_appointment_container_body [data-step-id="' + next_step_id + '"] .booknetic_fade', function() 1845 { 1846 booking_panel_js.find(".booknetic_appointment_container_body").scrollTop(0); 1847 booknetic.handleScroll(); 1848 booknetic.stepManager.enableActions(); 1849 }); 1850 bookneticHooks.doAction('loaded_cached_step', booknetic, next_step_id); 1851 } 1852 else 1853 { 1854 var next_step_el = booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="'+next_step_id+'"]'); 1855 var loader = booking_panel_js.find('.booknetic_preloader_' + next_step_el.data('loader') + '_box'); 1856 1857 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + next_step_id + '"]').empty(); 1858 1859 bookneticHooks.doAction('start_step_loading', booknetic, next_step_id, current_step_id); 1860 1861 loader.removeClass('booknetic_hidden').show(); 1862 let step 1863 const bookingPanelParams = { 1864 current_step: next_step_id, 1865 previous_step: booknetic.stepManager.getPrevStep().data( 'step-id' ), 1866 info: booking_panel_js.data( 'info' ), 1867 } 1868 if (next_step_id === "location" && (step = booking_panel_js.data('steps').find(s => s.id === "location"))?.options) { 1869 bookingPanelParams.location_filter = JSON.stringify(step.options); 1870 } 1871 1872 booknetic.ajax( 'get_data', booknetic.ajaxParameters({...bookingPanelParams}), function ( result ) 1873 { 1874 loader.hide(); 1875 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + next_step_id + '"]').show().html( booknetic.htmlspecialchars_decode( booknetic.sanitizeHTML(result['html']) ) ); 1876 1877 booknetic.fadeInAnimate('.booknetic_appointment_container_body [data-step-id="' + next_step_id + '"] .booknetic_fade', function () 1878 { 1879 booking_panel_js.find(".booknetic_appointment_container_body").scrollTop(0); 1880 booknetic.handleScroll(); 1881 }); 1882 1883 booknetic.stepManager.enableActions(); 1884 1885 bookneticHooks.doAction( 'loaded_step', booknetic, next_step_id, current_step_id, result ); 1886 bookneticHooks.doAction( `loaded_step_${next_step_id}`, booknetic, result ); 1887 1888 }, false , function ( result ) 1889 { 1890 loader.hide(); 1891 booknetic.stepManager.goBack(); 1892 bookneticHooks.doAction('step_loaded_with_error', booknetic, next_step_id, current_step_id, result); 1893 }); 1894 } 1895 }, 1896 1897 disableAction: function () 1898 { 1899 booking_panel_js.find(".booknetic_next_step, .booknetic_prev_step").attr('disabled', true); 1900 }, 1901 1902 enableActions: function () 1903 { 1904 booking_panel_js.find(".booknetic_next_step, .booknetic_prev_step").attr('disabled', false); 1905 }, 1906 1907 updateBookingPanelFooter: function () 1908 { 1909 booknetic.stepManager.updateGoBackButton(); 1910 }, 1911 1912 updateGoNextBtn: function ( step_el ) 1913 { 1914 var next_step_el = step_el.next('.booknetic_appointment_step_element'); 1915 1916 while( next_step_el.hasClass('booknetic_menu_hidden') ) 1917 next_step_el = next_step_el.next(); 1918 1919 if ( next_step_el.length === 0 ) { 1920 booking_panel_js.find('.booknetic_confirm_booking_btn').show(); 1921 booking_panel_js.find('.booknetic_next_step_btn').hide(); 1922 } 1923 else 1924 { 1925 booking_panel_js.find('.booknetic_confirm_booking_btn').hide(); 1926 booking_panel_js.find('.booknetic_next_step_btn').show(); 1927 } 1928 }, 1929 1930 updateGoBackButton: function () 1931 { 1932 const stepElement = '.booknetic_appointment_step_element'; 1933 const activeElement = '.booknetic_active_step'; 1934 const menuHidden = '.booknetic_menu_hidden'; 1935 1936 // hide the BACK button for the first step 1937 if ( booking_panel_js.find(stepElement ).not( menuHidden ).first().is( booking_panel_js.find( activeElement ) ) ) { 1938 booking_panel_js.find( '.booknetic_prev_step' ).css( 'opacity', 0 ).css( 'pointer-events', 'n
1938one' ); 1939 return; 1940 } 1941 1942 booking_panel_js.find( '.booknetic_prev_step' ).css( 'opacity', 1 ).css( 'pointer-events', 'auto' ); 1943 }, 1944 1945 saveData: ()=> 1946 { 1947 let obj = {}; 1948 1949 if(booknetic.cartArr[ booknetic.cartCurrentIndex ] !== undefined) 1950 { 1951 obj = booknetic.cartArr[ booknetic.cartCurrentIndex ]; 1952 } 1953 1954 obj['location'] = booknetic.getSelected.location(); 1955 obj['staff'] = booknetic.getSelected.staff(); 1956 obj['service_category'] = booknetic.getSelected.serviceCategory(); 1957 obj['service'] = booknetic.getSelected.service(); 1958 obj['service_extras'] = booknetic.getSelected.serviceExtras(); 1959 1960 obj['date'] = booknetic.getSelected.date(); 1961 obj['time'] = booknetic.getSelected.time(); 1962 obj['brought_people_count'] = booknetic.getSelected.brought_people_count(); 1963 1964 obj['recurring_start_date'] = booknetic.getSelected.recurringStartDate(); 1965 obj['recurring_end_date'] = booknetic.getSelected.recurringEndDate(); 1966 obj['recurring_times'] = booknetic.getSelected.recurringTimesArr(); 1967 obj['appointments'] = booknetic.getSelected.recurringTimesArrFinish(); 1968 1969 obj['customer_id'] = booknetic.getSelected.customerId(); 1970 obj['customer_data'] = booknetic.getSelected.formData()['data']; 1971 1972 booknetic.cartArr[ booknetic.cartCurrentIndex ] = bookneticHooks.doFilter('bkntc_cart' , obj , booknetic ); 1973 }, 1974 1975 goForward: function () 1976 { 1977 let current_step_el = booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step"), 1978 current_step_id = current_step_el.data('step-id'), 1979 next_step_el = booknetic.stepManager.getNextStep(), 1980 next_step_id = next_step_el.data('step-id'), 1981 validate_step = booknetic.stepManager.stepValidation( current_step_id ); 1982 1983 if( validate_step.status == false ) 1984 { 1985 booknetic.toast( validate_step.errorMsg ); 1986 return; 1987 } 1988 1989 if( next_step_el.length == 0 ) 1990 { 1991 booknetic.confirmAppointment(); 1992 return; 1993 } 1994 1995 current_step_el.addClass('booknetic_selected_step'); 1996 1997 let oldData = JSON.stringify( booknetic.cartArr[ booknetic.cartCurrentIndex ] ); 1998 booknetic.stepManager.saveData(); 1999 let newData = JSON.stringify( booknetic.cartArr[ booknetic.cartCurrentIndex ] ); 2000 2001 if( oldData !== newData ) 2002 { 2003 let startToEmpty = next_step_el; 2004 while( startToEmpty.length > 0 ) 2005 { 2006 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="'+startToEmpty.data('step-id')+'"]').empty(); 2007 startToEmpty = startToEmpty.next(); 2008 } 2009 } 2010 2011 booknetic.toast( false ); 2012 2013 if( booknetic.stepManager.loadStep( next_step_id ) && booknetic.isMobileView() ) 2014 { 2015 $('html,body').animate({scrollTop: parseInt(booking_panel_js.offset().top) - 100}, 1000); 2016 } 2017 }, 2018 2019 goBack: function () 2020 { 2021 let current_step_el = booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step"), 2022 prev_step_el = booknetic.stepManager.getPrevStep(); 2023 2024 if (current_step_el.data('step-id') === "date_time") { 2025 booknetic.current_month_is_empty = undefined 2026 } 2027 2028 current_step_el.removeClass('booknetic_selected_step').nextAll('.booknetic_appointment_step_element').removeClass('booknetic_selected_step'); 2029 2030 if( prev_step_el.length > 0 ) 2031 { 2032 if (prev_step_el.data( 'step-id' ) === 'service_extras' && BookneticData[ 'skip_extras_step_if_need' ] === 'on' && prev_step_el.css('display') === 'none') 2033 { 2034 prev_step_el.css('display', 'block'); 2035 prev_step_el.removeClass('booknetic_selected_step'); 2036 2037 do{ 2038 prev_step_el = prev_step_el.prev(); 2039 } 2040 while(prev_step_el.hasClass('booknetic_menu_hidden')); 2041 } 2042 2043 current_step_el.removeClass('booknetic_active_step'); 2044 prev_step_el.addClass('booknetic_active_step'); 2045 2046 booknetic.stepManager.disableAction(); 2047 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + current_step_el.data('step-id') + '"]').fadeOut(200, function() 2048 { 2049 booknetic.stepManager.enableActions();
2050 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + prev_step_el.data('step-id') + '"]').fadeIn(200, function () 2051 { 2052 booknetic.handleScroll(); 2053 }); 2054 }); 2055 2056 booking_panel_js.find(".booknetic_appointment_container_header_text").text( prev_step_el.data('title') ); 2057 } 2058 2059 booking_panel_js.find('.booknetic_confirm_booking_btn').hide(); 2060 booking_panel_js.find('.booknetic_next_step_btn').show(); 2061 2062 booknetic.stepManager.updateBookingPanelFooter(); 2063 }, 2064 2065 getNextStep: function () 2066 { 2067 let current_step_el = booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step"), 2068 next_step_el = current_step_el.next('.booknetic_appointment_step_element'); 2069 2070 while( next_step_el.hasClass('booknetic_menu_hidden') ) 2071 next_step_el = next_step_el.next(); 2072 2073 return next_step_el; 2074 }, 2075 2076 getPrevStep: function () 2077 { 2078 if( booknetic.cartPrevStep != undefined) 2079 { 2080 let x = booknetic.cartPrevStep; 2081 booknetic.cartPrevStep = undefined; 2082 return booking_panel_js.find(".booknetic_appointment_steps_body div[data-step-id=" + x + "]"); 2083 } 2084 let current_step_el = booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step"), 2085 prev_step_el = current_step_el.prev('.booknetic_appointment_step_element'); 2086 2087 while( prev_step_el.hasClass('booknetic_menu_hidden') ) 2088 prev_step_el = prev_step_el.prev(); 2089 2090 return prev_step_el; 2091 }, 2092 2093 getCurrentStep: function () 2094 { 2095 return booking_panel_js.find(".booknetic_appointment_step_element.booknetic_active_step"); 2096 }, 2097 2098 refreshStepNumbers: function () 2099 { 2100 var index = 1; 2101 2102 booking_panel_js.find('.booknetic_appointment_steps_body > .booknetic_appointment_step_element').each(function() 2103 { 2104 if( $(this).css('display') != 'none' ) 2105 { 2106 $(this).find('.booknetic_badge').text( index ); 2107 index++; 2108 } 2109 }); 2110 }, 2111 2112 needToReloadCache: function( stepId ) 2113 { 2114 if( stepId == 'confirm_details' || stepId=='cart' ) 2115 return true; 2116 2117 if( booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + stepId + '"] > *').length > 0 ) 2118 { 2119 return false; 2120 } 2121 2122 return true; 2123 }, 2124 2125 }, 2126 2127 addGroupAppointmentsCounterForBookneticCalendarDays: function () 2128 { 2129 const dates = booknetic.calendarDateTimes['dates']; 2130 2131 for ( const date in dates ) 2132 { 2133 if ( dates[ date ].length !== 1 ) 2134 { 2135 continue; 2136 } 2137 2138 let max_capacity = dates[ date ][ 0 ].max_capacity; 2139 let weight = dates[ date ][ 0 ].weight; 2140 2141 if ( 2142 weight == 0 || 2143 'hide_available_slots' in booknetic.calendarDateTimes && 2144 booknetic.calendarDateTimes['hide_available_slots'] == 'on' 2145 ) 2146 { 2147 continue; 2148 } 2149 2150 booking_panel_js.find( `.booknetic_calendar_days[data-date=${date}] > div` ).append( `<div class="booknetic_time_group_num booknetic_date_group_num">${weight} / ${max_capacity}</div>` ); 2151 } 2152 }, 2153 2154 checkIfNoDatesAvailable: function ( backendResult ) 2155 { 2156 return backendResult[ 'data' ][ 'dates' ].length === 0 || Object.values( backendResult[ 'data' ][ 'dates' ] ).every( d => d.length === 0 ); 2157 }, 2158 2159 intervalId: 0, 2160 2161 startPolling: (appointmentId) => { 2162 // Clear any existing polling 2163 if (booknetic.intervalId) clearInterval(booknetic.intervalId); 2164 2165 const intervalId = setInterval(() => { 2166 booknetic.ajaxAsync('isPaymentDone', { id: appointmentId }, false) 2167 .then(result => { 2168 if (!result.isDone) return; 2169 clearInterval(intervalId); 2170 booknetic.paymentFinished(true); 2171 }) 2172 .catch(_ => clearInterval(intervalId)); 2173 }, 3000); 2174 2175 setTimeout(() => clearInterval(intervalId), 1000 * 60 * 10); 2176 2177 booknetic.intervalId = intervalId; 2178 }, 2179 2180 2181 stopPolling: () => booknetic.intervalId && clearInterval(this.intervalId), 2182 }; 2183 2184 // steplerle bagli basic eventler 2185 booking_panel_js.on('click', '.booknetic_next_step', function() 2186 { 2187 booknetic.stepManager.goForward(); 2188 }).on('click', '.booknetic_prev_step', function() 2189 { 2190 booknetic.stepManager.goBack(); 2191 }); 2192 2193 booking_panel_js.on('click', '#booknetic_finish_btn', function () 2194 { 2195 let page = window.location; 2196 2197 // check if iframe 2198 if ( window.location !== window.parent.location ) 2199 { 2200 page = window.parent.location; 2201 } 2202 2203 if( ! $(this).data('redirect-url') ) 2204 { 2205 page.reload(); 2206 } 2207 else 2208 {
2209 page.href = $(this).data('redirect-url'); 2210 } 2211 }).on('click' ,'.bkntc_again_booking' , function () 2212 { 2213 let currentBody = booking_panel_js.find('.booknetic_need_copy'); 2214 booknetic.cartHTMLBody[booknetic.cartCurrentIndex] = currentBody.clone(true,true).get(0); 2215 2216 booking_panel_js.find('.booknetic_appointment_steps_body .booknetic_appointment_step_element.need_copy').each(function() 2217 { 2218 let id = $(this).attr('data-step-id'); 2219 if(booknetic.cartHTMLSideBar[booknetic.cartCurrentIndex] == undefined) 2220 { 2221 booknetic.cartHTMLSideBar[booknetic.cartCurrentIndex] = {}; 2222 } 2223 booknetic.cartHTMLSideBar[booknetic.cartCurrentIndex][id] = $(this).clone(true,true).get(0); 2224 }); 2225 2226 booknetic.cartCurrentIndex = booknetic.cartArr.length; 2227 booknetic.cartArr[booknetic.cartCurrentIndex] = {}; 2228 2229 booking_panel_js.find("#booknetic_start_new_booking_btn").trigger('click' , true); 2230 2231 }).on('click', '#booknetic_start_new_booking_btn', function ( e , param ) 2232 { 2233 if( param === undefined ) 2234 { 2235 booking_panel_js.find('.booknetic_appointment_container_header_cart').fadeOut(); 2236 2237 booknetic.cartHTMLBody = []; 2238 booknetic.cartHTMLSideBar = []; 2239 booknetic.cartArr = []; 2240 booknetic.cartCurrentIndex = 0; 2241 } 2242 booking_panel_js.find('.booknetic_appointment_finished').fadeOut(100, function() 2243 { 2244 const appointment_step_style = booking_panel_js.find('.booknetic_appointment_steps').attr( 'style' ); 2245 2246 // in case if booking_panel_js.find('.booknetic_appointment_steps').fadeOut() called 2247 if ( appointment_step_style && appointment_step_style.search( 'display: none;' ) !== -1 ) 2248 booking_panel_js.find('.booknetic_appointment_steps').fadeIn(100); 2249 2250 booking_panel_js.find('.booknetic_appointment_container').fadeIn(100); 2251 }); 2252 2253 booking_panel_js.find(".booknetic_selected_step").removeClass('booknetic_selected_step'); 2254 booking_panel_js.find(".booknetic_active_step").removeClass('booknetic_active_step'); 2255 2256 booknetic.current_month_is_empty = undefined 2257 booknetic.calendarDateTimes = {}; 2258 booknetic.time_show_format = 1; 2259 booknetic.calendarYear = null; 2260 booknetic.calendarMonth = null; 2261 booknetic.paymentWindow = null; 2262 booknetic.paymentStatus = null; 2263 booknetic.appointmentId = null; 2264 booknetic.paymentId = null; 2265 2266 var start_step = booking_panel_js.find(".booknetic_appointment_step_element:not(.booknetic_menu_hidden):eq(0)"); 2267 start_step.addClass('booknetic_active_step'); 2268 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id] ').empty(); 2269 booknetic.stepManager.loadStep( start_step.data('step-id') ); 2270 2271 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id]').hide(); 2272 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="' + start_step.data('step-id') + '"]').show(); 2273 2274 booking_panel_js.find('.booknetic_card_selected').removeClass('booknetic_card_selected'); 2275 booking_panel_js.find('.booknetic_service_card_selected').removeClass('booknetic_service_card_selected'); 2276 booking_panel_js.find('.booknetic_service_card_selected').removeClass('booknetic_service_card_selected'); 2277 2278 booking_panel_js.find(".booknetic_calendar_selected_day").data('date', null); 2279 booking_panel_js.find(".booknetic_selected_time").data('time', null); 2280 2281 booknetic.handleScroll(); 2282 2283 }).on('click', '#booknetic_add_to_google_calendar_btn', function () 2284 { 2285 window.open( $(this).data('url') ); 2286 }).on('click', '.booknetic_try_again_btn', function () 2287 { 2288 if (booknetic.intervalId) { 2289 clearInterval(booknetic.intervalId); 2290 booknetic.intervalId = null; 2291 } 2292 booknetic.ajax('delete_unpaid_appointment', booknetic.ajaxParameters({ payment_id: booknetic.paymentId }), function () 2293 { 2294 booknetic.paymentId = null; 2295 2296 booking_panel_js.find('.booknetic_appointment_finished_with_error').fadeOut(150, function () 2297 { 2298 booking_panel_js.find('.booknetic_appointment_container_body [data-step-id="confirm_details"]').fadeIn(150, function () 2299 { 2300 booknetic.handleScroll(); 2301 }); 2302 }); 2303 2304 booking_panel_js.find('.booknetic_try_again_btn').fadeOut(150, function () 2305 { 2306 booking_panel_js.find('.booknetic_next_step.booknetic_confirm_booking_btn').fadeIn(150); 2307 booking_panel_js.find('.booknetic_prev_step').css('opacity', '1').attr('disabled', false); 2308 }); 2309 2310 if( ! booking_panel_js.find('.booknetic_appointment_step_element[data-step-id="cart"]').hasClass('booknetic_menu_hidden') ) 2311 {
2312 booking_panel_js.find('.booknetic_appointment_container_header_cart').fadeIn( 150 ); 2313 } 2314 2315 }); 2316 }); 2317 2318 //doit staff stepi (locationdan ayirmag) 2319 2320 $( window ).resize(function () 2321 { 2322 booknetic.handleScroll(); 2323 }); 2324 2325 let bookneticStepsArray = booking_panel_js.data('steps'); 2326 for( let step of bookneticStepsArray ) 2327 { 2328 let classAttr = 'booknetic_appointment_step_element'; 2329 if( step.id === 'cart' || step.id === 'confirm_details' ) 2330 classAttr += ' need_copy'; 2331 2332 if( step.hidden ) 2333 classAttr += ' booknetic_menu_hidden'; 2334 2335 let attrs = step.attrs ?? ''; 2336 2337 attrs += ` data-step-id="${step.id}"`; 2338 attrs += ` data-loader="${step.loader}"`; 2339 attrs += ` data-title="${step.head_title}"`; 2340 2341 if( step.value != "" ) 2342 attrs += ` data-value="${step.value}"`; 2343 2344 booking_panel_js.find('.booknetic_appointment_steps_body').append(` 2345 <div class="${classAttr}" ${attrs}> 2346 <span class="booknetic_badge"></span> 2347 <span class="booknetic_step_title"> ${step.title}</span> 2348 </div> 2349 `); 2350 } 2351 2352 var first_step_id = booking_panel_js.find('.booknetic_appointment_steps_body > .booknetic_appointment_step_element:not(.booknetic_menu_hidden)').eq(0).data('step-id'); 2353 booknetic.stepManager.loadStep( first_step_id ); 2354 2355 booknetic.handleScroll(); 2356 2357 booknetic.fadeInAnimate('.booknetic_appointment_step_element:not(.booknetic_menu_hidden)', function () 2358 { 2359 booknetic.stepManager.refreshStepNumbers(); 2360 }); 2361 2362 booking_panel_js.find(".booknetic_appointment_steps_footer").fadeIn(200); 2363 2364 if( 'google_recaptcha_site_key' in BookneticData ) 2365 { 2366 grecaptcha.ready(function () 2367 { 2368 booknetic.refreshGoogleReCaptchaToken(); 2369 }); 2370 } 2371 2372 bookneticHooks.doAction('booking_panel_loaded', booknetic); 2373 2374 return booknetic; 2375 }; 2376 2377 $(document).ready( function() 2378 { 2379 if ( $( 'html' ).attr( 'dir' ) === 'rtl' ) 2380 { 2381 $( 'body' ).addClass( 'rtl' );// doit bu nedi bele arashdirmag lazimdi... .rtl classi chox tehlukelidi. booknetic_rtl etmek olar meselen ve ya bashga n qeder metod var, bu neye lazimdi umumiyyetle bele? 2382 } 2383 2384 /** 2385 * doit bu duzelmelidi. hem alqoritmde xeta var, meselen Cart stepi load olanda headerda icon show olur. geri qayidib nese deyishiklik eledik meselen Servisi deyishdik. 2386 * data deyishir deye cart iconu sifirlanmalidi. chunki butun stepleri tamamlamalidi, date&time sechmelidi, formu tezeden doldurmalidi, chunki service deyishende form inputlarda deyishe biler. 2387 * Amma bu stepleri doldurmadan hemen show olmush icona clickledikde birbasha tulluyur cart stepine. Ordanda next bassan error verir ki, meselen formu doldur ve ya date&time sech ve s. 2388 * Elave olarag $('.*') kimi select yolverilmezdir. booknetic.panel_js.find('.*') || booking_panel_js.find('.*') istifade olunmalidir. 2389 * Cunki 1 pagede eyni anda bir neche booking panel load ola biler. biri digerinin iconlariynan oynamasin deye bu metod hokmen her yerde istifade edilmelidi. 2390 */ 2391 $("body").click(function(e) 2392 { 2393 if( $(e.target).parent().hasClass('booknetic-cart-item-more') ) 2394 { 2395 let a = $(e.target).parents('.booknetic-cart-item-header').find('.booknetic-cart-item-btns').first(); 2396 let b = a.hasClass('show'); 2397 $(".booknetic-cart-item-btns").removeClass("show"); 2398 if(!b) 2399 { 2400 a.addClass('show') 2401 } 2402 else 2403 { 2404 a.removeClass('show'); 2405 } 2406 } 2407 else 2408 { 2409 2410 $(".booknetic-cart-item-btns").removeClass("show"); 2411 2412 } 2413 }); 2414 }); 2415 2416})(jQuery); 2417 2418// local payment gateway 2419(function($) 2420{ 2421 "use strict"; 2422 2423 $(document).ready(function() 2424 { 2425 let paymentData; 2426 2427 bookneticHooks.addAction( 'before_processing_payment', function ( payment_method, data ) 2428 { 2429 if( payment_method !== 'local' ) 2430 return; 2431 2432 paymentData = data; 2433 }); 2434 2435 bookneticHooks.addAction( 'after_processing_payment', function( payment_method, process_status, data ) 2436 { 2437 if( payment_method !== 'local' ) 2438 return; 2439 2440 if( ! process_status ) 2441 { 2442 return; 2443 } 2444 2445 bookneticHooks.doAction('payment_completed', true, paymentData); 2446 }); 2447 }); 2448 2449})(jQuery); 2450 2451
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.