PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / trunk
LatePoint – Calendar Booking Plugin for Appointments and Events vtrunk
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 day ago _events.js 1 year ago _razorpay_connect.js 1 month ago _stripe_connect.js 1 year ago main.js 1 day ago
main.js
2305 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 _wpnonce: jQuery(this).closest('.change-booking-status-trigger-wrapper').find('input[name="_wpnonce"]').val()
84 }
85 let data = {
86 action: latepoint_helper.route_action,
87 route_name: jQuery(this).closest('.change-booking-status-trigger-wrapper').data('route-name'),
88 params: params,
89 layout: 'none',
90 return_format: 'json'
91 };
92
93 jQuery.ajax({
94 type: "post",
95 dataType: "json",
96 url: latepoint_timestamped_ajaxurl(),
97 data: data,
98 success: function (data) {
99 $wrapper.removeClass('os-loading')
100 if (data.status === "success") {
101 latepoint_manage_by_key_reload_booking();
102 } else {
103 latepoint_show_message_inside_element(data.message, $wrapper, 'error');
104 }
105 }
106 });
107 return false;
108 });
109
110
111 $wrapper.on('click', '.qr-show-trigger', function () {
112 jQuery(this).closest('.manage-booking-wrapper').find('.qr-code-on-full-summary').addClass('show-vevent-qr-code');
113 return false;
114 });
115 $wrapper.on('click', '.os-item-details-popup-close', function () {
116 var $wrapper = jQuery(this).closest('.manage-booking-wrapper');
117 $wrapper.find('.os-item-details-popup.open').remove();
118 $wrapper.find('.manage-booking-inner, .manage-booking-controls').show();
119 return false;
120 });
121
122 $wrapper.on('click', '.os-trigger-item-details-popup', function () {
123 var $wrapper = jQuery(this).closest('.manage-booking-wrapper');
124 $wrapper.find('.manage-booking-inner, .manage-booking-controls').hide();
125 $wrapper.find('.os-item-details-popup.open').remove();
126 var $popup = $wrapper.find('#' + jQuery(this).data('item-details-popup-id')).clone();
127 $popup.addClass('open').appendTo($wrapper);
128 return false;
129 });
130 }
131
132 function latepoint_init_form_masks() {
133 if (('lp_intlTelInput' in window) && ('lp_intlTelInputGlobals' in window)) {
134 jQuery('.os-mask-phone').each(function () {
135 latepoint_mask_phone(jQuery(this));
136 });
137 }
138 }
139
140 function latepoint_scroll_to_top_of_booking_form($booking_form_element) {
141 // if it's a form shortcode (not lightbox), scroll to top of the form
142 if ($booking_form_element.parent().hasClass('latepoint-inline-form')) {
143 $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
144 }
145 // if lightbox - scroll body of lightbox to top
146 if ($booking_form_element.parent().hasClass('latepoint-lightbox-i')) {
147 $booking_form_element.find('.latepoint-body').scrollTop(0);
148 }
149 }
150
151 async function latepoint_init_payment_method_actions($booking_form_element, payment_method) {
152 let callbacks_list = [];
153 let is_last_step = $booking_form_element.data('next-submit-is-last') == 'yes';
154 $booking_form_element.trigger('latepoint:initPaymentMethod', [{
155 payment_method: payment_method,
156 callbacks_list: callbacks_list,
157 is_last_step: is_last_step
158 }]);
159 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
160
161
162 try {
163 for (const callback of callbacks_list) {
164 await callback.action();
165 }
166 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded').find('.lp-payment-method-content[data-payment-method="' + payment_method + '"]').show();
167 } catch (error) {
168 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
169 }
170 }
171
172 function latepoint_lightbox_close() {
173 jQuery('body').removeClass('latepoint-lightbox-active');
174 jQuery('.latepoint-lightbox-w').remove();
175 }
176
177 function latepoint_show_next_btn($booking_form_element) {
178 $booking_form_element.find('.latepoint-next-btn').removeClass('disabled');
179 $booking_form_element.removeClass('hidden-buttons');
180 }
181
182 function latepoint_clear_step_services($booking_form_element) {
183 }
184
185 function latepoint_clear_step_service_extras($booking_form_element) {
186 }
187
188 function latepoint_clear_step_locations($booking_form_element) {
189 }
190
191 function latepoint_clear_step_agents($booking_form_element) {
192 }
193
194 function latepoint_clear_step_datepicker($booking_form_element) {
195 }
196
197 function latepoint_hide_next_btn($booking_form_element) {
198 $booking_form_element.find('.latepoint-next-btn').addClass('disabled');
199 if ($booking_form_element.find('.latepoint-prev-btn.disabled').length) $booking_form_element.addClass('hidden-buttons');
200 }
201
202
203 function latepoint_show_prev_btn($booking_form_element) {
204 $booking_form_element.find('.latepoint-prev-btn').removeClass('disabled');
205 $booking_form_element.removeClass('hidden-buttons');
206 }
207
208 function latepoint_hide_prev_btn($booking_form_element) {
209 $booking_form_element.find('.latepoint-prev-btn').addClass('disabled');
210 if ($booking_form_element.find('.latepoint-next-btn.disabled').length) $booking_form_element.addClass('hidden-buttons');
211 }
212
213
214 function latepoint_remove_cart_item($trigger) {
215 let $booking_form_element = $trigger.closest('.latepoint-booking-form-element');
216 let cart_item_id = $trigger.data('cart-item-id');
217 let nonce = $trigger.data('nonce');
218
219
220 $trigger.addClass('os-loading');
221 let data = {
222 action: latepoint_helper.route_action,
223 route_name: $trigger.data('route'),
224 params: jQuery.param({cart_item_id: cart_item_id, _wpnonce: nonce}),
225 layout: 'none',
226 return_format: 'json'
227 }
228 jQuery.ajax({
229 type: "post",
230 dataType: "json",
231 url: latepoint_timestamped_ajaxurl(),
232 data: data,
233 success: function (data) {
234 if (data.status === "success") {
235 if (cart_item_id != $booking_form_element.find('input[name="active_cart_item[id]"]').val()) {
236 // cart has other items - just reload the summary/step
237 if ($trigger.closest('.latepoint-summary-w').length) {
238 // removed by clicking on summary side panel
239 latepoint_reload_summary($booking_form_element);
240 } else {
241 // remove by clicking on cart item on verify step
242 latepoint_reload_step($booking_form_element);
243 }
244 } else {
245 // this was a last item, need to go back to the start of a booking process
246 latepoint_restart_booking_process($booking_form_element);
247 }
248 } else {
249 $trigger.removeClass('os-loading');
250 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
251 }
252 }
253 });
254 }
255
256 function latepoint_apply_coupon($elem) {
257 var $booking_form_element = $elem.closest('.latepoint-booking-form-element');
258
259 var $coupon_input = $elem;
260 $coupon_input.closest('.coupon-code-input-w').addClass('os-loading');
261 var form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
262 var data = {
263 action: latepoint_helper.route_action,
264 route_name: $elem.data('route'),
265 params: latepoint_formdata_to_url_encoded_string(form_data),
266 layout: 'none',
267 return_format: 'json'
268 }
269 jQuery.ajax({
270 type: "post",
271 dataType: "json",
272 url: latepoint_timestamped_ajaxurl(),
273 data: data,
274 success: function (data) {
275 $coupon_input.closest('.coupon-code-input-w').removeClass('os-loading');
276 if (data.status === "success") {
277 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'success');
278 $booking_form_element.find('.step-payment-w input[name="cart[payment_method]"]').val('');
279 $booking_form_element.find('input[name="cart[payment_token]"]').val('');
280 $booking_form_element.find('input[name="cart[payment_portion]"]').val('');
281 latepoint_reload_step($booking_form_element);
282 } else {
283 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
284 }
285 }
286 });
287 }
288
289 function latepoint_remove_coupon($elem) {
290 $elem.closest('.applied-coupon-code-wrapper').fadeOut();
291 var $booking_form_element = $elem.closest('.latepoint-booking-form-element');
292 let $coupon_input = $booking_form_element.find('input[name="coupon_code"]');
293 $coupon_input.val('');
294 latepoint_apply_coupon($coupon_input);
295 }
296
297 function latepoint_restart_booking_process($booking_form_element) {
298 // first first step
299 let first_step_code = $booking_form_element.find('.latepoint-step-content').first().data('step-code');
300 latepoint_reload_step($booking_form_element, first_step_code);
301 return false;
302 }
303
304 function latepoint_reload_step($booking_form_element, step_code = false) {
305
306 if (step_code) {
307 $booking_form_element.find('.latepoint_current_step_code').val(step_code);
308 $booking_form_element.removeClass(function (index, className) {
309 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
310 }).addClass('current-step-' + step_code);
311 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]')) {
312 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').nextAll('.latepoint-step-content').remove();
313 $booking_form_element.find('.latepoint-step-content[data-step-code="' + step_code + '"]').remove();
314 }
315 }
316
317 $booking_form_element.data('next-submit-is-last', 'no');
318 $booking_form_element.find('.latepoint_step_direction').val('specific');
319 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form'));
320
321 return false;
322 }
323
324
325 function latepoint_reset_password_from_booking_init() {
326 jQuery('.os-step-existing-customer-login-w').hide();
327 jQuery('.os-password-reset-form-holder').on('click', '.password-reset-back-to-login', function () {
328 jQuery('.os-password-reset-form-holder').html('');
329 jQuery('.os-step-existing-customer-login-w').show();
330 return false;
331 });
332 }
333
334 function latepoint_bundle_selected($item) {
335 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
336 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('bundle');
337 $booking_form_element.find('input[name="booking[service_id]"]').val('');
338 }
339
340 function latepoint_service_selected($item) {
341 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
342 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('booking');
343 }
344
345 async function latepoint_reload_summary($booking_form_element) {
346 let $summary_panel = $booking_form_element.closest('.latepoint-with-summary');
347 if (!$summary_panel.length) return;
348
349 if ($booking_form_element.hasClass('is-bundle-scheduling')) {
350 return;
351 }
352
353 let current_step = $booking_form_element.find('.latepoint_current_step_code').val();
354
355 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading');
356 let $booking_form = $booking_form_element.find('.latepoint-form');
357 let form_data = new FormData($booking_form[0]);
358 let data = {
359 action: latepoint_helper.route_action,
360 route_name: latepoint_helper.reload_booking_form_summary_route,
361 params: latepoint_formdata_to_url_encoded_string(form_data),
362 layout: 'none',
363 return_format: 'json'
364 }
365
366 let response = await jQuery.ajax({
367 type: "post",
368 dataType: "json",
369 url: latepoint_timestamped_ajaxurl(),
370 data: data
371 });
372 if (response.status === 'success') {
373 $booking_form_element.find('.os-summary-contents').html(response.message);
374 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading');
375 // hide on verify and confirmation steps
376 if (current_step && !['verify', 'confirmation'].includes(current_step) && response.message) {
377 $summary_panel.addClass('latepoint-summary-is-open');
378 } else {
379 $summary_panel.removeClass('latepoint-summary-is-open');
380 }
381 latepoint_init_booking_summary_panel($booking_form_element);
382 } else {
383 throw new Error(response.message ? response.message : 'Error reloading summary');
384 }
385 }
386
387 function latepoint_init_booking_summary_panel($booking_form_element) {
388 let $summary_panel = $booking_form_element.find('.latepoint-summary-w');
389 if (!$summary_panel.length) return;
390
391 $summary_panel.find('.load-customer-step-trigger').on('click', function () {
392 jQuery(this).addClass('os-loading');
393 latepoint_reload_step($booking_form_element, 'customer');
394 return false;
395 });
396
397 $summary_panel.find('.price-breakdown-unfold').on('click', function () {
398 jQuery(this).closest('.summary-price-breakdown-wrapper').removeClass('compact-summary');
399 return false;
400 });
401
402 $summary_panel.find('.os-remove-item-from-cart').on('click keydown', function (event) {
403 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
404 latepoint_remove_cart_item(jQuery(this));
405 return false;
406 });
407 }
408
409 function latepoint_password_changed_show_login(response) {
410 jQuery('.os-step-existing-customer-login-w').show();
411 jQuery('.os-password-reset-form-holder').html('');
412 latepoint_show_message_inside_element(response.message, jQuery('.os-step-existing-customer-login-w'), 'success');
413 }
414
415 function latepoint_hide_message_inside_element($elem = jQuery('.latepoint-body')) {
416 if ($elem.length && $elem.find('.latepoint-message').length) {
417 $elem.find('.latepoint-message').remove();
418 }
419 }
420
421 function latepoint_show_message_inside_element(message, $elem = jQuery('.latepoint-body'), message_type = 'error') {
422 message = message || 'Error. Please try again.';
423 if ($elem.length) {
424 if ($elem.find('.latepoint-message').length) {
425 $elem.find('.latepoint-message').removeClass('latepoint-message-success').removeClass('latepoint-message-error').addClass('latepoint-message-' + message_type + '').html(message).show();
426 } else {
427 $elem.prepend('<div class="latepoint-message latepoint-message-' + message_type + '">' + message + '</div>');
428 }
429 // scroll errors into view
430 if (message_type == 'error') $elem.find('.latepoint-message')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
431 }
432 }
433
434 function latepoint_add_action(callbacks_list, action, priority = 10) {
435 callbacks_list.push({priority: priority, action: action});
436 callbacks_list.sort((a, b) => a.priority - b.priority);
437 return callbacks_list;
438 }
439
440 function latepoint_update_next_btn_label($booking_form_element) {
441 let btn_label = $booking_form_element.find('.latepoint-step-content').last().data('next-btn-label')
442 if (btn_label) {
443 $booking_form_element.find('.latepoint-next-btn span').text(btn_label);
444 }
445 }
446
447 function latepoint_init_step(step_code, $booking_form_element) {
448 latepoint_init_step_selectable_items($booking_form_element);
449 latepoint_init_step_category_items(step_code);
450 switch (step_code) {
451 case 'customer':
452 latepoint_init_step_customer($booking_form_element);
453 break;
454 case 'booking__datepicker':
455 latepoint_init_step_datepicker($booking_form_element);
456 break;
457 case 'booking__agents':
458 latepoint_init_step_agents();
459 break;
460 case 'booking__locations':
461 latepoint_init_step_locations();
462 break;
463 case 'booking__services':
464 latepoint_init_step_services();
465 break;
466 case 'payment__methods':
467 latepoint_init_step_payment__methods($booking_form_element);
468 break;
469 case 'payment__times':
470 latepoint_init_step_payment__times($booking_form_element);
471 break;
472 case 'payment__portions':
473 latepoint_init_step_payment__portions($booking_form_element);
474 break;
475 case 'payment__pay':
476 latepoint_init_step_payment__pay($booking_form_element);
477 break;
478 case 'verify':
479 latepoint_init_step_verify($booking_form_element);
480 break;
481 case 'confirmation':
482 latepoint_init_step_confirmation($booking_form_element);
483 break;
484 }
485
486 $booking_form_element.trigger("latepoint:initStep", [{step_code: step_code}]);
487 $booking_form_element.trigger("latepoint:initStep:" + step_code);
488 }
489
490
491 async function latepoint_generate_day_timeslots($day, $wrapper_element = false, $scrollable_wrapper = false) {
492 if (!$wrapper_element) $wrapper_element = $day.closest('.latepoint-booking-form-element');
493
494 $day.addClass('selected');
495
496 var service_duration = $day.data('service-duration');
497 var interval = $day.data('interval');
498 var work_start_minutes = $day.data('work-start-time');
499 var work_end_minutes = $day.data('work-end-time');
500 var total_work_minutes = $day.data('total-work-minutes');
501 var bookable_minutes = [];
502 var available_capacities_of_bookable_minute = [];
503 if ($day.attr('data-bookable-minutes')) {
504 if ($day.data('bookable-minutes').toString().indexOf(':') > -1) {
505 // has capacity information embedded into bookable minutes string
506 let bookable_minutes_with_capacity = $day.data('bookable-minutes').toString().split(',');
507 for (let i = 0; i < bookable_minutes_with_capacity.length; i++) {
508 bookable_minutes.push(parseInt(bookable_minutes_with_capacity[i].split(':')[0]));
509 available_capacities_of_bookable_minute.push(parseInt(bookable_minutes_with_capacity[i].split(':')[1]));
510 }
511 } else {
512 bookable_minutes = $day.data('bookable-minutes').toString().split(',').map(Number);
513 }
514 }
515 var work_minutes = $day.data('work-minutes').toString().split(',').map(Number);
516
517 var $timeslots = $wrapper_element.find('.timeslots');
518 $timeslots.html('');
519
520 if (total_work_minutes > 0 && bookable_minutes.length && work_minutes.length) {
521 var prev_minutes = false;
522 work_minutes.forEach(function (current_minutes) {
523 var ampm = latepoint_am_or_pm(current_minutes);
524
525 var timeslot_class = 'dp-timepicker-trigger';
526 var timeslot_available_capacity = 0;
527 if (latepoint_helper.time_pick_style == 'timeline') {
528 timeslot_class += ' dp-timeslot';
529 } else {
530 timeslot_class += ' dp-timebox';
531 }
532
533 if (prev_minutes !== false && ((current_minutes - prev_minutes) > service_duration)) {
534 // show interval that is off between two work periods
535 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);
536 var off_width = (((current_minutes - prev_minutes - service_duration) / total_work_minutes) * 100);
537 $timeslots.append('<div class="' + timeslot_class + ' is-off" style="max-width:' + off_width + '%; width:' + off_width + '%"><span class="dp-label">' + off_label + '</span></div>');
538 }
539
540 if (!bookable_minutes.includes(current_minutes)) {
541 timeslot_class += ' is-booked';
542 } else {
543 if (available_capacities_of_bookable_minute.length) timeslot_available_capacity = available_capacities_of_bookable_minute[bookable_minutes.indexOf(current_minutes)];
544 }
545 var tick_html = '';
546 var capacity_label = '';
547 var capacity_label_html = '';
548 var capacity_internal_label_html = '';
549
550 if (((current_minutes % 60) == 0) || (interval >= 60)) {
551 timeslot_class += ' with-tick';
552 tick_html = '<span class="dp-tick"><strong>' + latepoint_minutes_to_hours_preferably(current_minutes) + '</strong>' + ' ' + ampm + '</span>';
553 }
554 var timeslot_label = latepoint_minutes_to_hours_and_minutes(current_minutes) + ' ' + ampm;
555 if (latepoint_show_booking_end_time()) {
556 var end_minutes = current_minutes + service_duration;
557 if (end_minutes > 1440) end_minutes = end_minutes - 1440;
558 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
559 timeslot_label += ' - <span class="dp-label-end-time">' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm + '</span>';
560 }
561 if (timeslot_available_capacity) {
562 var spaces_message = timeslot_available_capacity > 1 ? latepoint_helper.many_spaces_message : latepoint_helper.single_space_message;
563 capacity_label = timeslot_available_capacity + ' ' + spaces_message;
564 capacity_label_html = '<span class="dp-capacity">' + capacity_label + '</span>';
565 capacity_internal_label_html = '<span class="dp-label-capacity">' + capacity_label + '</span>';
566 }
567 timeslot_label = timeslot_label.trim();
568 $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>');
569 prev_minutes = current_minutes;
570 });
571 } else {
572 // No working hours this day
573 $timeslots.addClass('slots-not-available').append('<div class="not-working-message">' + latepoint_helper.msg_not_available + "</div>");
574 }
575 jQuery('.times-header-label span').text($day.data('nice-date'));
576 $wrapper_element.find('.time-selector-w').slideDown(200, function () {
577 if (!$scrollable_wrapper) $scrollable_wrapper = $wrapper_element.find('.latepoint-body');
578 $scrollable_wrapper.stop();
579 $wrapper_element.find('.time-selector-w')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
580 });
581 }
582
583
584 function latepoint_recurring_option_clicked(event) {
585 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
586 let $btn = jQuery(this);
587 let $booking_form_element = $btn.closest('.latepoint-booking-form-element');
588 $booking_form_element.find('.latepoint_is_recurring').val($btn.data('value'));
589 latepoint_trigger_next_btn($booking_form_element);
590 $booking_form_element.find('.step-datepicker-w').removeClass('show-recurring-prompt');
591 return false;
592 }
593
594 function latepoint_timeslot_clicked(event) {
595 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
596 event.preventDefault();
597 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
598 let $trigger = jQuery(this);
599 if ($trigger.hasClass('is-booked') || jQuery(this).hasClass('is-off')) {
600 // Show error message that you cant select a booked period
601 } else {
602 if ($trigger.hasClass('selected')) {
603 $trigger.removeClass('selected');
604 $trigger.find('.dp-success-label').remove();
605 $booking_form_element.find('.latepoint_start_time').val('');
606 latepoint_hide_next_btn($booking_form_element);
607 latepoint_reload_summary($booking_form_element);
608 } else {
609 $booking_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove();
610 let selected_timeslot_time = $trigger.find('.dp-label-time').html();
611 $trigger.addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>');
612
613 let start_minutes = parseInt($trigger.data('minutes'));
614 let start_date = $trigger.closest('.os-dates-and-times-w').find('.os-day.selected').data('date');
615
616 if ($booking_form_element.find('.recurring-bookings-preview-wrapper').length && $booking_form_element.find('.os-recurrence-rules').length) {
617 // recurring datepicker
618 if ($booking_form_element.find('.recurring-bookings-preview-wrapper .recurring-booking-preview.is-editing').length) {
619 // editing one of timeslots, not the recurrence settings
620 let $recurring_bookings_fields = $booking_form_element.find('.os-recurrence-selection-fields-wrapper');
621 let $edited_booking = $booking_form_element.find('.recurring-bookings-preview-wrapper .recurring-booking-preview.is-editing');
622
623 $recurring_bookings_fields.find('input[name="recurrence[overrides][' + $edited_booking.data('stamp') + '][custom_day]"]').val(start_date);
624 $recurring_bookings_fields.find('input[name="recurrence[overrides][' + $edited_booking.data('stamp') + '][custom_minutes]"]').val(start_minutes);
625
626 return window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, false);
627 } else {
628 // editing recurrence start date/time
629 $booking_form_element.find('.latepoint_start_date').val(start_date);
630 $booking_form_element.find('.latepoint_start_time').val(start_minutes);
631 return window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, true);
632 }
633 } else {
634 $booking_form_element.find('.latepoint_start_date').val(start_date);
635 $booking_form_element.find('.latepoint_start_time').val(start_minutes);
636 if ($trigger.closest('.os-dates-and-times-w').data('allow-recurring') === 'yes') {
637 $booking_form_element.find('.step-datepicker-w').addClass('show-recurring-prompt');
638 $booking_form_element.find('.os-recurring-suggestion-wrapper')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
639 latepoint_hide_next_btn($booking_form_element);
640 latepoint_hide_prev_btn($booking_form_element);
641 } else {
642 latepoint_trigger_next_btn($booking_form_element);
643 }
644 }
645 }
646 }
647 return false;
648 }
649
650 function latepoint_init_timeslots($booking_form_element = false) {
651 if (!$booking_form_element) return;
652 $booking_form_element.off('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
653 $booking_form_element.on('click', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
654 $booking_form_element.off('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
655 $booking_form_element.on('keydown', '.dp-timepicker-trigger', latepoint_timeslot_clicked);
656
657 $booking_form_element.off('click', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
658 $booking_form_element.on('click', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
659 $booking_form_element.off('keydown', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
660 $booking_form_element.on('keydown', '.os-recurring-suggestion-option', latepoint_recurring_option_clicked);
661 }
662
663 async function latepoint_monthly_calendar_load_next_month($booking_form_element) {
664 try {
665
666 if ($booking_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length) {
667 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
668 $booking_form_element.find('.os-month-prev-btn').removeClass('disabled');
669 latepoint_calendar_set_month_label($booking_form_element);
670 return true;
671 } else {
672 let $btn = $booking_form_element.find('.os-month-next-btn');
673 let next_month_route_name = $btn.data('route');
674 $btn.addClass('os-loading');
675 let $calendar_element = $booking_form_element.find('.os-monthly-calendar-days-w').last();
676 let calendar_year = $calendar_element.data('calendar-year');
677 let calendar_month = $calendar_element.data('calendar-month');
678 if (calendar_month == 12) {
679 calendar_year = calendar_year + 1;
680 calendar_month = 1;
681 } else {
682 calendar_month = calendar_month + 1;
683 }
684 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
685 form_data.set('target_date_string', `${calendar_year}-${calendar_month}-1`);
686 let params = latepoint_formdata_to_url_encoded_string(form_data);
687 let data = {
688 action: latepoint_helper.route_action,
689 route_name: next_month_route_name,
690 params: params,
691 layout: 'none',
692 return_format: 'json'
693 }
694 let response = await jQuery.ajax({
695 type: "post",
696 dataType: "json",
697 url: latepoint_timestamped_ajaxurl(),
698 data: data,
699 success: function (data) {
700 }
701 });
702 $btn.removeClass('os-loading');
703 if (response.status === "success") {
704 $booking_form_element.find('.os-months').append(response.message);
705 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
706 latepoint_calendar_set_month_label($booking_form_element);
707 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
708 return true;
709 } else {
710 console.log(response.message);
711 return false;
712 }
713
714 }
715 } catch (e) {
716 console.log(e);
717 alert('Error:' + e);
718 return false;
719 }
720 }
721
722 function latepoint_init_monthly_calendar_navigation($booking_form_element = false) {
723 if (!$booking_form_element) return;
724 $booking_form_element.find('.os-month-next-btn').on('click', async function () {
725 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
726 let result = await latepoint_monthly_calendar_load_next_month($booking_form_element);
727 latepoint_datepicker_toggle_no_availability_message($booking_form_element);
728 return result;
729 });
730 $booking_form_element.find('.os-month-prev-btn').on('click', function () {
731 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
732 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) {
733 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active');
734 latepoint_calendar_set_month_label($booking_form_element);
735 }
736 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
737 latepoint_datepicker_toggle_no_availability_message($booking_form_element);
738 return false;
739 });
740 }
741
742 function latepoint_calendar_set_month_label($booking_form_element) {
743 $booking_form_element.find('.os-current-month-label .current-year').text($booking_form_element.find('.os-monthly-calendar-days-w.active').data('calendar-year'));
744 $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'));
745 }
746
747
748 function latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element) {
749 $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'));
750 $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'));
751
752 if ($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length) {
753 $booking_form_element.find('.os-month-prev-btn').removeClass('disabled');
754 } else {
755 $booking_form_element.find('.os-month-prev-btn').addClass('disabled');
756 }
757 }
758
759 function latepoint_format_minutes_to_time(minutes, service_duration) {
760 var ampm = latepoint_am_or_pm(minutes);
761 var formatted_time = latepoint_minutes_to_hours_and_minutes(minutes) + ' ' + ampm;
762 if (latepoint_show_booking_end_time()) {
763 var end_minutes = minutes + service_duration;
764 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
765 formatted_time += ' - ' + latepoint_minutes_to_hours_and_minutes(end_minutes) + ' ' + end_minutes_ampm;
766 }
767 formatted_time = formatted_time.trim();
768 return formatted_time;
769 }
770
771 function latepoint_monthly_calendar_day_clicked(event) {
772 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
773 let $day = jQuery(this);
774 if ($day.hasClass('os-day-passed')) return false;
775 if ($day.hasClass('os-not-in-allowed-period')) return false;
776 if ($day.closest('.os-dates-and-times-w').hasClass('calendar-style-modern')) {
777 if ($day.hasClass('os-month-prev')) return false;
778 if ($day.hasClass('os-month-next')) return false;
779 }
780 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
781 if ($day.closest('.os-recurrence-datepicker-wrapper').length) {
782 // recurrent datepicker
783 $day.closest('.os-recurrence-datepicker-wrapper').find('.os-day.selected').removeClass('selected');
784 $day.addClass('selected');
785 if ($day.closest('.os-dates-and-times-w').hasClass('days-only')) {
786 $day.closest('.step-recurring-bookings-w').find('input[name="recurrence[rules][repeat_end_date]"]').val($day.data('date'));
787 window.latepointRecurringBookingsFrontFeature.reload_recurrence_rules($booking_form_element, true);
788 } else {
789 latepoint_generate_day_timeslots($day);
790 $day.closest('.os-recurrence-datepicker-wrapper').find('.time-selector-w')[0].scrollIntoView({block: "nearest", behavior: 'smooth'});
791 }
792 } else {
793 // regular datepicker
794 if ($day.closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')) {
795 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT
796 if ($day.hasClass('os-not-available')) {
797 // clicked on a day that has no available timeslots
798 // do nothing
799 } else {
800 $booking_form_element.find('.os-day.selected').removeClass('selected');
801 $day.addClass('selected');
802 // set date
803 $booking_form_element.find('.latepoint_start_date').val($day.data('date'));
804 if ($day.hasClass('os-one-slot-only')) {
805 // clicked on a day that has only one slot available
806 var bookable_minutes = $day.data('bookable-minutes').toString().split(':')[0];
807 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number($day.data('service-duration')));
808 $booking_form_element.find('.latepoint_start_time').val($day.data('bookable-minutes'));
809 latepoint_show_next_btn($booking_form_element);
810 $booking_form_element.find('.time-selector-w').slideUp(200);
811 } else {
812 // regular day with more than 1 timeslots available
813 // build timeslots
814 latepoint_generate_day_timeslots($day);
815 // clear time and hide next btn
816 $booking_form_element.find('.latepoint_start_time').val('');
817 latepoint_hide_next_btn($booking_form_element);
818 }
819 latepoint_reload_summary($booking_form_element);
820 }
821 } else {
822
823 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT
824 $booking_form_element.find('.latepoint_start_date').val($day.data('date'));
825 $booking_form_element.find('.os-day.selected').removeClass('selected');
826 $day.addClass('selected');
827
828 // build timeslots
829 latepoint_generate_day_timeslots($day);
830 // clear time and hide next btn
831 latepoint_reload_summary($booking_form_element);
832 $booking_form_element.find('.latepoint_start_time').val('');
833 latepoint_hide_next_btn($booking_form_element);
834 }
835 }
836
837
838 return false;
839 }
840
841 // shows the "no availability" message when no loaded month has a day available for booking, hides it otherwise
842 function latepoint_datepicker_toggle_no_availability_message($booking_form_element) {
843 let has_available = $booking_form_element.find('.os-day.os-month-current').not('.os-not-available').length > 0;
844 $booking_form_element.find('.os-no-availability-message').toggle(!has_available);
845 }
846
847 async function latepoint_init_step_datepicker($booking_form_element = false) {
848 if (!$booking_form_element) return true;
849 latepoint_init_timeslots($booking_form_element);
850 latepoint_init_monthly_calendar_navigation($booking_form_element);
851 $booking_form_element.off('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
852 $booking_form_element.on('click', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
853 $booking_form_element.off('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
854 $booking_form_element.on('keydown', '.os-months .os-day', latepoint_monthly_calendar_day_clicked);
855
856 if ($booking_form_element.find('input[name="booking[start_date]"]').val()) {
857 $booking_form_element.find('.os-day[data-date="' + $booking_form_element.find('input[name="booking[start_date]"]').val() + '"]').trigger('click');
858 } else {
859 if ($booking_form_element.find('.os-dates-and-times-w').hasClass('auto-search')) {
860 let max_number_of_months_to_check = 24;
861 let current_year = new Date().getFullYear();
862 for (let i = 0; i < max_number_of_months_to_check; i++) {
863 let $active_month = $booking_form_element.find('.os-monthly-calendar-days-w.active');
864 let searching_month_label = $active_month.data('calendar-month-label');
865 if ($active_month.data('calendar-year') != current_year) searching_month_label += ' ' + $active_month.data('calendar-year');
866 $booking_form_element.find('.os-calendar-searching-info span').text(searching_month_label);
867 // check if active month has any days available for booking
868 let $first_available = $active_month.find('.os-day.os-month-current').not('.os-not-available').first();
869 if ($first_available.length) {
870 break;
871 } else {
872 await latepoint_monthly_calendar_load_next_month($booking_form_element);
873 }
874 }
875 }
876 latepoint_datepicker_toggle_no_availability_message($booking_form_element);
877 }
878 $booking_form_element.find('.os-dates-and-times-w').removeClass('is-searching');
879 return true;
880 }
881
882
883 function latepoint_init_step_verify($booking_form_element = false) {
884 if (!$booking_form_element) return;
885 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open');
886
887 $booking_form_element.find('.latepoint-body .load-customer-step-trigger').on('click', function () {
888 jQuery(this).addClass('os-loading');
889 latepoint_reload_step($booking_form_element, 'customer');
890 return false;
891 });
892
893 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-trigger-on-verify-w a').on('click', function (e) {
894 jQuery(this).closest('.coupon-code-wrapper-on-verify').addClass('entering-coupon').find('.coupon-code-input').trigger('focus');
895 return false;
896 });
897 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-cancel').on('click', function (e) {
898 jQuery(this).closest('.coupon-code-wrapper-on-verify').removeClass('entering-coupon');
899 return false;
900 });
901
902 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-input-submit').on('click', function (e) {
903 latepoint_apply_coupon(jQuery(this).closest('.coupon-code-input-w').find('.coupon-code-input'));
904 return false;
905 });
906
907 $booking_form_element.find('.os-remove-item-from-cart').on('click keydown', function (event) {
908 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
909 //make sure to clear active cart item so it doesn't add it again on reload!
910 if (confirm(jQuery(this).data('confirm-text'))) {
911 latepoint_remove_cart_item(jQuery(this));
912 }
913 return false;
914 });
915
916 $booking_form_element.find('.coupon-code-wrapper-on-verify .coupon-code-clear').on('click', function (e) {
917 latepoint_remove_coupon(jQuery(this));
918 return false;
919 });
920
921 $booking_form_element.find('.coupon-code-wrapper-on-verify input.coupon-code-input').on('keyup', function (e) {
922 if (e.which === 13) {
923 latepoint_apply_coupon(jQuery(this));
924 return false;
925 }
926 });
927 }
928
929
930 function latepoint_init_step_payment__pay($booking_form_element = false) {
931 var selected_payment_method = $booking_form_element.find('input[name="cart[payment_method]"]').val();
932 latepoint_init_payment_method_actions($booking_form_element, selected_payment_method);
933 }
934
935 function latepoint_init_step_payment__portions($booking_form_element = false) {
936 // Selecting Payment Time
937 $booking_form_element.find('.lp-payment-trigger-payment-portion-selector').on('click keydown', function (event) {
938 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
939 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
940 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
941 latepoint_show_prev_btn($booking_form_element);
942 latepoint_trigger_next_btn($booking_form_element);
943 return false;
944 });
945 }
946
947 function latepoint_init_step_payment__times($booking_form_element = false) {
948 // Selecting Payment Time
949 $booking_form_element.find('.lp-payment-trigger-payment-time-selector').on('click keydown', function (event) {
950 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
951 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
952 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
953 latepoint_show_prev_btn($booking_form_element);
954 latepoint_trigger_next_btn($booking_form_element);
955 return false;
956 });
957 }
958
959
960 function latepoint_init_step_payment__methods($booking_form_element = false) {
961 // Selecting Payment Time
962 $booking_form_element.find('.lp-payment-trigger-payment-method-selector').on('click', function (e) {
963 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
964 $booking_form_element.find('input[name="' + jQuery(this).data('holder') + '"]').val(jQuery(this).data('value'));
965 latepoint_show_prev_btn($booking_form_element);
966 latepoint_trigger_next_btn($booking_form_element);
967 return false;
968 });
969 }
970
971 function latepoint_category_item_clicked(event) {
972 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
973 let $item = jQuery(event.target);
974
975 let $booking_form_element = $item.closest('.latepoint-booking-form-element');
976 latepoint_show_prev_btn($booking_form_element);
977 $item.closest('.latepoint-step-content').addClass('selecting-item-category');
978 let $category_wrapper = $item.closest('.os-item-category-w');
979 let $main_parent = $item.closest('.os-item-categories-main-parent');
980 if ($category_wrapper.hasClass('selected')) {
981 $category_wrapper.removeClass('selected');
982 if ($category_wrapper.parent().closest('.os-item-category-w').length) {
983 $category_wrapper.parent().closest('.os-item-category-w').addClass('selected');
984 } else {
985 $main_parent.removeClass('show-selected-only');
986 }
987 } else {
988 $main_parent.find('.os-item-category-w.selected').removeClass('selected');
989 $main_parent.addClass('show-selected-only');
990 $category_wrapper.addClass('selected');
991 }
992 return false;
993 }
994
995 function latepoint_init_step_category_items(step_code) {
996 let $category_items = jQuery('.latepoint-step-content[data-step-code="' + step_code + '"] .os-item-category-info');
997 $category_items.on('click', latepoint_category_item_clicked);
998 $category_items.on('keydown', latepoint_category_item_clicked);
999 }
1000
1001
1002 function latepoint_init_step_selectable_items($booking_form_element) {
1003 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
1004 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
1005
1006 $booking_form_element.off('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
1007 $booking_form_element.on('click', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
1008
1009 // commit a manually typed quantity on focusout/blur (desktop) and on virtual keyboard dismiss (mobile)
1010 $booking_form_element.off('change', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
1011 $booking_form_element.on('change', '.os-selectable-items .os-selectable-item .item-quantity-selector-input', latepoint_selectable_item_quantity_keyup);
1012
1013
1014 $booking_form_element.off('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
1015 $booking_form_element.on('keydown', '.os-selectable-items .os-selectable-item', latepoint_selectable_item_clicked);
1016 }
1017
1018
1019 function latepoint_update_quantity_for_selectable_items($item) {
1020 var ids = $item.closest('.os-selectable-items')
1021 .find('.os-selectable-item.selected')
1022 .map(function () {
1023 if (jQuery(this).hasClass('has-quantity')) {
1024 return jQuery(this).data('item-id') + ':' + jQuery(this).find('input.item-quantity-selector-input').val();
1025 } else {
1026 return jQuery(this).data('item-id');
1027 }
1028 }).get();
1029 $item.closest('.latepoint-booking-form-element').find($item.data('id-holder')).val(ids);
1030 }
1031
1032 function latepoint_selectable_item_quantity_keyup(event) {
1033 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1034 var $item = jQuery(this).closest('.os-selectable-item');
1035 var new_value = jQuery(this).val();
1036 if (new_value && new_value.match(/^\d+$/)) {
1037 var max_quantity = $item.data('max-quantity');
1038 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity;
1039 } else {
1040 new_value = 0;
1041 }
1042 jQuery(this).val(new_value);
1043
1044 if (($item.hasClass('selected') && (new_value > 0)) || (!$item.hasClass('selected') && (new_value == 0))) {
1045 latepoint_update_quantity_for_selectable_items($item);
1046 latepoint_reload_summary($booking_form_element);
1047 return false;
1048 } else {
1049 $item.trigger('click');
1050 }
1051 }
1052
1053 function latepoint_selectable_item_clicked(event) {
1054 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
1055 event.stopPropagation();
1056 event.stopImmediatePropagation();
1057 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1058 if (jQuery(this).hasClass('has-quantity')) {
1059 if (jQuery(event.target).hasClass('item-quantity-selector')) {
1060 var current_value = parseInt(jQuery(this).find('input.item-quantity-selector-input').val());
1061 var new_value = (jQuery(event.target).data('sign') == 'minus') ? current_value - 1 : current_value + 1;
1062 var max_quantity = jQuery(this).data('max-quantity');
1063 if (new_value < 0) new_value = 0;
1064 if (max_quantity && (new_value > max_quantity)) new_value = max_quantity;
1065 jQuery(this).find('input.item-quantity-selector-input').val(new_value);
1066 if ((jQuery(this).hasClass('selected') && (new_value > 0)) || (!jQuery(this).hasClass('selected') && (new_value == 0))) {
1067 latepoint_update_quantity_for_selectable_items(jQuery(this));
1068 latepoint_reload_summary($booking_form_element);
1069 return false;
1070 }
1071 }
1072 if (jQuery(event.target).hasClass('item-quantity-selector-input')) {
1073 latepoint_update_quantity_for_selectable_items(jQuery(this));
1074 latepoint_reload_summary($booking_form_element);
1075 return false;
1076 }
1077 }
1078 var summary_value = '';
1079 if (jQuery(this).hasClass('os-allow-multiselect')) {
1080 if (jQuery(this).hasClass('selected')) {
1081 jQuery(this).removeClass('selected');
1082 if (jQuery(this).hasClass('has-quantity')) jQuery(this).find('input.item-quantity-selector-input').val(0);
1083 } else {
1084 jQuery(this).addClass('selected');
1085 if (jQuery(this).hasClass('has-quantity') && !(jQuery(this).find('input.item-quantity-selector-input').val() > 0)) {
1086 jQuery(this).find('input.item-quantity-selector-input').val(1);
1087 }
1088 }
1089 latepoint_update_quantity_for_selectable_items(jQuery(this));
1090 latepoint_reload_summary($booking_form_element);
1091 latepoint_show_next_btn($booking_form_element);
1092 } else {
1093 if (!jQuery(this).hasClass('os-duration-item')) jQuery(this).closest('.os-item-categories-main-parent').find('.os-selectable-item.selected').removeClass('selected');
1094 jQuery(this).closest('.os-selectable-items').find('.os-selectable-item.selected').removeClass('selected');
1095 jQuery(this).addClass('selected');
1096 $booking_form_element.find(jQuery(this).data('id-holder')).val(jQuery(this).data('item-id'));
1097 if (jQuery(this).data('cart-item-item-data-key')) {
1098 latepoint_update_active_cart_item_item_data($booking_form_element, jQuery(this).data('cart-item-item-data-key'), jQuery(this).data('item-id'));
1099 }
1100 if (jQuery(this).data('os-call-func')) {
1101 window[jQuery(this).data('os-call-func')](jQuery(this));
1102 }
1103 if (jQuery(this).data('activate-sub-step')) {
1104 window[jQuery(this).data('activate-sub-step')](jQuery(this));
1105 } else {
1106 latepoint_trigger_next_btn($booking_form_element);
1107 }
1108 }
1109 return false;
1110 }
1111
1112 function latepoint_update_active_cart_item_item_data($booking_form_element, key, value) {
1113 let item_data_json = $booking_form_element.find('input[name="active_cart_item[item_data]"]').val();
1114 let item_data = item_data_json ? JSON.parse($booking_form_element.find('input[name="active_cart_item[item_data]"]').val()) : {};
1115 item_data[key] = value;
1116 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val(JSON.stringify(item_data));
1117 }
1118
1119 function latepoint_format_price(price) {
1120 // replace default decimal separator dot with comma if it's in settings
1121 if (latepoint_helper.decimal_separator == ',') price = String(price).replace('.', ',');
1122 return latepoint_helper.currency_symbol_before + String(price) + latepoint_helper.currency_symbol_after;
1123 }
1124
1125
1126 function latepoint_init_step_services() {
1127 }
1128
1129
1130 function latepoint_trigger_next_btn($booking_form_element) {
1131 $booking_form_element.find('.latepoint_step_direction').val('next');
1132 latepoint_submit_booking_form($booking_form_element.find('.latepoint-form'));
1133 }
1134
1135 function latepoint_init_step_locations() {
1136 }
1137
1138 function latepoint_init_agent_details_link($booking_form_element) {
1139 $booking_form_element.on('click', '.os-trigger-item-details-popup', function () {
1140 $booking_form_element.find('.os-item-details-popup.open').remove();
1141 var $popup = $booking_form_element.find('#' + jQuery(this).data('item-details-popup-id')).first().clone().attr('id', '');
1142 $booking_form_element.find('.latepoint-form-w').addClass('showing-item-details-popup');
1143 $popup.addClass('open').appendTo($booking_form_element.find('.latepoint-body'));
1144 return false;
1145 });
1146 $booking_form_element.on('click', '.os-item-details-popup.open .os-item-details-popup-close', function () {
1147 $booking_form_element.find('.latepoint-form-w').removeClass('showing-item-details-popup');
1148 jQuery(this).closest('.os-item-details-popup.open').remove();
1149 return false;
1150 });
1151 }
1152
1153 function latepoint_init_step_agents() {
1154 }
1155
1156
1157 function latepoint_init_booking_summary_lightbox() {
1158 let $lightbox = jQuery('.customer-dashboard-booking-summary-lightbox');
1159 latepoint_init_qr_trigger($lightbox);
1160 latepoint_init_item_details_popup($lightbox);
1161 }
1162
1163 function latepoint_init_step_confirmation($booking_form_element = false) {
1164 if (!$booking_form_element) return;
1165 $booking_form_element.on('click', '.set-customer-password-btn', function () {
1166 let $btn = jQuery(this);
1167 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1168
1169 $btn.addClass('os-loading');
1170 let params = {
1171 password_nonce: jQuery('input[name="new_password_nonce"]').val(),
1172 password: jQuery('input[name="customer[password]"]').val()
1173 }
1174 let data = {
1175 action: latepoint_helper.route_action,
1176 route_name: jQuery(this).data('btn-action'),
1177 params: jQuery.param(params),
1178 layout: 'none',
1179 return_format: 'json'
1180 }
1181 jQuery.ajax({
1182 type: "post",
1183 dataType: "json",
1184 url: latepoint_timestamped_ajaxurl(),
1185 data: data,
1186 success: function (data) {
1187 $btn.removeClass('os-loading');
1188 if (data.status === "success") {
1189 $booking_form_element.find('.step-confirmation-set-password').html('').hide();
1190 $booking_form_element.find('.confirmation-cabinet-info').show();
1191 } else {
1192 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.step-confirmation-set-password'), 'error');
1193 }
1194 }
1195 });
1196 return false;
1197 });
1198
1199 $booking_form_element.on('click', '.qr-show-trigger', function () {
1200 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1201 $booking_form_element.find('.qr-code-on-full-summary').addClass('show-vevent-qr-code');
1202 return false;
1203 });
1204
1205 $booking_form_element.on('click', '.show-set-password-fields', function () {
1206 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
1207
1208 $booking_form_element.find('.step-confirmation-set-password').show();
1209 $booking_form_element.find('#customer_password').trigger('focus');
1210 jQuery(this).closest('.info-box').hide();
1211 return false;
1212 });
1213 }
1214
1215 function latepoint_init_customer_login_form(){
1216 if(jQuery('.latepoint-login-form-w').length){
1217 jQuery('.latepoint-login-form-w').each(function() {
1218 if(jQuery(this).data('success-action') == 'auto-redirect'){
1219 window.location.replace(jQuery(this).data('redirect-url'))
1220 }else{
1221 latepoint_init_auth_form(jQuery(this));
1222 }
1223 });
1224 }
1225 }
1226
1227 function latepoint_init_customer_dashboard() {
1228 latepoint_init_form_masks();
1229 jQuery('.latepoint-customer-timezone-selector-w select').on('change', function (e) {
1230 var $select_box = jQuery(this);
1231 $select_box.closest('.latepoint-customer-timezone-selector-w').addClass('os-loading');
1232 var data = {
1233 action: latepoint_helper.route_action,
1234 route_name: jQuery(this).closest('.latepoint-customer-timezone-selector-w').data('route-name'),
1235 params: {timezone_name: jQuery(this).val()},
1236 layout: 'none',
1237 return_format: 'json'
1238 }
1239 jQuery.ajax({
1240 type: "post",
1241 dataType: "json",
1242 url: latepoint_timestamped_ajaxurl(),
1243 data: data,
1244 success: function (data) {
1245 $select_box.closest('.latepoint-customer-timezone-selector-w').removeClass('os-loading');
1246 if (data.status === "success") {
1247 location.reload();
1248 } else {
1249
1250 }
1251 }
1252 });
1253 });
1254
1255
1256 jQuery('.latepoint-request-booking-cancellation').on('click', function () {
1257 if (!confirm(latepoint_helper.cancel_booking_prompt)) return false;
1258 var $this = jQuery(this);
1259 var $booking_box = $this.closest('.customer-booking');
1260
1261 var route = jQuery(this).data('route');
1262 var params = {id: $booking_box.data('id')};
1263
1264 var data = {
1265 action: latepoint_helper.route_action,
1266 route_name: route,
1267 params: params,
1268 layout: 'none',
1269 return_format: 'json'
1270 }
1271 $this.addClass('os-loading');
1272 jQuery.ajax({
1273 type: "post",
1274 dataType: "json",
1275 url: latepoint_timestamped_ajaxurl(),
1276 data: data,
1277 success: function (data) {
1278 if (data.status === "success") {
1279 $this.remove();
1280 location.reload();
1281 } else {
1282 $this.removeClass('os-loading');
1283 }
1284 }
1285 });
1286 return false;
1287 });
1288
1289 }
1290
1291
1292 function latepoint_get_customer_name($wrapper) {
1293 var customer_name = '';
1294 var first_name = $wrapper.find('input[name="customer[first_name]"]').val();
1295 var last_name = $wrapper.find('input[name="customer[last_name]"]').val();
1296 if (first_name) customer_name += first_name;
1297 if (last_name) customer_name += ' ' + last_name;
1298 return customer_name.trim();
1299 }
1300
1301 function latepoint_init_customer_otp_code_verify_form($booking_form_element) {
1302 let $verify_otp_btn = $booking_form_element.find('.latepoint-verify-otp-button');
1303 let $verify_otp_input = $booking_form_element.find('.os-otp-code-field');
1304
1305 if ($verify_otp_btn.length && $verify_otp_input.length) {
1306 $verify_otp_input.trigger('focus');
1307
1308 // trigger on enter/space to emulate a button
1309 $verify_otp_btn.on('keydown', function (e) {
1310 if (e.key === 'Enter' || e.key === ' ') {
1311 e.preventDefault();
1312 jQuery(this).trigger('click'); // Triggers the click handler above
1313 }
1314 });
1315 // close
1316 $booking_form_element.find('.latepoint-customer-otp-resend').on('click', function (e) {
1317 e.preventDefault();
1318 latepoint_resend_customer_otp_code($booking_form_element, jQuery(this));
1319 });
1320
1321 $booking_form_element.find('.latepoint-customer-otp-close').on('click', function () {
1322 $booking_form_element.find('.latepoint-customer-otp-input-container').html('');
1323 $booking_form_element.find('.hide-when-entering-otp').removeClass('os-hidden');
1324 latepoint_show_booking_form_footer($booking_form_element);
1325 return false;
1326 });
1327
1328 // input in code field
1329 $verify_otp_input.on('input', function () {
1330 // Remove non-numeric characters
1331 const cleanValue = jQuery(this).val().replace(/[^0-9]/g, '');
1332 jQuery(this).val(cleanValue);
1333 if (cleanValue.length === 6) {
1334 $verify_otp_btn.trigger('click');
1335 }
1336 });
1337 $verify_otp_input.on('keydown', function (e) {
1338 if (e.key === 'Enter') {
1339 e.preventDefault();
1340 $verify_otp_btn.trigger('click');
1341 }
1342 });
1343
1344 $verify_otp_btn.on('click', function (e) {
1345 return latepoint_verify_customer_otp_code($booking_form_element);
1346 });
1347 }
1348
1349 }
1350
1351 async function latepoint_verify_customer_otp_code($booking_form_element) {
1352 let $verify_otp_btn = $booking_form_element.find('.latepoint-verify-otp-button');
1353 let $verify_otp_input = $booking_form_element.find('.os-otp-code-field');
1354
1355 $verify_otp_input.removeClass('os-invalid');
1356 if ($verify_otp_input.val().length !== 6) {
1357 $verify_otp_input.addClass('os-invalid').addClass('os-shake');
1358 return false;
1359 }
1360
1361 $verify_otp_btn.addClass('os-loading');
1362
1363 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
1364
1365 let data = {
1366 action: 'latepoint_route_call',
1367 route_name: $verify_otp_btn.data('route'),
1368 params: latepoint_formdata_to_url_encoded_string(form_data),
1369 layout: 'none',
1370 return_format: 'json'
1371 }
1372 try {
1373 let response = await jQuery.ajax({
1374 type: "post",
1375 dataType: "json",
1376 url: latepoint_timestamped_ajaxurl(),
1377 data: data
1378 });
1379 $verify_otp_btn.removeClass('os-loading');
1380 if (response.status === 'success') {
1381 if($booking_form_element.data('success-action') === 'redirect'){
1382 window.location.replace($booking_form_element.data('redirect-url'));
1383 return true;
1384 }else{
1385 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-customer-otp-input-code-wrapper'));
1386 $booking_form_element.find('input[name="customer_contact_verification_token"]').val(response.message);
1387 latepoint_reload_step($booking_form_element);
1388 }
1389 } else {
1390 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-customer-otp-input-code-wrapper'), 'error');
1391 }
1392 return false;
1393 } catch (e) {
1394 latepoint_show_message_inside_element('Error generating OTP', $booking_form_element.find('.latepoint-customer-otp-input-code-wrapper'), 'error');
1395 throw e;
1396 }
1397 }
1398
1399 async function latepoint_show_verify_contact_form_with_otp_code($booking_form_element, form_html) {
1400 $booking_form_element.find('.latepoint-customer-otp-input-container').html(form_html);
1401 $booking_form_element.find('.hide-when-entering-otp').addClass('os-hidden');
1402 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded');
1403 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading');
1404 latepoint_init_customer_otp_code_verify_form($booking_form_element);
1405 latepoint_hide_booking_form_footer($booking_form_element);
1406 }
1407
1408 function latepoint_hide_booking_form_footer($booking_form_element) {
1409 $booking_form_element.addClass('hidden-buttons');
1410 }
1411
1412 function latepoint_show_booking_form_footer($booking_form_element) {
1413 $booking_form_element.removeClass('hidden-buttons');
1414 }
1415
1416 async function latepoint_resend_customer_otp_code($booking_form_element, $resend_otp_button) {
1417 $resend_otp_button.addClass('os-loading');
1418
1419 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
1420
1421 // get values from phone number fields
1422 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
1423 $booking_form_element.find('input.os-mask-phone').each(function () {
1424 const phoneInputName = this.getAttribute('name');
1425 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
1426 // override value generated automatically by formdata with a formatted value of a phone field with country code
1427 form_data.set(phoneInputName, phoneInputValue);
1428 });
1429 }
1430
1431 let data = {
1432 action: 'latepoint_route_call',
1433 route_name: $resend_otp_button.data('otp-resend-route'),
1434 params: latepoint_formdata_to_url_encoded_string(form_data),
1435 layout: 'none',
1436 return_format: 'json'
1437 }
1438 try {
1439 let response = await jQuery.ajax({
1440 type: "post",
1441 dataType: "json",
1442 url: latepoint_timestamped_ajaxurl(),
1443 data: data
1444 });
1445 $resend_otp_button.removeClass('os-loading');
1446 if (response.status === 'success') {
1447 latepoint_hide_message_inside_element($booking_form_element.find('.hide-when-entering-otp'));
1448 $booking_form_element.find('.hide-when-entering-otp').addClass('os-hidden');
1449 $booking_form_element.find('.latepoint-customer-otp-input-container').html(response.message);
1450 latepoint_init_customer_otp_code_verify_form($booking_form_element);
1451 } else {
1452 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-customer-otp-input-wrapper'), 'error');
1453 }
1454 return false;
1455 } catch (e) {
1456 latepoint_show_message_inside_element('Error generating OTP', $booking_form_element.find('.latepoint-customer-otp-input-wrapper'), 'error');
1457 throw e;
1458 }
1459 }
1460
1461 async function latepoint_request_customer_otp_code($booking_form_element, $request_otp_button) {
1462 $request_otp_button.addClass('os-loading');
1463
1464 let form_data = new FormData($booking_form_element.find('.latepoint-form')[0]);
1465
1466
1467 // get values from phone number fields
1468 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
1469 $booking_form_element.find('input.os-mask-phone').each(function () {
1470 const phoneInputName = this.getAttribute('name');
1471 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
1472 // override value generated automatically by formdata with a formatted value of a phone field with country code
1473 form_data.set(phoneInputName, phoneInputValue);
1474 });
1475 }
1476
1477 let data = {
1478 action: 'latepoint_route_call',
1479 route_name: $request_otp_button.data('otp-request-route'),
1480 params: latepoint_formdata_to_url_encoded_string(form_data),
1481 layout: 'none',
1482 return_format: 'json'
1483 }
1484 try {
1485 let response = await jQuery.ajax({
1486 type: "post",
1487 dataType: "json",
1488 url: latepoint_timestamped_ajaxurl(),
1489 data: data
1490 });
1491 $request_otp_button.removeClass('os-loading');
1492 if (response.status === 'success') {
1493 latepoint_hide_message_inside_element($booking_form_element.find('.hide-when-entering-otp'));
1494 $booking_form_element.find('.hide-when-entering-otp').addClass('os-hidden');
1495 $booking_form_element.find('.latepoint-customer-otp-input-container').html(response.message);
1496 latepoint_init_customer_otp_code_verify_form($booking_form_element);
1497 } else {
1498 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.hide-when-entering-otp'), 'error');
1499 }
1500 return false;
1501 } catch (e) {
1502 latepoint_show_message_inside_element('Error generating OTP', $booking_form_element.find('.hide-when-entering-otp'), 'error');
1503 throw e;
1504 }
1505 }
1506
1507 function latepoint_customer_auth_load_next_step($booking_form_element) {
1508
1509 }
1510
1511 function latepoint_init_customer_otp_code_request_form($booking_form_element) {
1512 let $request_otp_button = $booking_form_element.find('.latepoint-request-otp-button');
1513 if ($request_otp_button.length > 0) {
1514 $request_otp_button.on('click', function (e) {
1515 return latepoint_request_customer_otp_code($booking_form_element, jQuery(this));
1516 });
1517 // trigger on enter/space to emulate a button
1518 $request_otp_button.on('keydown', function (e) {
1519 if (e.key === 'Enter' || e.key === ' ') {
1520 e.preventDefault();
1521 jQuery(this).trigger('click'); // Triggers the click handler above
1522 }
1523 });
1524 $booking_form_element.find('.latepoint-customer-otp-request-wrapper').find('input, select').on('keydown', function (e) {
1525 if (e.key === 'Enter') {
1526 e.preventDefault();
1527 $request_otp_button.trigger('click');
1528 }
1529 });
1530 }
1531 }
1532
1533 async function latepoint_login_customer($booking_form_element, $request_otp_button) {
1534
1535 $request_otp_button.addClass('os-loading');
1536 let $form = $booking_form_element.find('.latepoint-form');
1537
1538 let form_data = new FormData($form[0]);
1539
1540 // get values from phone number fields
1541 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
1542 $form.find('input.os-mask-phone').each(function () {
1543 const phoneInputName = this.getAttribute('name');
1544 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
1545 // override value generated automatically by formdata with a formatted value of a phone field with country code
1546 form_data.set(phoneInputName, phoneInputValue);
1547 });
1548 }
1549
1550 let data = {
1551 action: 'latepoint_route_call',
1552 route_name: $request_otp_button.data('password-login-route'),
1553 params: latepoint_formdata_to_url_encoded_string(form_data),
1554 layout: 'none',
1555 return_format: 'json'
1556 }
1557 try {
1558 let response = await jQuery.ajax({
1559 type: "post",
1560 dataType: "json",
1561 url: latepoint_timestamped_ajaxurl(),
1562 data: data
1563 });
1564 $request_otp_button.removeClass('os-loading');
1565
1566 if (response.status === "success") {
1567 if($booking_form_element.data('success-action') === 'redirect'){
1568 window.location.replace($booking_form_element.data('redirect-url'));
1569 return true;
1570 }else {
1571 return latepoint_reload_step($booking_form_element);
1572 }
1573 } else {
1574 throw new Error(response.message);
1575 }
1576 } catch (e) {
1577 latepoint_show_message_inside_element(e.message, $booking_form_element.find('.os-step-existing-customer-login-w'));
1578 }
1579
1580 }
1581
1582
1583 function latepoint_init_auth_form($wrapper){
1584
1585 latepoint_init_customer_otp_code_request_form($wrapper);
1586 latepoint_init_customer_otp_code_verify_form($wrapper);
1587
1588
1589 $wrapper.find('.login-with-password-toggle').on('change', function () {
1590 if (jQuery(this).hasClass('os-opposite')) {
1591 if (jQuery(this).is(':checked')) {
1592 $wrapper.find('.os-customer-otp-notice').hide();
1593 $wrapper.find('.os-customer-login-password-fields-w').show();
1594 } else {
1595 $wrapper.find('.os-customer-otp-notice').show();
1596 $wrapper.find('.os-customer-login-password-fields-w').hide();
1597 }
1598 } else {
1599 if (jQuery(this).is(':checked')) {
1600 $wrapper.find('.os-customer-otp-notice').show();
1601 $wrapper.find('.os-customer-login-password-fields-w').hide();
1602 } else {
1603 $wrapper.find('.os-customer-otp-notice').hide();
1604 $wrapper.find('.os-customer-login-password-fields-w').show();
1605 }
1606 }
1607 });
1608
1609 $wrapper.find('.alternative-login-option').on('click', function () {
1610 let login_method = jQuery(this).data('auth-via');
1611 let delivery_method = jQuery(this).data('otp-delivery-method');
1612 $wrapper.find('input[name="auth[contact_type]"]').val(login_method);
1613 $wrapper.find('input[name="auth[delivery_method]"]').val(delivery_method);
1614 $wrapper.find('.customer-login-method-wrapper').addClass('os-hidden');
1615 $wrapper.find('.customer-login-method-wrapper[data-login-method="' + login_method + '"]').removeClass('os-hidden');
1616 $wrapper.find('.alternative-login-option').removeClass('os-hidden');
1617 jQuery(this).addClass('os-hidden');
1618 return false;
1619 });
1620
1621 $wrapper.find('.login-options-via-wrapper .login-option').on('click', function () {
1622 let $wrapper = jQuery(this).closest('.latepoint-customer-auth-options-wrapper');
1623 let login_method = jQuery(this).data('login-method');
1624 let delivery_method = jQuery(this).data('otp-delivery-method');
1625
1626 let otp_enabled = jQuery(this).data('is-otp-enabled');
1627 if(otp_enabled === 'no'){
1628 if($wrapper.find('.login-with-password-toggle.os-opposite:not(:checked)').length){
1629 $wrapper.find('.login-with-password-toggle.os-opposite').trigger('click');
1630 }
1631 $wrapper.find('.latepoint-customer-otp-option').hide();
1632 $wrapper.find('.step-login-existing-customer-btn').addClass('latepoint-btn-block');
1633 }else{
1634 if($wrapper.find('.latepoint-customer-otp-option').length){
1635 $wrapper.find('.latepoint-customer-otp-option').show();
1636 $wrapper.find('.step-login-existing-customer-btn').removeClass('latepoint-btn-block');
1637 }
1638 }
1639 $wrapper.find('input[name="auth[contact_type]"]').val(login_method);
1640 $wrapper.find('input[name="auth[delivery_method]"]').val(delivery_method);
1641 jQuery(this).closest('.login-options-via-wrapper').find('.login-option.os-selected').removeClass('os-selected')
1642 jQuery(this).addClass('os-selected');
1643 jQuery('.customer-login-method-wrapper').addClass('os-hidden');
1644 jQuery('.customer-login-method-wrapper[data-login-method="' + login_method + '"]').removeClass('os-hidden');
1645
1646 return false;
1647 });
1648
1649 // Init Login Existing Customer Button
1650 $wrapper.find('.os-customer-login-w input').on('keyup', function (e) {
1651 if (e.keyCode === 13) {
1652 e.preventDefault();
1653 $wrapper.find('.step-login-existing-customer-btn').trigger('click');
1654 return false;
1655 }
1656 });
1657
1658 $wrapper.find('.step-login-existing-customer-btn').on('click', function (e) {
1659 e.preventDefault();
1660 let via = $wrapper.find('input[name="auth[via]"]').val();
1661 if ($wrapper.find('input[name="auth[via]"]').is(':checkbox')) {
1662 let is_checked = $wrapper.find('input[name="auth[via]"]').is(':checked');
1663 if (via === 'otp' && !is_checked) {
1664 via = 'password';
1665 } else if (via === 'password' && !is_checked) {
1666 via = 'otp';
1667 }
1668 }
1669 if (via === 'otp') {
1670 latepoint_request_customer_otp_code($wrapper, jQuery(this));
1671 } else if (via === 'password') {
1672 latepoint_login_customer($wrapper, jQuery(this));
1673 }
1674
1675 });
1676 }
1677
1678 function latepoint_init_step_customer($booking_form_element) {
1679 latepoint_init_form_masks();
1680
1681 latepoint_init_auth_form($booking_form_element);
1682
1683 // Init Logout button
1684 $booking_form_element.find('.step-customer-logout-btn').on('click', function () {
1685 let $logout_btn = jQuery(this);
1686 let $booking_form_element = $logout_btn.closest('.latepoint-booking-form-element');
1687 $booking_form_element.find('input[name="customer_contact_verification_token"]').val('');
1688 let data = {
1689 action: latepoint_helper.route_action,
1690 route_name: $logout_btn.data('btn-action'),
1691 layout: 'none',
1692 return_format: 'json',
1693 params: {auth: {nonce: $logout_btn.data('nonce')}}
1694 }
1695 latepoint_step_content_change_start($booking_form_element);
1696 jQuery.ajax({
1697 type: "post",
1698 dataType: "json",
1699 url: latepoint_timestamped_ajaxurl(),
1700 data: data,
1701 success: function (data) {
1702 $booking_form_element.find('input[name="auth[action]"]').val('logout');
1703 latepoint_reload_step($booking_form_element);
1704 }
1705 });
1706 return false;
1707 });
1708
1709
1710 }
1711
1712 function latepoint_step_content_change_start($booking_form_element) {
1713 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
1714 }
1715
1716 // TODO
1717 function latepoint_step_content_change_end(new_content, $booking_form_element) {
1718 if (new_content) $booking_form_element.find('.latepoint-body .latepoint-step-content').replaceWith(new_content);
1719 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
1720 setTimeout(function () {
1721 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
1722 }, 50);
1723 }
1724
1725
1726 function latepoint_change_step_desc($booking_form_element, step_code) {
1727 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1728 setTimeout(function () {
1729 // Progress bar
1730 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1731 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1732 $step_progress.nextAll().removeClass('complete').removeClass('active');
1733 // Side panel
1734 var side_panel_desc = $booking_form_element.find('.latepoint-step-desc-library[data-step-code="' + step_code + '"]').html();
1735 $booking_form_element.find('.latepoint-step-desc').html(side_panel_desc);
1736
1737 // Top header
1738 var top_header_desc = $booking_form_element.find('.os-heading-text-library[data-step-code="' + step_code + '"]').html();
1739 $booking_form_element.find('.os-heading-text').html(top_header_desc);
1740 setTimeout(function () {
1741 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1742 }, 50);
1743 }, 500);
1744 }
1745
1746
1747 function latepoint_progress_prev($booking_form_element, step_code) {
1748 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1749 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1750 $step_progress.nextAll().removeClass('complete').removeClass('active');
1751 }
1752
1753
1754 function latepoint_progress_next($booking_form_element, step_code) {
1755 var $step_progress = $booking_form_element.find('.latepoint-progress li[data-step-code="' + step_code + '"]');
1756 $step_progress.addClass('active').addClass('complete').prevAll().addClass('complete').removeClass('active');
1757 $step_progress.nextAll().removeClass('complete').removeClass('active');
1758 }
1759
1760
1761 function latepoint_next_step_description($booking_form_element, step_code) {
1762 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1763 setTimeout(function () {
1764 $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());
1765 $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());
1766 setTimeout(function () {
1767 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1768 }, 50);
1769 }, 500);
1770 }
1771
1772 function latepoint_prev_step_description($booking_form_element, step_code) {
1773 $booking_form_element.removeClass('step-changed').addClass('step-changing');
1774 setTimeout(function () {
1775 $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());
1776 $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());
1777 setTimeout(function () {
1778 $booking_form_element.removeClass('step-changing').addClass('step-changed');
1779 }, 50);
1780 }, 500);
1781 }
1782
1783
1784 function latepoint_validate_fields($fields) {
1785 var is_valid = true;
1786 $fields.each(function (index) {
1787 if (jQuery(this).val() == '') {
1788 is_valid = false;
1789 return false;
1790 }
1791 });
1792 return is_valid;
1793 }
1794
1795
1796 async function latepoint_submit_booking_form($booking_form) {
1797 let $booking_form_element = $booking_form.closest('.latepoint-booking-form-element');
1798
1799 let current_step = $booking_form_element.find('.latepoint_current_step_code').val();
1800 let callbacks_list = [];
1801 if (latepoint_check_if_booking_form_is_final_submit($booking_form_element)) {
1802 // check if order intent is still bookable
1803 latepoint_add_action(callbacks_list, async () => {
1804 return await latepoint_check_if_order_intent_still_bookable($booking_form_element);
1805 }, 1);
1806 }
1807 $booking_form_element.trigger('latepoint:submitBookingForm', [{
1808 current_step: current_step,
1809 callbacks_list: callbacks_list,
1810 is_final_submit: latepoint_check_if_booking_form_is_final_submit($booking_form_element),
1811 direction: $booking_form_element.find('.latepoint_step_direction').val()
1812 }]);
1813 try {
1814 latepoint_hide_prev_btn($booking_form_element);
1815 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form);
1816 } catch (error) {
1817 latepoint_show_prev_btn($booking_form_element);
1818 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
1819 return false;
1820 }
1821
1822
1823 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
1824 latepoint_hide_prev_btn($booking_form_element);
1825 try {
1826 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body'));
1827 let response = await jQuery.ajax({
1828 type: "post",
1829 dataType: "json",
1830 processData: false,
1831 contentType: false,
1832 url: latepoint_timestamped_ajaxurl(),
1833 data: latepoint_create_form_data($booking_form)
1834 });
1835
1836 $booking_form.find('.latepoint_step_direction').val('next');
1837 if (response.status === 'success') {
1838 if (response.fields_to_update) {
1839 for (const [key, value] of Object.entries(response.fields_to_update)) {
1840 $booking_form_element.find('input[name="' + key + '"]').val(value)
1841 }
1842 }
1843 if ($booking_form_element.data('flash-error')) {
1844 latepoint_show_message_inside_element($booking_form_element.data('flash-error'), $booking_form_element.find('.latepoint-body'));
1845 $booking_form_element.data('flash-error', '');
1846 }
1847 $booking_form_element.find('.latepoint_current_step_code').val(response.step_code);
1848 $booking_form_element.removeClass(function (index, className) {
1849 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
1850 }).addClass('current-step-' + response.step_code);
1851 setTimeout(function () {
1852 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
1853 $booking_form_element.find('.latepoint-body').find('.latepoint-step-content').addClass('is-hidden');
1854 if ($booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]')) {
1855 $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.step_code + '"]').remove();
1856 }
1857 $booking_form_element.find('.latepoint-body').append(response.message);
1858
1859
1860 latepoint_update_next_btn_label($booking_form_element);
1861 latepoint_init_step(response.step_code, $booking_form_element);
1862 setTimeout(function () {
1863 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
1864 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading');
1865 latepoint_scroll_to_top_of_booking_form($booking_form_element);
1866 }, 50);
1867 }, 500);
1868
1869 if (response.is_pre_last_step) {
1870 $booking_form_element.data('next-submit-is-last', 'yes');
1871 } else {
1872 $booking_form_element.data('next-submit-is-last', 'no');
1873 }
1874 if (response.is_last_step) {
1875 $booking_form_element.addClass('hidden-buttons').find('.latepoint-footer').remove();
1876 $booking_form_element.find('.latepoint-progress').css('opacity', 0);
1877 $booking_form_element.closest('.latepoint-summary-is-open').removeClass('latepoint-summary-is-open');
1878 $booking_form_element.closest('.latepoint-show-side-panel').removeClass('latepoint-show-side-panel').addClass('latepoint-hide-side-panel');
1879 $booking_form_element.addClass('is-final-step');
1880 } else {
1881 if (response.show_next_btn === true) {
1882 latepoint_show_next_btn($booking_form_element);
1883 } else {
1884 latepoint_hide_next_btn($booking_form_element);
1885 }
1886 if (response.show_prev_btn === true) {
1887 latepoint_show_prev_btn($booking_form_element);
1888 } else {
1889 latepoint_hide_prev_btn($booking_form_element);
1890 }
1891 }
1892 latepoint_change_step_desc($booking_form_element, response.step_code);
1893 latepoint_reload_summary($booking_form_element);
1894 } else {
1895 if (response.fields_to_update) {
1896 for (const [key, value] of Object.entries(response.fields_to_update)) {
1897 $booking_form_element.find('input[name="' + key + '"]').val(value)
1898 }
1899 }
1900 if (response.callback) {
1901 let func_name = response.callback;
1902 if (func_name.includes('.')) {
1903 let func_arr = func_name.split('.');
1904 if (typeof window[func_arr[0]][func_arr[1]] !== 'function') {
1905 console.log(func_name + ' is undefined');
1906 }
1907 if (response.callback_data) {
1908 window[func_arr[0]][func_arr[1]]($booking_form_element, response.callback_data);
1909 } else {
1910 window[func_arr[0]][func_arr[1]]($booking_form_element);
1911 }
1912 } else {
1913 if (typeof window[func_name] !== 'function') {
1914 console.log(func_name + ' is undefined');
1915 }
1916 if (response.callback_data) {
1917 window[func_name]($booking_form_element, response.callback_data);
1918 } else {
1919 window[func_name]($booking_form_element);
1920 }
1921 }
1922 } else {
1923 if (response.send_to_step && response.send_to_step === 'resubmit') {
1924 let current_resubmit_count = parseInt($booking_form.data('resubmit-count')) ? parseInt($booking_form.data('resubmit-count')) : 1;
1925 $booking_form.data('resubmit-count', current_resubmit_count + 1);
1926 if (current_resubmit_count > 6) {
1927 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body'));
1928 } else {
1929 // resubmission probably caused by order intent still being processed, since
1930 // order intent is still processing, give it a little more time and try again
1931 await latepoint_sleep(2000);
1932 return latepoint_submit_booking_form($booking_form);
1933 }
1934 } else {
1935 $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded');
1936 $booking_form_element.find('.latepoint-next-btn, .latepoint-prev-btn').removeClass('os-loading');
1937 if (response.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + response.send_to_step + '"]').length) {
1938 $booking_form_element.data('flash-error', response.message);
1939 latepoint_reload_step($booking_form_element, response.send_to_step);
1940 } else {
1941 latepoint_show_message_inside_element(response.message, $booking_form_element.find('.latepoint-body'));
1942 latepoint_show_prev_btn($booking_form_element);
1943 }
1944 }
1945 }
1946 }
1947 } catch (e) {
1948 console.log(e);
1949 alert('Error:' + e);
1950 }
1951 }
1952
1953 function latepoint_sleep(ms) {
1954 return new Promise(resolve => setTimeout(resolve, ms));
1955 }
1956
1957 function latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element) {
1958 if (error.send_to_step && $booking_form_element.find('.latepoint-step-content[data-step-code="' + error.send_to_step + '"]').length) {
1959 latepoint_reload_step($booking_form_element, error.send_to_step);
1960 $booking_form_element.data('flash-error', error.message);
1961 } else {
1962 latepoint_show_message_inside_element(error.message, $booking_form_element.find('.latepoint-body'), 'error');
1963
1964 if ($booking_form_element.hasClass('step-content-loading')) $booking_form_element.removeClass('step-content-loading').addClass('step-content-loaded');
1965 $booking_form_element.find('.latepoint-next-btn').removeClass('os-loading');
1966
1967 // if previous step exists - show prev button
1968 if ($booking_form_element.find('.latepoint-step-content:last-child').prev('.latepoint-step-content').length) latepoint_show_prev_btn($booking_form_element);
1969 latepoint_scroll_to_top_of_booking_form($booking_form_element);
1970 }
1971 }
1972
1973 function latepoint_reset_active_cart_item($booking_form_element) {
1974 $booking_form_element.find('input[name="active_cart_item[id]"]').val('');
1975 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('');
1976 $booking_form_element.find('input[name="active_cart_item[item_data]"]').val('');
1977 }
1978
1979 function latepoint_check_if_booking_form_is_final_submit($booking_form_element) {
1980 return ($booking_form_element.data('next-submit-is-last') == 'yes');
1981 }
1982
1983
1984 async function latepoint_check_if_order_intent_still_bookable($booking_form_element) {
1985 let response = await jQuery.ajax({
1986 type: "post",
1987 dataType: "json",
1988 processData: false,
1989 contentType: false,
1990 url: latepoint_timestamped_ajaxurl(),
1991 data: latepoint_create_form_data($booking_form_element.find('.latepoint-form'), latepoint_helper.check_order_intent_bookable_route)
1992 });
1993 if (response.status === 'success') {
1994 return true;
1995 } else {
1996 throw new Error(response.message);
1997 }
1998 }
1999
2000 async function latepoint_process_list_of_callbacks(callbacks, $booking_form_element, $booking_form) {
2001 for (const callback of callbacks) {
2002 await callback.action();
2003 }
2004 }
2005
2006 function latepoint_clear_presets($booking_form_element) {
2007 $booking_form_element.find('.clear_for_new_item').val('');
2008 }
2009
2010 function latepoint_init_booking_form($booking_form_element) {
2011 $booking_form_element.on('click keydown', '.checkout-from-summary-panel-btn', function (event) {
2012 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
2013 latepoint_reload_step($booking_form_element, jQuery(this).data('step'));
2014 jQuery(this).closest('.latepoint-w').removeClass('show-summary-on-mobile');
2015 return false;
2016 });
2017
2018 $booking_form_element.on('click keydown', '.latepoint-add-another-item-trigger', function (event) {
2019 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
2020
2021 if (latepoint_helper.reset_presets_when_adding_new_item) {
2022 latepoint_clear_presets($booking_form_element);
2023 }
2024 latepoint_reset_active_cart_item($booking_form_element);
2025 latepoint_reload_step($booking_form_element, jQuery(this).data('step'));
2026 return false;
2027 });
2028 $booking_form_element.find('.latepoint-form').on('submit', function (e) {
2029 e.preventDefault();
2030 let $booking_form = jQuery(this);
2031 latepoint_submit_booking_form($booking_form);
2032 });
2033
2034 latepoint_init_booking_summary_panel($booking_form_element);
2035
2036 $booking_form_element.on('click keydown', '.latepoint-lightbox-summary-trigger', function (event) {
2037 event.preventDefault();
2038 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
2039 let $wrapper = jQuery(this).closest('.latepoint-w');
2040 $wrapper.toggleClass('show-summary-on-mobile');
2041 return false;
2042 });
2043
2044 $booking_form_element.find('.latepoint-lightbox-close').on('click', function () {
2045
2046 let params = new URLSearchParams(location.search);
2047 if (params.has('latepoint_order_intent_key')) {
2048 params.delete('latepoint_order_intent_key');
2049 history.replaceState(null, '', '?' + params + location.hash);
2050 }
2051
2052 jQuery('body').removeClass('latepoint-lightbox-active');
2053 jQuery('.latepoint-lightbox-w').remove();
2054 return false;
2055 });
2056
2057
2058 $booking_form_element.on('click keydown', '.lp-option', function (event) {
2059 if (event.type === 'keydown' && event.key !== ' ' && event.key !== 'Enter') return;
2060 jQuery(this).closest('.lp-options').find('.lp-option.selected').removeClass('selected');
2061 jQuery(this).addClass('selected');
2062 });
2063
2064
2065 // Next Step button Click
2066 $booking_form_element.find('.latepoint-next-btn').on('click', async function (e) {
2067 e.preventDefault();
2068 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false;
2069 var $next_btn = jQuery(this);
2070 $next_btn.addClass('os-loading');
2071 var $booking_form = jQuery(this).closest('.latepoint-form');
2072
2073 var current_step = $booking_form_element.find('.latepoint_current_step_code').val();
2074
2075 $booking_form.find('.latepoint_step_direction').val('next');
2076 var callbacks_list = [];
2077
2078 $booking_form_element.trigger('latepoint:nextStepClicked', [{
2079 current_step: current_step,
2080 callbacks_list: callbacks_list
2081 }]);
2082 latepoint_hide_prev_btn($booking_form_element);
2083
2084 try {
2085 await latepoint_process_list_of_callbacks(callbacks_list, $booking_form_element, $booking_form);
2086 await latepoint_submit_booking_form($booking_form);
2087 } catch (error) {
2088 latepoint_show_error_and_stop_loading_booking_form(error, $booking_form_element);
2089 }
2090 return false;
2091 });
2092
2093
2094 // Previous Step button Click
2095 $booking_form_element.find('.latepoint-prev-btn').on('click', function (e) {
2096 if (jQuery(this).hasClass('disabled') || jQuery(this).hasClass('os-loading')) return false;
2097
2098 let $current_step = $booking_form_element.find('.latepoint-step-content:last-child');
2099
2100
2101 // handle categories
2102 if ($current_step.hasClass('selecting-item-category')) {
2103 if ($current_step.find('.os-item-category-w .os-item-category-w.selected').length) {
2104 $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');
2105 } else {
2106 $current_step.removeClass('selecting-item-category').find('.os-item-category-w.selected').removeClass('selected');
2107 $current_step.removeClass('selecting-item-category').find('.os-item-categories-holder.show-selected-only').removeClass('show-selected-only');
2108 }
2109 if (($booking_form_element.find('.latepoint-step-content').length <= 1) && !$current_step.hasClass('selecting-item-category')) {
2110 latepoint_hide_prev_btn($booking_form_element);
2111 }
2112 latepoint_reload_summary($booking_form_element);
2113 return false;
2114 }
2115
2116 if ($current_step.data('clear-action')) {
2117 window[$current_step.data('clear-action')]($booking_form_element);
2118 }
2119
2120 let $back_btn = jQuery(this);
2121 $back_btn.addClass('os-loading');
2122 $booking_form_element.removeClass('step-content-loaded').addClass('step-content-loading');
2123 let $new_current_step = $booking_form_element.find('.latepoint-step-content.is-hidden').last();
2124 let new_current_step_code = $new_current_step.data('step-code');
2125 let current_step_code = $current_step.data('step-code');
2126
2127
2128 let current_parent_code_name = current_step_code.split('__')[0];
2129 let new_parent_code_name = new_current_step_code.split('__')[0];
2130
2131 let active_cart_item_id = $booking_form_element.find('input[name="active_cart_item[id]"]').val();
2132
2133 latepoint_change_step_desc($booking_form_element, new_current_step_code);
2134 setTimeout(function () {
2135 $new_current_step.removeClass('is-hidden');
2136 $current_step.remove();
2137 $booking_form_element.find('.latepoint_current_step_code').val(new_current_step_code);
2138 $booking_form_element.removeClass(function (index, className) {
2139 return (className.match(/(^|\s)current-step-\S+/g) || []).join(' ');
2140 }).addClass('current-step-' + new_current_step_code);
2141 $booking_form_element.find('.latepoint-next-btn span').text($booking_form_element.find('.latepoint-next-btn').data('label'));
2142 $booking_form_element.data('next-submit-is-last', 'no');
2143
2144 latepoint_update_next_btn_label($booking_form_element);
2145 latepoint_show_next_btn($booking_form_element);
2146 $back_btn.removeClass('os-loading');
2147 if ($booking_form_element.find('.latepoint-step-content').length <= 1) {
2148 if ($new_current_step.hasClass('selecting-item-category')) {
2149
2150 }
2151 if (new_current_step_code == 'booking__services') {
2152 var $services_step = $booking_form_element.find('.step-services-w');
2153 if ($services_step.hasClass('selecting-item-category')) {
2154 if ($services_step.find('.os-services > .os-item.selected').hasClass('is-preselected')) {
2155 // if service is preselected check if there are both multiple durations and quantity selector and only then show prev button
2156 } else {
2157 latepoint_show_prev_btn($booking_form_element);
2158 }
2159 } else {
2160 latepoint_hide_prev_btn($booking_form_element);
2161 }
2162 } else {
2163 if (!$new_current_step.hasClass('selecting-item-category')) {
2164 latepoint_hide_prev_btn($booking_form_element);
2165 }
2166 }
2167 }
2168 $booking_form_element.removeClass('step-content-loading').addClass('step-content-mid-loading');
2169
2170
2171 if (new_parent_code_name == 'booking' && current_parent_code_name != 'booking' && active_cart_item_id) {
2172
2173 // 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
2174 $booking_form_element.find('.latepoint-summary-w').addClass('os-loading');
2175 let data = {
2176 action: latepoint_helper.route_action,
2177 route_name: latepoint_helper.remove_cart_item_route,
2178 params: jQuery.param({cart_item_id: active_cart_item_id}),
2179 layout: 'none',
2180 return_format: 'json'
2181 }
2182 jQuery.ajax({
2183 type: "post",
2184 dataType: "json",
2185 url: latepoint_timestamped_ajaxurl(),
2186 data: data,
2187 success: function (data) {
2188 if (data.status === "success") {
2189 $booking_form_element.find('input[name="active_cart_item[id]"]').val('');
2190 if ($booking_form_element.find('input[name="active_cart_item[variant]"]').val() == 'bundle') {
2191 latepoint_update_active_cart_item_item_data($booking_form_element, 'bundle_id', '');
2192 $booking_form_element.find('input[name="active_cart_item[variant]"]').val('');
2193 }
2194 latepoint_reload_summary($booking_form_element);
2195 } else {
2196 $booking_form_element.find('.latepoint-summary-w').removeClass('os-loading');
2197 latepoint_show_message_inside_element(data.message, $booking_form_element.find('.latepoint-body'), 'error');
2198 }
2199 }
2200 });
2201 } else {
2202 latepoint_reload_summary($booking_form_element);
2203 }
2204 setTimeout(function () {
2205 $booking_form_element.removeClass('step-content-mid-loading').addClass('step-content-loaded');
2206 latepoint_hide_message_inside_element($booking_form_element.find('.latepoint-body'));
2207 latepoint_scroll_to_top_of_booking_form($booking_form_element);
2208
2209 let callbacks_list = [];
2210 $booking_form_element.trigger('latepoint:prevStepReInit', [{
2211 current_step: new_current_step_code,
2212 callbacks_list: callbacks_list
2213 }]);
2214 }, 150);
2215 }, 700);
2216 return false;
2217 });
2218
2219 latepoint_init_agent_details_link($booking_form_element);
2220 $booking_form_element.trigger('latepoint:initBookingForm');
2221 }
2222
2223
2224 function latepoint_init_booking_form_by_trigger($trigger) {
2225 let route = latepoint_helper.booking_button_route;
2226 let params = {};
2227 let restrictions = {};
2228 let presets = {};
2229 let booking_element_styles = {};
2230 if ($trigger.data('show-service-categories')) restrictions.show_service_categories = $trigger.data('show-service-categories');
2231 if ($trigger.data('show-locations')) restrictions.show_locations = $trigger.data('show-locations');
2232 if ($trigger.data('show-services')) restrictions.show_services = $trigger.data('show-services');
2233 if ($trigger.data('show-agents')) restrictions.show_agents = $trigger.data('show-agents');
2234 if ($trigger.data('calendar-start-date')) restrictions.calendar_start_date = $trigger.data('calendar-start-date');
2235 if ($trigger.data('service-display-mode')) restrictions.service_display_mode = $trigger.data('service-display-mode');
2236
2237 if ($trigger.data('selected-location')) presets.selected_location = $trigger.data('selected-location');
2238 if ($trigger.data('selected-agent')) presets.selected_agent = $trigger.data('selected-agent');
2239 if ($trigger.data('selected-service')) presets.selected_service = $trigger.data('selected-service');
2240 if ($trigger.data('selected-bundle')) presets.selected_bundle = $trigger.data('selected-bundle');
2241 if ($trigger.data('selected-duration')) presets.selected_duration = $trigger.data('selected-duration');
2242 if ($trigger.data('selected-total-attendees')) presets.selected_total_attendees = $trigger.data('selected-total-attendees');
2243 if ($trigger.data('selected-service-category')) presets.selected_service_category = $trigger.data('selected-service-category');
2244 if ($trigger.data('selected-start-date')) presets.selected_start_date = $trigger.data('selected-start-date');
2245 if ($trigger.data('selected-start-time')) presets.selected_start_time = $trigger.data('selected-start-time');
2246 if ($trigger.data('order-item-id')) presets.order_item_id = $trigger.data('order-item-id');
2247 if ($trigger.data('source-id')) presets.source_id = $trigger.data('source-id');
2248
2249 // Pass raw URL query parameters as a generic transport for addons (e.g. contact field pre-fill).
2250 if (window.location.search) {
2251 let url_params = {};
2252 new URLSearchParams(window.location.search).forEach(function(value, key) { url_params[key] = value; });
2253 if (Object.keys(url_params).length) presets.url_params = url_params;
2254 }
2255
2256 if ($trigger.data('hide-summary') == 'yes') booking_element_styles.hide_summary = true;
2257 if ($trigger.data('hide-side-panel') == 'yes') booking_element_styles.hide_side_panel = true;
2258
2259
2260 if (jQuery.isEmptyObject(restrictions) == false) params.restrictions = restrictions;
2261 if (jQuery.isEmptyObject(presets) == false) params.presets = presets;
2262 if (jQuery.isEmptyObject(booking_element_styles) == false) params.booking_element_styles = booking_element_styles;
2263
2264 let data = {
2265 action: latepoint_helper.route_action,
2266 route_name: route,
2267 params: params,
2268 layout: 'none',
2269 return_format: 'json'
2270 }
2271
2272 let is_inline_form = $trigger.hasClass('latepoint-book-form-wrapper');
2273 if (is_inline_form) {
2274 data.params.booking_element_type = 'inline_form';
2275 }
2276
2277 $trigger.addClass('os-loading');
2278 jQuery.ajax({
2279 type: "post",
2280 dataType: "json",
2281 url: latepoint_timestamped_ajaxurl(),
2282 data: data,
2283 success: (data) => {
2284 if (data.status === "success") {
2285 let $booking_form_element = false;
2286 if (is_inline_form) {
2287 $trigger.html(data.message);
2288 $booking_form_element = $trigger.find('.latepoint-booking-form-element');
2289 } else {
2290 let lightbox_class = 'booking-form-in-lightbox';
2291 latepoint_show_data_in_lightbox(data.message, lightbox_class, false);
2292 $booking_form_element = jQuery('.latepoint-lightbox-w .latepoint-booking-form-element');
2293 jQuery('body').addClass('latepoint-lightbox-active');
2294 }
2295 latepoint_init_booking_form($booking_form_element);
2296 latepoint_init_step(data.step, $booking_form_element);
2297 $trigger.removeClass('os-loading');
2298 } else {
2299 $trigger.removeClass('os-loading');
2300 // console.log(data.message);
2301 }
2302 }
2303 });
2304 }
2305