PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.1.8
LatePoint – Calendar Booking Plugin for Appointments and Events v5.1.8
5.6.7 5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / assets / javascripts / bin / front / main.js
latepoint / lib / assets / javascripts / bin / front Last commit date
_customer.js 1 year ago _events.js 1 year ago _stripe_connect.js 1 year ago main.js 1 year ago
main.js
1865 lines
1 /*
2 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
3 */
4
5
6 function latepoint_init_order_summary_lightbox() {
7 let $lightbox = jQuery('.customer-dashboard-order-summary-lightbox');
8 latepoint_init_qr_trigger($lightbox);
9 latepoint_init_item_details_popup($lightbox);
10 }
11
12 function latepoint_init_qr_trigger($lightbox){
13 $lightbox.on('click', '.qr-show-trigger', function () {
14 jQuery(this).closest('.summary-box-wrapper').find('.qr-code-on-full-summary').toggleClass('show-vevent-qr-code');
15 return false;
16 });
17 }
18
19 function latepoint_init_item_details_popup($lightbox){
20
21 $lightbox.on('click', '.os-item-details-popup-close', function () {
22 var $ligthbox = jQuery(this).closest('.latepoint-lightbox-content');
23 $ligthbox.find('.os-item-details-popup.open').remove();
24 $ligthbox.find('.full-summary-wrapper').show();
25 $ligthbox.find('.booking-status-info-wrapper').show();
26 return false;
27 });
28
29 $lightbox.on('click', '.os-trigger-item-details-popup', function () {
30 var $ligthbox = jQuery(this).closest('.latepoint-lightbox-content');
31 $ligthbox.find('.full-summary-wrapper').hide();
32 $ligthbox.find('.booking-status-info-wrapper').hide();
33 $ligthbox.find('.os-item-details-popup.open').remove();
34 var $popup = $ligthbox.find('#' + jQuery(this).data('item-details-popup-id')).clone();
35 $popup.addClass('open').appendTo($ligthbox);
36 return false;
37 });
38 }
39
40 function latepoint_init_bundle_scheduling_summary() {
41
42 }
43
44
45 function latepoint_manage_by_key_reload_booking() {
46 let $wrapper = jQuery('.manage-booking-wrapper');
47 $wrapper.addClass('os-loading')
48 let params = {
49 key: $wrapper.data('key')
50 }
51 let data = {
52 action: latepoint_helper.route_action,
53 route_name: $wrapper.data('route-name'),
54 params: params,
55 layout: 'none',
56 return_format: 'json'
57 };
58
59 jQuery.ajax({
60 type: "post",
61 dataType: "json",
62 url: latepoint_timestamped_ajaxurl(),
63 data: data,
64 success: function (data) {
65 $wrapper.removeClass('os-loading')
66 if (data.status === "success") {
67 $wrapper.replaceWith(data.message);
68 } else {
69 latepoint_show_message_inside_element(data.message, $wrapper, 'error');
70 }
71 }
72 });
73 }
74
75 function latepoint_init_manage_booking_by_key() {
76 let $wrapper = jQuery('.manage-booking-wrapper');
77 if (!$wrapper.length) return;
78 jQuery('.latepoint-w').on('change', '.change-booking-status-trigger', function () {
79 $wrapper.addClass('os-loading')
80 let params = {
81 key: $wrapper.data('key'),
82 status: jQuery(this).val()
83 }
84 let data = {
85 action: latepoint_helper.route_action,
86 route_name: jQuery(this).closest('.change-booking-status-trigger-wrapper').data('route-name'),
87 params: params,
88 layout: 'none',
89 return_format: 'json'
90 };
91
92 jQuery.ajax({
93 type: "post",
94 dataType: "json",
95 url: latepoint_timestamped_ajaxurl(),
96 data: data,
97 success: function (data) {
98 $wrapper.removeClass('os-loading')
99 if (data.status === "success") {
100 latepoint_manage_by_key_reload_booking();
101 } else {
102 latepoint_show_message_inside_element(data.message, $wrapper, 'error');
103 }
104 }
105 });
106 return false;
107 });
108
109
110 $wrapper.on('click', '.qr-show-trigger', function () {
111 jQuery(this).closest('.manage-booking-wrapper').find('.qr-code-on-full-summary').addClass('show-vevent-qr-code');
112 return false;
113 });
114 $wrapper.on('click', '.os-item-details-popup-close', function () {
115 var $wrapper = jQuery(this).closest('.manage-booking-wrapper');
116 $wrapper.find('.os-item-details-popup.open').remove();
117 $wrapper.find('.manage-booking-inner, .manage-booking-controls').show();
118 return false;
119 });
120
121 $wrapper.on('click', '.os-trigger-item-details-popup', function () {
122 var $wrapper = jQuery(this).closest('.manage-booking-wrapper');
123 $wrapper.find('.manage-booking-inner, .manage-booking-controls').hide();
124 $wrapper.find('.os-item-details-popup.open').remove();
125 var $popup = $wrapper.find('#' + jQuery(this).data('item-details-popup-id')).clone();
126 $popup.addClass('open').appendTo($wrapper);
127 return false;
128 });
129 }
130
131 function latepoint_init_form_masks() {
132 if (('lp_intlTelInput' in window) && ('lp_intlTelInputGlobals' in window)) {
133 jQuery('.os-mask-phone').each(function () {
134 latepoint_mask_phone(jQuery(this));
135 });
136 }
137 }
138
139 function latepoint_scroll_to_top_of_booking_form($booking_form_element) {
140 // if it's a form shortcode (not lightbox), scroll to top of the form
141 if ($booking_form_element.parent().hasClass('latepoint-inline-form')) {
142 $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
143 }
144 // if lightbox - scroll body of lightbox to top
145 if ($booking_form_element.parent().hasClass('latepoint-lightbox-i')) {
146 $booking_form_element.find('.latepoint-body').scrollTop(0);
147 }
148 }
149
150 async function latepoint_init_payment_method_actions($booking_form_element, payment_method) {
151 let callbacks_list = [];
152 let is_last_step = $booking_form_element.data('next-submit-is-last') == 'yes';
153 $booking_form_element.trigger('latepoint:initPaymentMethod', [{
154 payment_method: payment_method,
155 callbacks_list: callbacks_list,
156 is_last_step: is_last_step
157 }]);
158 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
159
160
161 try {
162 for (const callback of callbacks_list) {
163 await callback.action();
164 }
165 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded').find('.lp-payment-method-content[data-payment-method="' + payment_method + '"]').show();
166 } catch (error) {
167 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
168 }
169 }
170
171 function latepoint_lightbox_close() {
172 jQuery('body').removeClass('latepoint-lightbox-active');
173 jQuery('.latepoint-lightbox-w').remove();
174 }
175
176 function latepoint_show_next_btn($booking_form_element) {
177 $booking_form_element.find('.latepoint-next-btn').removeClass('disabled');
178 $booking_form_element.removeClass('hidden-buttons');
179 }
180
181 function clear_step_services($booking_form_element) {
182 }
183
184 function clear_step_service_extras($booking_form_element) {
185 }
186
187 function clear_step_locations($booking_form_element) {
188 }
189
190 function clear_step_agents($booking_form_element) {
191 }
192
193 function clear_step_datepicker($booking_form_element) {
194 }
195
196 function latepoint_hide_next_btn($booking_form_element) {
197 $booking_form_element.find('.latepoint-next-btn').addClass('disabled');
198 if ($booking_form_element.find('.latepoint-prev-btn.disabled').length) $booking_form_element.addClass('hidden-buttons');
199 }
200
201
202 function latepoint_show_prev_btn($booking_form_element) {
203 $booking_form_element.find('.latepoint-prev-btn').removeClass('disabled');
204 $booking_form_element.removeClass('hidden-buttons');
205 }
206
207 function latepoint_hide_prev_btn($booking_form_element) {
208 $booking_form_element.find('.latepoint-prev-btn').addClass('disabled');
209 if ($booking_form_element.find('.latepoint-next-btn.disabled').length) $booking_form_element.addClass('hidden-buttons');
210 }
211
212
213 function latepoint_remove_cart_item($trigger) {
214 let $booking_form_element = $trigger.closest('.latepoint-booking-form-element');
215 let cart_item_id = $trigger.data('cart-item-id');
216
217
218 $trigger.addClass('os-loading');
219 let data = {
220 action: latepoint_helper.route_action,
221 route_name: $trigger.data('route'),
222 params: jQuery.param({cart_item_id: cart_item_id}),
223 layout: 'none',
224 return_format: 'json'
225 }
226 jQuery.ajax({
227 type: "post",
228 dataType: "json",
229 url: latepoint_timestamped_ajaxurl(),
230 data: data,
231 success: function (data) {
232 if (data.status === "success") {
233 if (cart_item_id != $booking_form_element.find('input[name="active_cart_item[id]"]').val()) {
234 // cart has other items - just reload the summary/step
235 if ($trigger.closest('.latepoint-summary-w').length) {
236 // removed by clicking on summary side panel
237 latepoint_reload_summary($booking_form_element);
238 } else {
239 // remove by clicking on cart item on verify step
240 latepoint_reload_step($booking_form_element);
241 }
242 } else {
243 // this was a last item, need to go back to the start of a booking process
244 latepoint_restart_booking_process($booking_form_element);
245 }
246 } else {
247 $trigger.removeClass('os-loading');
248 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
249 }
250 }
251 });
252 }
253
254 function latepoint_apply_coupon($elem) {
255 var $booking_form_element = $elem.closest('.latepoint-booking-form-element');
256
257 var $coupon_input = $elem;
258 $coupon_input.closest('.coupon-code-input-w').addClass('os-loading');
259 var form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
260 var data = {
261 action: latepoint_helper.route_action,
262 route_name: $elem.data('route'),
263 params: latepoint_formdata_to_url_encoded_string(form_data),
264 layout: 'none',
265 return_format: 'json'
266 }
267 jQuery.ajax({
268 type: "post",
269 dataType: "json",
270 url: latepoint_timestamped_ajaxurl(),
271 data: data,
272 success: function (data) {
273 $coupon_input.closest('.coupon-code-input-w').removeClass('os-loading');
274 if (data.status === "success") {
275 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'success');
276 $booking_form_element.find('.step-payment-w input[name="cart[payment_method]"]').val('');
277 $booking_form_element.find('input[name="cart[payment_token]"]').val('');
278 $booking_form_element.find('input[name="cart[payment_portion]"]').val('');
279 latepoint_reload_step($booking_form_element);
280 } else {
281 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
282 }
283 }
284 });
285 }
286
287 function latepoint_remove_coupon($elem) {
288 $elem.closest('.applied-coupon-code-wrapper').fadeOut();
289 var $booking_form_element = $elem.closest('.latepoint-booking-form-element');
290 let $coupon_input = $booking_form_element.find('input[name="coupon_code"]');
291 $coupon_input.val('');
292 latepoint_apply_coupon($coupon_input);
293 }
294
295 function latepoint_restart_booking_process($booking_form_element) {
296 // first first step
297 let first_step_code = $booking_form_element.find('.latepoint-step-content').first().data('step-code');
298 latepoint_reload_step($booking_form_element, first_step_code);
299 return false;
300 }
301
302 function latepoint_reload_step($booking_form_element, step_code = false) {
303
304 if (step_code) {
305 $booking_form_element.find('.latepoint_current_step_code').val(step_code);
306 $booking_form_element.removeClass(function (index, className) {
307 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
308 }).addClass('current-step-' + step_code);
309 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]')) {
310 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').nextAll('.latepoint-step-content').remove();
311 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').remove();
312 }
313 }
314
315 $booking_form_element.find('.latepoint_step_direction').val('specific');
316 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form'));
317
318 return false;
319 }
320
321
322 function latepoint_reset_password_from_booking_init() {
323 jQuery('.os-step-existing-customer-login-w').hide();
324 jQuery('.os-password-reset-form-holder').on('click', '.password-reset-back-to-login', function () {
325 jQuery('.os-password-reset-form-holder').html('');
326 jQuery('.os-step-existing-customer-login-w').show();
327 return false;
328 });
329 }
330
331 function latepoint_bundle_selected($item) {
332 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
333 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('bundle');
334 $booking_form_element.find('input[name="booking[service_id]"]').val('');
335 }
336
337 function latepoint_service_selected($item) {
338 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
339 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('booking');
340 }
341
342 async function latepoint_reload_summary($booking_form_element) {
343 let $summary_panel = $booking_form_element.closest('.latepoint-with-summary');
344 if (!$summary_panel.length) return;
345
346 if ($booking_form_element.hasClass('is-bundle-scheduling')) {
347 return;
348 }
349
350 let current_step = $booking_form_element.find('.latepoint_current_step_code').val();
351
352 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading');
353 let $booking_form = $booking_form_element.find('.latepoint-form');
354 let form_data = new FormData($booking_form[0]);
355 let data = {
356 action: latepoint_helper.route_action,
357 route_name: latepoint_helper.reload_booking_form_summary_route,
358 params: latepoint_formdata_to_url_encoded_string(form_data),
359 layout: 'none',
360 return_format: 'json'
361 }
362
363 let response = await jQuery.ajax({
364 type: "post",
365 dataType: "json",
366 url: latepoint_timestamped_ajaxurl(),
367 data: data
368 });
369 if (response.status === 'success') {
370 $booking_form_element.find('.os-summary-contents').html(response.message);
371 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading');
372 // hide on verify and confirmation steps
373 if (current_step && !['verify', 'confirmation'].includes(current_step) && response.message) {
374 $summary_panel.addClass('latepoint-summary-is-open');
375 } else {
376 $summary_panel.removeClass('latepoint-summary-is-open');
377 }
378 latepoint_init_booking_summary_panel($booking_form_element);
379 } else {
380 throw new Error(response.message ? response.message : 'Error reloading summary');
381 }
382 }
383
384 function latepoint_init_booking_summary_panel($booking_form_element) {
385 let $summary_panel = $booking_form_element.find('.latepoint-summary-w');
386 if (!$summary_panel.length) return;
387
388 $summary_panel.find('.price-breakdown-unfold').on('click', function () {
389 jQuery(this).closest('.summary-price-breakdown-wrapper').removeClass('compact-summary');
390 return false;
391 });
392
393 $summary_panel.find('.os-remove-item-from-cart').on('click keydown', function (event) {
394 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
395 latepoint_remove_cart_item(jQuery(this));
396 return false;
397 });
398 }
399
400 function latepoint_password_changed_show_login(response) {
401 jQuery('.os-step-existing-customer-login-w').show();
402 jQuery('.os-password-reset-form-holder').html('');
403 latepoint_show_message_inside_element(response.message, jQuery('.os-step-existing-customer-login-w'), 'success');
404 }
405
406 function latepoint_hide_message_inside_element($elem = jQuery('.latepoint-body')) {
407 if ($elem.length && $elem.find('.latepoint-message').length) {
408 $elem.find('.latepoint-message').remove();
409 }
410 }
411
412 function latepoint_show_message_inside_element(message, $elem = jQuery('.latepoint-body'), message_type = 'error') {
413 message = message || 'Error. Please try again.';
414 if ($elem.length) {
415 if ($elem.find('.latepoint-message').length) {
416 $elem.find('.latepoint-message').removeClass('latepoint-message-success').removeClass('latepoint-message-error').addClass('latepoint-message-' + message_type + '').html(message).show();
417 } else {
418 $elem.prepend('<div class="latepoint-message latepoint-message-' + message_type + '">' + message + '</div>');
419 }
420 // scroll errors into view
421 if (message_type == 'error') $elem.find('.latepoint-message')[0].scrollIntoView();
422 }
423 }
424
425 function latepoint_add_action(callbacks_list, action, priority = 10) {
426 callbacks_list.push({priority: priority, action: action});
427 callbacks_list.sort((a, b) => a.priority - b.priority);
428 return callbacks_list;
429 }
430
431 function latepoint_update_next_btn_label($booking_form_element) {
432 let btn_label = $booking_form_element.find('.latepoint-step-content').last().data('next-btn-label')
433 if (btn_label) {
434 $booking_form_element.find('.latepoint-next-btn span').text(btn_label);
435 }
436 }
437
438 function latepoint_init_step(step_code, $booking_form_element) {
439 latepoint_init_step_selectable_items($booking_form_element);
440 latepoint_init_step_category_items(step_code);
441 switch (step_code) {
442 case 'customer':
443 latepoint_init_step_contact();
444 break;
445 case 'booking__datepicker':
446 latepoint_init_step_datepicker($booking_form_element);
447 break;
448 case 'booking__agents':
449 latepoint_init_step_agents();
450 break;
451 case 'booking__locations':
452 latepoint_init_step_locations();
453 break;
454 case 'booking__services':
455 latepoint_init_step_services();
456 break;
457 case 'payment__methods':
458 latepoint_init_step_payment__methods($booking_form_element);
459 break;
460 case 'payment__times':
461 latepoint_init_step_payment__times($booking_form_element);
462 break;
463 case 'payment__portions':
464 latepoint_init_step_payment__portions($booking_form_element);
465 break;
466 case 'payment__pay':
467 latepoint_init_step_payment__pay($booking_form_element);
468 break;
469 case 'verify':
470 latepoint_init_step_verify($booking_form_element);
471 break;
472 case 'confirmation':
473 latepoint_init_step_confirmation($booking_form_element);
474 break;
475 }
476
477 $booking_form_element.trigger("latepoint:initStep", [{step_code: step_code}]);
478 $booking_form_element.trigger("latepoint:initStep:" + step_code);
479 }
480
481
482 async function latepoint_generate_day_timeslots($day, $wrapper_element = false, $scrollable_wrapper = false) {
483 if (!$wrapper_element) $wrapper_element = $day.closest('.latepoint-booking-form-element');
484
485 $day.addClass('selected');
486
487 var service_duration = $day.data('service-duration');
488 var interval = $day.data('interval');
489 var work_start_minutes = $day.data('work-start-time');
490 var work_end_minutes = $day.data('work-end-time');
491 var total_work_minutes = $day.data('total-work-minutes');
492 var bookable_minutes = [];
493 var available_capacities_of_bookable_minute = [];
494 if ($day.attr('data-bookable-minutes')) {
495 if ($day.data('bookable-minutes').toString().indexOf(':') > -1) {
496 // has capacity information embedded into bookable minutes string
497 let bookable_minutes_with_capacity = $day.data('bookable-minutes').toString().split(',');
498 for (let i = 0; i < bookable_minutes_with_capacity.length; i++) {
499 bookable_minutes.push(parseInt(bookable_minutes_with_capacity[i].split(':')[0]));
500 available_capacities_of_bookable_minute.push(parseInt(bookable_minutes_with_capacity[i].split(':')[1]));
501 }
502 } else {
503 bookable_minutes = $day.data('bookable-minutes').toString().split(',').map(Number);
504 }
505 }
506 var work_minutes = $day.data('work-minutes').toString().split(',').map(Number);
507
508 var $timeslots = $wrapper_element.find('.timeslots');
509 $timeslots.html('');
510
511 if (total_work_minutes > 0 && bookable_minutes.length && work_minutes.length) {
512 var prev_minutes = false;
513 work_minutes.forEach(function (current_minutes) {
514 var ampm = latepoint_am_or_pm(current_minutes);
515
516 var timeslot_class = 'dp-timepicker-trigger';
517 var timeslot_available_capacity = 0;
518 if (latepoint_helper.time_pick_style == 'timeline') {
519 timeslot_class += ' dp-timeslot';
520 } else {
521 timeslot_class += ' dp-timebox';
522 }
523
524 if (prev_minutes !== false && ((current_minutes - prev_minutes) > service_duration)) {
525 // show interval that is off between two work periods
526 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);
527 var off_width = (((current_minutes - prev_minutes - service_duration) / total_work_minutes) * 100);
528 $timeslots.append('<div class="' + timeslot_class + ' is-off" style="max-width:' + off_width + '%; width:' + off_width + '%"><span class="dp-label">' + off_label + '</span></div>');
529 }
530
531 if (!bookable_minutes.includes(current_minutes)) {
532 timeslot_class += ' is-booked';
533 } else {
534 if (available_capacities_of_bookable_minute.length) timeslot_available_capacity = available_capacities_of_bookable_minute[bookable_minutes.indexOf(current_minutes)];
535 }
536 var tick_html = '';
537 var capacity_label = '';
538 var capacity_label_html = '';
539 var capacity_internal_label_html = '';
540
541 if (((current_minutes % 60) == 0) || (interval >= 60)) {
542 timeslot_class += ' with-tick';
543 tick_html = '<span class="dp-tick"><strong>' + latepoint_minutes_to_hours_preferably(current_minutes) + '</strong>' + ' ' + ampm + '</span>';
544 }
545 var timeslot_label = latepoint_minutes_to_hours_and_minutes(current_minutes) + ' ' + ampm;
546 if (latepoint_show_booking_end_time()) {
547 var end_minutes = current_minutes + service_duration;
548 if (end_minutes > 1440) end_minutes = end_minutes - 1440;
549 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
550 timeslot_label += ' - <span class="dp-label-end-time">' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm + '</span>';
551 }
552 if (timeslot_available_capacity) {
553 var spaces_message = timeslot_available_capacity > 1 ? latepoint_helper.many_spaces_message : latepoint_helper.single_space_message;
554 capacity_label = timeslot_available_capacity + ' ' + spaces_message;
555 capacity_label_html = '<span class="dp-capacity">' + capacity_label + '</span>';
556 capacity_internal_label_html = '<span class="dp-label-capacity">' + capacity_label + '</span>';
557 }
558 timeslot_label = timeslot_label.trim();
559 $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>');
560 prev_minutes = current_minutes;
561 });
562 } else {
563 // No working hours this day
564 $timeslots.addClass('slots-not-available').append('<div class="not-working-message">' + latepoint_helper.msg_not_available + "</div>");
565 }
566 jQuery('.times-header-label span').text($day.data('nice-date'));
567 $wrapper_element.find('.time-selector-w').slideDown(200, function () {
568 if (!$scrollable_wrapper) $scrollable_wrapper = $wrapper_element.find('.latepoint-body');
569 $scrollable_wrapper.stop();
570 $wrapper_element.find('.time-selector-w')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
571 });
572 }
573
574
575 function latepoint_recurring_option_clicked(event) {
576 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
577 let $btn = jQuery(this);
578 let $booking_form_element = $btn.closest('.latepoint-booking-form-element');
579 $booking_form_element.find('.latepoint_is_recurring').val($btn.data('value'));
580 latepoint_trigger_next_btn($booking_form_element);
581 $booking_form_element.find('.step-datepicker-w').removeClass('show-recurring-prompt');
582 return false;
583 }
584
585 function latepoint_timeslot_clicked(event) {
586 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
587 event.preventDefault();
588 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
589 let $trigger = jQuery(this);
590 if ($trigger.hasClass('is-booked') || jQuery(this).hasClass('is-off')) {
591 // Show error message that you cant select a booked period
592 } else {
593 if ($trigger.hasClass('selected')) {
594 $trigger.removeClass('selected');
595 $trigger.find('.dp-success-label').remove();
596 $booking_form_element.find('.latepoint_start_time').val('');
597 latepoint_hide_next_btn($booking_form_element);
598 latepoint_reload_summary($booking_form_element);
599 } else {
600 $booking_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove();
601 let selected_timeslot_time = $trigger.find('.dp-label-time').html();
602 $trigger.addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>');
603
604 let start_minutes = parseInt($trigger.data('minutes'));
605 let start_date = $trigger.closest('.os-dates-and-times-w').find('.os-day.selected').data('date');
606
607 if ($booking_form_element.find('.recurring-bookings-preview-wrapper').length && $booking_form_element.find('.os-recurrence-rules').length) {
608 // recurring datepicker
609 if ($booking_form_element.find('.recurring-bookings-preview-wrapper .recurring-booking-preview.is-editing').length) {
610 // editing one of timeslots, not the recurrence settings
611 let $recurring_bookings_fields = $booking_form_element.find('.os-recurrence-selection-fields-wrapper');
612 let $edited_booking = $booking_form_element.find('.recurring-bookings-preview-wrapper .recurring-booking-preview.is-editing');
613
614 $recurring_bookings_fields.find('input[name="recurrence[overrides][' + $edited_booking.data('stamp') + '][custom_day]"]').val(start_date);
615 $recurring_bookings_fields.find('input[name="recurrence[overrides][' + $edited_booking.data('stamp') + '][custom_minutes]"]').val(start_minutes);
616
617 return window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, false);
618 } else {
619 // editing recurrence start date/time
620 $booking_form_element.find('.latepoint_start_date').val(start_date);
621 $booking_form_element.find('.latepoint_start_time').val(start_minutes);
622 return window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, true);
623 }
624 } else {
625 $booking_form_element.find('.latepoint_start_date').val(start_date);
626 $booking_form_element.find('.latepoint_start_time').val(start_minutes);
627 if ($trigger.closest('.os-dates-and-times-w').data('allow-recurring') === 'yes') {
628 $booking_form_element.find('.step-datepicker-w').addClass('show-recurring-prompt');
629 $booking_form_element.find('.os-recurring-suggestion-wrapper')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
630 latepoint_hide_next_btn($booking_form_element);
631 latepoint_hide_prev_btn($booking_form_element);
632 } else {
633 latepoint_trigger_next_btn($booking_form_element);
634 }
635 }
636 }
637 }
638 return false;
639 }
640
641 function latepoint_init_timeslots($booking_form_element = false) {
642 if (!$booking_form_element) return;
643 $booking_form_element.off('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
644 $booking_form_element.on('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
645 $booking_form_element.off('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
646 $booking_form_element.on('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
647
648 $booking_form_element.off('click', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
649 $booking_form_element.on('click', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
650 $booking_form_element.off('keydown', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
651 $booking_form_element.on('keydown', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
652 }
653
654 async function latepoint_monthly_calendar_load_next_month($booking_form_element) {
655 try {
656
657 if ($booking_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length) {
658 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
659 $booking_form_element.find('.os-month-prev-btn').removeClass('disabled');
660 latepoint_calendar_set_month_label($booking_form_element);
661 return true;
662 } else {
663 let $btn = $booking_form_element.find('.os-month-next-btn');
664 let next_month_route_name = $btn.data('route');
665 $btn.addClass('os-loading');
666 let $calendar_element = $booking_form_element.find('.os-monthly-calendar-days-w').last();
667 let calendar_year = $calendar_element.data('calendar-year');
668 let calendar_month = $calendar_element.data('calendar-month');
669 if (calendar_month == 12) {
670 calendar_year = calendar_year + 1;
671 calendar_month = 1;
672 } else {
673 calendar_month = calendar_month + 1;
674 }
675 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
676 form_data.set('target_date_string', `${calendar_year}-${calendar_month}-1`);
677 let params = latepoint_formdata_to_url_encoded_string(form_data);
678 let data = {
679 action: latepoint_helper.route_action,
680 route_name: next_month_route_name,
681 params: params,
682 layout: 'none',
683 return_format: 'json'
684 }
685 let response = await jQuery.ajax({
686 type: "post",
687 dataType: "json",
688 url: latepoint_timestamped_ajaxurl(),
689 data: data,
690 success: function (data) {
691 }
692 });
693 $btn.removeClass('os-loading');
694 if (response.status === "success") {
695 $booking_form_element.find('.os-months').append(response.message);
696 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
697 latepoint_calendar_set_month_label($booking_form_element);
698 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
699 return true;
700 } else {
701 console.log(response.message);
702 return false;
703 }
704
705 }
706 } catch (e) {
707 console.log(e);
708 alert('Error:' + e);
709 return false;
710 }
711 }
712
713 function latepoint_init_monthly_calendar_navigation($booking_form_element = false) {
714 if (!$booking_form_element) return;
715 $booking_form_element.find('.os-month-next-btn').on('click', async function () {
716 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
717 return latepoint_monthly_calendar_load_next_month($booking_form_element);
718 });
719 $booking_form_element.find('.os-month-prev-btn').on('click', function () {
720 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
721 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) {
722 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active');
723 latepoint_calendar_set_month_label($booking_form_element);
724 }
725 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
726 return false;
727 });
728 }
729
730 function latepoint_calendar_set_month_label($booking_form_element) {
731 $booking_form_element.find('.os-current-month-label .current-year').text($booking_form_element.find('.os-monthly-calendar-days-w.active').data('calendar-year'));
732 $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'));
733 }
734
735
736 function latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element) {
737 $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'));
738 $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'));
739
740 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) {
741 $booking_form_element.find('.os-month-prev-btn').removeClass('disabled');
742 } else {
743 $booking_form_element.find('.os-month-prev-btn').addClass('disabled');
744 }
745 }
746
747 function latepoint_format_minutes_to_time(minutes, service_duration) {
748 var ampm = latepoint_am_or_pm(minutes);
749 var formatted_time = latepoint_minutes_to_hours_and_minutes(minutes) + ' ' + ampm;
750 if (latepoint_show_booking_end_time()) {
751 var end_minutes = minutes + service_duration;
752 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
753 formatted_time += ' - ' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm;
754 }
755 formatted_time = formatted_time.trim();
756 return formatted_time;
757 }
758
759 function latepoint_monthly_calendar_day_clicked(event) {
760 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
761 let $day = jQuery(this);
762 if ($day.hasClass('os-day-passed')) return false;
763 if ($day.hasClass('os-not-in-allowed-period')) return false;
764 if ($day.hasClass('os-month-prev')) return false;
765 if ($day.hasClass('os-month-next')) return false;
766 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
767 if ($day.closest('.os-recurrence-datepicker-wrapper').length) {
768 // recurrent datepicker
769 $day.closest('.os-recurrence-datepicker-wrapper').find('.os-day.selected').removeClass('selected');
770 $day.addClass('selected');
771 if ($day.closest('.os-dates-and-times-w').hasClass('days-only')) {
772 $day.closest('.step-recurring-bookings-w').find('input[name="recurrence[rules][repeat_end_date]"]').val($day.data('date'));
773 window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, true);
774 } else {
775 latepoint_generate_day_timeslots($day);
776 $day.closest('.os-recurrence-datepicker-wrapper').find('.time-selector-w')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
777 }
778 } else {
779 // regular datepicker
780 if ($day.closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')) {
781 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT
782 if ($day.hasClass('os-not-available')) {
783 // clicked on a day that has no available timeslots
784 // do nothing
785 } else {
786 $booking_form_element.find('.os-day.selected').removeClass('selected');
787 $day.addClass('selected');
788 // set date
789 $booking_form_element.find('.latepoint_start_date').val($day.data('date'));
790 if ($day.hasClass('os-one-slot-only')) {
791 // clicked on a day that has only one slot available
792 var bookable_minutes = $day.data('bookable-minutes').toString().split(':')[0];
793 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number($day.data('service-duration')));
794 $booking_form_element.find('.latepoint_start_time').val($day.data('bookable-minutes'));
795 latepoint_show_next_btn($booking_form_element);
796 $booking_form_element.find('.time-selector-w').slideUp(200);
797 } else {
798 // regular day with more than 1 timeslots available
799 // build timeslots
800 latepoint_generate_day_timeslots($day);
801 // clear time and hide next btn
802 $booking_form_element.find('.latepoint_start_time').val('');
803 latepoint_hide_next_btn($booking_form_element);
804 }
805 latepoint_reload_summary($booking_form_element);
806 }
807 } else {
808
809 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT
810 $booking_form_element.find('.latepoint_start_date').val($day.data('date'));
811 $booking_form_element.find('.os-day.selected').removeClass('selected');
812 $day.addClass('selected');
813
814 // build timeslots
815 latepoint_generate_day_timeslots($day);
816 // clear time and hide next btn
817 latepoint_reload_summary($booking_form_element);
818 $booking_form_element.find('.latepoint_start_time').val('');
819 latepoint_hide_next_btn($booking_form_element);
820 }
821 }
822
823
824 return false;
825 }
826
827 async function latepoint_init_step_datepicker($booking_form_element = false) {
828 if (!$booking_form_element) return true;
829 latepoint_init_timeslots($booking_form_element);
830 latepoint_init_monthly_calendar_navigation($booking_form_element);
831 $booking_form_element.off('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
832 $booking_form_element.on('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
833 $booking_form_element.off('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
834 $booking_form_element.on('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
835
836 if ($booking_form_element.find('input[name="booking[start_date]"]').val()) {
837 $booking_form_element.find('.os-day[data-date="' + $booking_form_element.find('input[name="booking[start_date]"]').val() + '"]').trigger('click');
838 } else {
839 let max_number_of_months_to_check = 24;
840 let current_year = new Date().getFullYear();
841 for (let i = 0; i < max_number_of_months_to_check; i++) {
842 let $active_month = $booking_form_element.find('.os-monthly-calendar-days-w.active');
843 let searching_month_label = $active_month.data('calendar-month-label');
844 if ($active_month.data('calendar-year') != current_year) searching_month_label += ' ' + $active_month.data('calendar-year');
845 $booking_form_element.find('.os-calendar-searching-info span').text(searching_month_label);
846 // check if active month has any days available for booking
847 let $first_available = $active_month.find('.os-day').not('.os-not-available').first();
848 if ($first_available.length) {
849 break;
850 } else {
851 await latepoint_monthly_calendar_load_next_month($booking_form_element);
852 }
853 }
854 }
855 $booking_form_element.find('.os-dates-w').removeClass('is-searching');
856 return true;
857 }
858
859
860 function latepoint_init_step_verify($booking_form_element = false) {
861 if (!$booking_form_element) return;
862 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open');
863
864 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-trigger-on-verify-w a').on('click', function (e) {
865 jQuery(this).closest('.coupon-code-wrapper-on-verify').addClass('entering-coupon').find('.coupon-code-input').trigger('focus');
866 return false;
867 });
868 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-cancel').on('click', function (e) {
869 jQuery(this).closest('.coupon-code-wrapper-on-verify').removeClass('entering-coupon');
870 return false;
871 });
872
873 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-submit').on('click', function (e) {
874 latepoint_apply_coupon(jQuery(this).closest('.coupon-code-input-w').find('.coupon-code-input'));
875 return false;
876 });
877
878 $booking_form_element.find('.os-remove-item-from-cart').on('click keydown', function (event) {
879 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
880 //make sure to clear active cart item so it doesn't add it again on reload!
881 if (confirm(jQuery(this).data('confirm-text'))) {
882 latepoint_remove_cart_item(jQuery(this));
883 }
884 return false;
885 });
886
887 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-clear').on('click', function (e) {
888 latepoint_remove_coupon(jQuery(this));
889 return false;
890 });
891
892 $booking_form_element.find('.coupon-code-wrapper-on-verify input.coupon-code-input').on('keyup', function (e) {
893 if (e.which === 13) {
894 latepoint_apply_coupon(jQuery(this));
895 return false;
896 }
897 });
898 }
899
900
901 function latepoint_init_step_payment__pay($booking_form_element = false) {
902 var selected_payment_method = $booking_form_element.find('input[name="cart[payment_method]"]').val();
903 latepoint_init_payment_method_actions($booking_form_element, selected_payment_method);
904 }
905
906 function latepoint_init_step_payment__portions($booking_form_element = false) {
907 // Selecting Payment Time
908 $booking_form_element.find('.lp-payment-trigger-payment-portion-selector').on('click keydown', function (event) {
909 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
910 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
911 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
912 latepoint_show_prev_btn($booking_form_element);
913 latepoint_trigger_next_btn($booking_form_element);
914 return false;
915 });
916 }
917
918 function latepoint_init_step_payment__times($booking_form_element = false) {
919 // Selecting Payment Time
920 $booking_form_element.find('.lp-payment-trigger-payment-time-selector').on('click keydown', function (event) {
921 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
922 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
923 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
924 latepoint_show_prev_btn($booking_form_element);
925 latepoint_trigger_next_btn($booking_form_element);
926 return false;
927 });
928 }
929
930
931 function latepoint_init_step_payment__methods($booking_form_element = false) {
932 // Selecting Payment Time
933 $booking_form_element.find('.lp-payment-trigger-payment-method-selector').on('click', function (e) {
934 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
935 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
936 latepoint_show_prev_btn($booking_form_element);
937 latepoint_trigger_next_btn($booking_form_element);
938 return false;
939 });
940 }
941
942 function latepoint_category_item_clicked(event) {
943 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
944 let $item = jQuery(event.target);
945
946 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
947 latepoint_show_prev_btn($booking_form_element);
948 $item.closest('.latepoint-step-content').addClass('selecting-item-category');
949 let $category_wrapper = $item.closest('.os-item-category-w');
950 let $main_parent = $item.closest('.os-item-categories-main-parent');
951 if ($category_wrapper.hasClass('selected')) {
952 $category_wrapper.removeClass('selected');
953 if ($category_wrapper.parent().closest('.os-item-category-w').length) {
954 $category_wrapper.parent().closest('.os-item-category-w').addClass('selected');
955 } else {
956 $main_parent.removeClass('show-selected-only');
957 }
958 } else {
959 $main_parent.find('.os-item-category-w.selected').removeClass('selected');
960 $main_parent.addClass('show-selected-only');
961 $category_wrapper.addClass('selected');
962 }
963 return false;
964 }
965
966 function latepoint_init_step_category_items(step_code) {
967 let $category_items = jQuery('.latepoint-step-content[data-step-code="' + step_code + '"] .os-item-category-info');
968 $category_items.on('click', latepoint_category_item_clicked);
969 $category_items.on('keydown', latepoint_category_item_clicked);
970 }
971
972
973 function latepoint_init_step_selectable_items($booking_form_element) {
974 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
975 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
976
977 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
978 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
979
980
981 $booking_form_element.off('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
982 $booking_form_element.on('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
983 }
984
985
986 function latepoint_update_quantity_for_selectable_items($item) {
987 var ids = $item.closest('.os-selectable-items')
988 .find('.os-selectable-item.selected')
989 .map(function () {
990 if (jQuery(this).hasClass('has-quantity')) {
991 return jQuery(this).data('item-id') + ':' + jQuery(this).find('input.item-quantity-selector-input').val();
992 } else {
993 return jQuery(this).data('item-id');
994 }
995 }).get();
996 $item.closest('.latepoint-booking-form-element').find($item.data('id-holder')).val(ids);
997 }
998
999 function latepoint_selectable_item_quantity_keyup(event) {
1000 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1001 var $item = jQuery(this).closest('.os-selectable-item');
1002 var new_value = jQuery(this).val();
1003 if (new_value && new_value.match(/^\d+$/)) {
1004 var max_quantity = $item.data('max-quantity');
1005 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity;
1006 } else {
1007 new_value = 0;
1008 }
1009 jQuery(this).val(new_value);
1010
1011 if (($item.hasClass('selected') && (new_value > 0)) || (!$item.hasClass('selected') && (new_value == 0))) {
1012 latepoint_update_quantity_for_selectable_items($item);
1013 latepoint_reload_summary($booking_form_element);
1014 return false;
1015 } else {
1016 $item.trigger('click');
1017 }
1018 }
1019
1020 function latepoint_selectable_item_clicked(event) {
1021 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1022 event.stopPropagation();
1023 event.stopImmediatePropagation();
1024 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1025 if (jQuery(this).hasClass('has-quantity')) {
1026 if (jQuery(event.target).hasClass('item-quantity-selector')) {
1027 var current_value = parseInt(jQuery(this).find('input.item-quantity-selector-input').val());
1028 var new_value = (jQuery(event.target).data('sign') == 'minus') ? current_value - 1 : current_value + 1;
1029 var max_quantity = jQuery(this).data('max-quantity');
1030 if (new_value < 0) new_value = 0;
1031 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity;
1032 jQuery(this).find('input.item-quantity-selector-input').val(new_value);
1033 if ((jQuery(this).hasClass('selected') && (new_value > 0)) || (!jQuery(this).hasClass('selected') && (new_value == 0))) {
1034 latepoint_update_quantity_for_selectable_items(jQuery(this));
1035 latepoint_reload_summary($booking_form_element);
1036 return false;
1037 }
1038 }
1039 if (jQuery(event.target).hasClass('item-quantity-selector-input')) {
1040 latepoint_update_quantity_for_selectable_items(jQuery(this));
1041 latepoint_reload_summary($booking_form_element);
1042 return false;
1043 }
1044 }
1045 var summary_value = '';
1046 if (jQuery(this).hasClass('os-allow-multiselect')) {
1047 if (jQuery(this).hasClass('selected')) {
1048 jQuery(this).removeClass('selected');
1049 if (jQuery(this).hasClass('has-quantity')) jQuery(this).find('input.item-quantity-selector-input').val(0);
1050 } else {
1051 jQuery(this).addClass('selected');
1052 if (jQuery(this).hasClass('has-quantity') && !(jQuery(this).find('input.item-quantity-selector-input').val() > 0)) {
1053 jQuery(this).find('input.item-quantity-selector-input').val(1);
1054 }
1055 }
1056 latepoint_update_quantity_for_selectable_items(jQuery(this));
1057 latepoint_reload_summary($booking_form_element);
1058 latepoint_show_next_btn($booking_form_element);
1059 } else {
1060 if (!jQuery(this).hasClass('os-duration-item')) jQuery(this).closest('.os-item-categories-main-parent').find('.os-selectable-item.selected').removeClass('selected');
1061 jQuery(this).closest('.os-selectable-items').find('.os-selectable-item.selected').removeClass('selected');
1062 jQuery(this).addClass('selected');
1063 $booking_form_element.find(jQuery(this).data('id-holder')).val(jQuery(this).data('item-id'));
1064 if (jQuery(this).data('cart-item-item-data-key')) {
1065 latepoint_update_active_cart_item_item_data($booking_form_element, jQuery(this).data('cart-item-item-data-key'), jQuery(this).data('item-id'));
1066 }
1067 if (jQuery(this).data('os-call-func')) {
1068 window[jQuery(this).data('os-call-func')](jQuery(this));
1069 }
1070 if (jQuery(this).data('activate-sub-step')) {
1071 window[jQuery(this).data('activate-sub-step')](jQuery(this));
1072 } else {
1073 latepoint_trigger_next_btn($booking_form_element);
1074 }
1075 }
1076 return false;
1077 }
1078
1079 function latepoint_update_active_cart_item_item_data($booking_form_element, key, value) {
1080 let item_data_json = $booking_form_element.find('input[name="active_cart_item[item_data]"]').val();
1081 let item_data = item_data_json ? JSON.parse($booking_form_element.find('input[name="active_cart_item[item_data]"]').val()) : {};
1082 item_data[key] = value;
1083 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val(JSON.stringify(item_data));
1084 }
1085
1086 function latepoint_format_price(price) {
1087 // replace default decimal separator dot with comma if it's in settings
1088 if (latepoint_helper.decimal_separator == ',') price = String(price).replace('.', ',');
1089 return latepoint_helper.currency_symbol_before + String(price) + latepoint_helper.currency_symbol_after;
1090 }
1091
1092
1093 function latepoint_init_step_services() {
1094 }
1095
1096
1097 function latepoint_trigger_next_btn($booking_form_element) {
1098 $booking_form_element.find('.latepoint_step_direction').val('next');
1099 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form'));
1100 }
1101
1102 function latepoint_init_step_locations() {
1103 }
1104
1105 function latepoint_init_agent_details_link($booking_form_element) {
1106 $booking_form_element.on('click', '.os-trigger-item-details-popup', function () {
1107 $booking_form_element.find('.os-item-details-popup.open').remove();
1108 var $popup = $booking_form_element.find('#' + jQuery(this).data('item-details-popup-id')).first().clone().attr('id', '');
1109 $booking_form_element.find('.latepoint-form-w').addClass('showing-item-details-popup');
1110 $popup.addClass('open').appendTo($booking_form_element.find('.latepoint-body'));
1111 return false;
1112 });
1113 $booking_form_element.on('click', '.os-item-details-popup.open .os-item-details-popup-close', function () {
1114 $booking_form_element.find('.latepoint-form-w').removeClass('showing-item-details-popup');
1115 jQuery(this).closest('.os-item-details-popup.open').remove();
1116 return false;
1117 });
1118 }
1119
1120 function latepoint_init_step_agents() {
1121 }
1122
1123
1124 function latepoint_init_booking_summary_lightbox() {
1125 let $lightbox = jQuery('.customer-dashboard-booking-summary-lightbox');
1126 latepoint_init_qr_trigger($lightbox);
1127 latepoint_init_item_details_popup($lightbox);
1128 }
1129
1130 function latepoint_init_step_confirmation($booking_form_element = false) {
1131 if (!$booking_form_element) return;
1132 $booking_form_element.on('click', '.set-customer-password-btn', function () {
1133 var $btn = jQuery(this);
1134 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1135
1136 $btn.addClass('os-loading');
1137 var params = {
1138 account_nonse: jQuery('input[name="account_nonse"]').val(),
1139 password: jQuery('input[name="customer[password]"]').val(),
1140 password_confirmation: jQuery('input[name="customer[password_confirmation]"]').val()
1141 }
1142 var data = {
1143 action: latepoint_helper.route_action,
1144 route_name: jQuery(this).data('btn-action'),
1145 params: jQuery.param(params),
1146 layout: 'none',
1147 return_format: 'json'
1148 }
1149 jQuery.ajax({
1150 type: "post",
1151 dataType: "json",
1152 url: latepoint_timestamped_ajaxurl(),
1153 data: data,
1154 success: function (data) {
1155 $btn.removeClass('os-loading');
1156 if (data.status === "success") {
1157 $booking_form_element.find('.step-confirmation-set-password').html('').hide();
1158 $booking_form_element.find('.confirmation-cabinet-info').show();
1159 } else {
1160 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.step-confirmation-set-password'), 'error');
1161 }
1162 }
1163 });
1164 return false;
1165 });
1166
1167 $booking_form_element.on('click', '.qr-show-trigger', function () {
1168 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1169 $booking_form_element.find('.qr-code-on-full-summary').addClass('show-vevent-qr-code');
1170 return false;
1171 });
1172
1173 $booking_form_element.on('click', '.show-set-password-fields', function () {
1174 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1175
1176 $booking_form_element.find('.step-confirmation-set-password').show();
1177 $booking_form_element.find('#customer_password').trigger('focus');
1178 jQuery(this).closest('.info-box').hide();
1179 return false;
1180 });
1181 }
1182
1183 function latepoint_init_customer_dashboard() {
1184 latepoint_init_form_masks();
1185 jQuery('.latepoint-customer-timezone-selector-w select').on('change', function (e) {
1186 var $select_box = jQuery(this);
1187 $select_box.closest('.latepoint-customer-timezone-selector-w').addClass('os-loading');
1188 var data = {
1189 action: latepoint_helper.route_action,
1190 route_name: jQuery(this).closest('.latepoint-customer-timezone-selector-w').data('route-name'),
1191 params: {timezone_name: jQuery(this).val()},
1192 layout: 'none',
1193 return_format: 'json'
1194 }
1195 jQuery.ajax({
1196 type: "post",
1197 dataType: "json",
1198 url: latepoint_timestamped_ajaxurl(),
1199 data: data,
1200 success: function (data) {
1201 $select_box.closest('.latepoint-customer-timezone-selector-w').removeClass('os-loading');
1202 if (data.status === "success") {
1203 location.reload();
1204 } else {
1205
1206 }
1207 }
1208 });
1209 });
1210
1211
1212 jQuery('.latepoint-request-booking-cancellation').on('click', function () {
1213 if (!confirm(latepoint_helper.cancel_booking_prompt)) return false;
1214 var $this = jQuery(this);
1215 var $booking_box = $this.closest('.customer-booking');
1216
1217 var route = jQuery(this).data('route');
1218 var params = {id: $booking_box.data('id')};
1219
1220 var data = {
1221 action: latepoint_helper.route_action,
1222 route_name: route,
1223 params: params,
1224 layout: 'none',
1225 return_format: 'json'
1226 }
1227 $this.addClass('os-loading');
1228 jQuery.ajax({
1229 type: "post",
1230 dataType: "json",
1231 url: latepoint_timestamped_ajaxurl(),
1232 data: data,
1233 success: function (data) {
1234 if (data.status === "success") {
1235 $this.remove();
1236 location.reload();
1237 } else {
1238 $this.removeClass('os-loading');
1239 }
1240 }
1241 });
1242 return false;
1243 });
1244
1245 }
1246
1247
1248 function get_customer_name($wrapper) {
1249 var customer_name = '';
1250 var first_name = $wrapper.find('input[name="customer[first_name]"]').val();
1251 var last_name = $wrapper.find('input[name="customer[last_name]"]').val();
1252 if (first_name) customer_name += first_name;
1253 if (last_name) customer_name += ' ' + last_name;
1254 return customer_name.trim();
1255 }
1256
1257 function latepoint_init_step_contact() {
1258 latepoint_init_form_masks();
1259
1260 // Init Logout button
1261 jQuery('.step-customer-logout-btn').on('click', function () {
1262 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1263 var data = {
1264 action: latepoint_helper.route_action,
1265 route_name: jQuery(this).data('btn-action'),
1266 layout: 'none',
1267 return_format: 'json'
1268 }
1269 latepoint_step_content_change_start($booking_form_element);
1270 jQuery.ajax({
1271 type: "post",
1272 dataType: "json",
1273 url: latepoint_timestamped_ajaxurl(),
1274 data: data,
1275 success: function (data) {
1276 latepoint_reload_step($booking_form_element);
1277 }
1278 });
1279 return false;
1280 });
1281
1282 // Init Login Existing Customer Button
1283 jQuery('.step-login-existing-customer-btn').on('click', function () {
1284 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1285 var params = {
1286 email: $booking_form_element.find('.os-step-existing-customer-login-w input[name="customer_login[email]"]').val(),
1287 password: $booking_form_element.find('.os-step-existing-customer-login-w input[name="customer_login[password]"]').val()
1288 }
1289 var data = {
1290 action: latepoint_helper.route_action,
1291 route_name: jQuery(this).data('btn-action'),
1292 params: jQuery.param(params),
1293 layout: 'none',
1294 return_format: 'json'
1295 }
1296 latepoint_step_content_change_start($booking_form_element);
1297 jQuery.ajax({
1298 type: "post",
1299 dataType: "json",
1300 url: latepoint_timestamped_ajaxurl(),
1301 data: data,
1302 success: function (data) {
1303 if (data.status === "success") {
1304 latepoint_reload_step($booking_form_element);
1305 } else {
1306 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.os-step-existing-customer-login-w'));
1307 latepoint_step_content_change_end(false, $booking_form_element);
1308 }
1309 }
1310 });
1311 return false;
1312 });
1313 }
1314
1315 function latepoint_step_content_change_start($booking_form_element) {
1316 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
1317 }
1318
1319 // TODO
1320 function latepoint_step_content_change_end(new_content, $booking_form_element) {
1321 if (new_content) $booking_form_element.find('.latepoint-body .latepoint-step-content').replaceWith(new_content);
1322 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
1323 setTimeout(function () {
1324 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
1325 }, 50);
1326 }
1327
1328
1329 function latepoint_change_step_desc($booking_form_element, step_code) {
1330 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1331 setTimeout(function () {
1332 // Progress bar
1333 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1334 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1335 $step_progress.nextAll().removeClass('complete').removeClass('active');
1336 // Side panel
1337 var side_panel_desc = $booking_form_element.find('.latepoint-step-desc-library[data-step-code="' + step_code + '"]').html();
1338 $booking_form_element.find('.latepoint-step-desc').html(side_panel_desc);
1339
1340 // Top header
1341 var top_header_desc = $booking_form_element.find('.os-heading-text-library[data-step-code="' + step_code + '"]').html();
1342 $booking_form_element.find('.os-heading-text').html(top_header_desc);
1343 setTimeout(function () {
1344 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1345 }, 50);
1346 }, 500);
1347 }
1348
1349
1350 function latepoint_progress_prev($booking_form_element, step_code) {
1351 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1352 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1353 $step_progress.nextAll().removeClass('complete').removeClass('active');
1354 }
1355
1356
1357 function latepoint_progress_next($booking_form_element, step_code) {
1358 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1359 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1360 $step_progress.nextAll().removeClass('complete').removeClass('active');
1361 }
1362
1363
1364 function latepoint_next_step_description($booking_form_element, step_code) {
1365 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1366 setTimeout(function () {
1367 $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());
1368 $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());
1369 setTimeout(function () {
1370 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1371 }, 50);
1372 }, 500);
1373 }
1374
1375 function latepoint_prev_step_description($booking_form_element, step_code) {
1376 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1377 setTimeout(function () {
1378 $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());
1379 $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());
1380 setTimeout(function () {
1381 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1382 }, 50);
1383 }, 500);
1384 }
1385
1386
1387 function latepoint_validate_fields($fields) {
1388 var is_valid = true;
1389 $fields.each(function (index) {
1390 if (jQuery(this).val() == '') {
1391 is_valid = false;
1392 return false;
1393 }
1394 });
1395 return is_valid;
1396 }
1397
1398
1399 async function latepoint_submit_booking_form($booking_form) {
1400 let $booking_form_element = $booking_form.closest('.latepoint-booking-form-element');
1401
1402 let current_step = $booking_form_element.find('.latepoint_current_step_code').val();
1403 let callbacks_list = [];
1404 if (latepoint_check_if_booking_form_is_final_submit($booking_form_element)) {
1405 // check if order intent is still bookable
1406 latepoint_add_action(callbacks_list, async () => {
1407 return await latepoint_check_if_order_intent_still_bookable($booking_form_element);
1408 }, 1);
1409 }
1410 $booking_form_element.trigger('latepoint:submitBookingForm', [{
1411 current_step: current_step,
1412 callbacks_list: callbacks_list,
1413 is_final_submit: latepoint_check_if_booking_form_is_final_submit($booking_form_element),
1414 direction: $booking_form_element.find('.latepoint_step_direction').val()
1415 }]);
1416 try {
1417 latepoint_hide_prev_btn($booking_form_element);
1418 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form);
1419 } catch (error) {
1420 latepoint_show_prev_btn($booking_form_element);
1421 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
1422 return false;
1423 }
1424
1425
1426 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
1427 latepoint_hide_prev_btn($booking_form_element);
1428 try {
1429 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body'));
1430 let response = await jQuery.ajax({
1431 type: "post",
1432 dataType: "json",
1433 processData: false,
1434 contentType: false,
1435 url: latepoint_timestamped_ajaxurl(),
1436 data: latepoint_create_form_data($booking_form)
1437 });
1438
1439 $booking_form.find('.latepoint_step_direction').val('next');
1440 if (response.status === 'success') {
1441 if (response.fields_to_update) {
1442 for (const [key, value] of Object.entries(response.fields_to_update)) {
1443 $booking_form_element.find('input[name="' + key + '"]').val(value)
1444 }
1445 }
1446 if ($booking_form_element.data('flash-error')) {
1447 latepoint_show_message_inside_element($booking_form_element.data('flash-error'), $booking_form_element.find('.latepoint-body'));
1448 $booking_form_element.data('flash-error', '');
1449 }
1450 $booking_form_element.find('.latepoint_current_step_code').val(response.step_code);
1451 $booking_form_element.removeClass(function (index, className) {
1452 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
1453 }).addClass('current-step-' + response.step_code);
1454 setTimeout(function () {
1455 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
1456 $booking_form_element.find('.latepoint-body').find('.latepoint-step-content').addClass('is-hidden');
1457 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]')) {
1458 $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]').remove();
1459 }
1460 $booking_form_element.find('.latepoint-body').append(response.message);
1461
1462
1463 latepoint_update_next_btn_label($booking_form_element);
1464 latepoint_init_step(response.step_code, $booking_form_element);
1465 setTimeout(function () {
1466 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
1467 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading');
1468 latepoint_scroll_to_top_of_booking_form($booking_form_element);
1469 }, 50);
1470 }, 500);
1471
1472 if (response.is_pre_last_step) {
1473 $booking_form_element.data('next-submit-is-last', 'yes');
1474 } else {
1475 $booking_form_element.data('next-submit-is-last', 'no');
1476 }
1477 if (response.is_last_step) {
1478 $booking_form_element.addClass('hidden-buttons').find('.latepoint-footer').remove();
1479 $booking_form_element.find('.latepoint-progress').css('opacity', 0);
1480 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open');
1481 $booking_form_element.closest('.latepoint-show-side-panel').removeClass('latepoint-show-side-panel').addClass('latepoint-hide-side-panel');
1482 $booking_form_element.addClass('is-final-step');
1483 } else {
1484 if (response.show_next_btn === true) {
1485 latepoint_show_next_btn($booking_form_element);
1486 } else {
1487 latepoint_hide_next_btn($booking_form_element);
1488 }
1489 if (response.show_prev_btn === true) {
1490 latepoint_show_prev_btn($booking_form_element);
1491 } else {
1492 latepoint_hide_prev_btn($booking_form_element);
1493 }
1494 }
1495 latepoint_change_step_desc($booking_form_element, response.step_code);
1496 latepoint_reload_summary($booking_form_element);
1497 } else {
1498 if (response.send_to_step && response.send_to_step === 'resubmit') {
1499 let current_resubmit_count = parseInt($booking_form.data('resubmit-count')) ? parseInt($booking_form.data('resubmit-count')) : 1;
1500 $booking_form.data('resubmit-count', current_resubmit_count + 1);
1501 if (current_resubmit_count > 6) {
1502 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body'));
1503 } else {
1504 // resubmission probably caused by order intent still being processed, since
1505 // order intent is still processing, give it a little more time and try again
1506 await latepoint_sleep(2000);
1507 return latepoint_submit_booking_form($booking_form);
1508 }
1509 } else {
1510 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded');
1511 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading');
1512 if (response.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.send_to_step + '"]').length) {
1513 $booking_form_element.data('flash-error', response.message);
1514 latepoint_reload_step($booking_form_element, response.send_to_step);
1515 } else {
1516 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body'));
1517 latepoint_show_prev_btn($booking_form_element);
1518 }
1519 }
1520 }
1521 } catch (e) {
1522 console.log(e);
1523 alert('Error:' + e);
1524 }
1525 }
1526
1527 function latepoint_sleep(ms) {
1528 return new Promise(resolve => setTimeout(resolve, ms));
1529 }
1530
1531 function latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element) {
1532 if (error.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + error.send_to_step + '"]').length) {
1533 latepoint_reload_step($booking_form_element, error.send_to_step);
1534 $booking_form_element.data('flash-error', error.message);
1535 } else {
1536 latepoint_show_message_inside_element(error.message, $booking_form_element.find('.latepoint-body'), 'error');
1537
1538 if ($booking_form_element.hasClass('step-content-loading')) $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded');
1539 $booking_form_element.find('.latepoint-next-btn').removeClass('os-loading');
1540
1541 // if previous step exists - show prev button
1542 if ($booking_form_element.find('.latepoint-step-content:last-child').prev('.latepoint-step-content').length) latepoint_show_prev_btn($booking_form_element);
1543 latepoint_scroll_to_top_of_booking_form($booking_form_element);
1544 }
1545 }
1546
1547 function latepoint_reset_active_cart_item($booking_form_element) {
1548 $booking_form_element.find('input[name="active_cart_item[id]"]').val('');
1549 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('');
1550 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val('');
1551 }
1552
1553 function latepoint_check_if_booking_form_is_final_submit($booking_form_element) {
1554 return ($booking_form_element.data('next-submit-is-last') == 'yes');
1555 }
1556
1557
1558 async function latepoint_check_if_order_intent_still_bookable($booking_form_element) {
1559 let response = await jQuery.ajax({
1560 type: "post",
1561 dataType: "json",
1562 processData: false,
1563 contentType: false,
1564 url: latepoint_timestamped_ajaxurl(),
1565 data: latepoint_create_form_data($booking_form_element.find('.latepoint-form'), latepoint_helper.check_order_intent_bookable_route)
1566 });
1567 if (response.status === 'success') {
1568 return true;
1569 } else {
1570 throw new Error(response.message);
1571 }
1572 }
1573
1574 async function latepoint_process_list_of_callbacks(callbacks, $booking_form_element, $booking_form) {
1575 for (const callback of callbacks) {
1576 await callback.action();
1577 }
1578 }
1579
1580 function latepoint_clear_presets($booking_form_element) {
1581 $booking_form_element.find('.clear_for_new_item').val('');
1582 }
1583
1584 function latepoint_init_booking_form($booking_form_element) {
1585 $booking_form_element.on('click keydown', '.checkout-from-summary-panel-btn', function (event) {
1586 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1587 latepoint_reload_step($booking_form_element, jQuery(this).data('step'));
1588 jQuery(this).closest('.latepoint-w').removeClass('show-summary-on-mobile');
1589 return false;
1590 });
1591
1592 $booking_form_element.on('click keydown', '.latepoint-add-another-item-trigger', function (event) {
1593 if(event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1594
1595 if (latepoint_helper.reset_presets_when_adding_new_item){
1596 latepoint_clear_presets($booking_form_element);
1597 }
1598 latepoint_reset_active_cart_item($booking_form_element);
1599 latepoint_reload_step($booking_form_element, jQuery(this).data('step'));
1600 return false;
1601 });
1602 $booking_form_element.find('.latepoint-form').on('submit', function (e) {
1603 e.preventDefault();
1604 let $booking_form = jQuery(this);
1605 latepoint_submit_booking_form($booking_form);
1606 });
1607
1608 latepoint_init_booking_summary_panel($booking_form_element);
1609
1610 $booking_form_element.on('click keydown', '.latepoint-lightbox-summary-trigger', function (event) {
1611 event.preventDefault();
1612 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1613 let $wrapper = jQuery(this).closest('.latepoint-w');
1614 $wrapper.toggleClass('show-summary-on-mobile');
1615 return false;
1616 });
1617
1618 $booking_form_element.find('.latepoint-lightbox-close').on('click', function () {
1619
1620 let params = new URLSearchParams(location.search);
1621 if (params.has('latepoint_order_intent_key')) {
1622 params.delete('latepoint_order_intent_key');
1623 history.replaceState(null, '', '?' + params + location.hash);
1624 }
1625
1626 jQuery('body').removeClass('latepoint-lightbox-active');
1627 jQuery('.latepoint-lightbox-w').remove();
1628 return false;
1629 });
1630
1631
1632 $booking_form_element.on('click keydown', '.lp-option', function (event) {
1633 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1634 jQuery(this).closest('.lp-options').find('.lp-option.selected').removeClass('selected');
1635 jQuery(this).addClass('selected');
1636 });
1637
1638
1639 // Next Step button Click
1640 $booking_form_element.find('.latepoint-next-btn').on('click', async function (e) {
1641 e.preventDefault();
1642 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false;
1643 var $next_btn = jQuery(this);
1644 $next_btn.addClass('os-loading');
1645 var $booking_form = jQuery(this).closest('.latepoint-form');
1646
1647 var current_step = $booking_form_element.find('.latepoint_current_step_code').val();
1648
1649 $booking_form.find('.latepoint_step_direction').val('next');
1650 var callbacks_list = [];
1651
1652 $booking_form_element.trigger('latepoint:nextStepClicked', [{
1653 current_step: current_step,
1654 callbacks_list: callbacks_list
1655 }]);
1656 latepoint_hide_prev_btn($booking_form_element);
1657
1658 try {
1659 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form);
1660 await latepoint_submit_booking_form($booking_form);
1661 } catch (error) {
1662 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
1663 }
1664 return false;
1665 });
1666
1667
1668 // Previous Step button Click
1669 $booking_form_element.find('.latepoint-prev-btn').on('click', function (e) {
1670 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false;
1671
1672 let $current_step = $booking_form_element.find('.latepoint-step-content:last-child');
1673
1674
1675 // handle categories
1676 if ($current_step.hasClass('selecting-item-category')) {
1677 if ($current_step.find('.os-item-category-w .os-item-category-w.selected').length) {
1678 $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');
1679 } else {
1680 $current_step.removeClass('selecting-item-category').find('.os-item-category-w.selected').removeClass('selected');
1681 $current_step.removeClass('selecting-item-category').find('.os-item-categories-holder.show-selected-only').removeClass('show-selected-only');
1682 }
1683 if (($booking_form_element.find('.latepoint-step-content').length <= 1) && !$current_step.hasClass('selecting-item-category')) {
1684 latepoint_hide_prev_btn($booking_form_element);
1685 }
1686 latepoint_reload_summary($booking_form_element);
1687 return false;
1688 }
1689
1690 if ($current_step.data('clear-action')) {
1691 window[$current_step.data('clear-action')]($booking_form_element);
1692 }
1693
1694 let $back_btn = jQuery(this);
1695 $back_btn.addClass('os-loading');
1696 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
1697 let $new_current_step = $booking_form_element.find('.latepoint-step-content.is-hidden').last();
1698 let new_current_step_code = $new_current_step.data('step-code');
1699 let current_step_code = $current_step.data('step-code');
1700
1701
1702 let current_parent_code_name = current_step_code.split('__')[0];
1703 let new_parent_code_name = new_current_step_code.split('__')[0];
1704
1705 let active_cart_item_id = $booking_form_element.find('input[name="active_cart_item[id]"]').val();
1706
1707 latepoint_change_step_desc($booking_form_element, new_current_step_code);
1708 setTimeout(function () {
1709 $new_current_step.removeClass('is-hidden');
1710 $current_step.remove();
1711 $booking_form_element.find('.latepoint_current_step_code').val(new_current_step_code);
1712 $booking_form_element.removeClass(function (index, className) {
1713 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
1714 }).addClass('current-step-' + new_current_step_code);
1715 $booking_form_element.find('.latepoint-next-btn span').text($booking_form_element.find('.latepoint-next-btn').data('label'));
1716 $booking_form_element.data('next-submit-is-last', 'no');
1717
1718 latepoint_update_next_btn_label($booking_form_element);
1719 latepoint_show_next_btn($booking_form_element);
1720 $back_btn.removeClass('os-loading');
1721 if ($booking_form_element.find('.latepoint-step-content').length <= 1) {
1722 if ($new_current_step.hasClass('selecting-item-category')) {
1723
1724 }
1725 if (new_current_step_code == 'booking__services') {
1726 var $services_step = $booking_form_element.find('.step-services-w');
1727 if ($services_step.hasClass('selecting-item-category')) {
1728 if ($services_step.find('.os-services > .os-item.selected').hasClass('is-preselected')) {
1729 // if service is preselected check if there are both multiple durations and quantity selector and only then show prev button
1730 } else {
1731 latepoint_show_prev_btn($booking_form_element);
1732 }
1733 } else {
1734 latepoint_hide_prev_btn($booking_form_element);
1735 }
1736 } else {
1737 if (!$new_current_step.hasClass('selecting-item-category')) {
1738 latepoint_hide_prev_btn($booking_form_element);
1739 }
1740 }
1741 }
1742 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
1743
1744
1745 if (new_parent_code_name == 'booking' && current_parent_code_name != 'booking' && active_cart_item_id) {
1746
1747 // 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
1748 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading');
1749 let data = {
1750 action: latepoint_helper.route_action,
1751 route_name: latepoint_helper.remove_cart_item_route,
1752 params: jQuery.param({cart_item_id: active_cart_item_id}),
1753 layout: 'none',
1754 return_format: 'json'
1755 }
1756 jQuery.ajax({
1757 type: "post",
1758 dataType: "json",
1759 url: latepoint_timestamped_ajaxurl(),
1760 data: data,
1761 success: function (data) {
1762 if (data.status === "success") {
1763 $booking_form_element.find('input[name="active_cart_item[id]"]').val('');
1764 if ($booking_form_element.find('input[name="active_cart_item[variant]"]').val() == 'bundle') {
1765 latepoint_update_active_cart_item_item_data($booking_form_element, 'bundle_id', '');
1766 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('');
1767 }
1768 latepoint_reload_summary($booking_form_element);
1769 } else {
1770 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading');
1771 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
1772 }
1773 }
1774 });
1775 } else {
1776 latepoint_reload_summary($booking_form_element);
1777 }
1778 setTimeout(function () {
1779 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
1780 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body'));
1781 latepoint_scroll_to_top_of_booking_form($booking_form_element);
1782 }, 150);
1783 }, 700);
1784 return false;
1785 });
1786
1787 latepoint_init_agent_details_link($booking_form_element);
1788 $booking_form_element.trigger('latepoint:initBookingForm');
1789 }
1790
1791
1792 function latepoint_init_booking_form_by_trigger($trigger) {
1793 let route = latepoint_helper.booking_button_route;
1794 let params = {};
1795 let restrictions = {};
1796 let presets = {};
1797 let booking_element_styles = {};
1798 if ($trigger.data('show-service-categories')) restrictions.show_service_categories = $trigger.data('show-service-categories');
1799 if ($trigger.data('show-locations')) restrictions.show_locations = $trigger.data('show-locations');
1800 if ($trigger.data('show-services')) restrictions.show_services = $trigger.data('show-services');
1801 if ($trigger.data('show-agents')) restrictions.show_agents = $trigger.data('show-agents');
1802 if ($trigger.data('calendar-start-date')) restrictions.calendar_start_date = $trigger.data('calendar-start-date');
1803
1804 if ($trigger.data('selected-location')) presets.selected_location = $trigger.data('selected-location');
1805 if ($trigger.data('selected-agent')) presets.selected_agent = $trigger.data('selected-agent');
1806 if ($trigger.data('selected-service')) presets.selected_service = $trigger.data('selected-service');
1807 if ($trigger.data('selected-bundle')) presets.selected_bundle = $trigger.data('selected-bundle');
1808 if ($trigger.data('selected-duration')) presets.selected_duration = $trigger.data('selected-duration');
1809 if ($trigger.data('selected-total-attendees')) presets.selected_total_attendees = $trigger.data('selected-total-attendees');
1810 if ($trigger.data('selected-service-category')) presets.selected_service_category = $trigger.data('selected-service-category');
1811 if ($trigger.data('selected-start-date')) presets.selected_start_date = $trigger.data('selected-start-date');
1812 if ($trigger.data('selected-start-time')) presets.selected_start_time = $trigger.data('selected-start-time');
1813 if ($trigger.data('order-item-id')) presets.order_item_id = $trigger.data('order-item-id');
1814 if ($trigger.data('source-id')) presets.source_id = $trigger.data('source-id');
1815
1816 if ($trigger.data('hide-summary') == 'yes') booking_element_styles.hide_summary = true;
1817 if ($trigger.data('hide-side-panel') == 'yes') booking_element_styles.hide_side_panel = true;
1818
1819
1820 if (jQuery.isEmptyObject(restrictions) == false) params.restrictions = restrictions;
1821 if (jQuery.isEmptyObject(presets) == false) params.presets = presets;
1822 if (jQuery.isEmptyObject(booking_element_styles) == false) params.booking_element_styles = booking_element_styles;
1823
1824 let data = {
1825 action: latepoint_helper.route_action,
1826 route_name: route,
1827 params: params,
1828 layout: 'none',
1829 return_format: 'json'
1830 }
1831
1832 let is_inline_form = $trigger.hasClass('latepoint-book-form-wrapper');
1833 if (is_inline_form) {
1834 data.params.booking_element_type = 'inline_form';
1835 }
1836
1837 $trigger.addClass('os-loading');
1838 jQuery.ajax({
1839 type: "post",
1840 dataType: "json",
1841 url: latepoint_timestamped_ajaxurl(),
1842 data: data,
1843 success: (data) => {
1844 if (data.status === "success") {
1845 let $booking_form_element = false;
1846 if (is_inline_form) {
1847 $trigger.html(data.message);
1848 $booking_form_element = $trigger.find('.latepoint-booking-form-element');
1849 } else {
1850 let lightbox_class = 'booking-form-in-lightbox';
1851 latepoint_show_data_in_lightbox(data.message, lightbox_class, false);
1852 $booking_form_element = jQuery('.latepoint-lightbox-w .latepoint-booking-form-element');
1853 jQuery('body').addClass('latepoint-lightbox-active');
1854 }
1855 latepoint_init_booking_form($booking_form_element);
1856 latepoint_init_step(data.step, $booking_form_element);
1857 $trigger.removeClass('os-loading');
1858 } else {
1859 $trigger.removeClass('os-loading');
1860 // console.log(data.message);
1861 }
1862 }
1863 });
1864 }
1865