1function latepoint_is_timeframe_in_periods(timeframe_start, timeframe_end, periods_arr) { 2 var is_inside = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; 3 4 for (var i = 0; i < periods_arr.length; i++) { 5 6 var period_start = 0; 7 var period_end = 0; 8 var buffer_before = 0; 9 var buffer_after = 0; 10 11 var period_info = periods_arr[i].split(':'); 12 if (period_info.length == 2) { 13 period_start = period_info[0]; 14 period_end = period_info[1]; 15 } else { 16 buffer_before = period_info[2]; 17 buffer_after = period_info[3]; 18 period_start = parseFloat(period_info[0]) - parseFloat(buffer_before); 19 period_end = parseFloat(period_info[1]) + parseFloat(buffer_after); 20 } 21 if (is_inside) { 22 if (latepoint_is_period_inside_another(timeframe_start, timeframe_end, period_start, period_end)) { 23 return true; 24 } 25 } else { 26 if (latepoint_is_period_overlapping(timeframe_start, timeframe_end, period_start, period_end)) { 27 return true; 28 } 29 } 30 } 31 return false; 32} 33 34function latepoint_is_period_overlapping(period_one_start, period_one_end, period_two_start, period_two_end) { 35 // https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap/ 36 return period_one_start < period_two_end && period_two_start < period_one_end; 37} 38 39function latepoint_is_period_inside_another(period_one_start, period_one_end, period_two_start, period_two_end) { 40 return period_one_start >= period_two_start && period_one_end <= period_two_end; 41} 42 43 44// Converts time in minutes to hours if possible, if minutes also exists - shows minutes too 45function latepoint_minutes_to_hours_preferably(time) { 46 var army_clock = latepoint_is_army_clock(); 47 48 var hours = Math.floor(time / 60); 49 if (!army_clock && hours > 12) hours = hours - 12; 50 51 var minutes = time % 60; 52 if (minutes > 0) hours = hours + ':' + minutes; 53 return hours; 54} 55 56 57function latepoint_minutes_to_hours(time) { 58 var army_clock = latepoint_is_army_clock(); 59 60 var hours = Math.floor(time / 60); 61 if (!army_clock && hours > 12) hours = hours - 12; 62 return hours; 63} 64 65 66function latepoint_am_or_pm(minutes) { 67 if (latepoint_is_army_clock()) return ''; 68 return (minutes < 720 || minutes == 1440) ? 'am' : 'pm'; 69} 70 71function latepoint_hours_and_minutes_to_minutes(hours_and_minutes, ampm) { 72 var hours_and_minutes_arr = hours_and_minutes.split(':'); 73 var hours = hours_and_minutes_arr[0]; 74 var minutes = hours_and_minutes_arr[1]; 75 if (ampm == "pm" && hours < 12) hours = parseInt(hours) + 12; 76 if (ampm == "am" && hours == 12) hours = 0; 77 minutes = parseInt(minutes) + (hours * 60); 78 return minutes; 79} 80 81function latepoint_get_time_system() { 82 return latepoint_helper.time_system; 83} 84 85function latepoint_is_army_clock() { 86 return (latepoint_get_time_system() == '24'); 87} 88 89function latepoint_minutes_to_hours_and_minutes(minutes) { 90 var army_clock = latepoint_is_army_clock(); 91 var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '%02d:%02d'; 92 93 var hours = Math.floor(minutes / 60); 94 if (!army_clock && (hours > 12)) hours = hours - 12; 95 if (!army_clock && hours == 0) hours = 12; 96 minutes = minutes % 60; 97 return sprintf(format, hours, minutes); 98} 99 100 101function latepoint_timestamped_ajaxurl(){ 102 let url = latepoint_helper.ajaxurl; 103 let timestamp = Date.now(); 104 105 // Check if the URL already has GET parameters 106 if (url.includes('?')) { 107 return `${url}&t=${timestamp}`; 108 } else { 109 return `${url}?t=${timestamp}`; 110 } 111} 112 113function latepoint_random_generator() { 114 var S4 = function () { 115 return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); 116 }; 117 return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); 118} 119 120function latepoint_validate_form($form) { 121 let errors = []; 122 $form.find('select[data-os-validate], input[data-os-validate], textarea[data-os-validate]').each(function () { 123 let validations = jQuery(this).data('os-validate').split(' '); 124 let $input = jQuery(this); 125 let label = $input.closest('.os-form-group').find('label').text(); 126 let field_has_errors = false;
127 if (validations) { 128 for (let i = 0; i < validations.length; i++) { 129 switch (validations[i]) { 130 case 'presence': 131 if($input.is(':checkbox')){ 132 if (!$input.is(':checked')) { 133 errors.push({message: label + ' ' + latepoint_helper.msg_validation_presence_checkbox}); 134 field_has_errors = true; 135 } 136 }else{ 137 if (!$input.val()) { 138 errors.push({message: label + ' ' + latepoint_helper.msg_validation_presence}); 139 field_has_errors = true; 140 } 141 } 142 break; 143 case 'phone': 144 if (!window.intlTelInputGlobals.getInstance($input[0]).isValidNumber()) { 145 errors.push({message: label + ' ' + latepoint_helper.msg_validation_invalid}); 146 field_has_errors = true; 147 } 148 break; 149 } 150 } 151 } 152 if (field_has_errors) { 153 $input.closest('.os-form-group').addClass('os-invalid'); 154 } else { 155 $input.closest('.os-form-group').removeClass('os-invalid'); 156 } 157 }); 158 return errors; 159} 160 161function latepoint_create_form_data_from_non_form_element($elem) { 162 let formData = new FormData(); 163 // create objecte from all input fields that are inside of the element 164 let fields = $elem.find('select, input, textarea').serializeArray(); 165 if (fields) { 166 fields.forEach(field => formData.append(field.name, field.value)); 167 } 168 return formData; 169} 170 171function latepoint_create_form_data($form, route_name = false, extra_params = false) { 172 let form_data = new FormData(); 173 let params = new FormData($form[0]); 174 175 if (extra_params) { 176 Object.keys(extra_params).forEach(key => { 177 params.set(key, extra_params[key]); 178 }); 179 } 180 181 // get values from phone number fields 182 if (('intlTelInputGlobals' in window) && ('intlTelInputUtils' in window)) { 183 $form.find('input.os-mask-phone').each(function () { 184 const phoneInputName = this.getAttribute('name'); 185 const phoneInputValue = window.intlTelInputGlobals.getInstance(this).getNumber(window.intlTelInputUtils.numberFormat.E164); 186 // override value generated automatically by formdata with a formatted value of a phone field with country code 187 params.set(phoneInputName, phoneInputValue); 188 }); 189 } 190 191 form_data.append('params', latepoint_formdata_to_url_encoded_string(params)); 192 form_data.append('action', latepoint_helper.route_action); 193 form_data.append('route_name', route_name ? route_name : $form.data('route-name')); 194 form_data.append('layout', 'none'); 195 form_data.append('return_format', 'json'); 196 197 let file_data; 198 // put file data into main form_data object, since we can't send them in "params" string 199 $form.find('input[type="file"]').each(function () { 200 file_data = this.files; // get multiple files from input file 201 let file_name = this.getAttribute("name"); 202 for (let i = 0; i < file_data.length; i++) { 203 form_data.append(file_name + '[]', file_data[i]); 204 } 205 }); 206 return form_data; 207} 208 209function latepoint_mask_timefield($elem) { 210 if (jQuery().inputmask) { 211 $elem.inputmask({ 212 'mask': '99:99', 213 'placeholder': 'HH:MM' 214 }); 215 } 216} 217 218function latepoint_formdata_to_url_encoded_string(form_data) { 219 let filtered_form_data = new FormData(); 220 // remove file fields from params, so we can serialize it into string, 221 // !important, this will not include file fields into the form_data, so you have to include them manually, see latepoint_create_form_data() that does it 222 // note: we don't use form_data.remove(key) on original object because we might want to preserve it 223 for (const [key, value] of form_data) { 224 if (value instanceof File) continue; 225 if (key.slice(-2) === '[]') { 226 // expecting array, append 227 filtered_form_data.append(key, value); 228 } else { 229 filtered_form_data.set(key, value); 230 } 231 } 232 return new URLSearchParams(filtered_form_data).toString(); 233} 234 235function latepoint_mask_percent($elem) { 236 if (jQuery().inputmask) { 237 $elem.inputmask({ 238 'alias': 'decimal', 239 'radixPoint': latepoint_helper.decimal_separator, 240 'digits': 4, 241 'digitsOptional': false, 242 'suffix': '%', 243 'placeholder': '0', 244 'rightAlign': false 245 }); 246 } 247} 248 249function latepoint_mask_minutes($elem) { 250 if (jQuery().inputmask) { 251 $elem.inputmask({ 252 'removeMaskOnSubmit': true, 253 'alias': 'numeric', 254 'digits': 0, 255 'suffix': latepoint_helper.msg_minutes_suffix, 256 'placeholder': '0', 257 'rightAlign': false 258 }); 259 } 260} 261 262 263function latepoint_mask_money($elem) { 264 if (jQuery().inputmask) { 265 $elem.inputmask({ 266 'alias': 'currency', 267 'groupSeparator': latepoint_helper.thousand_separator, 268 'radixPoint': latepoint_helper.decimal_separator, 269 'digits': latepoint_helper.number_of_decimals, 270 'digitsOptional': false, 271 'prefix': latepoint_helper.currency_symbol_before ? latepoint_helper.currency_symbol_before + ' ' : '', 272 'suffix': latepoint_helper.currency_symbol_after ? ' ' + latepoint_helper.currency_symbol_after : '', 273 'placeholder': '0', 274 'rightAlign': false 275 }); 276 } 277} 278 279function latepoint_mask_date($elem) { 280 if (jQuery().inputmask) { 281 $elem.inputmask({ 282 'alias': 'datetime', 283 'inputFormat': latepoint_helper.date_format_for_js 284 }); 285 } 286} 287 288function latepoint_init_phone_masking_from_placeholder($input) { 289 if (!latepoint_helper.mask_phone_number_fields) return; 290 let format = $input.attr('placeholder'); 291 if (format && jQuery().inputmask) { 292 $input.inputmask(format.replace(/[0-9]/g, 9)); 293 } 294} 295 296function latepoint_mask_phone($elem) { 297 let jsElem = $elem[0]; 298 299 // First priority is to prevent duplicates (common in non-document.body contexts) 300 if (jsElem && !window.intlTelInputGlobals.getInstance(jsElem)) { 301 let dropdownContainer = document.body; 302 303 let onlyCountries = JSON.parse(latepoint_helper.included_phone_countries); 304 // Remedy a quirk with json_encode(EMPTY_ARRAY) 305 if (onlyCountries.length === 1 && onlyCountries[0] === "") { 306 onlyCountries = []; 307 } 308 const preferredCountries = onlyCountries.length ? [] : window.intlTelInputGlobals.defaults.preferredCountries; 309 310 // remove country name in english and only use names in country language 311 var countryData = window.intlTelInputGlobals.getCountryData(); 312 313 for (var i = 0; i < countryData.length; i++) { 314 var country = countryData[i]; 315 country.name = country.name.replace(/ *\([^)]*\) */g, ""); 316 } 317 318 let defaultCountryCode = latepoint_helper.default_phone_country; 319 if (onlyCountries.length && !onlyCountries.includes(defaultCountryCode)) { 320 defaultCountryCode = onlyCountries[0]; 321 } 322 323 324 let iti = window.intlTelInput(jsElem, { 325 dropdownContainer: dropdownContainer, 326 formatOnDisplay: true, 327 nationalMode: true, 328 autoPlaceholder: 'aggressive', 329 initialCountry: defaultCountryCode, 330 geoIpLookup: function (callback) { 331 const cookieName = 'latepoint_phone_country'; 332 333 if (latepoint_has_cookie(cookieName)) { 334 callback(latepoint_get_cookie(cookieName)); 335 } else { 336 jQuery.get('https://ipinfo.io', function () { 337 }, 'jsonp').always(function (response) { 338 // Sensible default 339 let countryCode = defaultCountryCode; 340 341 if (response && response.country) { 342 countryCode = response.country.toLowerCase(); 343 latepoint_set_cookie(cookieName, countryCode); 344 } 345 callback(countryCode); 346 }) 347 } 348 }, 349 allowDropdown: onlyCountries.length != 1, 350 onlyCountries: onlyCountries, 351 preferredCountries: preferredCountries, 352 separateDialCode: latepoint_helper.is_enabled_show_dial_code_with_flag 353 }); 354 355 iti.promise.then(function () { 356 latepoint_init_phone_masking_from_placeholder($elem); 357 }); 358 359 360 $elem.on("countrychange", function (event) { 361 latepoint_init_phone_masking_from_placeholder(jQuery(this)); 362 }); 363 } 364} 365 366function latepoint_show_booking_end_time() { 367 return (latepoint_helper.show_booking_end_time == 'yes'); 368} 369 370function latepoint_set_cookie(name, value, days) { 371 let date = new Date; 372 date.setTime(date.getTime() + 24 * 60 * 60 * 1000 * days); 373 document.cookie = name + "=" + value + ";path=/;expires=" + date.toGMTString(); 374} 375 376function latepoint_get_cookie(name) { 377 let cookie = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); 378 return cookie ? cookie[2] : null; 379} 380 381function latepoint_has_cookie(name) { 382 return latepoint_get_cookie(name) !== null; 383} 384 385function latepoint_delete_cookie(name) { 386 latepoint_set_cookie(name, '', -1); 387} 388 389function latepoint_add_notification(message, message_type = 'success'){ 390 var wrapper = jQuery('body').find('.os-notifications'); 391 if(!wrapper.length){ 392 jQuery('body').append('<div class="os-notifications"></div>'); 393 wrapper = jQuery('body').find('.os-notifications'); 394 } 395 if(wrapper.find('.item').length > 0) wrapper.find('.item:first-child').remove(); 396 wrapper.append('<div class="item item-type-'+ message_type +'">' + message + '<span class="os-notification-close"><i class="latepoint-icon latepoint-icon-x"></i></span></div>'); 397} 398 399function latepoint_add_lightbox_notification(message, message_type = 'success'){ 400 var wrapper = jQuery('.latepoint-lightbox-content').find('.os-notifications'); 401 if(!wrapper.length){ 402 jQuery('.latepoint-lightbox-content').prepend('<div class="os-notifications"></div>'); 403 wrapper = jQuery('.latepoint-lightbox-content').find('.os-notifications'); 404 } 405 if(wrapper.find('.item').length > 0) wrapper.find('.item:first-child').remove(); 406 wrapper.append('<div class="item item-type-'+ message_type +'">' + message + '<span class="os-notification-close"><i class="latepoint-icon latepoint-icon-x"></i></span></div>'); 407} 408 409function latepoint_generate_form_message_html(messages, status){ 410 var message_html = '<div class="os-form-message-w status-' + status + '"><ul>'; 411 if(Array.isArray(messages)){
412 messages.forEach(function(message){ 413 message_html+= '<li>' + message + '</li>'; 414 }); 415 }else{ 416 message_html+= '<li>' + messages + '</li>'; 417 } 418 message_html+= '</ul></div>'; 419 return message_html; 420} 421 422function latepoint_display_in_side_sub_panel(html){ 423 if(!jQuery('.latepoint-side-panel-w').length) latepoint_show_data_in_side_panel(''); 424 jQuery('.latepoint-side-panel-w .latepoint-side-panels .side-sub-panel-wrapper').remove(); 425 jQuery('.latepoint-side-panel-w .latepoint-side-panels').append(html); 426} 427 428function latepoint_clear_form_messages($form){ 429 $form.find('.os-form-message-w').remove(); 430} 431 432function latepoint_show_data_in_side_panel(message, extra_classes = '', close_btn = true){ 433 jQuery('.latepoint-side-panel-w').remove(); 434 jQuery('body').append('<div class="latepoint-side-panel-w ' + extra_classes + ' os-loading"><div class="latepoint-side-panel-shadow"></div><div class="latepoint-side-panels"><div class="latepoint-side-panel-i"></div></div></div>'); 435 jQuery('.latepoint-side-panel-i').html(message); 436 if(close_btn){ 437 jQuery('.latepoint-side-panel-i').find('.os-form-header .latepoint-side-panel-close').remove(); 438 jQuery('.latepoint-side-panel-i').find('.os-form-header').append('<a href="#" class="latepoint-side-panel-close latepoint-side-panel-close-trigger"><i class="latepoint-icon latepoint-icon-x"></i></a>'); 439 } 440 setTimeout(function(){ 441 jQuery('.latepoint-side-panel-w').removeClass('os-loading'); 442 }, 100); 443} 444 445function latepoint_show_data_in_lightbox(message, extra_classes = '', close_btn = true, tag = 'div', inner_extra_classes = '', inner_tag = 'div'){ 446 jQuery('.latepoint-lightbox-w').remove(); 447 let lightbox_css_classes = 'latepoint-lightbox-w latepoint-w latepoint-border-radius-' + latepoint_helper.style_border_radius+ ' '; 448 if(extra_classes) lightbox_css_classes+= extra_classes; 449 let lightbox_css_inner_classes = 'latepoint-lightbox-i '; 450 if(inner_extra_classes) lightbox_css_inner_classes += inner_extra_classes; 451 452 let close_btn_html = close_btn ? '<a href="#" class="latepoint-lightbox-close" tabindex="0"><i class="latepoint-icon latepoint-icon-x"></i></a>' : ''; 453 jQuery('body').append('<'+tag+' class="'+ lightbox_css_classes +'"><'+inner_tag+' class="'+ lightbox_css_inner_classes +'">' + message + close_btn_html + '</'+inner_tag+'><div class="latepoint-lightbox-shadow"></div></'+tag+'>'); 454 455 jQuery('body').addClass('latepoint-lightbox-active'); 456} 457 458 459 460// DOCUMENT READY 461jQuery(function( $ ) { 462 463 if($('.latepoint').find('[data-os-action-onload]').length){ 464 $('.latepoint').find('[data-os-action-onload]').each(function(){ 465 var $this = jQuery(this); 466 $this.addClass('os-loading'); 467 var params = $this.data('os-params'); 468 var return_format = $this.data('os-return-format') ? $this.data('os-return-format') : 'json' 469 var data = { action: 'latepoint_route_call', route_name: $this.data('os-action-onload'), params: params, return_format: return_format } 470 jQuery.ajax({ 471 type : "post", 472 dataType : "json", 473 url : latepoint_timestamped_ajaxurl(), 474 data : data, 475 success: function(response) { 476 $this.removeClass('os-loading'); 477 if (response.status === "success") { 478 if($this.data('os-output-target') == 'self'){ 479 $this.html(response.message); 480 } 481 } 482 } 483 }); 484 }); 485 } 486 487 /* 488 Ajax buttons action 489 */ 490 $('.latepoint').on('click', 'button[data-os-action], a[data-os-action], div[data-os-action], span[data-os-action], tr[data-os-action]', function(e){ 491 var $this = jQuery(this); 492 if($this.data('os-prompt') && !confirm($this.data('os-prompt'))) return false; 493 var params = $this.data('os-params'); 494 if($this.data('os-source-of-params')){ 495 var form_data = latepoint_create_form_data_from_non_form_element($($this.data('os-source-of-params'))); 496 params = latepoint_formdata_to_url_encoded_string(form_data); 497 } 498 var return_format = $this.data('os-return-format') ? $this.data('os-return-format') : 'json' 499 var data = { action: 'latepoint_route_call', route_name: $this.data('os-action'), params: params, return_format: return_format } 500 $this.addClass('os-loading'); 501 if($this.data('os-output-target') == 'side-panel'){ 502 $('.latepoint-side-panel-w').remove();
503 let css_classes = $this.data('os-lightbox-classes') ? $this.data('os-lightbox-classes') : ''; 504 $('body').append('<div class="latepoint-side-panel-w ' + css_classes + ' os-loading"><div class="latepoint-side-panel-shadow"></div><div class="latepoint-side-panels"><div class="latepoint-side-panel-i"></div></div></div>'); 505 } 506 $.ajax({ 507 type : "post", 508 dataType : "json", 509 url : latepoint_timestamped_ajaxurl(), 510 data : data, 511 success: function(response){ 512 if(response.status === "success"){ 513 if($this.data('os-output-target') == 'lightbox'){ 514 latepoint_show_data_in_lightbox(response.message, $this.data('os-lightbox-classes'), ($this.data('os-lightbox-no-close-button') !== 'yes'), $this.data('os-lightbox-tag'), $this.data('os-lightbox-inner-classes'), $this.data('os-lightbox-inner-tag')); 515 }else if($this.data('os-output-target') == 'side-panel'){ 516 $('.latepoint-side-panel-i').html(response.message); 517 jQuery('.latepoint-side-panel-i').find('.os-form-header .latepoint-side-panel-close').remove(); 518 jQuery('.latepoint-side-panel-i').find('.os-form-header').append('<a href="#" class="latepoint-side-panel-close latepoint-side-panel-close-trigger"><i class="latepoint-icon latepoint-icon-x"></i></a>'); 519 setTimeout(function(){ 520 $('.latepoint-side-panel-w').removeClass('os-loading'); 521 }, 100); 522 }else if($this.data('os-success-action') == 'reload'){ 523 latepoint_add_notification(response.message); 524 location.reload(); 525 return; 526 }else if($this.data('os-success-action') == 'redirect'){ 527 if($this.data('os-redirect-to')){ 528 latepoint_add_notification(response.message); 529 window.location.replace($this.data('os-redirect-to')); 530 }else{ 531 window.location.replace(response.message); 532 } 533 return; 534 }else if($this.data('os-output-target') && $($this.data('os-output-target')).length){ 535 if($this.data('os-output-target-do') == 'append') { 536 $($this.data('os-output-target')).append(response.message); 537 }else if($this.data('os-output-target-do') == 'prepend'){ 538 $($this.data('os-output-target')).prepend(response.message); 539 }else{ 540 $($this.data('os-output-target')).html(response.message); 541 } 542 }else{ 543 switch($this.data('os-before-after')){ 544 case 'before': 545 $this.before(response.message); 546 break; 547 case 'after': 548 $this.after(response.message); 549 break; 550 case 'replace': 551 $this.replaceWith(response.message); 552 break; 553 case 'none': 554 break; 555 default: 556 latepoint_add_notification(response.message); 557 } 558 } 559 if($this.data('os-after-call')){ 560 var func_name = $this.data('os-after-call'); 561 var callback = false; 562 if(func_name.includes('.')){ 563 var func_arr = func_name.split('.'); 564 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){ 565 console.log(func_name + ' is undefined'); 566 } 567 if($this.data('os-pass-this') && $this.data('os-pass-response')){ 568 window[func_arr[0]][func_arr[1]]($this, response); 569 }else if($this.data('os-pass-this')){ 570 window[func_arr[0]][func_arr[1]]($this); 571 }else if($this.data('os-pass-response')){ 572 window[func_arr[0]][func_arr[1]](response); 573 }else{ 574 window[func_arr[0]][func_arr[1]](); 575 } 576 }else{ 577 if(typeof window[func_name] !== 'function'){ 578 console.log(func_name + ' is undefined'); 579 } 580 if($this.data('os-pass-this') && $this.data('os-pass-response')){ 581 window[func_name]($this, response); 582 }else if($this.data('os-pass-this')){ 583 window[func_name]($this); 584 }else if($this.data('os-pass-response')){ 585 window[func_name](response); 586 }else{ 587 window[func_name](); 588 } 589 } 590 } 591 $this.removeClass('os-loading'); 592 }else{ 593 $this.removeClass('os-loading'); 594 if($this.data('os-output-target') && $($this.data('os-output-target')).length){ 595 $($this.data('os-output-target')).prepend(latepoint_generate_form_message_html(response.message, 'error')); 596 }else{ 597 alert(response.message); 598 } 599 if($this.data('os-after-call-error')){ 600 var func_name = $this.data('os-after-call-error'); 601 var callback = false;
602 if(func_name.includes('.')){ 603 var func_arr = func_name.split('.'); 604 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){ 605 console.log(func_name + ' is undefined'); 606 } 607 if($this.data('os-pass-this') && $this.data('os-pass-response')){ 608 window[func_arr[0]][func_arr[1]]($this, response); 609 }else if($this.data('os-pass-this')){ 610 window[func_arr[0]][func_arr[1]]($this); 611 }else if($this.data('os-pass-response')){ 612 window[func_arr[0]][func_arr[1]](response); 613 }else{ 614 window[func_arr[0]][func_arr[1]](); 615 } 616 }else{ 617 if(typeof window[func_name] !== 'function'){ 618 console.log(func_name + ' is undefined'); 619 } 620 if($this.data('os-pass-this') && $this.data('os-pass-response')){ 621 window[func_name]($this, response); 622 }else if($this.data('os-pass-this')){ 623 window[func_name]($this); 624 }else if($this.data('os-pass-response')){ 625 window[func_name](response); 626 }else{ 627 window[func_name](); 628 } 629 } 630 } 631 } 632 } 633 }); 634 return false; 635 }); 636 637 638 $('.latepoint').on('click', 'form[data-os-action] button[type="submit"]', function(e){ 639 $(this).addClass('os-loading'); 640 }); 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 /* 659 Form ajax submit action 660 */ 661 $('.latepoint').on('submit', 'form[data-os-action]', function(e){ 662 e.preventDefault(); // prevent native submit 663 var $form = $(this); 664 var form_data = new FormData($form[0]); 665 666 if (('intlTelInputGlobals' in window) && ('intlTelInputUtils' in window)) { 667 // Get e164 formatted number from phone fields when form is submitted 668 $form.find('input.os-mask-phone').each(function () { 669 let telInstance = window.intlTelInputGlobals.getInstance(this); 670 if(telInstance){ 671 const phoneInputName = this.getAttribute('name'); 672 const phoneInputValue = window.intlTelInputGlobals.getInstance(this).getNumber(window.intlTelInputUtils.numberFormat.E164); 673 form_data.set(phoneInputName, phoneInputValue); 674 } 675 }); 676 } 677 678 var data = { action: 'latepoint_route_call', route_name: $(this).data('os-action'), params: latepoint_formdata_to_url_encoded_string(form_data), return_format: 'json' } 679 $form.find('button[type="submit"]').addClass('os-loading'); 680 $.ajax({ 681 type : "post", 682 dataType : "json", 683 url : latepoint_timestamped_ajaxurl(), 684 data : data, 685 success: function(response){ 686 $form.find('button[type="submit"].os-loading').removeClass('os-loading'); 687 latepoint_clear_form_messages($form); 688 if(response.status === "success"){ 689 if($form.data('os-success-action') == 'reload'){ 690 latepoint_add_notification(response.message); 691 location.reload(); 692 return; 693 }else if($form.data('os-success-action') == 'redirect'){ 694 if($form.data('os-redirect-to')){ 695 latepoint_add_notification(response.message); 696 window.location.replace($form.data('os-redirect-to')); 697 }else{ 698 window.location.replace(response.message); 699 } 700 return; 701 }else if($form.data('os-output-target') && $($form.data('os-output-target')).length){ 702 $($form.data('os-output-target')).html(response.message); 703 }else{ 704 if(response.message == 'redirect'){ 705 window.location.replace(response.url); 706 }else{ 707 latepoint_add_notification(response.message); 708 $form.prepend(latepoint_generate_form_message_html(response.message, 'success')); 709 } 710 } 711 if($form.data('os-record-id-holder') && response.record_id){ 712 $form.find('[name="' + $form.data('os-record-id-holder') + '"]').val(response.record_id) 713 } 714 if($form.data('os-after-call')){ 715 716 var func_name = $form.data('os-after-call'); 717 var callback = false;
718 if(func_name.includes('.')){ 719 var func_arr = func_name.split('.'); 720 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){ 721 console.log(func_name + ' is undefined'); 722 } 723 if($form.data('os-pass-this') && $form.data('os-pass-response')){ 724 window[func_arr[0]][func_arr[1]]($form, response); 725 }else if($form.data('os-pass-this')){ 726 window[func_arr[0]][func_arr[1]]($form); 727 }else if($form.data('os-pass-response')){ 728 window[func_arr[0]][func_arr[1]](response); 729 }else{ 730 window[func_arr[0]][func_arr[1]](); 731 } 732 }else{ 733 if(typeof window[func_name] !== 'function'){ 734 console.log(func_name + ' is undefined'); 735 } 736 if($form.data('os-pass-this') && $form.data('os-pass-response')){ 737 window[func_name]($form, response); 738 }else if($form.data('os-pass-this')){ 739 window[func_name]($form); 740 }else if($form.data('os-pass-response')){ 741 window[func_name](response); 742 }else{ 743 window[func_name](); 744 } 745 } 746 } 747 $('button.os-loading').removeClass('os-loading'); 748 }else{ 749 $('button.os-loading').removeClass('os-loading'); 750 if($form.data('os-show-errors-as-notification')){ 751 latepoint_add_notification(response.message, 'error'); 752 }else{ 753 $form.prepend(latepoint_generate_form_message_html(response.message, 'error')); 754 $([document.documentElement, document.body]).animate({ 755 scrollTop: ($form.find(".os-form-message-w").offset().top - 30) 756 }, 200); 757 } 758 } 759 if(response.form_values_to_update){ 760 $.each(response.form_values_to_update, function(name, value){ 761 $form.find('[name="'+ name +'"]').val(value); 762 }); 763 } 764 } 765 }); 766 return false; 767 }); 768}); 769 770/* 771 * Copyright (c) 2022 LatePoint LLC. All rights reserved. 772 */ 773 774 775function latepoint_init_order_summary_lightbox() { 776 777} 778 779function latepoint_init_bundle_scheduling_summary() { 780 781} 782 783 784function latepoint_manage_by_key_reload_booking() { 785 let $wrapper = jQuery('.manage-booking-wrapper'); 786 $wrapper.addClass('os-loading') 787 let params = { 788 key: $wrapper.data('key') 789 } 790 let data = { 791 action: latepoint_helper.route_action, 792 route_name: $wrapper.data('route-name'), 793 params: params, 794 layout: 'none', 795 return_format: 'json' 796 }; 797 798 jQuery.ajax({ 799 type: "post", 800 dataType: "json", 801 url: latepoint_timestamped_ajaxurl(), 802 data: data, 803 success: function (data) { 804 $wrapper.removeClass('os-loading') 805 if (data.status === "success") { 806 $wrapper.replaceWith(data.message); 807 } else { 808 latepoint_show_message_inside_element(data.message, $wrapper, 'error'); 809 } 810 } 811 }); 812} 813 814function latepoint_init_manage_booking_by_key() { 815 let $wrapper = jQuery('.manage-booking-wrapper'); 816 if (!$wrapper.length) return; 817 jQuery('.latepoint-w').on('change', '.change-booking-status-trigger', function () { 818 $wrapper.addClass('os-loading') 819 let params = { 820 key: $wrapper.data('key'), 821 status: jQuery(this).val() 822 } 823 let data = { 824 action: latepoint_helper.route_action, 825 route_name: jQuery(this).closest('.change-booking-status-trigger-wrapper').data('route-name'), 826 params: params, 827 layout: 'none', 828 return_format: 'json' 829 }; 830 831 jQuery.ajax({ 832 type: "post", 833 dataType: "json", 834 url: latepoint_timestamped_ajaxurl(), 835 data: data, 836 success: function (data) { 837 $wrapper.removeClass('os-loading') 838 if (data.status === "success") { 839 latepoint_manage_by_key_reload_booking(); 840 } else {
841 latepoint_show_message_inside_element(data.message, $wrapper, 'error'); 842 } 843 } 844 }); 845 return false; 846 }); 847 848 849 $wrapper.on('click', '.qr-show-trigger', function () { 850 jQuery(this).closest('.manage-booking-wrapper').find('.qr-code-on-full-summary').addClass('show-vevent-qr-code'); 851 return false; 852 }); 853 $wrapper.on('click', '.os-item-details-popup-close', function () { 854 var $wrapper = jQuery(this).closest('.manage-booking-wrapper'); 855 $wrapper.find('.os-item-details-popup.open').remove(); 856 $wrapper.find('.manage-booking-inner, .manage-booking-controls').show(); 857 return false; 858 }); 859 860 $wrapper.on('click', '.os-trigger-item-details-popup', function () { 861 var $wrapper = jQuery(this).closest('.manage-booking-wrapper'); 862 $wrapper.find('.manage-booking-inner, .manage-booking-controls').hide(); 863 $wrapper.find('.os-item-details-popup.open').remove(); 864 var $popup = $wrapper.find('#' + jQuery(this).data('item-details-popup-id')).clone(); 865 $popup.addClass('open').appendTo($wrapper); 866 return false; 867 }); 868} 869 870function latepoint_init_form_masks() { 871 if (('intlTelInput' in window) && ('intlTelInputGlobals' in window)) { 872 jQuery('.os-mask-phone').each(function () { 873 latepoint_mask_phone(jQuery(this)); 874 }); 875 } 876} 877 878function latepoint_scroll_to_top_of_booking_form($booking_form_element) { 879 // if it's a form shortcode (not lightbox), scroll to top of the form 880 if ($booking_form_element.parent().hasClass('latepoint-inline-form')) { 881 $booking_form_element[0].scrollIntoView({block: "nearest", behavior: 'smooth'}); // SHOULD NOT BE FIRST!! Also need to FIX, scroll only if TOP of the booking form is above the viewport 882 } 883 // if lightbox - scroll body of lightbox to top 884 if ($booking_form_element.parent().hasClass('latepoint-lightbox-i')) { 885 $booking_form_element.find('.latepoint-body').scrollTop(0); 886 } 887} 888 889async function latepoint_init_payment_method_actions($booking_form_element, payment_method) {
890 let callbacks_list = []; 891 let is_last_step = $booking_form_element.data('next-submit-is-last') == 'yes'; 892 $booking_form_element.trigger('latepoint:initPaymentMethod', [{ 893 payment_method: payment_method, 894 callbacks_list: callbacks_list, 895 is_last_step: is_last_step 896 }]); 897 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading'); 898 899 900 try { 901 for (const callback of callbacks_list) { 902 await callback.action(); 903 } 904 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded').find('.lp-payment-method-content[data-payment-method="' + payment_method + '"]').show(); 905 } catch (error) { 906 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element); 907 } 908} 909 910function latepoint_lightbox_close() { 911 jQuery('body').removeClass('latepoint-lightbox-active'); 912 jQuery('.latepoint-lightbox-w').remove(); 913} 914 915function latepoint_show_next_btn($booking_form_element) { 916 $booking_form_element.find('.latepoint-next-btn').removeClass('disabled'); 917 $booking_form_element.removeClass('hidden-buttons'); 918} 919 920function clear_step_services($booking_form_element) { 921} 922 923function clear_step_service_extras($booking_form_element) { 924} 925 926function clear_step_locations($booking_form_element) { 927} 928 929function clear_step_agents($booking_form_element) { 930} 931 932function clear_step_datepicker($booking_form_element) { 933} 934 935function latepoint_hide_next_btn($booking_form_element) { 936 $booking_form_element.find('.latepoint-next-btn').addClass('disabled'); 937 if ($booking_form_element.find('.latepoint-prev-btn.disabled').length) $booking_form_element.addClass('hidden-buttons'); 938} 939 940 941function latepoint_show_prev_btn($booking_form_element) { 942 $booking_form_element.find('.latepoint-prev-btn').removeClass('disabled'); 943 $booking_form_element.removeClass('hidden-buttons'); 944} 945 946function latepoint_hide_prev_btn($booking_form_element) { 947 $booking_form_element.find('.latepoint-prev-btn').addClass('disabled'); 948 if ($booking_form_element.find('.latepoint-next-btn.disabled').length) $booking_form_element.addClass('hidden-buttons'); 949} 950 951 952function latepoint_remove_cart_item($trigger) { 953 let $booking_form_element = $trigger.closest('.latepoint-booking-form-element'); 954 let cart_item_id = $trigger.data('cart-item-id'); 955 956 957 $trigger.addClass('os-loading'); 958 let data = { 959 action: latepoint_helper.route_action, 960 route_name: $trigger.data('route'), 961 params: jQuery.param({cart_item_id: cart_item_id}), 962 layout: 'none', 963 return_format: 'json' 964 } 965 jQuery.ajax({ 966 type: "post", 967 dataType: "json", 968 url: latepoint_timestamped_ajaxurl(), 969 data: data, 970 success: function (data) { 971 if (data.status === "success") { 972 if(cart_item_id != $booking_form_element.find('input[name="active_cart_item[id]"]').val()){ 973 // cart has other items - just reload the summary/step 974 if ($trigger.closest('.latepoint-summary-w').length) { 975 // removed by clicking on summary side panel 976 latepoint_reload_summary($booking_form_element); 977 } else { 978 // remove by clicking on cart item on verify step 979 latepoint_reload_step($booking_form_element); 980 } 981 }else{ 982 // this was a last item, need to go back to the start of a booking process 983 latepoint_restart_booking_process($booking_form_element); 984 } 985 } else { 986 $trigger.removeClass('os-loading'); 987 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error'); 988 } 989 } 990 }); 991} 992 993function latepoint_apply_coupon($elem) { 994 var $booking_form_element = $elem.closest('.latepoint-booking-form-element'); 995 996 var $coupon_input = $elem; 997 $coupon_input.closest('.coupon-code-input-w').addClass('os-loading'); 998 var form_data = new FormData($booking_form_element.find('.latepoint-form')[0]); 999 var data = { 1000 action: latepoint_helper.route_action, 1001 route_name: $elem.data('route'), 1002 params: latepoint_formdata_to_url_encoded_string(form_data), 1003 layout: 'none', 1004 return_format: 'json' 1005 } 1006 jQuery.ajax({ 1007 type: "post", 1008 dataType: "json", 1009 url: latepoint_timestamped_ajaxurl(), 1010 data: data, 1011 success: function (data) { 1012 $coupon_input.closest('.coupon-code-input-w').removeClass('os-loading'); 1013 if (data.status === "success") {
1014 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'success'); 1015 $booking_form_element.find('.step-payment-w input[name="cart[payment_method]"]').val(''); 1016 $booking_form_element.find('input[name="cart[payment_token]"]').val(''); 1017 $booking_form_element.find('input[name="cart[payment_portion]"]').val(''); 1018 latepoint_reload_step($booking_form_element); 1019 } else { 1020 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error'); 1021 } 1022 } 1023 }); 1024} 1025 1026function latepoint_remove_coupon($elem) { 1027 $elem.closest('.applied-coupon-code-wrapper').fadeOut(); 1028 var $booking_form_element = $elem.closest('.latepoint-booking-form-element'); 1029 let $coupon_input = $booking_form_element.find('input[name="coupon_code"]'); 1030 $coupon_input.val(''); 1031 latepoint_apply_coupon($coupon_input); 1032} 1033 1034function latepoint_restart_booking_process($booking_form_element) { 1035 // first first step 1036 let first_step_code = $booking_form_element.find('.latepoint-step-content').first().data('step-code'); 1037 latepoint_reload_step($booking_form_element, first_step_code); 1038 return false; 1039} 1040 1041function latepoint_reload_step($booking_form_element, step_code = false) { 1042 1043 if (step_code) { 1044 $booking_form_element.find('.latepoint_current_step_code').val(step_code); 1045 $booking_form_element.removeClass(function (index, className) { 1046 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' '); 1047 }).addClass('current-step-' + step_code); 1048 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]')) { 1049 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').nextAll('.latepoint-step-content').remove(); 1050 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').remove(); 1051 } 1052 } 1053 1054 $booking_form_element.find('.latepoint_step_direction').val('specific'); 1055 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form')); 1056 1057 return false; 1058} 1059 1060 1061function latepoint_reset_password_from_booking_init() { 1062 jQuery('.os-step-existing-customer-login-w').hide(); 1063 jQuery('.os-password-reset-form-holder').on('click', '.password-reset-back-to-login', function () { 1064 jQuery('.os-password-reset-form-holder').html(''); 1065 jQuery('.os-step-existing-customer-login-w').show(); 1066 return false; 1067 }); 1068} 1069 1070function latepoint_bundle_selected($item) { 1071 let $booking_form_element = $item.closest('.latepoint-booking-form-element'); 1072 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('bundle'); 1073 $booking_form_element.find('input[name="booking[service_id]"]').val(''); 1074} 1075 1076function latepoint_service_selected($item) { 1077 let $booking_form_element = $item.closest('.latepoint-booking-form-element'); 1078 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('booking'); 1079} 1080 1081async function latepoint_reload_summary($booking_form_element) { 1082 let $summary_panel = $booking_form_element.closest('.latepoint-with-summary'); 1083 if (!$summary_panel.length) return; 1084 1085 let current_step = $booking_form_element.find('.latepoint_current_step_code').val(); 1086 1087 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading'); 1088 let $booking_form = $booking_form_element.find('.latepoint-form'); 1089 let form_data = new FormData($booking_form[0]); 1090 let data = { 1091 action: latepoint_helper.route_action, 1092 route_name: latepoint_helper.reload_booking_form_summary_route, 1093 params: latepoint_formdata_to_url_encoded_string(form_data), 1094 layout: 'none', 1095 return_format: 'json' 1096 } 1097 1098 let response = await jQuery.ajax({ 1099 type: "post", 1100 dataType: "json", 1101 url: latepoint_timestamped_ajaxurl(), 1102 data: data 1103 }); 1104 if(response.status === 'success'){ 1105 $booking_form_element.find('.os-summary-contents').html(response.message); 1106 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading'); 1107 // hide on verify and confirmation steps 1108 if (current_step && !['verify', 'confirmation'].includes(current_step) && response.message) { 1109 $summary_panel.addClass('latepoint-summary-is-open'); 1110 } else { 1111 $summary_panel.removeClass('latepoint-summary-is-open'); 1112 } 1113 latepoint_init_booking_summary_panel($booking_form_element); 1114 }else{ 1115 throw new Error(response.message ? response.message : 'Error reloading summary'); 1116 } 1117} 1118 1119function latepoint_init_booking_summary_panel($booking_form_element) { 1120 let $summary_panel = $booking_form_element.find('.latepoint-summary-w'); 1121 if (!$summary_panel.length) return; 1122 1123 $summary_panel.find('.price-breakdown-unfold').on('click', function () { 1124 jQuery(this).closest('.summary-price-breakdown-wrapper').removeClass('compact-summary'); 1125 return false;
1126 }); 1127 1128 $summary_panel.find('.os-remove-item-from-cart').on('click keydown', function (event) { 1129 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1130 latepoint_remove_cart_item(jQuery(this)); 1131 return false; 1132 }); 1133 1134 $summary_panel.find('.latepoint-lightbox-summary-trigger').on('click', function () { 1135 var $wrapper = jQuery(this).closest('.latepoint-w'); 1136 $wrapper.toggleClass('show-summary-on-mobile'); 1137 return false; 1138 }); 1139} 1140 1141function latepoint_password_changed_show_login(response) { 1142 jQuery('.os-step-existing-customer-login-w').show(); 1143 jQuery('.os-password-reset-form-holder').html(''); 1144 latepoint_show_message_inside_element(response.message, jQuery('.os-step-existing-customer-login-w'), 'success'); 1145} 1146 1147function latepoint_hide_message_inside_element($elem = jQuery('.latepoint-body')) { 1148 if ($elem.length && $elem.find('.latepoint-message').length) { 1149 $elem.find('.latepoint-message').remove(); 1150 } 1151} 1152 1153function latepoint_show_message_inside_element(message, $elem = jQuery('.latepoint-body'), message_type = 'error') { 1154 message = message || 'Error. Please try again.'; 1155 if ($elem.length) { 1156 if ($elem.find('.latepoint-message').length) { 1157 $elem.find('.latepoint-message').removeClass('latepoint-message-success').removeClass('latepoint-message-error').addClass('latepoint-message-' + message_type + '').html(message).show(); 1158 } else { 1159 $elem.prepend('<div class="latepoint-message latepoint-message-' + message_type + '">' + message + '</div>'); 1160 } 1161 // scroll errors into view 1162 if (message_type == 'error') $elem.find('.latepoint-message')[0].scrollIntoView(); 1163 } 1164} 1165 1166function latepoint_add_action(callbacks_list, action, priority = 10) { 1167 callbacks_list.push({priority: priority, action: action}); 1168 callbacks_list.sort((a, b) => a.priority - b.priority); 1169 return callbacks_list; 1170} 1171 1172function latepoint_update_next_btn_label($booking_form_element) { 1173 let btn_label = $booking_form_element.find('.latepoint-step-content').last().data('next-btn-label') 1174 if (btn_label) { 1175 $booking_form_element.find('.latepoint-next-btn span').text(btn_label); 1176 } 1177} 1178 1179function latepoint_init_step(step_code, $booking_form_element) { 1180 latepoint_init_step_selectable_items($booking_form_element); 1181 latepoint_init_step_category_items(step_code); 1182 switch (step_code) { 1183 case 'customer': 1184 latepoint_init_step_contact(); 1185 break; 1186 case 'booking__datepicker': 1187 latepoint_init_step_datepicker($booking_form_element); 1188 break; 1189 case 'booking__agents': 1190 latepoint_init_step_agents(); 1191 break; 1192 case 'booking__locations': 1193 latepoint_init_step_locations(); 1194 break; 1195 case 'booking__services': 1196 latepoint_init_step_services(); 1197 break; 1198 case 'payment__methods': 1199 latepoint_init_step_payment__methods($booking_form_element); 1200 break; 1201 case 'payment__times': 1202 latepoint_init_step_payment__times($booking_form_element); 1203 break; 1204 case 'payment__portions': 1205 latepoint_init_step_payment__portions($booking_form_element); 1206 break; 1207 case 'payment__pay': 1208 latepoint_init_step_payment__pay($booking_form_element); 1209 break; 1210 case 'verify': 1211 latepoint_init_step_verify($booking_form_element); 1212 break; 1213 case 'confirmation': 1214 latepoint_init_step_confirmation($booking_form_element); 1215 break; 1216 } 1217 1218 $booking_form_element.trigger("latepoint:initStep", [{step_code: step_code}]); 1219 $booking_form_element.trigger("latepoint:initStep:" + step_code); 1220} 1221 1222 1223function day_timeslots($day, $wrapper_element = false, $scrollable_wrapper = false) { 1224 if (!$wrapper_element) $wrapper_element = $day.closest('.latepoint-booking-form-element'); 1225 $day.addClass('selected'); 1226 1227 var service_duration = $day.data('service-duration'); 1228 var interval = $day.data('interval'); 1229 var work_start_minutes = $day.data('work-start-time'); 1230 var work_end_minutes = $day.data('work-end-time'); 1231 var total_work_minutes = $day.data('total-work-minutes'); 1232 var bookable_minutes = []; 1233 var available_capacities_of_bookable_minute = []; 1234 if ($day.attr('data-bookable-minutes')) { 1235 if ($day.data('bookable-minutes').toString().indexOf(':') > -1) { 1236 // has capacity information embedded into bookable minutes string 1237 let bookable_minutes_with_capacity = $day.data('bookable-minutes').toString().split(','); 1238 for (let i = 0; i < bookable_minutes_with_capacity.length; i++) { 1239 bookable_minutes.push(parseInt(bookable_minutes_with_capacity[i].split(':')[0])); 1240 available_capacities_of_bookable_minute.push(parseInt(bookable_minutes_with_capacity[i].split(':')[1])); 1241 } 1242 } else { 1243 bookable_minutes = $day.data('bookable-minutes').toString().split(',').map(Number); 1244 } 1245 } 1246 var work_minutes = $day.data('work-minutes').toString().split(',').map(Number); 1247 1248 var $timeslots = $wrapper_element.find('.timeslots'); 1249 $timeslots.html(''); 1250 1251 if (total_work_minutes > 0 && bookable_minutes.length && work_minutes.length) { 1252 var prev_minutes = false;
1253 work_minutes.forEach(function (current_minutes) { 1254 var ampm = latepoint_am_or_pm(current_minutes); 1255 1256 var timeslot_class = 'dp-timepicker-trigger'; 1257 var timeslot_available_capacity = 0; 1258 if (latepoint_helper.time_pick_style == 'timeline') { 1259 timeslot_class += ' dp-timeslot'; 1260 } else { 1261 timeslot_class += ' dp-timebox'; 1262 } 1263 1264 if (prev_minutes !== false && ((current_minutes - prev_minutes) > service_duration)) { 1265 // show interval that is off between two work periods 1266 var off_label = latepoint_minutes_to_hours_and_minutes(prev_minutes + service_duration) + ' ' + latepoint_am_or_pm(prev_minutes + service_duration) + ' - ' + latepoint_minutes_to_hours_and_minutes(current_minutes) + ' ' + latepoint_am_or_pm(current_minutes); 1267 var off_width = (((current_minutes - prev_minutes - service_duration) / total_work_minutes) * 100); 1268 $timeslots.append('<div class="' + timeslot_class + ' is-off" style="max-width:' + off_width + '%; width:' + off_width + '%"><span class="dp-label">' + off_label + '</span></div>'); 1269 } 1270 1271 if (!bookable_minutes.includes(current_minutes)) { 1272 timeslot_class += ' is-booked'; 1273 } else { 1274 if (available_capacities_of_bookable_minute.length) timeslot_available_capacity = available_capacities_of_bookable_minute[bookable_minutes.indexOf(current_minutes)]; 1275 } 1276 var tick_html = ''; 1277 var capacity_label = ''; 1278 var capacity_label_html = ''; 1279 var capacity_internal_label_html = ''; 1280 1281 if (((current_minutes % 60) == 0) || (interval >= 60)) { 1282 timeslot_class += ' with-tick'; 1283 tick_html = '<span class="dp-tick"><strong>' + latepoint_minutes_to_hours_preferably(current_minutes) + '</strong>' + ' ' + ampm + '</span>'; 1284 } 1285 var timeslot_label = latepoint_minutes_to_hours_and_minutes(current_minutes) + ' ' + ampm; 1286 if (latepoint_show_booking_end_time()) { 1287 var end_minutes = current_minutes + service_duration; 1288 if (end_minutes > 1440) end_minutes = end_minutes - 1440; 1289 var end_minutes_ampm = latepoint_am_or_pm(end_minutes); 1290 timeslot_label += ' - <span class="dp-label-end-time">' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm + '</span>'; 1291 } 1292 if (timeslot_available_capacity) { 1293 var spaces_message = timeslot_available_capacity > 1 ? latepoint_helper.many_spaces_message : latepoint_helper.single_space_message; 1294 capacity_label = timeslot_available_capacity + ' ' + spaces_message; 1295 capacity_label_html = '<span class="dp-capacity">' + capacity_label + '</span>'; 1296 capacity_internal_label_html = '<span class="dp-label-capacity">' + capacity_label + '</span>'; 1297 } 1298 timeslot_label = timeslot_label.trim(); 1299 $timeslots.removeClass('slots-not-available').append('<div tabindex="0" class="' + timeslot_class + '" data-minutes="' + current_minutes + '"><span class="dp-label">' + capacity_internal_label_html + '<span class="dp-label-time">' + timeslot_label + '</span>' + '</span>' + tick_html + capacity_label_html + '</div>'); 1300 prev_minutes = current_minutes; 1301 }); 1302 } else { 1303 // No working hours this day 1304 $timeslots.addClass('slots-not-available').append('<div class="not-working-message">' + latepoint_helper.msg_not_available + "</div>"); 1305 } 1306 jQuery('.times-header-label span').text($day.data('nice-date')); 1307 $wrapper_element.find('.time-selector-w').slideDown(200, function () { 1308 if (!$scrollable_wrapper) $scrollable_wrapper = $wrapper_element.find('.latepoint-body'); 1309 $scrollable_wrapper.stop(); 1310 $wrapper_element.find('.time-selector-w')[0].scrollIntoView({block: "nearest", behavior: 'smooth'}); 1311 }); 1312} 1313 1314 1315function latepoint_timeslot_clicked(event) { 1316 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1317 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1318 if (jQuery(this).hasClass('is-booked') || jQuery(this).hasClass('is-off')) { 1319 // Show error message that you cant select a booked period 1320 } else { 1321 if (jQuery(this).hasClass('selected')) { 1322 jQuery(this).removeClass('selected'); 1323 jQuery(this).find('.dp-success-label').remove(); 1324 $booking_form_element.find('.latepoint_start_time').val(''); 1325 latepoint_hide_next_btn($booking_form_element); 1326 latepoint_reload_summary($booking_form_element); 1327 } else { 1328 $booking_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove(); 1329 var selected_timeslot_time = jQuery(this).find('.dp-label-time').html(); 1330 jQuery(this).addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>'); 1331
1332 var minutes = parseInt(jQuery(this).data('minutes')); 1333 var timeshift_minutes = parseInt($booking_form_element.find('.latepoint_timeshift_minutes').val()); 1334 // we substract timeshift minutes because its timeshift minutes that the business is running in, in opposite of what we do when we generate a calendar for a client 1335 if (timeshift_minutes) minutes = minutes - timeshift_minutes; 1336 var start_date = new Date($booking_form_element.find('.os-day.selected').data('date')); 1337 if (minutes < 0) { 1338 // business minutes are in previous day 1339 minutes = 24 * 60 + minutes; 1340 // move start date back 1 day 1341 start_date.setDate(start_date.getDate() - 1); 1342 } else if (minutes >= 24 * 60) { 1343 // business minutes are in next day 1344 minutes = minutes - 24 * 60; 1345 start_date.setDate(start_date.getDate() + 1); 1346 } 1347 $booking_form_element.find('.latepoint_start_date').val(start_date.toISOString().split('T')[0]) 1348 $booking_form_element.find('.latepoint_start_time').val(minutes); 1349 latepoint_trigger_next_btn($booking_form_element); 1350 } 1351 } 1352 return false; 1353} 1354 1355function latepoint_init_timeslots($booking_form_element = false) { 1356 if (!$booking_form_element) return; 1357 $booking_form_element.off('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked); 1358 $booking_form_element.on('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked); 1359 $booking_form_element.off('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked); 1360 $booking_form_element.on('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked); 1361} 1362 1363async function latepoint_monthly_calendar_load_next_month($booking_form_element){ 1364 try { 1365 1366 if ($booking_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length) { 1367 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active'); 1368 latepoint_calendar_set_month_label($booking_form_element); 1369 return true; 1370 } else { 1371 let $btn = $booking_form_element.find('.os-month-next-btn'); 1372 let next_month_route_name = $btn.data('route'); 1373 $btn.addClass('os-loading'); 1374 let $calendar_element = $booking_form_element.find('.os-monthly-calendar-days-w').last(); 1375 let calendar_year = $calendar_element.data('calendar-year'); 1376 let calendar_month = $calendar_element.data('calendar-month'); 1377 if (calendar_month == 12) { 1378 calendar_year = calendar_year + 1; 1379 calendar_month = 1; 1380 } else { 1381 calendar_month = calendar_month + 1; 1382 } 1383 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]); 1384 form_data.set('target_date_string', `${calendar_year}-${calendar_month}-1`); 1385 let params = latepoint_formdata_to_url_encoded_string(form_data); 1386 let data = { 1387 action: latepoint_helper.route_action, 1388 route_name: next_month_route_name, 1389 params: params, 1390 layout: 'none', 1391 return_format: 'json' 1392 } 1393 let response = await jQuery.ajax({ 1394 type: "post", 1395 dataType: "json", 1396 url: latepoint_timestamped_ajaxurl(), 1397 data: data, 1398 success: function (data) { 1399 } 1400 }); 1401 $btn.removeClass('os-loading'); 1402 if (response.status === "success") { 1403 $booking_form_element.find('.os-months').append(response.message); 1404 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active'); 1405 latepoint_calendar_set_month_label($booking_form_element); 1406 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element); 1407 return true; 1408 } else { 1409 console.log(response.message); 1410 return false;
1411 } 1412 1413 } 1414 } catch (e) { 1415 console.log(e); 1416 alert('Error:' + e); 1417 return false; 1418 } 1419} 1420 1421function latepoint_init_monthly_calendar_navigation($booking_form_element = false) { 1422 if (!$booking_form_element) return; 1423 $booking_form_element.find('.os-month-next-btn').on('click', async function () { 1424 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1425 return latepoint_monthly_calendar_load_next_month($booking_form_element); 1426 }); 1427 $booking_form_element.find('.os-month-prev-btn').on('click', function () { 1428 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1429 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) { 1430 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active'); 1431 latepoint_calendar_set_month_label($booking_form_element); 1432 } 1433 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element); 1434 return false; 1435 }); 1436} 1437 1438function latepoint_calendar_set_month_label($booking_form_element) { 1439 $booking_form_element.find('.os-current-month-label .current-year').text($booking_form_element.find('.os-monthly-calendar-days-w.active').data('calendar-year')); 1440 $booking_form_element.find('.os-current-month-label .current-month').text($booking_form_element.find('.os-monthly-calendar-days-w.active').data('calendar-month-label')); 1441} 1442 1443 1444function latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element) { 1445 $booking_form_element.find('.os-current-month-label .current-year').text($booking_form_element.find('.os-monthly-calendar-days-w.active .os-monthly-calendar-days').data('calendar-year')); 1446 $booking_form_element.find('.os-current-month-label .current-month').text($booking_form_element.find('.os-monthly-calendar-days-w.active .os-monthly-calendar-days').data('calendar-month-label')); 1447 1448 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) { 1449 $booking_form_element.find('.os-month-prev-btn').removeClass('disabled'); 1450 } else { 1451 $booking_form_element.find('.os-month-prev-btn').addClass('disabled'); 1452 } 1453} 1454 1455function latepoint_format_minutes_to_time(minutes, service_duration) { 1456 var ampm = latepoint_am_or_pm(minutes); 1457 var formatted_time = latepoint_minutes_to_hours_and_minutes(minutes) + ' ' + ampm; 1458 if (latepoint_show_booking_end_time()) { 1459 var end_minutes = minutes + service_duration; 1460 var end_minutes_ampm = latepoint_am_or_pm(end_minutes); 1461 formatted_time += ' - ' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm; 1462 } 1463 formatted_time = formatted_time.trim(); 1464 return formatted_time; 1465} 1466 1467function latepoint_monthly_calendar_day_clicked(event) { 1468 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1469 if (jQuery(this).hasClass('os-day-passed')) return false; 1470 if (jQuery(this).hasClass('os-not-in-allowed-period')) return false; 1471 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1472 if (jQuery(this).closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')) { 1473 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT 1474 if (jQuery(this).hasClass('os-not-available')) { 1475 // clicked on a day that has no available timeslots 1476 // do nothing 1477 } else { 1478 $booking_form_element.find('.os-day.selected').removeClass('selected'); 1479 jQuery(this).addClass('selected'); 1480 // set date 1481 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date')); 1482 if (jQuery(this).hasClass('os-one-slot-only')) { 1483 // clicked on a day that has only one slot available 1484 var bookable_minutes = jQuery(this).data('bookable-minutes').toString().split(':')[0]; 1485 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number(jQuery(this).data('service-duration'))); 1486 $booking_form_element.find('.latepoint_start_time').val(jQuery(this).data('bookable-minutes')); 1487 latepoint_show_next_btn($booking_form_element); 1488 $booking_form_element.find('.time-selector-w').slide
1488Up(200); 1489 } else { 1490 // regular day with more than 1 timeslots available 1491 // build timeslots 1492 day_timeslots(jQuery(this)); 1493 // clear time and hide next btn 1494 $booking_form_element.find('.latepoint_start_time').val(''); 1495 latepoint_hide_next_btn($booking_form_element); 1496 } 1497 latepoint_reload_summary($booking_form_element); 1498 } 1499 } else { 1500 1501 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT 1502 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date')); 1503 $booking_form_element.find('.os-day.selected').removeClass('selected'); 1504 jQuery(this).addClass('selected'); 1505 1506 // build timeslots 1507 day_timeslots(jQuery(this)); 1508 // clear time and hide next btn 1509 latepoint_reload_summary($booking_form_element); 1510 $booking_form_element.find('.latepoint_start_time').val(''); 1511 latepoint_hide_next_btn($booking_form_element); 1512 } 1513 1514 1515 return false; 1516} 1517 1518async function latepoint_init_step_datepicker($booking_form_element = false) { 1519 if (!$booking_form_element) return true; 1520 latepoint_init_timeslots($booking_form_element); 1521 latepoint_init_monthly_calendar_navigation($booking_form_element); 1522 $booking_form_element.off('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked); 1523 $booking_form_element.on('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked); 1524 $booking_form_element.off('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked); 1525 $booking_form_element.on('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked); 1526 if ($booking_form_element.find('input[name="booking[start_date]"]').val()){ 1527 $booking_form_element.find('.os-day[data-date="' + $booking_form_element.find('input[name="booking[start_date]"]').val() + '"]').trigger('click'); 1528 }else{ 1529 let max_number_of_months_to_check = 24; 1530 let current_year = new Date().getFullYear(); 1531 for (let i = 0; i < max_number_of_months_to_check; i++){ 1532 let $active_month = $booking_form_element.find('.os-monthly-calendar-days-w.active'); 1533 let searching_month_label = $active_month.data('calendar-month-label'); 1534 if($active_month.data('calendar-year') != current_year) searching_month_label+= ' '+$active_month.data('calendar-year'); 1535 $booking_form_element.find('.os-calendar-searching-info span').text(searching_month_label); 1536 // check if active month has any days available for booking 1537 let $first_available = $active_month.find('.os-day').not('.os-not-available').first(); 1538 if($first_available.length){ 1539 break; 1540 }else{ 1541 await latepoint_monthly_calendar_load_next_month($booking_form_element); 1542 } 1543 } 1544 $booking_form_element.find('.os-dates-w').removeClass('is-searching'); 1545 } 1546 return true; 1547} 1548 1549 1550function latepoint_init_step_verify($booking_form_element = false) { 1551 if (!$booking_form_element) return; 1552 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open'); 1553 1554 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-trigger-on-verify-w a').on('click', function (e) { 1555 jQuery(this).closest('.coupon-code-wrapper-on-verify').addClass('entering-coupon').find('.coupon-code-input').trigger('focus'); 1556 return false; 1557 }); 1558 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-cancel').on('click', function (e) { 1559 jQuery(this).closest('.coupon-code-wrapper-on-verify').removeClass('entering-coupon'); 1560 return false; 1561 }); 1562 1563 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-submit').on('click', function (e) { 1564 latepoint_apply_coupon(jQuery(this).closest('.coupon-code-input-w').find('.coupon-code-input')); 1565 return false; 1566 }); 1567 1568 $booking_form_element.find('.os-remove-item-from-cart').on('click keydown', function (event) { 1569 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1570 //make sure to clear active cart item so it doesn't add it again on reload! 1571 if (confirm(jQuery(this).data('confirm-text'))) { 1572 latepoint_remove_cart_item(jQuery(this)); 1573 } 1574 return false;
1575 }); 1576 1577 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-clear').on('click', function (e) { 1578 latepoint_remove_coupon(jQuery(this)); 1579 return false; 1580 }); 1581 1582 $booking_form_element.find('.coupon-code-wrapper-on-verify input.coupon-code-input').on('keyup', function (e) { 1583 if (e.which === 13) { 1584 latepoint_apply_coupon(jQuery(this)); 1585 return false; 1586 } 1587 }); 1588} 1589 1590 1591function latepoint_init_step_payment__pay($booking_form_element = false) { 1592 var selected_payment_method = $booking_form_element.find('input[name="cart[payment_method]"]').val(); 1593 latepoint_init_payment_method_actions($booking_form_element, selected_payment_method); 1594} 1595 1596function latepoint_init_step_payment__portions($booking_form_element = false) { 1597 // Selecting Payment Time 1598 $booking_form_element.find('.lp-payment-trigger-payment-portion-selector').on('click keydown', function (event) { 1599 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1600 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1601 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value')); 1602 latepoint_show_prev_btn($booking_form_element); 1603 latepoint_trigger_next_btn($booking_form_element); 1604 return false; 1605 }); 1606} 1607 1608function latepoint_init_step_payment__times($booking_form_element = false) { 1609 // Selecting Payment Time 1610 $booking_form_element.find('.lp-payment-trigger-payment-time-selector').on('click keydown', function (event) { 1611 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1612 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1613 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value')); 1614 latepoint_show_prev_btn($booking_form_element); 1615 latepoint_trigger_next_btn($booking_form_element); 1616 return false; 1617 }); 1618} 1619 1620 1621function latepoint_init_step_payment__methods($booking_form_element = false) { 1622 // Selecting Payment Time 1623 $booking_form_element.find('.lp-payment-trigger-payment-method-selector').on('click', function (e) { 1624 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1625 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value')); 1626 latepoint_show_prev_btn($booking_form_element); 1627 latepoint_trigger_next_btn($booking_form_element); 1628 return false; 1629 }); 1630} 1631 1632function latepoint_category_item_clicked(event){ 1633 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1634 let $item = jQuery(event.target); 1635 1636 let $booking_form_element = $item.closest('.latepoint-booking-form-element'); 1637 latepoint_show_prev_btn($booking_form_element); 1638 $item.closest('.latepoint-step-content').addClass('selecting-item-category'); 1639 let $category_wrapper = $item.closest('.os-item-category-w'); 1640 let $main_parent = $item.closest('.os-item-categories-main-parent'); 1641 if ($category_wrapper.hasClass('selected')) { 1642 $category_wrapper.removeClass('selected'); 1643 if ($category_wrapper.parent().closest('.os-item-category-w').length) { 1644 $category_wrapper.parent().closest('.os-item-category-w').addClass('selected'); 1645 } else { 1646 $main_parent.removeClass('show-selected-only'); 1647 } 1648 } else { 1649 $main_parent.find('.os-item-category-w.selected').removeClass('selected'); 1650 $main_parent.addClass('show-selected-only'); 1651 $category_wrapper.addClass('selected'); 1652 } 1653 return false; 1654} 1655 1656function latepoint_init_step_category_items(step_code) { 1657 let $category_items = jQuery('.latepoint-step-content[data-step-code="' + step_code + '"] .os-item-category-info'); 1658 $category_items.on('click', latepoint_category_item_clicked); 1659 $category_items.on('keydown', latepoint_category_item_clicked); 1660} 1661 1662 1663function latepoint_init_step_selectable_items($booking_form_element) { 1664 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked); 1665 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked); 1666 1667 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup); 1668 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup); 1669 1670 1671 $booking_form_element.off('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked); 1672 $booking_form_element.on('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked); 1673} 1674 1675 1676function latepoint_update_quantity_for_selectable_items($item) { 1677 var ids = $item.closest('.os-selectable-items') 1678 .find('.os-selectable-item.selected') 1679 .map(function () { 1680 if (jQuery(this).hasClass('has-quantity')) { 1681 return jQuery(this).data('item-id') + ':' + jQuery(this).find('input.item-quantity-selector-input').val(); 1682 } else { 1683 return jQuery(this).data('item-id'); 1684 } 1685 }).get(); 1686 $item.closest('.latepoint-booking-form-element').find($item.data('id-holder')).val(ids); 1687} 1688 1689function latepoint_selectable_item_quantity_keyup(event) { 1690 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1691 var $item = jQuery(this).closest('.os-selectable-item'); 1692 var new_value = jQuery(this).val(); 1693 if (new_value && new_value.match(/^\d+$/)) { 1694 var max_quantity = $item.data('max-quantity'); 1695 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity; 1696 } else { 1697 new_value = 0; 1698 } 1699 jQuery(this).val(new_value); 1700 1701 if (($item.hasClass('selected') && (new_value > 0)) || (!$item.hasClass('selected') && (new_value == 0))) { 1702 latepoint_update_quantity_for_selectable_items($item); 1703 latepoint_reload_summary($booking_form_element); 1704 return false;
1705 } else { 1706 $item.trigger('click'); 1707 } 1708} 1709 1710function latepoint_selectable_item_clicked(event) { 1711 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 1712 event.stopPropagation(); 1713 event.stopImmediatePropagation(); 1714 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1715 if (jQuery(this).hasClass('has-quantity')) { 1716 if (jQuery(event.target).hasClass('item-quantity-selector')) { 1717 var current_value = parseInt(jQuery(this).find('input.item-quantity-selector-input').val()); 1718 var new_value = (jQuery(event.target).data('sign') == 'minus') ? current_value - 1 : current_value + 1; 1719 var max_quantity = jQuery(this).data('max-quantity'); 1720 if (new_value < 0) new_value = 0; 1721 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity; 1722 jQuery(this).find('input.item-quantity-selector-input').val(new_value); 1723 if ((jQuery(this).hasClass('selected') && (new_value > 0)) || (!jQuery(this).hasClass('selected') && (new_value == 0))) { 1724 latepoint_update_quantity_for_selectable_items(jQuery(this)); 1725 latepoint_reload_summary($booking_form_element); 1726 return false; 1727 } 1728 } 1729 if (jQuery(event.target).hasClass('item-quantity-selector-input')) { 1730 latepoint_update_quantity_for_selectable_items(jQuery(this)); 1731 latepoint_reload_summary($booking_form_element); 1732 return false; 1733 } 1734 } 1735 var summary_value = ''; 1736 if (jQuery(this).hasClass('os-allow-multiselect')) { 1737 if (jQuery(this).hasClass('selected')) { 1738 jQuery(this).removeClass('selected'); 1739 if (jQuery(this).hasClass('has-quantity')) jQuery(this).find('input.item-quantity-selector-input').val(0); 1740 } else { 1741 jQuery(this).addClass('selected'); 1742 if (jQuery(this).hasClass('has-quantity') && !(jQuery(this).find('input.item-quantity-selector-input').val() > 0)) { 1743 jQuery(this).find('input.item-quantity-selector-input').val(1); 1744 } 1745 } 1746 latepoint_update_quantity_for_selectable_items(jQuery(this)); 1747 summary_value = String(jQuery(this).closest('.os-selectable-items').find('.os-selectable-item.selected').map(function () { 1748 return (' ' + jQuery(this).data('summary-value')); 1749 }).get()).trim(); 1750 latepoint_show_next_btn($booking_form_element); 1751 } else { 1752 if (!jQuery(this).hasClass('os-duration-item')) jQuery(this).closest('.os-item-categories-main-parent').find('.os-selectable-item.selected').removeClass('selected'); 1753 jQuery(this).closest('.os-selectable-items').find('.os-selectable-item.selected').removeClass('selected'); 1754 jQuery(this).addClass('selected'); 1755 $booking_form_element.find(jQuery(this).data('id-holder')).val(jQuery(this).data('item-id')); 1756 summary_value = jQuery(this).data('summary-value'); 1757 if (jQuery(this).data('cart-item-item-data-key')) { 1758 latepoint_update_active_cart_item_item_data($booking_form_element, jQuery(this).data('cart-item-item-data-key'), jQuery(this).data('item-id')); 1759 } 1760 if (jQuery(this).data('os-call-func')) { 1761 window[jQuery(this).data('os-call-func')](jQuery(this)); 1762 } 1763 if (jQuery(this).data('activate-sub-step')) { 1764 window[jQuery(this).data('activate-sub-step')](jQuery(this)); 1765 } else { 1766 latepoint_trigger_next_btn($booking_form_element); 1767 } 1768 } 1769 return false; 1770} 1771 1772function latepoint_update_active_cart_item_item_data($booking_form_element, key, value) { 1773 let item_data_json = $booking_form_element.find('input[name="active_cart_item[item_data]"]').val(); 1774 let item_data = item_data_json ? JSON.parse($booking_form_element.find('input[name="active_cart_item[item_data]"]').val()) : {}; 1775 item_data[key] = value; 1776 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val(JSON.stringify(item_data)); 1777} 1778 1779function latepoint_format_price(price) { 1780 // replace default decimal separator dot with comma if it's in settings 1781 if (latepoint_helper.decimal_separator == ',') price = String(price).replace('.', ','); 1782 return latepoint_helper.currency_symbol_before + String(price) + latepoint_helper.currency_symbol_after; 1783} 1784 1785 1786function latepoint_init_step_services() { 1787} 1788 1789 1790function latepoint_trigger_next_btn($booking_form_element) { 1791 $booking_form_element.find('.latepoint_step_direction').val('next'); 1792 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form')); 1793} 1794 1795function latepoint_init_step_locations() { 1796} 1797 1798function latepoint_init_agent_details_link($booking_form_element) { 1799 $booking_form_element.on('click', '.os-trigger-item-details-popup', function () { 1800 $booking_form_element.find('.os-item-details-popup.open').remove(); 1801 var $popup = $booking_form_element.find('#' + jQuery(this).data('item-details-popup-id')).first().clone().attr('id', ''); 1802 $booking_form_element.find('.latepoint-form-w').addClass('showing-item-details-popup'); 1803 $popup.addClass('open').appendTo($booking_form_element.find('.latepoint-body')); 1804 return false;
1805 }); 1806 $booking_form_element.on('click', '.os-item-details-popup.open .os-item-details-popup-close', function () { 1807 $booking_form_element.find('.latepoint-form-w').removeClass('showing-item-details-popup'); 1808 jQuery(this).closest('.os-item-details-popup.open').remove(); 1809 return false; 1810 }); 1811} 1812 1813function latepoint_init_step_agents() { 1814} 1815 1816 1817function latepoint_init_booking_summary_lightbox() { 1818 jQuery('.customer-dashboard-booking-summary-lightbox').on('click', '.qr-show-trigger', function () { 1819 jQuery(this).closest('.latepoint-lightbox-i').find('.qr-code-on-full-summary').addClass('show-vevent-qr-code'); 1820 return false; 1821 }); 1822 jQuery('.customer-dashboard-booking-summary-lightbox').on('click', '.os-item-details-popup-close', function () { 1823 var $ligthbox = jQuery(this).closest('.latepoint-lightbox-content'); 1824 $ligthbox.find('.os-item-details-popup.open').remove(); 1825 $ligthbox.find('.full-summary-wrapper').show(); 1826 return false; 1827 }); 1828 1829 jQuery('.customer-dashboard-booking-summary-lightbox').on('click', '.os-trigger-item-details-popup', function () { 1830 var $ligthbox = jQuery(this).closest('.latepoint-lightbox-content'); 1831 $ligthbox.find('.full-summary-wrapper').hide(); 1832 $ligthbox.find('.os-item-details-popup.open').remove(); 1833 var $popup = $ligthbox.find('#' + jQuery(this).data('item-details-popup-id')).clone(); 1834 $popup.addClass('open').appendTo($ligthbox); 1835 return false; 1836 }); 1837} 1838 1839function latepoint_init_step_confirmation($booking_form_element = false) { 1840 if (!$booking_form_element) return; 1841 $booking_form_element.on('click', '.set-customer-password-btn', function () { 1842 var $btn = jQuery(this); 1843 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1844 1845 $btn.addClass('os-loading'); 1846 var params = { 1847 account_nonse: jQuery('input[name="account_nonse"]').val(), 1848 password: jQuery('input[name="customer[password]"]').val(), 1849 password_confirmation: jQuery('input[name="customer[password_confirmation]"]').val() 1850 } 1851 var data = { 1852 action: latepoint_helper.route_action, 1853 route_name: jQuery(this).data('btn-action'), 1854 params: jQuery.param(params), 1855 layout: 'none', 1856 return_format: 'json' 1857 } 1858 jQuery.ajax({ 1859 type: "post", 1860 dataType: "json", 1861 url: latepoint_timestamped_ajaxurl(), 1862 data: data, 1863 success: function (data) { 1864 $btn.removeClass('os-loading'); 1865 if (data.status === "success") { 1866 $booking_form_element.find('.step-confirmation-set-password').html('').hide(); 1867 $booking_form_element.find('.confirmation-cabinet-info').show(); 1868 } else { 1869 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.step-confirmation-set-password'), 'error'); 1870 } 1871 } 1872 }); 1873 return false; 1874 }); 1875 1876 $booking_form_element.on('click', '.qr-show-trigger', function () { 1877 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1878 $booking_form_element.find('.qr-code-on-full-summary').addClass('show-vevent-qr-code'); 1879 return false; 1880 }); 1881 1882 $booking_form_element.on('click', '.show-set-password-fields', function () { 1883 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1884 1885 $booking_form_element.find('.step-confirmation-set-password').show(); 1886 $booking_form_element.find('#customer_password').trigger('focus'); 1887 jQuery(this).closest('.info-box').hide(); 1888 return false; 1889 }); 1890} 1891 1892function latepoint_init_customer_dashboard() { 1893 latepoint_init_form_masks(); 1894 jQuery('.latepoint-customer-timezone-selector-w select').on('change', function (e) { 1895 var $select_box = jQuery(this); 1896 $select_box.closest('.latepoint-customer-timezone-selector-w').addClass('os-loading'); 1897 var data = { 1898 action: latepoint_helper.route_action, 1899 route_name: jQuery(this).closest('.latepoint-customer-timezone-selector-w').data('route-name'), 1900 params: {timezone_name: jQuery(this).val()}, 1901 layout: 'none', 1902 return_format: 'json' 1903 } 1904 jQuery.ajax({ 1905 type: "post", 1906 dataType: "json", 1907 url: latepoint_timestamped_ajaxurl(), 1908 data: data, 1909 success: function (data) { 1910 $select_box.closest('.latepoint-customer-timezone-selector-w').removeClass('os-loading'); 1911 if (data.status === "success") { 1912 location.reload(); 1913 } else { 1914 1915 } 1916 } 1917 }); 1918 }); 1919 1920 1921 jQuery('.latepoint-request-booking-cancellation').on('click', function () { 1922 if (!confirm(latepoint_helper.cancel_booking_prompt)) return false;
1923 var $this = jQuery(this); 1924 var $booking_box = $this.closest('.customer-booking'); 1925 1926 var route = jQuery(this).data('route'); 1927 var params = {id: $booking_box.data('id')}; 1928 1929 var data = { 1930 action: latepoint_helper.route_action, 1931 route_name: route, 1932 params: params, 1933 layout: 'none', 1934 return_format: 'json' 1935 } 1936 $this.addClass('os-loading'); 1937 jQuery.ajax({ 1938 type: "post", 1939 dataType: "json", 1940 url: latepoint_timestamped_ajaxurl(), 1941 data: data, 1942 success: function (data) { 1943 if (data.status === "success") { 1944 $this.remove(); 1945 location.reload(); 1946 } else { 1947 $this.removeClass('os-loading'); 1948 } 1949 } 1950 }); 1951 return false; 1952 }); 1953 1954} 1955 1956 1957function get_customer_name($wrapper) { 1958 var customer_name = ''; 1959 var first_name = $wrapper.find('input[name="customer[first_name]"]').val(); 1960 var last_name = $wrapper.find('input[name="customer[last_name]"]').val(); 1961 if (first_name) customer_name += first_name; 1962 if (last_name) customer_name += ' ' + last_name; 1963 return customer_name.trim(); 1964} 1965 1966function latepoint_init_step_contact() { 1967 latepoint_init_form_masks(); 1968 1969 // Init Logout button 1970 jQuery('.step-customer-logout-btn').on('click', function () { 1971 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1972 var data = { 1973 action: latepoint_helper.route_action, 1974 route_name: jQuery(this).data('btn-action'), 1975 layout: 'none', 1976 return_format: 'json' 1977 } 1978 latepoint_step_content_change_start($booking_form_element); 1979 jQuery.ajax({ 1980 type: "post", 1981 dataType: "json", 1982 url: latepoint_timestamped_ajaxurl(), 1983 data: data, 1984 success: function (data) { 1985 latepoint_reload_step($booking_form_element); 1986 } 1987 }); 1988 return false; 1989 }); 1990 1991 // Init Login Existing Customer Button 1992 jQuery('.step-login-existing-customer-btn').on('click', function () { 1993 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 1994 var params = { 1995 email: $booking_form_element.find('.os-step-existing-customer-login-w input[name="customer_login[email]"]').val(), 1996 password: $booking_form_element.find('.os-step-existing-customer-login-w input[name="customer_login[password]"]').val() 1997 } 1998 var data = { 1999 action: latepoint_helper.route_action, 2000 route_name: jQuery(this).data('btn-action'), 2001 params: jQuery.param(params), 2002 layout: 'none', 2003 return_format: 'json' 2004 } 2005 latepoint_step_content_change_start($booking_form_element); 2006 jQuery.ajax({ 2007 type: "post", 2008 dataType: "json", 2009 url: latepoint_timestamped_ajaxurl(), 2010 data: data, 2011 success: function (data) { 2012 if (data.status === "success") { 2013 latepoint_reload_step($booking_form_element); 2014 } else { 2015 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.os-step-existing-customer-login-w')); 2016 latepoint_step_content_change_end(false, $booking_form_element); 2017 } 2018 } 2019 }); 2020 return false; 2021 }); 2022} 2023 2024function latepoint_step_content_change_start($booking_form_element) { 2025 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading'); 2026} 2027 2028// TODO 2029function latepoint_step_content_change_end(new_content, $booking_form_element) { 2030 if (new_content) $booking_form_element.find('.latepoint-body .latepoint-step-content').replaceWith(new_content); 2031 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading'); 2032 setTimeout(function () { 2033 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded'); 2034 }, 50); 2035} 2036 2037 2038function latepoint_change_step_desc($booking_form_element, step_code) { 2039 $booking_form_element.removeClass('step-changed').addClass('step-changing'); 2040 setTimeout(function () { 2041 // Progress bar 2042 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]'); 2043 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active'); 2044 $step_progress.nextAll().removeClass('complete').removeClass('active'); 2045 // Side panel 2046 var side_panel_desc = $booking_form_element.find('.latepoint-step-desc-library[data-step-code="' + step_code + '"]').html(); 2047 $booking_form_element.find('.latepoint-step-desc').html(side_panel_desc); 2048 2049 // Top header 2050 var top_header_desc = $booking_form_element.find('.os-heading-text-library[data-step-code="' + step_code + '"]').html(); 2051 $booking_form_element.find('.os-heading-text').html(top_header_desc); 2052 setTimeout(function () { 2053 $booking_form_element.removeClass('step-changing').addClass('step-changed'); 2054 }, 50); 2055 }, 500); 2056} 2057 2058 2059function latepoint_progress_prev($booking_form_element, step_code) { 2060 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]'); 2061 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active'); 2062 $step_progress.nextAll().removeClass('complete').removeClass('active'); 2063} 2064 2065 2066function latepoint_progress_next($booking_form_element, step_code) { 2067 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]'); 2068 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active'); 2069 $step_progress.nextAll().removeClass('complete').removeClass('active'); 2070} 2071 2072 2073function latepoint_next_step_description($booking_form_element, step_code) { 2074 $booking_form_element.removeClass('step-changed').addClass('step-changing'); 2075 setTimeout(function () { 2076 $booking_form_element.find('.latepoint-step-desc').html($booking_form_element.find('.latepoint-step-desc-library.active').removeClass('active').next('.latepoint-step-desc-library').addClass('active').html()); 2077 $booking_form_element.find('.os-heading-text').html($booking_form_element.find('.os-heading-text-library.active').removeClass('active').next('.os-heading-text-library').addClass('active').html()); 2078 setTimeout(function () { 2079 $booking_form_element.removeClass('step-changing').addClass('step-changed'); 2080 }, 50); 2081 }, 500); 2082} 2083 2084function latepoint_prev_step_description($booking_form_element, step_code) { 2085 $booking_form_element.removeClass('step-changed').addClass('step-changing'); 2086 setTimeout(function () { 2087 $booking_form_element.find('.latepoint-step-desc').html($booking_form_element.find('.latepoint-step-desc-library.active').removeClass('active').prev('.latepoint-step-desc-library').addClass('active').html()); 2088 $booking_form_element.find('.os-heading-text').html($booking_form_element.find('.os-heading-text-library.active').removeClass('active').prev('.os-heading-text-library').addClass('active').html()); 2089 setTimeout(function () { 2090 $booking_form_element.removeClass('step-changing').addClass('step-changed'); 2091 }, 50); 2092 }, 500); 2093} 2094 2095 2096function latepoint_validate_fields($fields) { 2097 var is_valid = true; 2098 $fields.each(function (index) { 2099 if (jQuery(this).val() == '') { 2100 is_valid = false;
2101 return false; 2102 } 2103 }); 2104 return is_valid; 2105} 2106 2107 2108async function latepoint_submit_booking_form($booking_form) { 2109 let $booking_form_element = $booking_form.closest('.latepoint-booking-form-element'); 2110 2111 let current_step = $booking_form_element.find('.latepoint_current_step_code').val(); 2112 let callbacks_list = []; 2113 if (latepoint_check_if_booking_form_is_final_submit($booking_form_element)) { 2114 // check if order intent is still bookable 2115 latepoint_add_action(callbacks_list, async () => { 2116 return await latepoint_check_if_order_intent_still_bookable($booking_form_element); 2117 }, 1); 2118 } 2119 $booking_form_element.trigger('latepoint:submitBookingForm', [{ 2120 current_step: current_step, 2121 callbacks_list: callbacks_list, 2122 is_final_submit: latepoint_check_if_booking_form_is_final_submit($booking_form_element), 2123 direction: $booking_form_element.find('.latepoint_step_direction').val() 2124 }]); 2125 try { 2126 latepoint_hide_prev_btn($booking_form_element); 2127 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form); 2128 } catch (error) { 2129 latepoint_show_prev_btn($booking_form_element); 2130 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element); 2131 return false; 2132 } 2133 2134 2135 2136 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading'); 2137 latepoint_hide_prev_btn($booking_form_element); 2138 try{ 2139 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body')); 2140 let response = await jQuery.ajax({ 2141 type: "post", 2142 dataType: "json", 2143 processData: false, 2144 contentType: false, 2145 url: latepoint_timestamped_ajaxurl(), 2146 data: latepoint_create_form_data($booking_form) 2147 }); 2148 2149 $booking_form.find('.latepoint_step_direction').val('next'); 2150 if(response.status === 'success'){ 2151 if (response.fields_to_update) { 2152 for (const [key, value] of Object.entries(response.fields_to_update)) { 2153 $booking_form_element.find('input[name="' + key + '"]').val(value) 2154 } 2155 } 2156 if ($booking_form_element.data('flash-error')) { 2157 latepoint_show_message_inside_element($booking_form_element.data('flash-error'), $booking_form_element.find('.latepoint-body')); 2158 $booking_form_element.data('flash-error', ''); 2159 } 2160 $booking_form_element.find('.latepoint_current_step_code').val(response.step_code); 2161 $booking_form_element.removeClass(function (index, className) { 2162 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' '); 2163 }).addClass('current-step-' + response.step_code); 2164 setTimeout(function () { 2165 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading'); 2166 $booking_form_element.find('.latepoint-body').find('.latepoint-step-content').addClass('is-hidden'); 2167 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]')) { 2168 $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]').remove(); 2169 } 2170 $booking_form_element.find('.latepoint-body').append(response.message); 2171 2172 2173 latepoint_update_next_btn_label($booking_form_element); 2174 latepoint_init_step(response.step_code, $booking_form_element); 2175 setTimeout(function () { 2176 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded'); 2177 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading'); 2178 latepoint_scroll_to_top_of_booking_form($booking_form_element); 2179 }, 50); 2180 }, 500); 2181 2182 if (response.is_pre_last_step) { 2183 $booking_form_element.data('next-submit-is-last', 'yes'); 2184 } else { 2185 $booking_form_element.data('next-submit-is-last', 'no'); 2186 } 2187 if (response.is_last_step) { 2188 $booking_form_element.addClass('hidden-buttons').find('.latepoint-footer').remove(); 2189 $booking_form_element.find('.latepoint-progress').css('opacity', 0); 2190 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open'); 2191 $booking_form_element.closest('.latepoint-show-side-panel').removeClass('latepoint-show-side-panel').addClass('latepoint-hide-side-panel'); 2192 $booking_form_element.addClass('is-final-step'); 2193 } else { 2194 if (response.show_next_btn === true) { 2195 latepoint_show_next_btn($booking_form_element); 2196 } else { 2197 latepoint_hide_next_btn($booking_form_element); 2198 } 2199 if (response.show_prev_btn === true) { 2200 latepoint_show_prev_btn($booking_form_element); 2201 } else { 2202 latepoint_hide_prev_btn($booking_form_element); 2203 } 2204 } 2205 latepoint_change_step_desc($booking_form_element, response.step_code); 2206 latepoint_reload_summary($booking_form_element); 2207 }else{ 2208 if(response.send_to_step && response.send_to_step === 'resubmit'){ 2209 let current_resubmit_count = parseInt($booking_form.data('resubmit-count')) ? parseInt($booking_form.data('resubmit-count')) : 1; 2210 $booking_form.data('resubmit-count', current_resubmit_count + 1); 2211 if(current_resubmit_count > 6){
2212 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body')); 2213 }else{ 2214 // resubmission probably caused by order intent still being processed, since 2215 // order intent is still processing, give it a little more time and try again 2216 await latepoint_sleep(2000); 2217 return latepoint_submit_booking_form($booking_form); 2218 } 2219 }else{ 2220 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded'); 2221 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading'); 2222 if (response.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.send_to_step + '"]').length) { 2223 $booking_form_element.data('flash-error', response.message); 2224 latepoint_reload_step($booking_form_element, response.send_to_step); 2225 } else { 2226 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body')); 2227 latepoint_show_prev_btn($booking_form_element); 2228 } 2229 } 2230 } 2231 }catch(e){ 2232 console.log(e); 2233 alert('Error:' + e); 2234 } 2235} 2236 2237function latepoint_sleep(ms) { 2238 return new Promise(resolve => setTimeout(resolve, ms)); 2239} 2240 2241function latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element) { 2242 if (error.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + error.send_to_step + '"]').length) { 2243 latepoint_reload_step($booking_form_element, error.send_to_step); 2244 $booking_form_element.data('flash-error', error.message); 2245 } else { 2246 latepoint_show_message_inside_element(error.message, $booking_form_element.find('.latepoint-body'), 'error'); 2247 2248 if ($booking_form_element.hasClass('step-content-loading')) $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded'); 2249 $booking_form_element.find('.latepoint-next-btn').removeClass('os-loading'); 2250 2251 // if previous step exists - show prev button 2252 if ($booking_form_element.find('.latepoint-step-content:last-child').prev('.latepoint-step-content').length) latepoint_show_prev_btn($booking_form_element); 2253 latepoint_scroll_to_top_of_booking_form($booking_form_element); 2254 } 2255} 2256 2257function latepoint_reset_active_cart_item($booking_form_element) { 2258 $booking_form_element.find('input[name="active_cart_item[id]"]').val(''); 2259 $booking_form_element.find('input[name="active_cart_item[variant]"]').val(''); 2260 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val(''); 2261} 2262 2263function latepoint_check_if_booking_form_is_final_submit($booking_form_element) { 2264 return ($booking_form_element.data('next-submit-is-last') == 'yes'); 2265} 2266 2267 2268async function latepoint_check_if_order_intent_still_bookable($booking_form_element) { 2269 let response = await jQuery.ajax({ 2270 type: "post", 2271 dataType: "json", 2272 processData: false, 2273 contentType: false, 2274 url: latepoint_timestamped_ajaxurl(), 2275 data: latepoint_create_form_data($booking_form_element.find('.latepoint-form'), latepoint_helper.check_order_intent_bookable_route) 2276 }); 2277 if(response.status === 'success'){ 2278 return true; 2279 }else{ 2280 throw new Error(response.message); 2281 } 2282} 2283 2284async function latepoint_process_list_of_callbacks(callbacks, $booking_form_element, $booking_form) { 2285 for (const callback of callbacks) { 2286 await callback.action(); 2287 } 2288} 2289 2290function latepoint_clear_presets($booking_form_element){ 2291 $booking_form_element.find('.clear_for_new_item').val(''); 2292} 2293 2294function latepoint_init_booking_form($booking_form_element) { 2295 $booking_form_element.on('click keydown', '.checkout-from-summary-panel-btn', function (event) { 2296 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 2297 latepoint_reload_step($booking_form_element, jQuery(this).data('step')); 2298 jQuery(this).closest('.latepoint-w').removeClass('show-summary-on-mobile'); 2299 return false;
2300 }); 2301 2302 $booking_form_element.on('click keydown', '.latepoint-add-another-item-trigger', function (event) { 2303 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 2304 latepoint_clear_presets($booking_form_element); 2305 latepoint_reset_active_cart_item($booking_form_element); 2306 latepoint_reload_step($booking_form_element, jQuery(this).data('step')); 2307 return false; 2308 }); 2309 $booking_form_element.find('.latepoint-form').on('submit', function (e) { 2310 e.preventDefault(); 2311 let $booking_form = jQuery(this); 2312 latepoint_submit_booking_form($booking_form); 2313 }); 2314 2315 latepoint_init_booking_summary_panel($booking_form_element); 2316 2317 $booking_form_element.find('.latepoint-heading-w .latepoint-lightbox-summary-trigger').on('click', function () { 2318 var $wrapper = jQuery(this).closest('.latepoint-w'); 2319 $wrapper.toggleClass('show-summary-on-mobile'); 2320 return false; 2321 }); 2322 2323 $booking_form_element.find('.latepoint-lightbox-close').on('click', function () { 2324 2325 let params = new URLSearchParams(location.search); 2326 if (params.has('latepoint_order_intent_key')) { 2327 params.delete('latepoint_order_intent_key'); 2328 history.replaceState(null, '', '?' + params + location.hash); 2329 } 2330 2331 jQuery('body').removeClass('latepoint-lightbox-active'); 2332 jQuery('.latepoint-lightbox-w').remove(); 2333 return false; 2334 }); 2335 2336 2337 $booking_form_element.find('.latepoint-timezone-selector-w select').on('change', function (e) { 2338 var $select_box = jQuery(this); 2339 $select_box.closest('.latepoint-timezone-selector-w').addClass('os-loading'); 2340 var data = { 2341 action: latepoint_helper.route_action, 2342 route_name: jQuery(this).closest('.latepoint-timezone-selector-w').data('route-name'), 2343 params: {timezone_name: jQuery(this).val()}, 2344 layout: 'none', 2345 return_format: 'json' 2346 } 2347 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading'); 2348 jQuery.ajax({ 2349 type: "post", 2350 dataType: "json", 2351 url: latepoint_timestamped_ajaxurl(), 2352 data: data, 2353 success: function (data) { 2354 $select_box.closest('.latepoint-timezone-selector-w').removeClass('os-loading'); 2355 $booking_form_element.removeClass('step-content-loading'); 2356 if (data.status === "success") { 2357 // reload datepicker if its the step 2358 if ($select_box.closest('.latepoint-booking-form-element').hasClass('current-step-booking__datepicker')) { 2359 latepoint_reload_step($select_box.closest('.latepoint-booking-form-element')); 2360 } 2361 } else { 2362 2363 } 2364 } 2365 }); 2366 }); 2367 2368 if (!latepoint_helper.is_timezone_selected) { 2369 const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone; 2370 if (tzid) { 2371 if (tzid != $booking_form_element.find('.latepoint-timezone-selector-w select').val()) $booking_form_element.find('.latepoint-timezone-selector-w select').val(tzid).trigger('change'); 2372 } 2373 } 2374 2375 2376 $booking_form_element.on('click keydown', '.lp-option', function (event) { 2377 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 2378 jQuery(this).closest('.lp-options').find('.lp-option.selected').removeClass('selected'); 2379 jQuery(this).addClass('selected'); 2380 }); 2381 2382 2383 // Next Step button Click 2384 $booking_form_element.find('.latepoint-next-btn').on('click', async function (e) { 2385 e.preventDefault(); 2386 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false; 2387 var $next_btn = jQuery(this); 2388 $next_btn.addClass('os-loading'); 2389 var $booking_form = jQuery(this).closest('.latepoint-form'); 2390 2391 var current_step = $booking_form_element.find('.latepoint_current_step_code').val(); 2392 2393 $booking_form.find('.latepoint_step_direction').val('next'); 2394 var callbacks_list = []; 2395 2396 $booking_form_element.trigger('latepoint:nextStepClicked', [{ 2397 current_step: current_step, 2398 callbacks_list: callbacks_list 2399 }]); 2400 latepoint_hide_prev_btn($booking_form_element); 2401 2402 try{ 2403 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form ); 2404 await latepoint_submit_booking_form($booking_form); 2405 }catch(error){ 2406 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element); 2407 } 2408 return false;
2409 }); 2410 2411 2412 // Previous Step button Click 2413 $booking_form_element.find('.latepoint-prev-btn').on('click', function (e) { 2414 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false; 2415 2416 let $current_step = $booking_form_element.find('.latepoint-step-content:last-child'); 2417 2418 2419 // handle categories 2420 if ($current_step.hasClass('selecting-item-category')) { 2421 if ($current_step.find('.os-item-category-w .os-item-category-w.selected').length) { 2422 $current_step.find('.os-item-category-w .os-item-category-w.selected').parents('.os-item-category-w').addClass('selected').find('.os-item-category-w.selected').removeClass('selected'); 2423 } else { 2424 $current_step.removeClass('selecting-item-category').find('.os-item-category-w.selected').removeClass('selected'); 2425 $current_step.removeClass('selecting-item-category').find('.os-item-categories-holder.show-selected-only').removeClass('show-selected-only'); 2426 } 2427 if (($booking_form_element.find('.latepoint-step-content').length <= 1) && !$current_step.hasClass('selecting-item-category')) { 2428 latepoint_hide_prev_btn($booking_form_element); 2429 } 2430 latepoint_reload_summary($booking_form_element); 2431 return false; 2432 } 2433 2434 if ($current_step.data('clear-action')) { 2435 window[$current_step.data('clear-action')]($booking_form_element); 2436 } 2437 2438 let $back_btn = jQuery(this); 2439 $back_btn.addClass('os-loading'); 2440 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading'); 2441 let $new_current_step = $booking_form_element.find('.latepoint-step-content.is-hidden').last(); 2442 let new_current_step_code = $new_current_step.data('step-code'); 2443 let current_step_code = $current_step.data('step-code'); 2444 2445 2446 let current_parent_code_name = current_step_code.split('__')[0]; 2447 let new_parent_code_name = new_current_step_code.split('__')[0]; 2448 2449 let active_cart_item_id = $booking_form_element.find('input[name="active_cart_item[id]"]').val(); 2450 2451 latepoint_change_step_desc($booking_form_element, new_current_step_code); 2452 setTimeout(function () { 2453 $new_current_step.removeClass('is-hidden'); 2454 $current_step.remove(); 2455 $booking_form_element.find('.latepoint_current_step_code').val(new_current_step_code); 2456 $booking_form_element.removeClass(function (index, className) { 2457 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' '); 2458 }).addClass('current-step-' + new_current_step_code); 2459 $booking_form_element.find('.latepoint-next-btn span').text($booking_form_element.find('.latepoint-next-btn').data('label')); 2460 $booking_form_element.data('next-submit-is-last', 'no'); 2461 2462 latepoint_update_next_btn_label($booking_form_element); 2463 latepoint_show_next_btn($booking_form_element); 2464 $back_btn.removeClass('os-loading'); 2465 if ($booking_form_element.find('.latepoint-step-content').length <= 1) { 2466 if ($new_current_step.hasClass('selecting-item-category')) { 2467 2468 } 2469 if (new_current_step_code == 'booking__services') { 2470 var $services_step = $booking_form_element.find('.step-services-w'); 2471 if ($services_step.hasClass('selecting-item-category')) { 2472 if ($services_step.find('.os-services > .os-item.selected').hasClass('is-preselected')) { 2473 // if service is preselected check if there are both multiple durations and quantity selector and only then show prev button 2474 } else { 2475 latepoint_show_prev_btn($booking_form_element); 2476 } 2477 } else { 2478 latepoint_hide_prev_btn($booking_form_element); 2479 } 2480 } else { 2481 if (!$new_current_step.hasClass('selecting-item-category')) { 2482 latepoint_hide_prev_btn($booking_form_element); 2483 } 2484 } 2485 } 2486 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading'); 2487 2488 2489 if(new_parent_code_name == 'booking' && current_parent_code_name != 'booking' && active_cart_item_id){ 2490 2491 // we are going back to one of the steps of a booking process, we need to remove the item that was just added to the cart and start over 2492 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading'); 2493 let data = { 2494 action: latepoint_helper.route_action, 2495 route_name: latepoint_helper.remove_cart_item_route, 2496 params: jQuery.param({cart_item_id: active_cart_item_id}), 2497 layout: 'none', 2498 return_format: 'json' 2499 } 2500 jQuery.ajax({ 2501 type: "post", 2502 dataType: "json", 2503 url: latepoint_timestamped_ajaxurl(), 2504 data: data, 2505 success: function (data) { 2506 if (data.status === "success") { 2507 $booking_form_element.find('input[name="active_cart_item[id]"]').val(''); 2508 if($booking_form_element.find('input[name="active_cart_item[variant]"]').val() == 'bundle'){ 2509 latepoint_update_active_cart_item_item_data($booking_form_element, 'bundle_id', ''); 2510 $booking_form_element.find('input[name="active_cart_item[variant]"]').val(''); 2511 } 2512 latepoint_reload_summary($booking_form_element); 2513 } else { 2514 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading'); 2515 latepoint_show_message_inside_element
2515(data.message, $booking_form_element.find('.latepoint-body'), 'error'); 2516 } 2517 } 2518 }); 2519 }else{ 2520 latepoint_reload_summary($booking_form_element); 2521 } 2522 setTimeout(function () { 2523 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded'); 2524 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body')); 2525 latepoint_scroll_to_top_of_booking_form($booking_form_element); 2526 }, 150); 2527 }, 700); 2528 return false; 2529 }); 2530 2531 latepoint_init_agent_details_link($booking_form_element); 2532} 2533 2534 2535function latepoint_init_booking_form_by_trigger($trigger) { 2536 let route = latepoint_helper.booking_button_route; 2537 let params = {}; 2538 let restrictions = {}; 2539 let presets = {}; 2540 let booking_element_styles = {}; 2541 if ($trigger.data('show-service-categories')) restrictions.show_service_categories = $trigger.data('show-service-categories'); 2542 if ($trigger.data('show-locations')) restrictions.show_locations = $trigger.data('show-locations'); 2543 if ($trigger.data('show-services')) restrictions.show_services = $trigger.data('show-services'); 2544 if ($trigger.data('show-agents')) restrictions.show_agents = $trigger.data('show-agents'); 2545 if ($trigger.data('calendar-start-date')) restrictions.calendar_start_date = $trigger.data('calendar-start-date'); 2546 2547 if ($trigger.data('selected-location')) presets.selected_location = $trigger.data('selected-location'); 2548 if ($trigger.data('selected-agent')) presets.selected_agent = $trigger.data('selected-agent'); 2549 if ($trigger.data('selected-service')) presets.selected_service = $trigger.data('selected-service'); 2550 if ($trigger.data('selected-bundle')) presets.selected_bundle = $trigger.data('selected-bundle'); 2551 if ($trigger.data('selected-duration')) presets.selected_duration = $trigger.data('selected-duration'); 2552 if ($trigger.data('selected-total-attendees')) presets.selected_total_attendees = $trigger.data('selected-total-attendees'); 2553 if ($trigger.data('selected-service-category')) presets.selected_service_category = $trigger.data('selected-service-category'); 2554 if ($trigger.data('selected-start-date')) presets.selected_start_date = $trigger.data('selected-start-date'); 2555 if ($trigger.data('selected-start-time')) presets.selected_start_time = $trigger.data('selected-start-time'); 2556 if ($trigger.data('order-item-id')) presets.order_item_id = $trigger.data('order-item-id'); 2557 if ($trigger.data('source-id')) presets.source_id = $trigger.data('source-id'); 2558 2559 if ($trigger.data('hide-summary') == 'yes') booking_element_styles.hide_summary = true; 2560 if ($trigger.data('hide-side-panel') == 'yes') booking_element_styles.hide_side_panel = true; 2561 2562 2563 if (jQuery.isEmptyObject(restrictions) == false) params.restrictions = restrictions; 2564 if (jQuery.isEmptyObject(presets) == false) params.presets = presets; 2565 if (jQuery.isEmptyObject(booking_element_styles) == false) params.booking_element_styles = booking_element_styles; 2566 2567 let data = { 2568 action: latepoint_helper.route_action, 2569 route_name: route, 2570 params: params, 2571 layout: 'none', 2572 return_format: 'json' 2573 } 2574 2575 let is_inline_form = $trigger.hasClass('latepoint-book-form-wrapper'); 2576 if(is_inline_form){ 2577 data.params.booking_element_type = 'inline_form'; 2578 } 2579 2580 $trigger.addClass('os-loading'); 2581 jQuery.ajax({ 2582 type: "post", 2583 dataType: "json", 2584 url: latepoint_timestamped_ajaxurl(), 2585 data: data, 2586 success: (data) => { 2587 if (data.status === "success") { 2588 let $booking_form_element = false; 2589 if(is_inline_form){ 2590 $trigger.html(data.message); 2591 $booking_form_element = $trigger.find('.latepoint-booking-form-element'); 2592 }else{ 2593 let lightbox_class = 'booking-form-in-lightbox'; 2594 latepoint_show_data_in_lightbox(data.message, lightbox_class, false); 2595 $booking_form_element = jQuery('.latepoint-lightbox-w .latepoint-booking-form-element'); 2596 jQuery('body').addClass('latepoint-lightbox-active'); 2597 } 2598 latepoint_init_booking_form($booking_form_element); 2599 latepoint_init_step(data.step, $booking_form_element); 2600 $trigger.removeClass('os-loading'); 2601 } else { 2602 $trigger.removeClass('os-loading'); 2603 // console.log(data.message); 2604 } 2605 } 2606 }); 2607} 2608 2609 2610/* 2611 * Copyright (c) 2023 LatePoint LLC. All rights reserved. 2612 */ 2613 2614async function latepoint_init_transaction_payment_form() {
2615 let callbacks_list = []; 2616 let $transaction_payment_form = jQuery('.latepoint-transaction-payment-form'); 2617 let current_step = $transaction_payment_form.find('input[name="current_step"]').val(); 2618 2619 $transaction_payment_form.on('click keydown', '.lp-option', (e) => { 2620 let $option = jQuery(e.currentTarget); 2621 if(e.type === 'keydown' && e.key !== ' ' && e.key !== 'Enter') return; 2622 $option.closest('.lp-options').find('.lp-option.selected').removeClass('selected'); 2623 $option.addClass('selected'); 2624 $transaction_payment_form.find('input[name="' + $option.data('holder') + '"]').val($option.data('value')); 2625 $transaction_payment_form.trigger('submit'); 2626 return false; 2627 }); 2628 2629 2630 switch (current_step) { 2631 case 'methods': 2632 break; 2633 case 'processors': 2634 break; 2635 case 'pay': 2636 $transaction_payment_form.trigger('latepoint:initOrderPaymentMethod', [{ 2637 callbacks_list: callbacks_list, 2638 payment_method: $transaction_payment_form.find('input[name="payment_method"]').val(), 2639 payment_processor: $transaction_payment_form.find('input[name="payment_processor"]').val(), 2640 }]); 2641 $transaction_payment_form.addClass('os-loading'); 2642 2643 try { 2644 for (const callback of callbacks_list) { 2645 await callback.action(); 2646 } 2647 $transaction_payment_form.removeClass('os-loading'); 2648 } catch (error) { 2649 latepoint_show_error_and_stop_loading_booking_form(error, $transaction_payment_form); 2650 } 2651 break; 2652 case 'confirmation': 2653 break; 2654 } 2655 2656 $transaction_payment_form.on('submit', async function (e) { 2657 e.preventDefault(); 2658 await latepoint_submit_transaction_payment_form(jQuery(e.target)); 2659 }); 2660} 2661 2662async function latepoint_submit_transaction_payment_form($transaction_payment_form) { 2663 2664 if($transaction_payment_form.hasClass('os-loading')) return false; 2665 let callbacks_list = []; 2666 2667 $transaction_payment_form.find('.latepoint-message').remove(); 2668 $transaction_payment_form.addClass('os-loading'); 2669 $transaction_payment_form.find('.latepoint-btn').addClass('os-loading'); 2670 2671 $transaction_payment_form.trigger('latepoint:submitTransactionPaymentForm', [{ 2672 callbacks_list: callbacks_list, 2673 payment_method: $transaction_payment_form.find('input[name="payment_method"]').val(), 2674 payment_processor: $transaction_payment_form.find('input[name="payment_processor"]').val(), 2675 current_step: $transaction_payment_form.find('input[name="current_step"]').val(), 2676 }]); 2677 2678 try { 2679 for (const callback of callbacks_list) { 2680 await callback.action(); 2681 } 2682 } catch (error) { 2683 $transaction_payment_form.removeClass('os-loading').find('.os-loading').removeClass('os-loading'); 2684 latepoint_show_message_inside_element(error.message, $transaction_payment_form.find('.lp-payment-method-content'), 'error'); 2685 return false; 2686 } 2687 2688 2689 try { 2690 let response = await jQuery.ajax({ 2691 type: "post", 2692 dataType: "json", 2693 processData: false, 2694 contentType: false, 2695 url: latepoint_timestamped_ajaxurl(), 2696 data: latepoint_create_form_data($transaction_payment_form, latepoint_helper.invoices_payment_form_route) 2697 }); 2698 2699 $transaction_payment_form.removeClass('os-loading').find('.os-loading').removeClass('os-loading'); 2700 2701 if (response.status === 'success') { 2702 $transaction_payment_form.html(response.message); 2703 return await latepoint_init_transaction_payment_form(); 2704 2705 } else { 2706 latepoint_show_message_inside_element(response.message, $transaction_payment_form.find('.lp-payment-method-content'), 'error'); 2707 return false; 2708 } 2709 } catch (e) { 2710 2711 $transaction_payment_form.removeClass('os-loading').find('.os-loading').removeClass('os-loading'); 2712 console.log(e); 2713 alert('Error:' + e); 2714 } 2715 2716} 2717 2718function latepoint_hide_reschedule_button() { 2719 jQuery('.reschedule-confirmation-button-wrapper').hide(); 2720} 2721 2722function latepoint_show_reschedule_button() { 2723 jQuery('.reschedule-confirmation-button-wrapper').show(); 2724} 2725 2726function latepoint_customer_cabinet_reload_booking_tile($booking_tile) { 2727 $booking_tile.addClass('os-loading'); 2728 let params = { 2729 booking_id: $booking_tile.data('id'), 2730 } 2731 let data = { 2732 action: latepoint_helper.route_action, 2733 route_name: $booking_tile.data('route-name'), 2734 params: params, 2735 layout: 'none', 2736 return_format: 'json' 2737 }; 2738 jQuery.ajax({ 2739 type: "post", 2740 dataType: "json", 2741 url: latepoint_timestamped_ajaxurl(), 2742 data: data, 2743 success: function (data) { 2744 $booking_tile.removeClass('os-loading') 2745 if (data.status === "success") { 2746 $booking_tile.replaceWith(data.message); 2747 } else { 2748 alert(data.message); 2749 } 2750 } 2751 }); 2752} 2753 2754 2755function latepoint_init_reschedule() { 2756 2757 jQuery('.reschedule-calendar-wrapper').on('click', '.latepoint-request-reschedule-trigger', function () { 2758 let $trigger = jQuery(this) 2759 let $wrapper = $trigger.closest('.reschedule-calendar-wrapper') 2760 let booking_id = $wrapper.find('input[type="hidden"].latepoint_booking_id').val() 2761 2762 $trigger.addClass('os-loading') 2763 let params = { 2764 booking_id: booking_id, 2765 key: $wrapper.find('input[type="hidden"].latepoint_manage_booking_key').val(), 2766 start_date: $wrapper.find('input[type="hidden"].latepoint_start_date').val(), 2767 start_time: $wrapper.find('input[type="hidden"].latepoint_start_time').val(), 2768 } 2769 let data = { 2770 action: latepoint_helper.route_action, 2771 route_name: $trigger.data('route-name'), 2772 params: params, 2773 layout: 'none', 2774 return_format: 'json' 2775 }; 2776 jQuery.ajax({ 2777 type: "post", 2778 dataType: "json", 2779 url: latepoint_timestamped_ajaxurl(), 2780 data: data, 2781 success: function (data) { 2782 $trigger.removeClass('os-loading') 2783 if (data.status === "success") { 2784 jQuery('.latepoint-lightbox-content').html(data.message); 2785 jQuery('.latepoint-lightbox-footer, .latepoint-lightbox-heading').remove(); 2786 if (jQuery('.customer-bookings-tiles').length) { 2787 // called from customer cabinet 2788 latepoint_customer_cabinet_reload_booking_tile(jQuery('.customer-bookings-tiles .customer-booking[data-id="' + booking_id + '"]')); 2789 } else {
2790 // called from manage by key 2791 latepoint_manage_by_key_reload_booking(); 2792 } 2793 } else { 2794 latepoint_show_message_inside_element(data.message, jQuery('.latepoint-lightbox-content'), 'error'); 2795 jQuery('.latepoint-lightbox-content').animate({scrollTop: 0}, 300); 2796 } 2797 } 2798 }); 2799 return false; 2800 }); 2801 2802 jQuery('.reschedule-calendar-wrapper').on('click keydown', '.dp-timepicker-trigger', function (event) { 2803 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return; 2804 var $reschedule_form_element = jQuery(this).closest('.reschedule-calendar-wrapper'); 2805 if (jQuery(this).hasClass('is-booked') || jQuery(this).hasClass('is-off')) { 2806 // Show error message that you cant select a booked period 2807 } else { 2808 if (jQuery(this).hasClass('selected')) { 2809 jQuery(this).removeClass('selected'); 2810 jQuery(this).find('.dp-success-label').remove(); 2811 $reschedule_form_element.find('.latepoint_start_time').val(''); 2812 latepoint_hide_reschedule_button(); 2813 } else { 2814 $reschedule_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove(); 2815 var selected_timeslot_time = jQuery(this).find('.dp-label-time').html(); 2816 jQuery(this).addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>'); 2817 2818 var minutes = parseInt(jQuery(this).data('minutes')); 2819 var timeshift_minutes = parseInt($reschedule_form_element.find('.latepoint_timeshift_minutes').val()); 2820 // we substract timeshift minutes because its timeshift minutes that the business is running in, in opposite of what we do when we generate a calendar for a client 2821 if (timeshift_minutes) minutes = minutes - timeshift_minutes; 2822 var start_date = new Date($reschedule_form_element.find('.os-day.selected').data('date')); 2823 if (minutes < 0) { 2824 // business minutes are in previous day 2825 minutes = 24 * 60 + minutes; 2826 // move start date back 1 day 2827 start_date.setDate(start_date.getDate() - 1); 2828 } else if (minutes >= 24 * 60) { 2829 // business minutes are in next day 2830 minutes = minutes - 24 * 60; 2831 start_date.setDate(start_date.getDate() + 1); 2832 } 2833 $reschedule_form_element.find('.latepoint_start_date').val(start_date.toISOString().split('T')[0]) 2834 $reschedule_form_element.find('.latepoint_start_time').val(minutes); 2835 latepoint_show_reschedule_button(); 2836 } 2837 } 2838 return false; 2839 }); 2840 2841 2842 jQuery('.reschedule-calendar-wrapper').on('click', '.os-month-next-btn', function () { 2843 var $reschedule_form_element = jQuery(this).closest('.reschedule-calendar-wrapper'); 2844 var next_month_route_name = jQuery(this).data('route'); 2845 if ($reschedule_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length) { 2846 $reschedule_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active'); 2847 latepoint_calendar_set_month_label($reschedule_form_element); 2848 } else { 2849 // TODO add condition to check maximum number months to call into the future 2850 if (true) { 2851 var $btn = jQuery(this); 2852 $btn.addClass('os-loading'); 2853 var $calendar_element = $reschedule_form_element.find('.os-monthly-calendar-days-w').last(); 2854 var calendar_year = $calendar_element.data('calendar-year'); 2855 var calendar_month = $calendar_element.data('calendar-month');
2856 if (calendar_month == 12) { 2857 calendar_year = calendar_year + 1; 2858 calendar_month = 1; 2859 } else { 2860 calendar_month = calendar_month + 1; 2861 } 2862 var data = { 2863 action: latepoint_helper.route_action, 2864 route_name: next_month_route_name, 2865 params: { 2866 timezone_name: $reschedule_form_element.find('input[type="hidden"].latepoint_timezone_name').val(), 2867 key: $reschedule_form_element.find('input[type="hidden"].latepoint_manage_booking_key').val(), 2868 target_date_string: `${calendar_year}-${calendar_month}-1`, 2869 booking: { 2870 id: $reschedule_form_element.find('input[type="hidden"].latepoint_booking_id').val() 2871 } 2872 }, 2873 layout: 'none', 2874 return_format: 'json' 2875 } 2876 jQuery.ajax({ 2877 type: "post", 2878 dataType: "json", 2879 url: latepoint_timestamped_ajaxurl(), 2880 data: data, 2881 success: function (data) { 2882 $btn.removeClass('os-loading'); 2883 if (data.status === "success") { 2884 $reschedule_form_element.find('.os-months').append(data.message); 2885 $reschedule_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active'); 2886 latepoint_calendar_set_month_label($reschedule_form_element); 2887 } else { 2888 // console.log(data.message); 2889 } 2890 } 2891 }); 2892 } 2893 } 2894 latepoint_calendar_show_or_hide_prev_next_buttons($reschedule_form_element); 2895 return false; 2896 }); 2897 2898 jQuery('.reschedule-calendar-wrapper').on('click', '.os-month-prev-btn', function () { 2899 var $reschedule_form_element = jQuery(this).closest('.reschedule-calendar-wrapper'); 2900 if ($reschedule_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) { 2901 $reschedule_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active'); 2902 latepoint_calendar_set_month_label($reschedule_form_element); 2903 } 2904 latepoint_calendar_show_or_hide_prev_next_buttons($reschedule_form_element); 2905 return false; 2906 }); 2907 2908 jQuery('.reschedule-calendar-wrapper .os-months').on('click', '.os-day', function () { 2909 if (jQuery(this).hasClass('os-day-passed')) return false; 2910 if (jQuery(this).hasClass('os-not-in-allowed-period')) return false; 2911 var $reschedule_form_element = jQuery(this).closest('.reschedule-calendar-wrapper'); 2912 if (jQuery(this).closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')) { 2913 2914 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT 2915 if (jQuery(this).hasClass('os-not-available')) { 2916 // clicked on a day that has no available timeslots 2917 // do nothing 2918 } else { 2919 $reschedule_form_element.find('.os-day.selected').removeClass('selected'); 2920 jQuery(this).addClass('selected'); 2921 // set date 2922 $reschedule_form_element.find('.latepoint_start_date').val(jQuery(this).data('date')); 2923 if (jQuery(this).hasClass('os-one-slot-only')) { 2924 // clicked on a day that has only one slot available 2925 var bookable_minutes = jQuery(this).data('bookable-minutes').toString().split(':')[0]; 2926 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number(jQuery(this).data('service-duration'))); 2927 $reschedule_form_element.find('.latepoint_start_time').val(jQuery(this).data('bookable-minutes')); 2928 $reschedule_form_element.find('.time-selector-w').slide
2928Up(200); 2929 latepoint_show_reschedule_button() 2930 } else { 2931 // regular day with more than 1 timeslots available 2932 // build timeslots 2933 day_timeslots(jQuery(this), $reschedule_form_element, $reschedule_form_element.find('.latepoint-lightbox-content')); 2934 // initialize timeslots events 2935 // clear time and hide next btn 2936 $reschedule_form_element.find('.latepoint_start_time').val(''); 2937 } 2938 } 2939 } else { 2940 2941 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT 2942 $reschedule_form_element.find('.latepoint_start_date').val(jQuery(this).data('date')); 2943 $reschedule_form_element.find('.os-day.selected').removeClass('selected'); 2944 jQuery(this).addClass('selected'); 2945 2946 // build timeslots 2947 day_timeslots(jQuery(this), $reschedule_form_element, $reschedule_form_element.find('.latepoint-lightbox-content')); 2948 // initialize timeslots events 2949 // clear time and hide next btn 2950 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element'); 2951 if ($booking_form_element.length) latepoint_reload_summary($booking_form_element); 2952 $reschedule_form_element.find('.latepoint_start_time').val(''); 2953 latepoint_hide_next_btn($reschedule_form_element); 2954 } 2955 2956 return false; 2957 }); 2958} 2959 2960 2961/* 2962 * Copyright (c) 2024 LatePoint LLC. All rights reserved. 2963 */ 2964 2965function latepoint_reload_day_schedule($day_view){ 2966 $day_view.addClass('os-loading'); 2967 let data = { 2968 action: latepoint_helper.route_action, 2969 route_name: $day_view.data('route-name'), 2970 params: $day_view.find("select, textarea, input").serialize(), 2971 layout: 'none', 2972 return_format: 'json' 2973 } 2974 2975 jQuery.ajax({ 2976 type: "post", 2977 dataType: "json", 2978 url: latepoint_timestamped_ajaxurl(), 2979 data: data, 2980 success: function (data) { 2981 if (data.status === "success") { 2982 $day_view.replaceWith(data.message); 2983 } 2984 } 2985 }); 2986} 2987 2988function latepoint_reload_events_calendar($events_calendar){ 2989 $events_calendar.addClass('os-loading'); 2990 let data = { 2991 action: latepoint_helper.route_action, 2992 route_name: $events_calendar.data('route-name'), 2993 params: $events_calendar.find("select, textarea, input").serialize(), 2994 layout: 'none', 2995 return_format: 'json' 2996 } 2997 2998 jQuery.ajax({ 2999 type: "post", 3000 dataType: "json", 3001 url: latepoint_timestamped_ajaxurl(), 3002 data: data, 3003 success: function (data) { 3004 if (data.status === "success") { 3005 $events_calendar.replaceWith(data.message); 3006 } 3007 } 3008 }); 3009 3010} 3011 3012/* 3013 * Copyright (c) 2024 LatePoint LLC. All rights reserved. 3014 */ 3015 3016class LatepointStripeConnectFront { 3017 3018 // Init 3019 constructor(stripeKey) { 3020 this.stripeKey = stripeKey; 3021 this.stripeElements = null; 3022 this.stripeCore = null; 3023 this.stripePaymentMethod = null; 3024 this.stripeContinueOrderIntentURL = null; 3025 this.stripeContinueTransactionIntentURL = null; 3026 this.stripePaymentIntentSecret = null; 3027 this.stripePaymentElement = null; 3028 this.ready(); 3029 } 3030 3031 ready() { 3032 jQuery(document).ready(() => { 3033 jQuery('body').on('latepoint:submitBookingForm', '.latepoint-booking-form-element', (e, data) => { 3034 if (!latepoint_helper.demo_mode && data.is_final_submit && data.direction == 'next') { 3035 let payment_method = jQuery(e.currentTarget).find('input[name="cart[payment_method]"]').val(); 3036 switch (payment_method) { 3037 case 'payment_element': 3038 latepoint_add_action(data.callbacks_list, async () => { 3039 if (this.stripePaymentIntentSecret && this.stripeCore) { 3040 return await this.confirmPaymentElementPayment(jQuery(e.currentTarget)); 3041 } 3042 }); 3043 break; 3044 } 3045 } 3046 }); 3047 jQuery('body').on('latepoint:submitTransactionPaymentForm', '.latepoint-transaction-payment-form', (e, data) => { 3048 if (data.current_step === 'pay' && data.payment_processor === 'stripe_connect' && data.payment_method === 'payment_element') { 3049 latepoint_add_action(data.callbacks_list, async () => { 3050 if (this.stripePaymentIntentSecret && this.stripeCore) { 3051 return await this.confirmPaymentElementPaymentForTransaction(jQuery(e.currentTarget)); 3052 } 3053 }); 3054 } 3055 }); 3056 3057 // INITIALIZE PAYMENT METHOD 3058 jQuery('body').on('latepoint:initPaymentMethod', '.latepoint-booking-form-element', (e, data) => { 3059 if (!latepoint_helper.demo_mode) { 3060 switch (data.payment_method) { 3061 case 'payment_element': 3062 latepoint_add_action(data.callbacks_list, async () => { 3063 return await this.createPaymentIntent(jQuery(e.currentTarget), data.payment_method); 3064 }); 3065 break; 3066 } 3067 } else { 3068 latepoint_show_next_btn(jQuery(e.currentTarget)); 3069 } 3070 }); 3071 // INITIALIZE PAYMENT METHOD on order payment form 3072 jQuery('body').on('latepoint:initOrderPaymentMethod', '.latepoint-transaction-payment-form', (e, data) => { 3073 if (data.payment_processor === 'stripe_connect') { 3074 switch (data.payment_method) { 3075 case 'payment_element': 3076 latepoint_add_action(data.callbacks_list, async () => { 3077 return await this.createPaymentIntentForTransaction(jQuery(e.currentTarget)); 3078 }); 3079 break; 3080 } 3081 } 3082 }); 3083 }); 3084 } 3085 3086 3087 async createPaymentIntentForTransaction($transaction_intent_form) { 3088 3089 try { 3090 this.stripeCore = Stripe(this.stripeKey, {stripeAccount: latepoint_helper.stripe_connected_account_id}); 3091 this.stripeElements = this.stripeCore.elements(); 3092 }catch(e){ 3093 console.log(e); 3094 alert(e); 3095 } 3096 3097 let data = latepoint_create_form_data($transaction_intent_form, latepoint_helper.stripe_connect_route_create_payment_intent_for_transaction_intent); 3098 3099 let response = await jQuery.ajax({ 3100 type: "post", 3101 dataType: "json", 3102 processData: false, 3103 contentType: false, 3104 url: latepoint_timestamped_ajaxurl(), 3105 data: data 3106 }); 3107 3108 if (response.status === "success") { 3109 $transaction_intent_form.find('input[name="payment_token"]').val(response.payment_intent_id); 3110 this.stripePaymentIntentSecret = response.payment_intent_secret; 3111 this.stripeContinueTransactionIntentURL = response.continue_transaction_intent_url; 3112 latepoint_show_next_btn($transaction_intent_form); 3113 3114 if ($transaction_intent_form.find('.stripe-payment-element').length) { 3115 return this.initPaymentElement($transaction_intent_form); 3116 } 3117 } else { 3118 alert(response.message); 3119 throw new Error(response.message); 3120 } 3121 } 3122 3123 async createPaymentIntent($booking_form_element, payment_method) { 3124 this.stripeCore = Stripe(this.stripeKey, {stripeAccount: latepoint_helper.stripe_connected_account_id}); 3125 this.stripeElements = this.stripeCore.elements(); 3126 3127 let data = latepoint_create_form_data($booking_form_element.find('.latepoint-form'), latepoint_helper.stripe_connect_route_create_payment_intent, {booking_form_page_url: window.location.href}); 3128 3129 let response = await jQuery.ajax({ 3130 type: "post", 3131 dataType: "json", 3132 processData: false, 3133 contentType: false, 3134 url: latepoint_timestamped_ajaxurl(), 3135 data: data 3136 }); 3137 3138 if (response.status === "success") { 3139 $booking_form_element.find('input[name="cart[payment_token]"]').val(response.payment_intent_id); 3140 this.stripePaymentIntentSecret = response.payment_intent_secret; 3141 this.stripeContinueOrderIntentURL = response.continue_order_intent_url; 3142 latepoint_show_next_btn($booking_form_element); 3143 3144 if ($booking_form_element.find('.stripe-payment-element').length) { 3145 return this.initPaymentElement($booking_form_element); 3146 } 3147 } else { 3148 alert(response.message); 3149 throw new Error(response.message); 3150 } 3151 } 3152 3153 async confirmPaymentElementPaymentForTransaction($transaction_intent_form) { 3154 let elements = this.stripeElements; 3155 let continue_transaction_intent_url = this.stripeContinueTransactionIntentURL; 3156 let result = await this.stripeCore.confirmPayment({ 3157 elements, 3158 confirmParams: { 3159 // Return URL where the customer should be redirected after the PaymentIntent is confirmed. 3160 return_url: continue_transaction_intent_url, 3161 }, 3162 redirect: "if_required", 3163 }); 3164 if (result.error) { 3165 throw new Error(result.error.message); 3166 } else { 3167 $transaction_intent_form.find('input[name="payment_token"]').val(result.paymentIntent.i
3167d); 3168 return result.paymentIntent.id; 3169 } 3170 } 3171 3172 async confirmPaymentElementPayment($booking_form_element) { 3173 let elements = this.stripeElements; 3174 let continue_order_intent_url = this.stripeContinueOrderIntentURL; 3175 let result = await this.stripeCore.confirmPayment({ 3176 elements, 3177 confirmParams: { 3178 // Return URL where the customer should be redirected after the PaymentIntent is confirmed. 3179 return_url: continue_order_intent_url, 3180 }, 3181 redirect: "if_required", 3182 }); 3183 if (result.error) { 3184 throw new Error(result.error.message); 3185 } else { 3186 $booking_form_element.find('input[name="cart[payment_token]"]').val(result.paymentIntent.id); 3187 return result.paymentIntent.id; 3188 } 3189 } 3190 3191 initPaymentElement($booking_form_element) { 3192 let appearance = { 3193 theme: 'stripe', 3194 variables: { 3195 fontFamily: 'Overpass', 3196 colorPrimary: '#1d7bff' 3197 }, 3198 rules: { 3199 '.Tab': { 3200 border: '1px solid #E0E6EB', 3201 boxShadow: 'none', 3202 borderRadius: '0', 3203 marginBottom: '10px' 3204 }, 3205 '.Input': { 3206 boxShadow: 'none', 3207 borderRadius: '0' 3208 }, 3209 3210 '.Tab:hover': { 3211 color: 'var(--colorText)', 3212 }, 3213 3214 '.Tab--selected': { 3215 borderColor: 'var(--colorPrimary)', 3216 boxShadow: `0 0 0 1px var(--colorPrimary)`, 3217 }, 3218 3219 '.Input--invalid': { 3220 boxShadow: '0 1px 1px 0 rgba(0, 0, 0, 0.07), 0 0 0 2px var(--colorPrimary)', 3221 }, 3222 3223 // See all supported class names and selector syntax below 3224 } 3225 }; 3226 3227 3228 // Create an instance of the Payment Element 3229 this.stripeElements = this.stripeCore.elements({ 3230 clientSecret: this.stripePaymentIntentSecret, 3231 appearance, 3232 fonts: [{cssSrc: 'https://fonts.googleapis.com/css2?family=Overpass&display=swap'}], 3233 }); 3234 3235 let options = { 3236 layout: { 3237 type: 'tabs', 3238 defaultCollapsed: false, 3239 }, 3240 }; 3241 this.stripePaymentElement = this.stripeElements.create('payment', options); 3242 3243 return this.stripePaymentElement.mount($booking_form_element.find('.stripe-payment-element')[0]); 3244 } 3245 3246 3247} 3248 3249 3250if (latepoint_helper.is_stripe_connect_enabled) window.latepointStripeConnectFront = new LatepointStripeConnectFront(latepoint_helper.stripe_connect_key); 3251 3252/* 3253 * Copyright (c) 2022 LatePoint LLC. All rights reserved. 3254 */ 3255// @codekit-prepend "bin/time.js" 3256// @codekit-prepend "bin/shared.js" 3257// @codekit-prepend "bin/notifications.js"; 3258// @codekit-prepend "bin/actions.js" 3259// @codekit-prepend "bin/front/main.js" 3260// @codekit-prepend "bin/front/_customer.js" 3261// @codekit-prepend "bin/front/_events.js" 3262// @codekit-prepend "bin/front/_stripe_connect.js" 3263 3264 3265// DOCUMENT READY 3266jQuery(document).ready(function ($) { 3267 3268 latepoint_init_customer_dashboard(); 3269 latepoint_init_manage_booking_by_key(); 3270 3271 3272 jQuery('body').on('click', '.le-filter-trigger', function () { 3273 let $events_calendar = jQuery(this).closest('.latepoint-calendar-wrapper'); 3274 if ($events_calendar.hasClass('show-filters')) { 3275 $events_calendar.removeClass('show-filters'); 3276 $events_calendar.find('.latepoint-calendar-filters select').val(''); 3277 latepoint_reload_events_calendar($events_calendar); 3278 } else { 3279 $events_calendar.addClass('show-filters'); 3280 } 3281 return false; 3282 }); 3283 3284 jQuery('body').on('click', '.le-navigation-trigger', function () { 3285 let $trigger = jQuery(this); 3286 let $events_calendar = $trigger.closest('.latepoint-calendar-wrapper'); 3287 $events_calendar.find('input[name="target_date_string"]').val($trigger.data('target-date')); 3288 $trigger.addClass('os-loading'); 3289 latepoint_reload_events_calendar($events_calendar); 3290 return false;
3291 }); 3292 3293 jQuery('body').on('change', '.le-day-filters select', function () { 3294 let $trigger = jQuery(this); 3295 let $day_view = $trigger.closest('.le-day-view-wrapper'); 3296 latepoint_reload_day_schedule($day_view); 3297 return false; 3298 }); 3299 3300 jQuery('body').on('change', '.latepoint-calendar-filters select, .le-range-selector select', function () { 3301 let $trigger = jQuery(this); 3302 let $events_calendar = $trigger.closest('.latepoint-calendar-wrapper'); 3303 $events_calendar.find('.le-filter').addClass('os-loading'); 3304 latepoint_reload_events_calendar($events_calendar); 3305 return false; 3306 }); 3307 3308 jQuery('body').on('click', '.close-calendar-types', function () { 3309 jQuery(this).closest('.add-to-calendar-wrapper').removeClass('show-types'); 3310 return false; 3311 }); 3312 jQuery('body').on('click', '.open-calendar-types', function () { 3313 jQuery(this).closest('.add-to-calendar-wrapper').addClass('show-types'); 3314 return false; 3315 }); 3316 3317 jQuery('body').on('latepoint:nextStepClicked', '.latepoint-booking-form-element', (e, data) => { 3318 3319 latepoint_add_action(data.callbacks_list, async () => { 3320 let $booking_form = jQuery(e.currentTarget).find('.latepoint-form'); 3321 let errors = latepoint_validate_form($booking_form); 3322 if (errors.length) { 3323 let error_messages = errors.map(error => error.message).join(', '); 3324 throw new Error(error_messages); 3325 } else { 3326 return true; 3327 } 3328 }, 1); 3329 3330 }); 3331 3332 if (latepoint_helper.start_from_order_intent_key) { 3333 $('body').append('<div class="latepoint-continue-intent-loading"></div>'); 3334 3335 var data = { 3336 action: latepoint_helper.route_action, 3337 route_name: latepoint_helper.start_from_order_intent_route, 3338 params: {order_intent_key: latepoint_helper.start_from_order_intent_key}, 3339 layout: 'none', 3340 return_format: 'json' 3341 } 3342 3343 $.ajax({ 3344 type: "post", 3345 dataType: "json", 3346 url: latepoint_timestamped_ajaxurl(), 3347 data: data, 3348 success: function (data) { 3349 $('.latepoint-continue-intent-loading').remove(); 3350 if (data.status === "success") { 3351 var lightbox_class = ''; 3352 latepoint_show_data_in_lightbox(data.message, data.lightbox_class); 3353 var $booking_form_element = jQuery('.latepoint-lightbox-w .latepoint-booking-form-element'); 3354 latepoint_init_booking_form($booking_form_element); 3355 $booking_form_element.find('.latepoint-step-content').addClass('is-hidden').last().removeClass('is-hidden'); 3356 if ($booking_form_element.find('.latepoint-step-content').length > 1) latepoint_show_prev_btn($booking_form_element); 3357 var $booking_form_element = jQuery('.latepoint-lightbox-w .latepoint-booking-form-element'); 3358 $booking_form_element.find('.latepoint-step-content').each(function () { 3359 latepoint_init_step($(this).data('step-code'), $booking_form_element); 3360 }); 3361 $('body').addClass('latepoint-lightbox-active'); 3362 } else { 3363 // console.log(data.message); 3364 } 3365 } 3366 }); 3367 } 3368 3369 if (jQuery('.latepoint-booking-form-element').length) { 3370 jQuery('.latepoint-booking-form-element').each(function () { 3371 latepoint_init_booking_form(jQuery(this)); 3372 latepoint_init_step(jQuery(this).find('.latepoint_current_step_code').val(), jQuery(this)); 3373 }); 3374 } 3375 3376 3377 jQuery('body').on('click', '.latepoint-lightbox-close', function () { 3378 latepoint_lightbox_close(); 3379 return false; 3380 }); 3381 3382 3383 jQuery('body').on('click', '.os-step-tabs .os-step-tab', function () { 3384 jQuery(this).closest('.os-step-tabs').find('.os-step-tab').removeClass('active'); 3385 jQuery(this).addClass('active'); 3386 var target = jQuery(this).data('target'); 3387 jQuery(this).closest('.os-step-tabs-w').find('.os-step-tab-content').hide(); 3388 jQuery(target).show(); 3389 }); 3390 3391 jQuery('body').on('keyup', '.os-form-group .os-form-control', function () { 3392 if (jQuery(this).val()) { 3393 jQuery(this).closest('.os-form-group').addClass('has-value'); 3394 } else { 3395 jQuery(this).closest('.os-form-group').removeClass('has-value'); 3396 } 3397 }); 3398 3399 jQuery('.latepoint-tab-triggers').on('click', '.latepoint-tab-trigger', function () { 3400 var $tabs_wrapper = jQuery(this).closest('.latepoint-tabs-w') 3401 $tabs_wrapper.find('.latepoint-tab-trigger.active').removeClass('active'); 3402 $tabs_wrapper.find('.latepoint-tab-content').removeClass('active'); 3403 jQuery(this).addClass('active'); 3404 $tabs_wrapper.find('.latepoint-tab-content' + jQuery(this).data('tab-target')).addClass('active'); 3405 return false;
3406 }); 3407 3408 3409 // Main Button to trigger lightbox opening 3410 if(jQuery('.latepoint-book-form-wrapper').length){ 3411 jQuery('.latepoint-book-form-wrapper').each(function(){ 3412 latepoint_init_booking_form_by_trigger(jQuery(this)); 3413 }); 3414 } 3415 3416 jQuery('body').on('click', '.latepoint-book-button, .os_trigger_booking', function () { 3417 latepoint_init_booking_form_by_trigger(jQuery(this)); 3418 return false; 3419 }); 3420 3421});
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.