PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.0
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.0
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 / public / javascripts / admin.js
latepoint / public / javascripts Last commit date
vendor 1 year ago admin.js 9 months ago admin.js.map 1 year ago front.js 9 months ago front.js.map 1 year ago vendor-admin.js 1 year ago vendor-front.js 1 year ago
admin.js
5681 lines
1 function latepoint_is_timeframe_in_periods(timeframe_start, timeframe_end, periods_arr) {
2 var is_inside = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
3
4 for (var i = 0; i < periods_arr.length; i++) {
5
6 var period_start = 0;
7 var period_end = 0;
8 var buffer_before = 0;
9 var buffer_after = 0;
10
11 var period_info = periods_arr[i].split(':');
12 if (period_info.length == 2) {
13 period_start = period_info[0];
14 period_end = period_info[1];
15 } else {
16 buffer_before = period_info[2];
17 buffer_after = period_info[3];
18 period_start = parseFloat(period_info[0]) - parseFloat(buffer_before);
19 period_end = parseFloat(period_info[1]) + parseFloat(buffer_after);
20 }
21 if (is_inside) {
22 if (latepoint_is_period_inside_another(timeframe_start, timeframe_end, period_start, period_end)) {
23 return true;
24 }
25 } else {
26 if (latepoint_is_period_overlapping(timeframe_start, timeframe_end, period_start, period_end)) {
27 return true;
28 }
29 }
30 }
31 return false;
32 }
33
34 function latepoint_is_period_overlapping(period_one_start, period_one_end, period_two_start, period_two_end) {
35 // https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap/
36 return period_one_start < period_two_end && period_two_start < period_one_end;
37 }
38
39 function latepoint_is_period_inside_another(period_one_start, period_one_end, period_two_start, period_two_end) {
40 return period_one_start >= period_two_start && period_one_end <= period_two_end;
41 }
42
43
44 // Converts time in minutes to hours if possible, if minutes also exists - shows minutes too
45 function latepoint_minutes_to_hours_preferably(time) {
46 var army_clock = latepoint_is_army_clock();
47
48 var hours = Math.floor(time / 60);
49 if (!army_clock && hours > 12) hours = hours - 12;
50
51 var minutes = time % 60;
52 if (minutes > 0) hours = hours + ':' + minutes;
53 return hours;
54 }
55
56
57 function latepoint_minutes_to_hours(time) {
58 var army_clock = latepoint_is_army_clock();
59
60 var hours = Math.floor(time / 60);
61 if (!army_clock && hours > 12) hours = hours - 12;
62 return hours;
63 }
64
65
66 function latepoint_am_or_pm(minutes) {
67 if (latepoint_is_army_clock()) return '';
68 return (minutes < 720 || minutes == 1440) ? 'am' : 'pm';
69 }
70
71 function latepoint_hours_and_minutes_to_minutes(hours_and_minutes, ampm) {
72 var hours_and_minutes_arr = hours_and_minutes.split(':');
73 var hours = hours_and_minutes_arr[0];
74 var minutes = hours_and_minutes_arr[1];
75 if (ampm == "pm" && hours < 12) hours = parseInt(hours) + 12;
76 if (ampm == "am" && hours == 12) hours = 0;
77 minutes = parseInt(minutes) + (hours * 60);
78 return minutes;
79 }
80
81 function latepoint_get_time_system() {
82 return latepoint_helper.time_system;
83 }
84
85 function latepoint_is_army_clock() {
86 return (latepoint_get_time_system() == '24');
87 }
88
89 function latepoint_minutes_to_hours_and_minutes(minutes) {
90 var army_clock = latepoint_is_army_clock();
91 var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '%02d:%02d';
92
93 var hours = Math.floor(minutes / 60);
94 if (!army_clock && (hours > 12)) hours = hours - 12;
95 if (!army_clock && hours == 0) hours = 12;
96 minutes = minutes % 60;
97 // Check if sprintf is available (either native or from a library)
98 if (typeof sprintf === 'function') {
99 return sprintf(format, hours, minutes);
100 } else {
101 return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
102 }
103 }
104
105
106 (function($) {
107
108 jQuery.fn.lateSelect = function() {
109
110 function os_build_selected_item($option){
111 var quantity_html = '';
112 if($option.data('quantity')) quantity_html = '<span class="os-late-quantity-selector-w"><span class="os-late-quantity-selector minus" data-sign="minus"></span><input class="os-late-quantity-selector-input" type="text" data-max-quantity="'+ $option.data('max-quantity') +'" value="' + $option.data('quantity') + '"/><span class="os-late-quantity-selector plus" data-sign="plus"></span></span>';
113 return '<div class="ls-item" data-value="' + $option.val() + '"><span class="latepoint-icon latepoint-icon-cross ls-item-remover"></span><span>' + $option.text() + '</span>' + quantity_html + '</div>'
114 }
115
116 this.each( function() {
117 var lateselect_html = '';
118 var all_items = '';
119 var selected_items = '';
120 var is_selected = '';
121 if(jQuery(this).hasClass('os-late-select-active')) return;
122 jQuery(this).hide().addClass('os-late-select-active');
123 jQuery(this).find('option').each(function(){
124 if(jQuery(this).is(':selected')) selected_items+= os_build_selected_item(jQuery(this));
125 is_selected = jQuery(this).is(':selected') ? 'selected' : '';
126 all_items+= '<div class="ls-item '+ is_selected +'" data-value="' + jQuery(this).val() + '">' + jQuery(this).text() + '</div>';
127 });
128 var placeholder = '<div class="ls-placeholder">' + jQuery(this).data('placeholder') + '</div>';
129 lateselect_html = jQuery('<div class="lateselect-w"></div>');
130 jQuery(this).wrap(lateselect_html);
131 var $lateselect_wrapper = jQuery(this).closest('.lateselect-w');
132 $lateselect_wrapper.append('<div class="ls-selected-items-w">' + placeholder + selected_items + '</div>');
133 $lateselect_wrapper.append('<div class="ls-all-items-w">' + all_items + '</div>');
134
135
136 // ADD ITEM
137 $lateselect_wrapper.on('click', '.ls-all-items-w .ls-item:not(.selected)', function(){
138 var selected_value = jQuery(this).data('value');
139 $lateselect_wrapper.find('.ls-selected-items-w').append(os_build_selected_item($lateselect_wrapper.find('select option[value="'+ selected_value +'"]')));
140 jQuery(this).addClass('selected');
141 $lateselect_wrapper.removeClass('ls-selecting');
142 $lateselect_wrapper.find('select option[value="'+ selected_value +'"]').prop('selected', true);
143 $lateselect_wrapper.find('select').trigger('change');
144 return false;
145 });
146
147 // REMOVE ITEM
148 $lateselect_wrapper.on('click', '.ls-selected-items-w .ls-item-remover', function(){
149 var selected_value = jQuery(this).closest('.ls-item').data('value');
150 jQuery(this).closest('.ls-item').remove();
151 $lateselect_wrapper.find('.ls-all-items-w .ls-item.selected[data-value="' + selected_value + '"]').removeClass('selected');
152 $lateselect_wrapper.find('select option[value="'+ selected_value +'"]').prop('selected', false);
153 $lateselect_wrapper.find('select').trigger('change');
154 return false;
155 });
156
157 $lateselect_wrapper.on('click', '.ls-selected-items-w', function(){
158 $lateselect_wrapper.toggleClass('ls-selecting');
159 return false;
160 });
161
162 $lateselect_wrapper.on('click', '.os-late-quantity-selector', function(){
163 var $input = jQuery(this).closest('.ls-item').find('input.os-late-quantity-selector-input');
164 var current_value = parseInt($input.val());
165 var new_quantity = (jQuery(this).data('sign') == 'minus') ? current_value - 1 : current_value + 1;
166 var max_quantity = $input.data('max-quantity');
167 if(new_quantity <= 0) new_quantity = 1;
168 if(max_quantity && (new_quantity > max_quantity)) new_quantity = max_quantity;
169 var selected_value = jQuery(this).closest('.ls-item').data('value');
170 $lateselect_wrapper.find('select option[value="'+ selected_value +'"]').data('quantity', new_quantity);
171 $input.val(new_quantity);
172 $lateselect_wrapper.find('select').trigger('change');
173 return false;
174 });
175
176 jQuery(this).on('change', function(){
177 var $hidden_connection = false;
178 if(jQuery(this).data('hidden-connection')){
179 $hidden_connection = jQuery(jQuery(this).data('hidden-connection'));
180 }else{
181 $hidden_connection = jQuery(this).closest('.lateselect-w').next('input[type="hidden"]');
182 }
183 var formatted_ids = '';
184 if(jQuery(this).find('option:selected').length){
185 jQuery(this).find('option:selected').each(function(){
186 if(jQuery(this).data('quantity')){
187 var quantity = jQuery(this).data('quantity') ? jQuery(this).data('quantity') : 1;
188 formatted_ids+= jQuery(this).val() + ':' + quantity + ',';
189 }else{
190 formatted_ids+= jQuery(this).val() + ',';
191 }
192 });
193 }else{
194 formatted_ids = '';
195 }
196 if(formatted_ids != '') formatted_ids = formatted_ids.slice(0, -1);
197 $hidden_connection.val(formatted_ids);
198 });
199 });
200 }
201 }(jQuery));
202
203 /*
204 * Copyright (c) 2023 LatePoint LLC. All rights reserved.
205 */
206
207 (function($) {
208
209 jQuery.fn.lateCheckbox = function() {
210
211 function applyChanges(id){
212 let $wrapper = jQuery('.latecheckbox-w[data-latecheckbox-id="' + id + '"]');
213 $wrapper.find('.latecheckbox-options-w').html(jQuery('.latecheckbox-options-w[data-latecheckbox-id="' + id + '"]').html());
214
215 let $options = $wrapper.find('.latecheckbox-options');
216 let total_checked = $options.find('.latecheckbox-option input[type="checkbox"]:checked').length;
217 let total_available = $options.find('.latecheckbox-option input[type="checkbox"]').length;
218 if(total_checked < total_available){
219 $wrapper.find('.latecheckbox .filter-value').text(total_checked);
220 }else{
221 $wrapper.find('.latecheckbox .filter-value').text('All');
222 }
223 // set indeterminate, since it can only be set via JS
224 $wrapper.find('input[type="checkbox"][indeterminate="indeterminate"]').prop('indeterminate', true).removeAttr('indeterminate');
225
226 $wrapper.find('.latecheckbox').trigger('change');
227 }
228
229 this.each( function() {
230 var $latecheckbox_wrapper = jQuery(this).closest('.latecheckbox-w');
231 $latecheckbox_wrapper.attr('data-latecheckbox-id', 'latecheckbox-' + latepoint_random_generator());
232
233 $latecheckbox_wrapper.on('click', '.latecheckbox', function(){
234 let $latecheckbox = jQuery(this);
235 jQuery('body > .latecheckbox-options-w').remove();
236 if(jQuery(this).hasClass('is-active')){
237 jQuery(this).removeClass('is-active');
238 }else{
239 jQuery('.latecheckbox.is-active').removeClass('is-active');
240 jQuery(this).addClass('is-active');
241 let position = jQuery(this).position();
242 let left = position.left;
243 let $options_wrapper = $latecheckbox_wrapper.find('.latecheckbox-options-w');
244 let $options_wrapper_clone = $options_wrapper.clone();
245 $options_wrapper_clone.attr('data-latecheckbox-id', jQuery(this).closest('.latecheckbox-w').attr('data-latecheckbox-id')).appendTo('body');
246 if(true){
247 // todo add ability to change position
248 left = left + jQuery(this).outerWidth() - $options_wrapper_clone.outerWidth();
249 }
250 $options_wrapper_clone.css({"top": position.top + jQuery(this).outerHeight() +5 , "left": left});
251 if($options_wrapper_clone.find('.latecheckbox-filter-input').length) $options_wrapper_clone.find('.latecheckbox-filter-input').trigger('focus');
252
253 $options_wrapper_clone.on('change', '.latecheckbox-all-check', function(){
254 if(jQuery(this).is(':checked')){
255 jQuery(this).attr('checked', 'checked').removeAttr('indeterminate');
256 jQuery(this).closest('.latecheckbox-options-w').find('.latecheckbox-options input[type="checkbox"]').prop('checked', true).prop('indeterminate', false).attr('checked', 'checked');
257 }else{
258 jQuery(this).removeAttr('checked').removeAttr('indeterminate');
259 jQuery(this).closest('.latecheckbox-options-w').find('.latecheckbox-options input[type="checkbox"]').prop('checked', false).prop('indeterminate', false).removeAttr('checked');
260 }
261 applyChanges(jQuery(this).closest('.latecheckbox-options-w').attr('data-latecheckbox-id'));
262 });
263 $options_wrapper_clone.on('change', '.latecheckbox-group-check', function(){
264 if(jQuery(this).is(':checked')){
265 jQuery(this).attr('checked', 'checked').removeAttr('indeterminate');
266 jQuery(this).closest('.latecheckbox-group').find('.latecheckbox-group-options input[type="checkbox"]').prop('checked', true).attr('checked', 'checked');
267 }else{
268 jQuery(this).removeAttr('checked').removeAttr('indeterminate');
269 jQuery(this).closest('.latecheckbox-group').find('.latecheckbox-group-options input[type="checkbox"]').prop('checked', false).removeAttr('checked');
270 }
271 applyChanges(jQuery(this).closest('.latecheckbox-options-w').attr('data-latecheckbox-id'));
272 });
273
274 $options_wrapper_clone.on('keyup', '.latecheckbox-filter-input', function(){
275 let q = jQuery(this).val().toLowerCase();
276 if(q == ''){
277 jQuery(this).closest('.latecheckbox-options-w').find('.latecheckbox-option.hidden').removeClass('hidden');
278 }else{
279 jQuery(this).closest('.latecheckbox-options-w').find('.latecheckbox-option').each(function(){
280 let text = jQuery(this).text().toLowerCase();
281 (text.indexOf(q) >= 0) ? jQuery(this).removeClass('hidden') : jQuery(this).addClass('hidden');
282 });
283 }
284 });
285
286 $options_wrapper_clone.on('change', '.latecheckbox-option input[type="checkbox"]', function(){
287 if(jQuery(this).is(':checked')){
288 jQuery(this).attr('checked', 'checked');
289 }else{
290 jQuery(this).removeAttr('checked');
291 }
292
293 // group checkbox
294 if(jQuery(this).closest('.latecheckbox-group-options').length){
295 let $group = jQuery(this).closest('.latecheckbox-group');
296 let checked_count = $group.find('.latecheckbox-option input:checked').length;
297 let unchecked_count = $group.find('.latecheckbox-option input:not(:checked)').length;
298
299 if(checked_count && unchecked_count){
300 $group.find('.latecheckbox-group-check').prop('indeterminate', true).attr('indeterminate', 'indeterminate');
301 $group.find('.latecheckbox-group-check').prop('checked', false).removeAttr('checked');
302 }else{
303 $group.find('.latecheckbox-group-check').prop('indeterminate', false).removeAttr('indeterminate');
304 if(!checked_count){
305 $group.find('.latecheckbox-group-check').prop('checked', false).removeAttr('checked');
306 }
307 if(!unchecked_count){
308 $group.find('.latecheckbox-group-check').prop('checked', true).attr('checked', 'checked');
309 }
310 }
311 }
312 let checked_count = $options_wrapper_clone.find('.latecheckbox-option input:checked').length;
313 let unchecked_count = $options_wrapper_clone.find('.latecheckbox-option input:not(:checked)').length;
314
315 if(checked_count && unchecked_count){
316 $options_wrapper_clone.find('.latecheckbox-all-check').prop('indeterminate', true).attr('indeterminate', 'indeterminate');
317 $options_wrapper_clone.find('.latecheckbox-all-check').prop('checked', false).removeAttr('checked');
318 }else{
319 $options_wrapper_clone.find('.latecheckbox-all-check').prop('indeterminate', false).removeAttr('indeterminate');
320 if(!checked_count){
321 $options_wrapper_clone.find('.latecheckbox-all-check').prop('checked', false).removeAttr('checked');
322 }
323 if(!unchecked_count){
324 $options_wrapper_clone.find('.latecheckbox-all-check').prop('checked', true).attr('checked', 'checked');
325 }
326 }
327 applyChanges(jQuery(this).closest('.latecheckbox-options-w').attr('data-latecheckbox-id'));
328 });
329 }
330 return false;
331 });
332
333 });
334 }
335 }(jQuery));
336
337 function latepoint_generate_form_message_html(messages, status){
338 var message_html = '<div class="os-form-message-w status-' + status + '"><ul>';
339 if(Array.isArray(messages)){
340 messages.forEach(function(message){
341 message_html+= '<li>' + message + '</li>';
342 });
343 }else{
344 message_html+= '<li>' + messages + '</li>';
345 }
346 message_html+= '</ul></div>';
347 return message_html;
348 }
349
350 function latepoint_display_in_side_sub_panel(html){
351 if(!jQuery('.latepoint-side-panel-w').length) latepoint_show_data_in_side_panel('');
352 jQuery('.latepoint-side-panel-w .latepoint-side-panels .side-sub-panel-wrapper').remove();
353 jQuery('.latepoint-side-panel-w .latepoint-side-panels').append(html);
354 }
355
356 function latepoint_clear_form_messages($form){
357 $form.find('.os-form-message-w').remove();
358 }
359
360 function latepoint_show_data_in_side_panel(message, extra_classes = '', close_btn = true){
361 jQuery('.latepoint-side-panel-w').remove();
362 jQuery('body').append('<div class="latepoint-side-panel-w ' + extra_classes + ' os-loading"><div class="latepoint-side-panel-shadow"></div><div class="latepoint-side-panels"><div class="latepoint-side-panel-i"></div></div></div>');
363 jQuery('.latepoint-side-panel-i').html(message);
364 if(close_btn){
365 jQuery('.latepoint-side-panel-i').find('.os-form-header .latepoint-side-panel-close').remove();
366 jQuery('.latepoint-side-panel-i').find('.os-form-header').append('<a href="#" class="latepoint-side-panel-close latepoint-side-panel-close-trigger"><i class="latepoint-icon latepoint-icon-x"></i></a>');
367 }
368 setTimeout(function(){
369 jQuery('.latepoint-side-panel-w').removeClass('os-loading');
370 }, 100);
371 }
372
373 function latepoint_show_data_in_lightbox(message, extra_classes = '', close_btn = true, tag = 'div', inner_extra_classes = '', inner_tag = 'div'){
374 jQuery('.latepoint-lightbox-w').remove();
375 let lightbox_css_classes = 'latepoint-lightbox-w latepoint-w latepoint-border-radius-' + latepoint_helper.style_border_radius+ ' ';
376 if(extra_classes) lightbox_css_classes+= extra_classes;
377 let lightbox_css_inner_classes = 'latepoint-lightbox-i ';
378 if(inner_extra_classes) lightbox_css_inner_classes += inner_extra_classes;
379
380 let close_btn_html = close_btn ? '<a href="#" class="latepoint-lightbox-close" tabindex="0"><i class="latepoint-icon latepoint-icon-x"></i></a>' : '';
381 jQuery('body').append('<'+tag+' class="'+ lightbox_css_classes +'"><'+inner_tag+' class="'+ lightbox_css_inner_classes +'">' + message + close_btn_html + '</'+inner_tag+'><div class="latepoint-lightbox-shadow"></div></'+tag+'>');
382
383 jQuery('body').addClass('latepoint-lightbox-active');
384 }
385
386
387
388 // DOCUMENT READY
389 jQuery(function( $ ) {
390
391 if($('.latepoint').find('[data-os-action-onload]').length){
392 $('.latepoint').find('[data-os-action-onload]').each(function(){
393 var $this = jQuery(this);
394 $this.addClass('os-loading');
395 var params = $this.data('os-params');
396 var return_format = $this.data('os-return-format') ? $this.data('os-return-format') : 'json'
397 var data = { action: 'latepoint_route_call', route_name: $this.data('os-action-onload'), params: params, return_format: return_format }
398 jQuery.ajax({
399 type : "post",
400 dataType : "json",
401 url : latepoint_timestamped_ajaxurl(),
402 data : data,
403 success: function(response) {
404 $this.removeClass('os-loading');
405 if (response.status === "success") {
406 if($this.data('os-output-target') == 'self'){
407 $this.html(response.message);
408 }
409 }
410 }
411 });
412 });
413 }
414
415 jQuery('body.latepoint').on('change', 'select[data-os-on-change]', function(e){
416 let $this = jQuery(this);
417
418 let func_name = $this.data('os-on-change');
419 if(func_name.includes('.')){
420 let func_arr = func_name.split('.');
421 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){
422 console.log(func_name + ' is undefined');
423 }else{
424 window[func_arr[0]][func_arr[1]]($this);
425 }
426 }else{
427 if(typeof window[func_name] !== 'function'){
428 console.log(func_name + ' is undefined');
429 }else{
430 window[func_name]($this);
431 }
432 }
433 });
434
435 /*
436 Ajax buttons action
437 */
438 $('.latepoint').on('click', 'button[data-os-action], a[data-os-action], div[data-os-action], span[data-os-action], tr[data-os-action]', function(e){
439 var $this = jQuery(this);
440 if($this.data('os-prompt') && !confirm($this.data('os-prompt'))) return false;
441 var params = $this.data('os-params');
442 if($this.data('os-source-of-params')){
443 var form_data = latepoint_create_form_data_from_non_form_element($($this.data('os-source-of-params')));
444 params = latepoint_formdata_to_url_encoded_string(form_data);
445 }
446 var return_format = $this.data('os-return-format') ? $this.data('os-return-format') : 'json'
447 var data = { action: 'latepoint_route_call', route_name: $this.data('os-action'), params: params, return_format: return_format }
448 $this.addClass('os-loading');
449 if($this.data('os-output-target') == 'side-panel'){
450 $('.latepoint-side-panel-w').remove();
451 let css_classes = $this.data('os-lightbox-classes') ? $this.data('os-lightbox-classes') : '';
452 $('body').append('<div class="latepoint-side-panel-w ' + css_classes + ' os-loading"><div class="latepoint-side-panel-shadow"></div><div class="latepoint-side-panels"><div class="latepoint-side-panel-i"></div></div></div>');
453 }else if($this.data('os-output-target') == 'full-panel'){
454 $('.latepoint-full-panel-w').remove();
455 $('body').append('<div class="latepoint-full-panel-w os-loading"></div>');
456 }
457 $.ajax({
458 type : "post",
459 dataType : "json",
460 url : latepoint_timestamped_ajaxurl(),
461 data : data,
462 success: function(response){
463 if(response.status === "success"){
464 if($this.data('os-output-target') == 'lightbox'){
465 latepoint_show_data_in_lightbox(response.message, $this.data('os-lightbox-classes'), ($this.data('os-lightbox-no-close-button') !== 'yes'), $this.data('os-lightbox-tag'), $this.data('os-lightbox-inner-classes'), $this.data('os-lightbox-inner-tag'));
466 }else if($this.data('os-output-target') == 'side-panel'){
467 $('.latepoint-side-panel-i').html(response.message);
468 jQuery('.latepoint-side-panel-i').find('.os-form-header .latepoint-side-panel-close').remove();
469 jQuery('.latepoint-side-panel-i').find('.os-form-header').append('<a href="#" class="latepoint-side-panel-close latepoint-side-panel-close-trigger"><i class="latepoint-icon latepoint-icon-x"></i></a>');
470 setTimeout(function(){
471 $('.latepoint-side-panel-w').removeClass('os-loading');
472 }, 100);
473 }else if($this.data('os-output-target') == 'full-panel'){
474 $('.latepoint-full-panel-w').html(response.message);
475 setTimeout(function(){
476 $('.latepoint-full-panel-w').removeClass('os-loading');
477 }, 100);
478 }else if($this.data('os-success-action') == 'reload'){
479 latepoint_add_notification(response.message);
480 location.reload();
481 return;
482 }else if($this.data('os-success-action') == 'redirect'){
483 if($this.data('os-redirect-to')){
484 latepoint_add_notification(response.message);
485 window.location.replace($this.data('os-redirect-to'));
486 }else{
487 window.location.replace(response.message);
488 }
489 return;
490 }else if($this.data('os-output-target') && $($this.data('os-output-target')).length){
491 if($this.data('os-output-target-do') == 'append') {
492 $($this.data('os-output-target')).append(response.message);
493 }else if($this.data('os-output-target-do') == 'prepend'){
494 $($this.data('os-output-target')).prepend(response.message);
495 }else{
496 $($this.data('os-output-target')).html(response.message);
497 }
498 }else{
499 switch($this.data('os-before-after')){
500 case 'before':
501 $this.before(response.message);
502 break;
503 case 'after':
504 $this.after(response.message);
505 break;
506 case 'replace':
507 $this.replaceWith(response.message);
508 break;
509 case 'none':
510 break;
511 default:
512 latepoint_add_notification(response.message);
513 }
514 }
515 if($this.data('os-after-call')){
516 var func_name = $this.data('os-after-call');
517 var callback = false;
518 if(func_name.includes('.')){
519 var func_arr = func_name.split('.');
520 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){
521 console.log(func_name + ' is undefined');
522 }
523 if($this.data('os-pass-this') && $this.data('os-pass-response')){
524 window[func_arr[0]][func_arr[1]]($this, response);
525 }else if($this.data('os-pass-this')){
526 window[func_arr[0]][func_arr[1]]($this);
527 }else if($this.data('os-pass-response')){
528 window[func_arr[0]][func_arr[1]](response);
529 }else{
530 window[func_arr[0]][func_arr[1]]();
531 }
532 }else{
533 if(typeof window[func_name] !== 'function'){
534 console.log(func_name + ' is undefined');
535 }
536 if($this.data('os-pass-this') && $this.data('os-pass-response')){
537 window[func_name]($this, response);
538 }else if($this.data('os-pass-this')){
539 window[func_name]($this);
540 }else if($this.data('os-pass-response')){
541 window[func_name](response);
542 }else{
543 window[func_name]();
544 }
545 }
546 }
547 $this.removeClass('os-loading');
548 }else{
549 $this.removeClass('os-loading');
550 if($this.data('os-output-target') && $($this.data('os-output-target')).length){
551 $($this.data('os-output-target')).prepend(latepoint_generate_form_message_html(response.message, 'error'));
552 }else{
553 alert(response.message);
554 }
555 if($this.data('os-after-call-error')){
556 var func_name = $this.data('os-after-call-error');
557 var callback = false;
558 if(func_name.includes('.')){
559 var func_arr = func_name.split('.');
560 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){
561 console.log(func_name + ' is undefined');
562 }
563 if($this.data('os-pass-this') && $this.data('os-pass-response')){
564 window[func_arr[0]][func_arr[1]]($this, response);
565 }else if($this.data('os-pass-this')){
566 window[func_arr[0]][func_arr[1]]($this);
567 }else if($this.data('os-pass-response')){
568 window[func_arr[0]][func_arr[1]](response);
569 }else{
570 window[func_arr[0]][func_arr[1]]();
571 }
572 }else{
573 if(typeof window[func_name] !== 'function'){
574 console.log(func_name + ' is undefined');
575 }
576 if($this.data('os-pass-this') && $this.data('os-pass-response')){
577 window[func_name]($this, response);
578 }else if($this.data('os-pass-this')){
579 window[func_name]($this);
580 }else if($this.data('os-pass-response')){
581 window[func_name](response);
582 }else{
583 window[func_name]();
584 }
585 }
586 }
587 }
588 }
589 });
590 return false;
591 });
592
593
594 $('.latepoint').on('click', 'form[data-os-action] button[type="submit"]', function(e){
595 $(this).addClass('os-loading');
596 });
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614 /*
615 Form ajax submit action
616 */
617 $('.latepoint').on('submit', 'form[data-os-action]', function(e){
618 e.preventDefault(); // prevent native submit
619 var $form = $(this);
620 var form_data = new FormData($form[0]);
621
622 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
623 // Get e164 formatted number from phone fields when form is submitted
624 $form.find('input.os-mask-phone').each(function () {
625 let telInstance = window.lp_intlTelInputGlobals.getInstance(this);
626 if(telInstance){
627 const phoneInputName = this.getAttribute('name');
628 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
629 form_data.set(phoneInputName, phoneInputValue);
630 }
631 });
632 }
633
634 let data = latepoint_create_form_data($form, $(this).data('os-action'));
635
636 // var data = { action: 'latepoint_route_call', route_name: $(this).data('os-action'), params: latepoint_formdata_to_url_encoded_string(form_data), return_format: 'json' }
637 $form.find('button[type="submit"]').addClass('os-loading');
638 $.ajax({
639 type : "post",
640 dataType : "json",
641 processData: false,
642 contentType: false,
643 url : latepoint_timestamped_ajaxurl(),
644 data : data,
645 success: function(response){
646 $form.find('button[type="submit"].os-loading').removeClass('os-loading');
647 latepoint_clear_form_messages($form);
648 if(response.status === "success"){
649 if($form.data('os-success-action') == 'reload'){
650 latepoint_add_notification(response.message);
651 location.reload();
652 return;
653 }else if($form.data('os-success-action') == 'redirect'){
654 if($form.data('os-redirect-to')){
655 latepoint_add_notification(response.message);
656 window.location.replace($form.data('os-redirect-to'));
657 }else{
658 window.location.replace(response.message);
659 }
660 return;
661 }else if($form.data('os-output-target') && $($form.data('os-output-target')).length){
662 $($form.data('os-output-target')).html(response.message);
663 }else{
664 if(response.message == 'redirect'){
665 window.location.replace(response.url);
666 }else{
667 latepoint_add_notification(response.message);
668 }
669 }
670 if($form.data('os-record-id-holder') && response.record_id){
671 $form.find('[name="' + $form.data('os-record-id-holder') + '"]').val(response.record_id)
672 }
673 if($form.data('os-after-call')){
674
675 var func_name = $form.data('os-after-call');
676 var callback = false;
677 if(func_name.includes('.')){
678 var func_arr = func_name.split('.');
679 if(typeof window[func_arr[0]][func_arr[1]] !== 'function'){
680 console.log(func_name + ' is undefined');
681 }
682 if($form.data('os-pass-this') && $form.data('os-pass-response')){
683 window[func_arr[0]][func_arr[1]]($form, response);
684 }else if($form.data('os-pass-this')){
685 window[func_arr[0]][func_arr[1]]($form);
686 }else if($form.data('os-pass-response')){
687 window[func_arr[0]][func_arr[1]](response);
688 }else{
689 window[func_arr[0]][func_arr[1]]();
690 }
691 }else{
692 if(typeof window[func_name] !== 'function'){
693 console.log(func_name + ' is undefined');
694 }
695 if($form.data('os-pass-this') && $form.data('os-pass-response')){
696 window[func_name]($form, response);
697 }else if($form.data('os-pass-this')){
698 window[func_name]($form);
699 }else if($form.data('os-pass-response')){
700 window[func_name](response);
701 }else{
702 window[func_name]();
703 }
704 }
705 }
706 $('button.os-loading').removeClass('os-loading');
707 }else{
708 $('button.os-loading').removeClass('os-loading');
709 if($form.data('os-show-errors-as-notification')){
710 latepoint_add_notification(response.message, 'error');
711 }else{
712 latepoint_add_notification(response.message, 'error');
713 $([document.documentElement, document.body]).animate({
714 scrollTop: ($form.find(".os-form-message-w").offset().top - 30)
715 }, 200);
716 }
717 }
718 if(response.form_values_to_update){
719 $.each(response.form_values_to_update, function(name, value){
720 $form.find('[name="'+ name +'"]').val(value);
721 });
722 }
723 }
724 });
725 return false;
726 });
727 });
728
729 function latepoint_add_notification(message, message_type = 'success'){
730 var wrapper = jQuery('body').find('.os-notifications');
731 if(!wrapper.length){
732 jQuery('body').append('<div class="os-notifications"></div>');
733 wrapper = jQuery('body').find('.os-notifications');
734 }
735 if(wrapper.find('.item').length > 0) wrapper.find('.item:first-child').remove();
736 wrapper.append('<div class="item item-type-'+ message_type +'">' + message + '<span class="os-notification-close"><i class="latepoint-icon latepoint-icon-x"></i></span></div>');
737 }
738
739 function latepoint_add_lightbox_notification(message, message_type = 'success'){
740 var wrapper = jQuery('.latepoint-lightbox-content').find('.os-notifications');
741 if(!wrapper.length){
742 jQuery('.latepoint-lightbox-content').prepend('<div class="os-notifications"></div>');
743 wrapper = jQuery('.latepoint-lightbox-content').find('.os-notifications');
744 }
745 if(wrapper.find('.item').length > 0) wrapper.find('.item:first-child').remove();
746 wrapper.append('<div class="item item-type-'+ message_type +'">' + message + '<span class="os-notification-close"><i class="latepoint-icon latepoint-icon-x"></i></span></div>');
747 }
748
749 function latepoint_timestamped_ajaxurl(){
750 let url = latepoint_helper.ajaxurl;
751 let timestamp = Date.now();
752
753 // Check if the URL already has GET parameters
754 if (url.includes('?')) {
755 return `${url}&t=${timestamp}`;
756 } else {
757 return `${url}?t=${timestamp}`;
758 }
759 }
760
761 function latepoint_random_generator() {
762 var S4 = function () {
763 return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
764 };
765 return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
766 }
767
768 function latepoint_validate_form($form) {
769 let errors = [];
770 $form.find('select[data-os-validate], input[data-os-validate], textarea[data-os-validate]').each(function () {
771 let validations = jQuery(this).data('os-validate').split(' ');
772 let $input = jQuery(this);
773 let label = $input.closest('.os-form-group').find('label').text();
774 let field_has_errors = false;
775 if (validations) {
776 for (let i = 0; i < validations.length; i++) {
777 switch (validations[i]) {
778 case 'presence':
779 if($input.is(':checkbox')){
780 if (!$input.is(':checked')) {
781 errors.push({message: label + ' ' + latepoint_helper.msg_validation_presence_checkbox});
782 field_has_errors = true;
783 }
784 }else{
785 if (!$input.val()) {
786 errors.push({message: label + ' ' + latepoint_helper.msg_validation_presence});
787 field_has_errors = true;
788 }
789 }
790 break;
791 case 'phone':
792 if (!window.lp_intlTelInputGlobals.getInstance($input[0]).isValidNumber()) {
793 errors.push({message: label + ' ' + latepoint_helper.msg_validation_invalid});
794 field_has_errors = true;
795 }
796 break;
797 }
798 }
799 }
800 if (field_has_errors) {
801 $input.closest('.os-form-group').addClass('os-invalid');
802 } else {
803 $input.closest('.os-form-group').removeClass('os-invalid');
804 }
805 });
806 return errors;
807 }
808
809 function latepoint_create_form_data_from_non_form_element($elem) {
810 let formData = new FormData();
811 // create objecte from all input fields that are inside of the element
812 let fields = $elem.find('select, input, textarea').serializeArray();
813 if (fields) {
814 fields.forEach(field => formData.append(field.name, field.value));
815 }
816 return formData;
817 }
818
819 function latepoint_create_form_data($form, route_name = false, extra_params = false) {
820 let form_data = new FormData();
821 let params = new FormData($form[0]);
822
823 if (extra_params) {
824 Object.keys(extra_params).forEach(key => {
825 params.set(key, extra_params[key]);
826 });
827 }
828
829 // get values from phone number fields
830 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
831 $form.find('input.os-mask-phone').each(function () {
832 const phoneInputName = this.getAttribute('name');
833 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
834 // override value generated automatically by formdata with a formatted value of a phone field with country code
835 params.set(phoneInputName, phoneInputValue);
836 });
837 }
838
839 form_data.append('params', latepoint_formdata_to_url_encoded_string(params));
840 form_data.append('action', latepoint_helper.route_action);
841 form_data.append('route_name', route_name ? route_name : $form.data('route-name'));
842 form_data.append('layout', 'none');
843 form_data.append('return_format', 'json');
844
845 let file_data;
846 // put file data into main form_data object, since we can't send them in "params" string
847 $form.find('input[type="file"]').each(function () {
848 file_data = this.files; // get multiple files from input file
849 let file_name = this.getAttribute("name");
850 for (let i = 0; i < file_data.length; i++) {
851 form_data.append(file_name + '[]', file_data[i]);
852 }
853 });
854 return form_data;
855 }
856
857 function latepoint_mask_timefield($elem) {
858 if (jQuery().inputmask) {
859 $elem.inputmask({
860 'mask': '99:99',
861 'placeholder': 'HH:MM'
862 });
863 }
864 }
865
866 function latepoint_formdata_to_url_encoded_string(form_data) {
867 let filtered_form_data = new FormData();
868 // remove file fields from params, so we can serialize it into string,
869 // !important, this will not include file fields into the form_data, so you have to include them manually, see latepoint_create_form_data() that does it
870 // note: we don't use form_data.remove(key) on original object because we might want to preserve it
871 for (const [key, value] of form_data) {
872 if (value instanceof File) continue;
873 if (key.slice(-2) === '[]') {
874 // expecting array, append
875 filtered_form_data.append(key, value);
876 } else {
877 filtered_form_data.set(key, value);
878 }
879 }
880 return new URLSearchParams(filtered_form_data).toString();
881 }
882
883 function latepoint_mask_percent($elem) {
884 if (jQuery().inputmask) {
885 $elem.inputmask({
886 'alias': 'decimal',
887 'radixPoint': latepoint_helper.decimal_separator,
888 'digits': 4,
889 'digitsOptional': false,
890 'suffix': '%',
891 'placeholder': '0',
892 'rightAlign': false
893 });
894 }
895 }
896
897 function latepoint_mask_minutes($elem) {
898 if (jQuery().inputmask) {
899 $elem.inputmask({
900 'removeMaskOnSubmit': true,
901 'alias': 'numeric',
902 'digits': 0,
903 'suffix': latepoint_helper.msg_minutes_suffix,
904 'placeholder': '0',
905 'rightAlign': false
906 });
907 }
908 }
909
910
911 function latepoint_mask_money($elem) {
912 if (jQuery().inputmask) {
913 $elem.inputmask({
914 'alias': 'currency',
915 'groupSeparator': latepoint_helper.thousand_separator,
916 'radixPoint': latepoint_helper.decimal_separator,
917 'digits': latepoint_helper.number_of_decimals,
918 'digitsOptional': false,
919 'prefix': latepoint_helper.currency_symbol_before ? latepoint_helper.currency_symbol_before + ' ' : '',
920 'suffix': latepoint_helper.currency_symbol_after ? ' ' + latepoint_helper.currency_symbol_after : '',
921 'placeholder': '0',
922 'rightAlign': false
923 });
924 }
925 }
926
927 function latepoint_mask_date($elem) {
928 if (jQuery().inputmask) {
929 $elem.inputmask({
930 'alias': 'datetime',
931 'inputFormat': latepoint_helper.date_format_for_js
932 });
933 }
934 }
935
936 function latepoint_init_phone_masking_from_placeholder($input) {
937 if (!latepoint_helper.mask_phone_number_fields) return;
938 let format = $input.attr('placeholder');
939 if (format && jQuery().inputmask) {
940 $input.inputmask(format.replace(/[0-9]/g, 9));
941 }
942 }
943
944 function latepoint_mask_phone($elem) {
945 let jsElem = $elem[0];
946
947 // First priority is to prevent duplicates (common in non-document.body contexts)
948 if (jsElem && !window.lp_intlTelInputGlobals.getInstance(jsElem)) {
949 let dropdownContainer = document.body;
950
951 let onlyCountries = JSON.parse(latepoint_helper.included_phone_countries);
952 // Remedy a quirk with json_encode(EMPTY_ARRAY)
953 if (onlyCountries.length === 1 && onlyCountries[0] === "") {
954 onlyCountries = [];
955 }
956 const preferredCountries = onlyCountries.length ? [] : window.lp_intlTelInputGlobals.defaults.preferredCountries;
957
958 // remove country name in english and only use names in country language
959 var countryData = window.lp_intlTelInputGlobals.getCountryData();
960
961 for (var i = 0; i < countryData.length; i++) {
962 var country = countryData[i];
963 country.name = country.name.replace(/ *\([^)]*\) */g, "");
964 }
965
966 let defaultCountryCode = latepoint_helper.default_phone_country;
967 if (onlyCountries.length && !onlyCountries.includes(defaultCountryCode)) {
968 defaultCountryCode = onlyCountries[0];
969 }
970
971
972 let iti = window.lp_intlTelInput(jsElem, {
973 dropdownContainer: dropdownContainer,
974 formatOnDisplay: true,
975 nationalMode: true,
976 autoPlaceholder: 'aggressive',
977 initialCountry: defaultCountryCode,
978 geoIpLookup: function (callback) {
979 const cookieName = 'latepoint_phone_country';
980
981 if (latepoint_has_cookie(cookieName)) {
982 callback(latepoint_get_cookie(cookieName));
983 } else {
984 jQuery.get('https://ipinfo.io', function () {
985 }, 'jsonp').always(function (response) {
986 // Sensible default
987 let countryCode = defaultCountryCode;
988
989 if (response && response.country) {
990 countryCode = response.country.toLowerCase();
991 latepoint_set_cookie(cookieName, countryCode);
992 }
993 callback(countryCode);
994 })
995 }
996 },
997 allowDropdown: onlyCountries.length != 1,
998 onlyCountries: onlyCountries,
999 preferredCountries: preferredCountries,
1000 separateDialCode: latepoint_helper.is_enabled_show_dial_code_with_flag
1001 });
1002
1003 iti.promise.then(function () {
1004 latepoint_init_phone_masking_from_placeholder($elem);
1005 });
1006
1007
1008 $elem.on("countrychange", function (event) {
1009 latepoint_init_phone_masking_from_placeholder(jQuery(this));
1010 });
1011 }
1012 }
1013
1014 function latepoint_show_booking_end_time() {
1015 return (latepoint_helper.show_booking_end_time == 'yes');
1016 }
1017
1018 function latepoint_set_cookie(name, value, days) {
1019 let date = new Date;
1020 date.setTime(date.getTime() + 24 * 60 * 60 * 1000 * days);
1021 document.cookie = name + "=" + value + ";path=/;expires=" + date.toGMTString();
1022 }
1023
1024 function latepoint_get_cookie(name) {
1025 let cookie = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
1026 return cookie ? cookie[2] : null;
1027 }
1028
1029 function latepoint_has_cookie(name) {
1030 return latepoint_get_cookie(name) !== null;
1031 }
1032
1033 function latepoint_delete_cookie(name) {
1034 latepoint_set_cookie(name, '', -1);
1035 }
1036
1037 function latepoint_load_addons_info(){
1038 var $addons_info_wrapper = jQuery('.addons-info-holder');
1039 $addons_info_wrapper.addClass('os-loading');
1040 var route = $addons_info_wrapper.data('route');
1041
1042 var data = { action: 'latepoint_route_call', route_name: route, params: '', return_format: 'json' }
1043 jQuery.ajax({ type : "post", dataType : "json", url : latepoint_timestamped_ajaxurl(), data : data,
1044 success: function(response){
1045 $addons_info_wrapper.removeClass('os-loading');
1046 if(response.status === "success"){
1047 if(response.message){
1048 $addons_info_wrapper.html(response.message);
1049 }else{
1050 $addons_info_wrapper.html('Something is wrong. Try refreshing the page.')
1051 }
1052 }else{
1053 alert(response.message, 'error');
1054 }
1055 }
1056 });
1057 }
1058
1059
1060 function latepoint_dismiss_message($elem){
1061 $elem.closest('.addon-message').slideUp(300);
1062 return false;
1063 }
1064
1065 function latepoint_check_for_updates(){
1066 if(jQuery('.version-log-w').length){
1067 var $log_wrapper = jQuery('.version-log-w');
1068 $log_wrapper.addClass('os-loading');
1069 var route = $log_wrapper.data('route');
1070
1071 var data = { action: 'latepoint_route_call', route_name: route, params: '', return_format: 'json' }
1072 jQuery.ajax({ type : "post", dataType : "json", url : latepoint_timestamped_ajaxurl(), data : data,
1073 success: function(response){
1074 $log_wrapper.removeClass('os-loading');
1075 if(response.status === "success"){
1076 $log_wrapper.html(response.message);
1077 }else{
1078 alert(response.message, 'error');
1079 }
1080 }
1081 });
1082 }
1083 if(jQuery('.version-status-info').length){
1084
1085 var $version_info_wrapper = jQuery('.version-status-info');
1086 $version_info_wrapper.addClass('os-loading');
1087 var route = $version_info_wrapper.data('route');
1088
1089 var data = { action: 'latepoint_route_call', route_name: route, params: '', return_format: 'json' }
1090 jQuery.ajax({ type : "post", dataType : "json", url : latepoint_timestamped_ajaxurl(), data : data,
1091 success: function(response){
1092 $version_info_wrapper.removeClass('os-loading');
1093 if(response.status === "success"){
1094 $version_info_wrapper.html(response.message);
1095 }else{
1096 alert(response.message, 'error');
1097 }
1098 }
1099 });
1100 }
1101 if(jQuery('.addons-info-holder').length){
1102 latepoint_load_addons_info();
1103 }
1104 }
1105
1106
1107 // DOCUMENT READY
1108 jQuery(document).ready(function( $ ) {
1109 latepoint_check_for_updates();
1110
1111
1112 jQuery('body').on('click', '.addon-category-filter-trigger', function(){
1113 jQuery('.addons-categories-wrapper .addon-category-filter-trigger.is-selected').removeClass('is-selected');
1114 if(jQuery(this).data('category')){
1115 let category = jQuery(this).data('category').toString();
1116 jQuery('.addon-box').addClass('hidden');
1117 jQuery('.addon-box').each(function(){
1118 if(jQuery(this).data('category').toString().split(',').includes(category)) jQuery(this).removeClass('hidden');
1119 })
1120 }else{
1121 jQuery('.addon-box').removeClass('hidden');
1122 }
1123
1124 jQuery(this).addClass('is-selected');
1125 return false;
1126 })
1127
1128
1129 // Install addon button click
1130 jQuery('.addons-info-holder').on('click', '.os-addon-action-btn', function(){
1131 var $install_btn = jQuery(this);
1132 $install_btn.addClass('os-loading');
1133
1134 var data = { action: 'latepoint_route_call', route_name: $install_btn.data('route-name'), params: { addon_name: $install_btn.data('addon-name'), addon_path: $install_btn.data('addon-path') }, layout: 'none', return_format: 'json'};
1135 jQuery.ajax({
1136 type : "post",
1137 dataType : "json",
1138 url : latepoint_timestamped_ajaxurl(),
1139 data : data,
1140 success: function(response){
1141 $install_btn.removeClass('os-loading');
1142 if(response.status === "success"){
1143 latepoint_add_notification(response.message);
1144 latepoint_load_addons_info();
1145 }else{
1146 if(response.code == '404'){
1147 latepoint_show_data_in_lightbox(response.message);
1148 }else{
1149 alert(response.message);
1150 }
1151 }
1152 }
1153 });
1154 return false;
1155 });
1156 });
1157
1158 /*
1159 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
1160 */
1161
1162 function latepoint_init_version5_intro(){
1163 if(jQuery('.improvement-install-pro').length){
1164 let $install_btn = jQuery('.improvement-install-pro');
1165 var data = {
1166 action: latepoint_helper.route_action,
1167 route_name: $install_btn.data('route-name'),
1168 params: {},
1169 return_format: 'json'
1170 }
1171 jQuery.ajax({
1172 type : "post",
1173 dataType : "json",
1174 url : latepoint_timestamped_ajaxurl(),
1175 data : data,
1176 success: function(response){
1177 $install_btn.removeClass('os-loading');
1178 if(response.status == 'success'){
1179 $install_btn.addClass('is-installed').find('span').html(response.message);
1180 }else{
1181 $install_btn.addClass('is-not-installed').find('span').html(response.message);
1182 }
1183 }
1184 });
1185 }
1186 }
1187
1188
1189 function latepoint_settings_customer_authentication_method_changed($select){
1190 if($select.val() === 'password_or_otp'){
1191 jQuery('#authDefaultMethod').show();
1192 }else{
1193 jQuery('#authDefaultMethod').hide();
1194 }
1195 }
1196
1197 function latepoint_settings_customer_authentication_field_type_changed($select){
1198 if($select.val() === 'disabled'){
1199 jQuery('#passwordFields, #customerStepSettings').hide();
1200 }else{
1201 jQuery('#passwordFields, #customerStepSettings').show();
1202 }
1203 if($select.val() === 'email_or_phone'){
1204 jQuery('#authDefaultContactType').show();
1205 }else{
1206 jQuery('#authDefaultContactType').hide();
1207 }
1208 }
1209
1210 function latepoint_init_sticky_side_nav(){
1211 jQuery('.latepoint-page-side-nav a').on('click', function(e) {
1212 e.preventDefault();
1213 let target = jQuery(this).attr('href');
1214 let targetOffset = jQuery(target).offset().top - 20;
1215
1216 jQuery('html, body').animate({
1217 scrollTop: targetOffset
1218 }, 400, 'swing');
1219 });
1220 if(jQuery('.latepoint-page-side-nav').length){
1221 jQuery(window).on('scroll', function() {
1222 let scrollPos = jQuery(window).scrollTop() + 100; // 100px offset for better UX
1223
1224 jQuery('.section-anchor').each(function() {
1225 let sectionTop = jQuery(this).offset().top;
1226 let sectionBottom = sectionTop + jQuery(this).outerHeight();
1227 let sectionId = jQuery(this).attr('id');
1228
1229 // Check if current scroll position is within this section
1230 if (scrollPos >= sectionTop && scrollPos < sectionBottom) {
1231 // Remove active class from all menu items
1232 jQuery('.latepoint-page-side-nav a').removeClass('is-active');
1233
1234 // Add active class to current section's menu item
1235 jQuery('.latepoint-page-side-nav a[href="#' + sectionId + '"]').addClass('is-active');
1236 }
1237 });
1238 });
1239 }
1240 }
1241
1242 function latepoint_init_instant_booking_settings(){
1243
1244 jQuery('.instant-copy-url').on('click', function(e){
1245 e.preventDefault();
1246 let $this = jQuery(this);
1247 jQuery('body').find('.os-click-to-copy-prompt').hide();
1248 let text_to_copy = jQuery('.instant-visit-url').prop('href');
1249 navigator.clipboard.writeText(text_to_copy);
1250
1251 let position_info = $this.offset();
1252 let position_left = position_info.left;
1253 let position_top = position_info.top;
1254
1255 let $done_prompt = jQuery('<div class="os-click-to-copy-done color-dark" style="top: '+position_top+'px; left: '+position_left+'px;">' + latepoint_helper.click_to_copy_done + '</div>');
1256 $done_prompt.appendTo(jQuery('body')).animate({
1257 opacity: 0,
1258 left: (position_left + 20),
1259 }, 600);
1260 setTimeout(function(){
1261 jQuery('body').find('.os-click-to-copy-done').remove();
1262 jQuery('body').find('.os-click-to-copy-prompt').show();
1263 }, 800);
1264 });
1265
1266 jQuery('.instant-booking-preview-settings-content').find('select, input').on('change', function(){
1267 latepoint_build_url_for_instant_booking_page();
1268 })
1269 jQuery('.preview-background-option').on('click', function(e){
1270 jQuery('.preview-background-option').removeClass('selected');
1271 jQuery(this).addClass('selected');
1272 jQuery('input[name="instant_booking[background_pattern]"]').val(jQuery(this).data('pattern-key')).trigger('change');
1273 });
1274
1275 jQuery('.latepoint-instant-preview-close-trigger').on('click', function(e){
1276 jQuery('.latepoint-full-panel-w').remove();
1277 return false;
1278 });
1279
1280 }
1281
1282 async function latepoint_build_url_for_instant_booking_page(){
1283 let data = {
1284 action: 'latepoint_route_call',
1285 route_name: jQuery('.instant-booking-preview-settings-content').data('route-name'),
1286 params: jQuery('.instant-booking-preview-settings-content').find('select, input').serialize(),
1287 layout: 'none',
1288 return_format: 'json'
1289 }
1290 try {
1291 let response = await jQuery.ajax({
1292 type: "post",
1293 dataType: "json",
1294 url: latepoint_timestamped_ajaxurl(),
1295 data: data
1296 });
1297 if (response.status == 'success') {
1298 jQuery('.instant-booking-settings-iframe-wrapper').html('<iframe class="instant-preview-iframe" src="' + response.message + '"/>');
1299 jQuery('.instant-visit-url').attr('href', response.message);
1300 } else {
1301 throw new Error('Error: ' + response.message);
1302 }
1303 } catch (e) {
1304 throw e;
1305 }
1306 }
1307
1308 function latepoint_build_and_save_step_order(){
1309 var $steps_wrapper = jQuery('.os-ordered-steps');
1310 let steps_in_order = [];
1311 $steps_wrapper.find('.os-ordered-step').each(function(index){
1312 if(jQuery(this).find('.os-ordered-step-children').length){
1313 jQuery(this).find('.os-ordered-step-child').each(function(){
1314 steps_in_order.push(jQuery(this).data('step-code'));
1315 });
1316 }else{
1317 steps_in_order.push(jQuery(this).data('step-code'));
1318 }
1319 });
1320 var data = { action: latepoint_helper.route_action, route_name: $steps_wrapper.data('route-name'), params: {steps_order: steps_in_order.join(',')}, return_format: 'json' }
1321 jQuery('.latepoint-lightbox-heading').addClass('os-loading');
1322 jQuery.ajax({
1323 type : "post",
1324 dataType : "json",
1325 url : latepoint_timestamped_ajaxurl(),
1326 data : data,
1327 success: function(response){
1328 jQuery('.latepoint-lightbox-heading').removeClass('os-loading');
1329 latepoint_add_lightbox_notification(response.message, response.status);
1330 }
1331 });
1332 }
1333
1334 function latepoint_init_step_reordering(){
1335 jQuery('.os-ordered-step-expand').on('click', function(){
1336 jQuery(this).closest('.os-ordered-step').toggleClass('is-expanded');
1337 return false;
1338 });
1339
1340
1341 // Steps Order Dragging
1342 dragula([jQuery('.os-ordered-steps')[0]], {
1343 moves: function (el, container, handle) {
1344 return handle.classList.contains('os-ordered-step-drag-handle');
1345 },
1346 }).on('drop', function(el){
1347 latepoint_build_and_save_step_order();
1348 });
1349
1350 jQuery('.os-ordered-step-children').each(function(){
1351 let step_holder = jQuery(this)
1352 // Child steps Order Dragging
1353 dragula([step_holder[0]], {
1354 moves: function (el, container, handle) {
1355 return handle.classList.contains('os-ordered-step-child-drag-handle');
1356 },
1357 }).on('drop', function(el){
1358 latepoint_build_and_save_step_order();
1359 });
1360 });
1361 }
1362
1363
1364 function latepoint_init_json_view($pre_element = false){
1365 if(!$pre_element){
1366 // if pre is not provided -search for all unitialised ones
1367 $pre_element = jQuery('pre.format-json:not(.json-document)');
1368 }
1369 if($pre_element.length){
1370 $pre_element.each(function(){
1371 let json_data = JSON.parse(jQuery(this).html());
1372 jQuery(this).jsonViewer(json_data);
1373 });
1374 }
1375 }
1376
1377 function latepoint_init_accordions(){
1378 jQuery('.latepoint-admin').on('click', '.os-accordion-title', function(){
1379 jQuery(this).closest('.os-accordion-wrapper').toggleClass('is-open');
1380 return false;
1381 });
1382 }
1383
1384
1385 function latepoint_init_sticky_side_menu(){
1386 jQuery('.os-sticky-side-menu a').on('click', function(){
1387 jQuery('.os-sticky-side-menu li.os-active').removeClass('os-active');
1388 jQuery(this).closest('li').addClass('os-active');
1389 let section_anchor = jQuery(this).data('section-anchor');
1390 let position = jQuery('.section-anchor#'+section_anchor).offset();
1391 jQuery('html').animate({ scrollTop: position.top }, 300);
1392 return false;
1393 });
1394 }
1395
1396 function latepoint_init_template_library(){
1397 jQuery('.os-templates-wrapper .template-type-selector').on('click', function(){
1398 jQuery(this).toggleClass('is-selected');
1399 let user_type = jQuery(this).data('user-type');
1400 jQuery('.os-template-items[data-user-type="'+user_type+'"]').toggleClass('hidden');
1401 return false;
1402 });
1403
1404 jQuery('.os-templates-wrapper .os-template-item').on('click', function(){
1405 let $this = jQuery(this);
1406 $this.closest('.os-templates-list').find('.os-template-item.selected').removeClass('selected');
1407 $this.addClass('selected');
1408 let templateId = $this.data('id');
1409 jQuery('.os-template-preview').hide();
1410 jQuery('.os-template-preview[data-id="'+ templateId+'"]').show();
1411 jQuery('.os-no-template-selected-message').hide();
1412 jQuery('.os-template-use-button-wrapper').removeClass('hidden');
1413 return false;
1414 });
1415
1416 jQuery('.latepoint-select-template-btn').on('click', function(){
1417 let $btn = jQuery(this);
1418 let route_name = $btn.data('route');
1419 let action_id = $btn.data('action-id');
1420 let process_id = $btn.data('process-id');
1421 let action_type = $btn.data('action-type');
1422 $btn.addClass('os-loading');
1423
1424 let data = { action: latepoint_helper.route_action,
1425 route_name: route_name,
1426 params: {
1427 template_id: jQuery('.os-template-item.selected').data('id'),
1428 action_id: action_id,
1429 process_id: process_id,
1430 action_type: action_type
1431 },
1432 return_format: 'json' }
1433 jQuery.ajax({
1434 type: 'post',
1435 dataType : "json",
1436 url : latepoint_timestamped_ajaxurl(),
1437 data : data,
1438 success: (response) => {
1439 $btn.removeClass('os-loading');
1440 if(response.status === latepoint_helper.response_status.success){
1441 let $action_form = jQuery('.process-action-form[data-id="'+action_id+'"]');
1442 $action_form.find('.process-action-settings').html(response.message);
1443 latepoint_init_process_action_form($action_form);
1444 latepoint_close_side_panel();
1445 }else{
1446 alert("Error!");
1447 }
1448 }
1449 });
1450
1451 return false;
1452 });
1453 }
1454
1455 function latepoint_init_default_form_fields_settings(){
1456
1457 if(jQuery('.os-default-fields').length){
1458 jQuery('.os-default-field input[type="checkbox"], .os-default-field select').on('change', (event) => {
1459 latepoint_update_default_form_fields_settings();
1460 });
1461
1462 jQuery('.os-default-field .os-toggler').on('ostoggler:toggle', (event) => {
1463 if(jQuery(event.currentTarget).hasClass('off')){
1464 jQuery(event.currentTarget).closest('.os-default-field').addClass('is-disabled');
1465 }else{
1466 jQuery(event.currentTarget).closest('.os-default-field').removeClass('is-disabled');
1467 }
1468 latepoint_update_default_form_fields_settings();
1469 });
1470 }
1471 }
1472
1473 function latepoint_update_default_form_fields_settings(){
1474 var $wrapper = jQuery('.os-default-fields');
1475
1476 var form_data = new FormData($wrapper.find('form')[0]);
1477 var data = { action: latepoint_helper.route_action,
1478 route_name: $wrapper.data('route'),
1479 params: latepoint_formdata_to_url_encoded_string(form_data),
1480 return_format: 'json' }
1481
1482 jQuery.ajax({
1483 type : "post",
1484 dataType : "json",
1485 url : latepoint_timestamped_ajaxurl(),
1486 data : data,
1487 success: (response) => {
1488 latepoint_add_notification(response.message);
1489 }
1490 });
1491 }
1492
1493 function latepoint_init_side_menu(){
1494 jQuery('.menu-toggler').on('click', function(){
1495 var layout_style = 'full';
1496 if(jQuery('.latepoint-side-menu-w').hasClass('side-menu-full')){
1497 layout_style = 'compact';
1498 jQuery('.latepoint-side-menu-w').addClass('side-menu-compact').removeClass('side-menu-full');
1499 }else{
1500 jQuery('.latepoint-side-menu-w').addClass('side-menu-full').removeClass('side-menu-compact');
1501 }
1502 var route_name = jQuery(this).data('route');
1503 var data = { action: latepoint_helper.route_action, route_name: route_name, params: { menu_layout_style: layout_style }, layout: 'none', return_format: 'json' }
1504 jQuery.ajax({
1505 type : "post",
1506 dataType : "json",
1507 url : latepoint_timestamped_ajaxurl(),
1508 data : data,
1509 success: function(data){
1510 }
1511 });
1512 return false;
1513 });
1514 }
1515
1516 function latepoint_init_grouped_bookings_form(){
1517
1518 }
1519
1520 function latepoint_quick_order_customer_cleared(){
1521 latepoint_init_input_masks(jQuery('.quick-order-form-w .customer-quick-edit-form-w'));
1522 }
1523
1524 function latepoint_quick_order_customer_selected(){
1525 latepoint_init_input_masks(jQuery('.quick-order-form-w .customer-quick-edit-form-w'));
1526 jQuery('.customer-info-w').removeClass('selecting').addClass('selected');
1527 }
1528
1529 function latepoint_custom_day_removed($elem){
1530 $elem.closest('.custom-day-work-period').fadeOut(300, function(){ jQuery(this).remove()});
1531 }
1532
1533
1534 function latepoint_count_active_connections($connection_wrapper){
1535 var connected_services_count = $connection_wrapper.find('.connection-children-list li.active').length;
1536 var all_services_count = $connection_wrapper.find('.connection-children-list li').length;
1537 if(connected_services_count == all_services_count){
1538 connected_services_count = jQuery('.selected-connections').data('all-text');
1539 jQuery('.selected-connections').removeClass('not-all-selected');
1540 }else{
1541 connected_services_count = connected_services_count + '/' + all_services_count;
1542 jQuery('.selected-connections').addClass('not-all-selected');
1543 $connection_wrapper.closest('.white-box').find('.os-select-all-toggler').prop('checked', false);
1544 }
1545 $connection_wrapper.find('.selected-connections strong').text(connected_services_count);
1546 }
1547
1548 function latepoint_custom_field_removed($elem){
1549 $elem.closest('.os-form-block').remove();
1550 }
1551
1552 function latepoint_coupon_removed($elem){
1553 $elem.closest('.os-coupon-form').remove();
1554 }
1555
1556 function latepoint_reminder_removed($elem){
1557 $elem.closest('.os-reminder-form').remove();
1558 }
1559
1560 function latepoint_init_form_blocks(){
1561 jQuery('.latepoint-content-w').on('click', '.os-form-block-header', function(){
1562 jQuery(this).closest('.os-form-block').toggleClass('os-is-editing');
1563 return false;
1564 });
1565 jQuery('.latepoint-content-w').on('keyup', '.os-form-block-name-input', function(){
1566 jQuery(this).closest('.os-form-block').find('.os-form-block-name').text(jQuery(this).val());
1567 });
1568 }
1569
1570
1571 function latepoint_init_coupons_form(){
1572 jQuery('.latepoint-content-w').on('click', '.os-coupon-form-info', function(){
1573 jQuery(this).closest('.os-coupon-form').toggleClass('os-is-editing');
1574 return false;
1575 });
1576 jQuery('.latepoint-content-w').on('change', 'select.os-coupon-medium-select', function(){
1577 if(jQuery(this).val() == 'email'){
1578 jQuery(this).closest('.os-coupon-form').find('.os-coupon-email-subject').show();
1579 }else{
1580 jQuery(this).closest('.os-coupon-form').find('.os-coupon-email-subject').hide();
1581 }
1582 });
1583 jQuery('.latepoint-content-w').on('keyup', '.os-coupon-name-input', function(){
1584 jQuery(this).closest('.os-coupon-form').find('.os-coupon-name').text(jQuery(this).val());
1585 });
1586 jQuery('.latepoint-content-w').on('keyup', '.os-coupon-code-input', function(){
1587 jQuery(this).closest('.os-coupon-form').find('.os-coupon-code').text(jQuery(this).val());
1588 });
1589 }
1590
1591 function latepoint_init_reminders_form(){
1592 jQuery('.latepoint-content-w').on('click', '.os-reminder-form-info', function(){
1593 jQuery(this).closest('.os-reminder-form').toggleClass('os-is-editing');
1594 return false;
1595 });
1596 jQuery('.latepoint-content-w').on('change', 'select.os-reminder-medium-select', function(){
1597 if(jQuery(this).val() == 'email'){
1598 jQuery(this).closest('.os-reminder-form').find('.os-reminder-email-subject').show();
1599 }else{
1600 jQuery(this).closest('.os-reminder-form').find('.os-reminder-email-subject').hide();
1601 }
1602 });
1603 jQuery('.latepoint-content-w').on('keyup', '.os-reminder-name-input', function(){
1604 jQuery(this).closest('.os-reminder-form').find('.os-reminder-name').text(jQuery(this).val());
1605 });
1606 }
1607
1608 function latepoint_custom_field_saved($elem){
1609 }
1610
1611 function latepoint_init_custom_day_schedule(){
1612 latepoint_init_input_masks(jQuery('.latepoint-lightbox-w .custom-day-schedule-w'));
1613
1614 jQuery('.period-type-selector').on('change', function(){
1615 jQuery(this).closest('.custom-day-calendar').attr('data-period-type', jQuery(this).val());
1616 jQuery('.custom-day-calendar').attr('data-picking', 'start').data('picking', 'start');
1617 if(jQuery(this).val() == 'range'){
1618 jQuery('.custom-day-calendar-head .calendar-heading').text(jQuery('.custom-day-calendar-head .calendar-heading').data('label-start'));
1619 jQuery('.custom-day-calendar #start_custom_date').trigger('focus');
1620 }else{
1621 jQuery('.custom-day-calendar .os-day.selected').removeClass('selected');
1622 jQuery('.latepoint-lightbox-footer').hide();
1623 jQuery('.custom-day-calendar-head .calendar-heading').text(jQuery('.custom-day-calendar-head .calendar-heading').data('label-single'));
1624 }
1625 });
1626
1627
1628 jQuery('#custom_day_calendar_month, #custom_day_calendar_year').on('change', function(){
1629 var $calendar = jQuery('.custom-day-calendar-month');
1630 var route_name = $calendar.data('route');
1631 $calendar.addClass('os-loading');
1632 var target_date_string = jQuery('#custom_day_calendar_year').val() + '-' + jQuery('#custom_day_calendar_month').val() + '-01';
1633 var data = { action: latepoint_helper.route_action, route_name: route_name, params: { target_date_string: target_date_string }, layout: 'none', return_format: 'json' }
1634 jQuery.ajax({
1635 type : "post",
1636 dataType : "json",
1637 url : latepoint_timestamped_ajaxurl(),
1638 data : data,
1639 success: function(data){
1640 $calendar.removeClass('os-loading');
1641 if(data.status === "success"){
1642 $calendar.html(data.message);
1643 }else{
1644 // console.log(data.message);
1645 }
1646 }
1647 });
1648 });
1649
1650
1651
1652 jQuery('.custom-day-calendar').on('focus', '#start_custom_date', function(){
1653 jQuery('.custom-day-calendar-head .calendar-heading').text(jQuery('.custom-day-calendar-head .calendar-heading').data('label-start'));
1654 jQuery('.custom-day-calendar').attr('data-picking', 'start').data('picking', 'start');
1655 });
1656
1657 jQuery('.custom-day-calendar').on('focus', '#end_custom_date', function(){
1658 jQuery('.custom-day-calendar-head .calendar-heading').text(jQuery('.custom-day-calendar-head .calendar-heading').data('label-end'));
1659 jQuery('.custom-day-calendar').attr('data-picking', 'end').data('picking', 'end');
1660 });
1661
1662 jQuery('.custom-day-calendar').on('click', '.os-day', function(){
1663 var $this = jQuery(this);
1664 $this.closest('.custom-day-calendar').find('.os-day.selected').removeClass('selected');
1665 $this.addClass('selected');
1666
1667 if(jQuery('.custom-day-calendar').data('picking') == 'start'){
1668 jQuery('.custom-day-settings-w #start_custom_date').val($this.data('date')).trigger('keyup');
1669 if(jQuery('.period-type-selector').val() == 'range'){
1670 jQuery('.custom-day-calendar #end_custom_date').trigger('focus');
1671 if(!jQuery('.custom-day-calendar #end_custom_date').val()) return false;
1672 }
1673 }else{
1674 jQuery('.custom-day-settings-w #end_custom_date').val($this.data('date')).trigger('keyup');
1675 }
1676 jQuery('.latepoint-lightbox-footer').slideDown(200);
1677 if(jQuery('.custom-day-calendar').data('show-schedule') == 'yes') jQuery('.latepoint-lightbox-w').removeClass('hide-schedule');
1678 return false;
1679 });
1680 }
1681
1682 function latepoint_init_updates_page(){
1683
1684 }
1685
1686 function latepoint_calendar_set_month_label(){
1687 jQuery('.os-current-month-label .current-month').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-month-label'));
1688 jQuery('.os-current-month-label .current-year').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-year'));
1689 }
1690
1691
1692 function latepoint_init_element_togglers(){
1693 jQuery('[data-toggle-element]').on('click', function(){
1694 var $this = jQuery(this);
1695 $this.closest('.os-form-checkbox-group').toggleClass('is-checked');
1696 jQuery($this.data('toggle-element')).toggle();
1697 });
1698 }
1699
1700
1701 function latepoint_init_color_picker(){
1702 if(jQuery('.latepoint-color-picker').length){
1703 jQuery('.latepoint-color-picker').each(function(){
1704 var color = jQuery(this).data('color');
1705 var picker = jQuery(this)[0];
1706 var $picker_wrapper = jQuery(this).closest('.latepoint-color-picker-w');
1707 Pickr.create({
1708 el: picker,
1709 default: color,
1710 comparison: false,
1711 useAsButton: true,
1712 components: {
1713
1714 // Main components
1715 preview: false,
1716 opacity: false,
1717 hue: true,
1718
1719 // Input / output Options
1720 interaction: {
1721 input: false,
1722 clear: false,
1723 save: true
1724 }
1725 },
1726 onChange(hsva, instance) {
1727 $picker_wrapper.find('.os-form-control').val(hsva.toHEX().toString());
1728 },
1729 });
1730 });
1731 }
1732 }
1733
1734
1735 function latepoint_lightbox_close(){
1736 jQuery('body').removeClass('latepoint-lightbox-active');
1737 jQuery('.latepoint-lightbox-w').remove();
1738 }
1739
1740 function latepoint_reload_select_service_categories(){
1741 jQuery('.service-selector-adder-field-w').each(function(){
1742 var $trigger_elem = jQuery(this);
1743 var route = jQuery('.service-selector-adder-field-w').find('select').data('select-source');
1744 var data = { action: latepoint_helper.route_action, route_name: route, params: '', return_format: 'json' }
1745 jQuery.ajax({
1746 type : "post",
1747 dataType : "json",
1748 url : latepoint_timestamped_ajaxurl(),
1749 data : data,
1750 success: function(response){
1751 $trigger_elem.removeClass('os-loading');
1752 if(response.status === "success"){
1753 latepoint_lightbox_close();
1754 $trigger_elem.find('select').html(response.message);
1755 $trigger_elem.find('select option:last').attr('selected', 'selected');
1756 }else{
1757 alert(response.message, 'error');
1758 }
1759 }
1760 });
1761 });
1762 }
1763
1764 function latepoint_wizard_item_editing_cancelled(response){
1765 jQuery('.os-wizard-setup-w').removeClass('is-sub-editing');
1766 jQuery('.os-wizard-footer').show();
1767 jQuery('.os-wizard-footer .os-wizard-next-btn').show();
1768 if(response.show_prev_btn){
1769 jQuery('.os-wizard-footer .os-wizard-prev-btn').show();
1770 }
1771 }
1772
1773
1774 function latepoint_reload_week_view_calendar(start_date = false){
1775 var service_id = (jQuery('.cc-availability-toggler #overlay_service_availability').val() == 'on') ? jQuery('.calendar-service-selector').val() : false;
1776 var agent_id = jQuery('.calendar-agent-selector').val();
1777 var location_id = jQuery('.calendar-location-selector').val();
1778 var calendar_start_date = (start_date) ? start_date : jQuery('.calendar-start-date').val();
1779 latepoint_load_calendar(calendar_start_date, agent_id, location_id, service_id);
1780 }
1781
1782 function latepoint_init_work_period_form(){
1783 latepoint_mask_timefield(jQuery('.os-time-input-w .os-mask-time'));
1784 }
1785
1786 function latepoint_close_side_panel(){
1787 latepoint_close_quick_availability_form();
1788 jQuery('.latepoint-side-panel-w').remove();
1789 }
1790
1791 function reload_process_jobs_table(){
1792 if(jQuery('table.os-reload-on-booking-update').length) latepoint_filter_table(jQuery('table.os-reload-on-booking-update'), jQuery('table.os-reload-on-booking-update'));
1793 }
1794
1795
1796 function latepoint_transaction_removed($trigger){
1797 $trigger.closest('.quick-add-transaction-box-w').remove();
1798 latepoint_reload_balance_and_payments();
1799 }
1800
1801 function latepoint_reload_widget($widget_elem){
1802 var form_data = $widget_elem.find('select, input').serialize();
1803 var data = { action: latepoint_helper.route_action, route_name: $widget_elem.data('os-reload-action'), params: form_data, return_format: 'json' }
1804 $widget_elem.addClass('os-loading');
1805 jQuery.ajax({
1806 type : "post",
1807 dataType : "json",
1808 url : latepoint_timestamped_ajaxurl(),
1809 data : data,
1810 success: function(response){
1811 $widget_elem.removeClass('os-loading');
1812 if(response.status === "success"){
1813 var $updated_widget_elem = jQuery(response.message);
1814 $updated_widget_elem.removeClass('os-widget-animated');
1815 $widget_elem = $widget_elem.replaceWith($updated_widget_elem);
1816 latepoint_init_daterangepicker($updated_widget_elem.find('.os-date-range-picker'));
1817 if($widget_elem.hasClass('os-widget-top-agents')) latepoint_init_circles_charts();
1818 if($widget_elem.hasClass('os-widget-daily-bookings')){
1819 latepoint_init_daily_bookings_chart();
1820 latepoint_init_donut_charts();
1821 }
1822 }else{
1823 alert(response.message);
1824 }
1825 }
1826 });
1827 }
1828
1829 function latepoint_load_calendar(target_date, agent_id, location_id = false, service_id = false){
1830 var route_name = jQuery('.calendar-week-agent-w').data('calendar-action');
1831 jQuery('.calendar-week-agent-w').addClass('os-loading');
1832 var params_arr = {target_date: target_date, agent_id: agent_id};
1833 if(location_id) params_arr.location_id = location_id;
1834 if(service_id) params_arr.service_id = service_id;
1835 var data = { action: latepoint_helper.route_action, route_name: route_name, params: jQuery.param(params_arr), return_format: 'json' }
1836 jQuery.ajax({
1837 type : "post",
1838 dataType : "json",
1839 url : latepoint_timestamped_ajaxurl(),
1840 data : data,
1841 success: function(response){
1842 if(response.status === "success"){
1843 jQuery('.calendar-week-agent-w').html(response.message).removeClass('os-loading');
1844 jQuery('.calendar-load-target-date.os-loading').removeClass('os-loading');
1845 }else{
1846 alert(response.message);
1847 }
1848 }
1849 });
1850 }
1851
1852 function latepoint_init_quick_transaction_form(){
1853 latepoint_mask_money(jQuery('.quick-add-transaction-box-w .os-mask-money'));
1854 }
1855
1856 function latepoint_reload_price_breakdown(){
1857 var $trigger = jQuery('.reload-price-breakdown');
1858 $trigger.addClass('os-loading');
1859 var $quick_edit_form = $trigger.closest('form.order-quick-edit-form');
1860 var form_data = new FormData($quick_edit_form[0]);
1861 var route = $trigger.data('route');
1862
1863 var data = { action: latepoint_helper.route_action, route_name: route, params: latepoint_formdata_to_url_encoded_string(form_data), return_format: 'json' }
1864 jQuery.ajax({
1865 type : "post",
1866 dataType : "json",
1867 url : latepoint_timestamped_ajaxurl(),
1868 data : data,
1869 success: function(response){
1870 $trigger.removeClass('os-loading');
1871 if(response.status === "success"){
1872 jQuery('.price-breakdown-wrapper').html(response.message);
1873 latepoint_mask_money(jQuery('.price-breakdown-wrapper .os-mask-money'));
1874 latepoint_reload_balance_and_payments();
1875 }else{
1876 alert(response.message);
1877 }
1878 }
1879 });
1880 }
1881
1882 function latepoint_complex_selector_select($connection_wrappers, qty = 1){
1883 $connection_wrappers.each(function(){
1884 jQuery(this).addClass('active');
1885 jQuery(this).find('.connection-children-list li').addClass('active');
1886 jQuery(this).find('.connection-child-is-connected').val('yes');
1887 jQuery(this).find('.item-quantity-selector-input').val(qty);
1888 latepoint_count_active_connections(jQuery(this));
1889 });
1890 }
1891
1892 function latepoint_complex_selector_deselect($connection_wrappers){
1893 $connection_wrappers.each(function(){
1894 jQuery(this).removeClass('active');
1895 jQuery(this).removeClass('show-customize-box');
1896 jQuery(this).find('.connection-children-list li.active').removeClass('active');
1897 jQuery(this).find('.connection-child-is-connected').val('no');
1898 jQuery(this).find('.item-quantity-selector-input').val(0);
1899 latepoint_count_active_connections(jQuery(this));
1900 });
1901 }
1902
1903
1904
1905 function latepoint_is_next_day($form){
1906 let field_base_name = 'order_items[' + $form.data('order-item-id') +'][bookings][' + $form.data('booking-id') +']';
1907
1908 var start_time = $form.find('input[name="' + field_base_name + '[start_time][formatted_value]"]').val();
1909 var start_time_ampm = $form.find('input[name="' + field_base_name + '[start_time][ampm]"]').val();
1910 var start_time_minutes = latepoint_hours_and_minutes_to_minutes(start_time, start_time_ampm);
1911 var end_time = $form.find('input[name="' + field_base_name + '[end_time][formatted_value]"]').val();
1912 var end_time_ampm = $form.find('input[name="' + field_base_name + '[end_time][ampm]"]').val();
1913 var end_time_minutes = latepoint_hours_and_minutes_to_minutes(end_time, end_time_ampm);
1914
1915 if(end_time_minutes && (end_time_minutes <= start_time_minutes)){
1916 $form.find('.quick-end-time-w').addClass('ending-next-day');
1917 }else{
1918 $form.find('.quick-end-time-w').removeClass('ending-next-day');
1919 }
1920 }
1921
1922 function latepoint_set_booking_end_time($booking_data_form){
1923 var booking_duration = 0;
1924 var service_duration = Number($booking_data_form.find('.os-service-durations select').val());
1925
1926 let field_base_name = 'order_items[' + $booking_data_form.data('order-item-id') +'][bookings][' + $booking_data_form.data('booking-id') +']';
1927
1928 booking_duration = booking_duration + service_duration;
1929 if($booking_data_form.find('select[name="temp_service_extras_ids"] option:selected').length){
1930 $booking_data_form.find('select[name="temp_service_extras_ids"] option:selected').each(function(){
1931 var extra_duration = Number(jQuery(this).data('duration'));
1932 var $extra_quantity_input = jQuery(this).closest('.lateselect-w').find('.ls-item[data-value="' + jQuery(this).val() + '"]').find('.os-late-quantity-selector-input');
1933 if($extra_quantity_input.length) extra_duration = Number(extra_duration) * Number($extra_quantity_input.val());
1934 booking_duration = Number(booking_duration) + Number(extra_duration);
1935 });
1936 }
1937
1938 var start_time = $booking_data_form.find('input[name="'+field_base_name+'[start_time][formatted_value]"]').val();
1939
1940 if(start_time){
1941 var start_time_ampm = $booking_data_form.find('input[name="'+field_base_name+'[start_time][ampm]"]').val();
1942 var start_time_minutes = latepoint_hours_and_minutes_to_minutes(start_time, start_time_ampm);
1943 var end_time_minutes = parseInt(start_time_minutes) + parseInt(booking_duration);
1944 if(end_time_minutes >= (24 * 60)) end_time_minutes = (end_time_minutes - 24 * 60);
1945 var end_time_ampm = (end_time_minutes >= 720 && end_time_minutes < (24 * 60)) ? 'pm' : 'am';
1946 var end_hours_and_minutes = latepoint_minutes_to_hours_and_minutes(end_time_minutes);
1947
1948 $booking_data_form.find('input[name="'+field_base_name+'[end_time][formatted_value]"]').val(end_hours_and_minutes);
1949 $booking_data_form.find('.quick-end-time-w .time-ampm-select.time-' + end_time_ampm).trigger('click');
1950 $booking_data_form.find('input[name="'+field_base_name+'[end_time][formatted_value]"]').closest('.os-form-group').addClass('has-value');
1951 }
1952 latepoint_is_next_day($booking_data_form);
1953 }
1954
1955
1956
1957 function latepoint_init_sortable_columns(){
1958 jQuery('.os-sortable-column').on('click', function(){
1959 let current_direction = jQuery(this).hasClass('ordered-desc') ? 'desc' : 'asc';
1960 let new_direction = (current_direction == 'desc') ? 'asc' : 'desc';
1961 jQuery(this).closest('table').find('.os-sortable-column').removeClass('ordered-desc').removeClass('ordered-asc');
1962 jQuery(this).addClass('ordered-' + new_direction);
1963
1964 jQuery(this).closest('table').find('.records-ordered-by-key').val(jQuery(this).data('order-key'));
1965 jQuery(this).closest('table').find('.records-ordered-by-direction').val(new_direction);
1966 latepoint_filter_table(jQuery(this).closest('table'), jQuery(this).closest('.os-form-group'));
1967 return false;
1968 });
1969 }
1970 function latepoint_random_text(length){
1971 var result = '';
1972 var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
1973 var charactersLength = characters.length;
1974 for ( var i = 0; i < length; i++ ) {
1975 result += characters.charAt(Math.floor(Math.random() * charactersLength));
1976 }
1977 return result;
1978 }
1979
1980 function latepoint_get_order_for_service_categories(){
1981
1982 }
1983
1984
1985 function latepoint_init_daterangepicker($elem){
1986 $elem.each(function(){
1987 // DATERANGEPICKER
1988 var picker_start_time = jQuery(this).find('input[name="date_from"], .os-datepicker-date-from').val();
1989 var picker_end_time = jQuery(this).find('input[name="date_to"], .os-datepicker-date-to').val();
1990 var locale = {};
1991 if(jQuery(this).data('can-be-cleared')) locale = { cancelLabel: jQuery(this).data('clear-btn-label')};
1992
1993
1994 moment.locale(latepoint_helper.wp_locale);
1995
1996 jQuery(this).daterangepicker({
1997 opens: 'center',
1998 singleDatePicker: (jQuery(this).data('single-date') == 'yes'),
1999 startDate: (picker_start_time) ? moment(picker_start_time) : moment(),
2000 endDate: (picker_end_time) ? moment(picker_end_time) : moment(),
2001 locale: locale
2002 });
2003 });
2004
2005 $elem.on('cancel.daterangepicker', function(ev, picker) {
2006 if(picker.element.data('can-be-cleared')){
2007 picker.element.find('input[name="date_from"], .os-datepicker-date-from').val('');
2008 picker.element.find('input[name="date_to"], .os-datepicker-date-to').val('');
2009 picker.element.find('span.range-picker-value').text(picker.element.data('no-value-label'));
2010 if(picker.element.hasClass('os-table-filter-datepicker')){
2011 latepoint_filter_table(picker.element.closest('table'), picker.element.closest('.os-form-group'));
2012 }
2013 }
2014 });
2015
2016 $elem.on('apply.daterangepicker', function(ev, picker) {
2017 if(picker.element.data('single-date') == 'yes'){
2018 picker.element.find('.range-picker-value').text(picker.startDate.format('ll'));
2019 }else{
2020 picker.element.find('.range-picker-value').text(picker.startDate.format('ll') + ' - ' + picker.endDate.format('ll'));
2021 }
2022 picker.element.find('input[name="date_from"], .os-datepicker-date-from').attr('value', picker.startDate.format('YYYY-MM-DD'));
2023 picker.element.find('input[name="date_to"], .os-datepicker-date-to').attr('value', picker.endDate.format('YYYY-MM-DD'));
2024 if(picker.element.closest('.os-widget').length){
2025 latepoint_reload_widget(picker.element.closest('.os-widget'));
2026 }
2027 if(picker.element.hasClass('os-table-filter-datepicker')){
2028 latepoint_filter_table(picker.element.closest('table'), picker.element.closest('.os-form-group'));
2029 }
2030 });
2031 }
2032
2033 function latepoint_recalculate_items_count_in_category(){
2034 jQuery('.os-category-items-count').each(function(){
2035 var number_of_items = jQuery(this).closest('.os-category-parent-w').find('.item-in-category-w').length;
2036 jQuery(this).find('span').text(number_of_items);
2037 });
2038 }
2039
2040 function latepoint_remove_agent_box($remove_btn){
2041 var $agent_box = $remove_btn.closest('.agent-box-w');
2042 $agent_box.fadeOut(300, function(){ jQuery(this).remove(); });
2043 }
2044
2045 function latepoint_remove_service_box($remove_btn){
2046 var $service_box = $remove_btn.closest('.service-box-w');
2047 $service_box.fadeOut(300, function(){ jQuery(this).remove(); });
2048 }
2049
2050 function latepoint_init_monthly_view(){
2051 if(!jQuery('.calendar-month-agents-w').length) return;
2052
2053 jQuery('.monthly-calendar-headers select').on('change', function(){
2054 var $calendar = jQuery('.calendar-month-agents-w');
2055 var route_name = $calendar.data('route');
2056 $calendar.addClass('os-loading');
2057 var params = { month: jQuery('#monthly_calendar_month_select').val(), year: jQuery('#monthly_calendar_year_select').val() };
2058 if(jQuery('#monthly_calendar_location_select').length && jQuery('#monthly_calendar_location_select').val()) params.location_id = jQuery('#monthly_calendar_location_select').val();
2059 if(jQuery('#monthly_calendar_service_select').length && jQuery('#monthly_calendar_service_select').val()) params.service_id = jQuery('#monthly_calendar_service_select').val();
2060 var data = { action: latepoint_helper.route_action, route_name: route_name, params: params, layout: 'none', return_format: 'json' }
2061 jQuery.ajax({
2062 type : "post",
2063 dataType : "json",
2064 url : latepoint_timestamped_ajaxurl(),
2065 data : data,
2066 success: function(data){
2067 $calendar.removeClass('os-loading');
2068 if(data.status === "success"){
2069 $calendar.html(data.message);
2070 }else{
2071 // console.log(data.message);
2072 }
2073 }
2074 });
2075 });
2076 }
2077
2078
2079 function latepoint_init_copy_on_click_elements(){
2080
2081 jQuery('.os-click-to-copy').on('mouseenter', function() {
2082 var $this = jQuery(this);
2083 var position_info = $this.offset();
2084 var width = jQuery(this).outerWidth();
2085 var position_left = position_info.left;
2086 var position_top = position_info.top - 20 - jQuery(window).scrollTop();
2087
2088 let color = ($this.data('copy-tooltip-color') == 'dark') ? 'dark' : 'light';
2089 if($this.data('copy-tooltip-position') == 'left'){
2090 position_left = position_left - width - 5;
2091 position_top = position_top + $this.outerHeight() - jQuery(window).scrollTop();
2092 }
2093 jQuery('body').append('<div class="os-click-to-copy-prompt color-'+color+'" style="top: '+position_top+'px; left: '+position_left+'px;">' + latepoint_helper.click_to_copy_prompt + '</div>');
2094 }).on('mouseleave', function() {
2095 jQuery('body').find('.os-click-to-copy-prompt').remove();
2096 });
2097 jQuery('.os-click-to-copy').on('click', function(){
2098 var $this = jQuery(this);
2099 let color = ($this.data('copy-tooltip-color') == 'dark') ? 'dark' : 'light';
2100 jQuery('body').find('.os-click-to-copy-prompt').hide();
2101 var text_to_copy = $this.is('input') ? $this.val() : $this.text();
2102 navigator.clipboard.writeText(text_to_copy);
2103
2104 var position_info = $this.offset();
2105 var width = $this.outerWidth();
2106 var position_left = position_info.left;
2107 var position_top = position_info.top - 20 - jQuery(window).scrollTop();
2108
2109 if($this.data('copy-tooltip-position') == 'left'){
2110 position_left = position_left - width - 5;
2111 position_top = position_top + $this.outerHeight() - jQuery(window).scrollTop();
2112 }
2113 var $done_prompt = jQuery('<div class="os-click-to-copy-done color-'+color+'" style="top: '+position_top+'px; left: '+position_left+'px;">' + latepoint_helper.click_to_copy_done + '</div>');
2114 $done_prompt.appendTo(jQuery('body')).animate({
2115 opacity: 0,
2116 left: (position_left + 20),
2117 }, 600);
2118 setTimeout(function(){
2119 jQuery('body').find('.os-click-to-copy-done').remove();
2120 jQuery('body').find('.os-click-to-copy-prompt').show();
2121 }, 800);
2122 });
2123 }
2124
2125 function latepoint_remove_floating_popup(){
2126 jQuery('.os-showing-popup').removeClass('os-showing-popup');
2127 jQuery('.os-floating-popup').remove();
2128 }
2129
2130 function latepoint_init_clickable_cells(){
2131 jQuery('.os-clickable-popup-trigger').on('click', function(){
2132 var $this = jQuery(this);
2133 var position = $this.offset();
2134 var width = $this.outerWidth();
2135 var $popup = jQuery('<div class="os-floating-popup os-loading"></div>');
2136 if($this.hasClass('os-showing-popup')){
2137 latepoint_remove_floating_popup();
2138 }else{
2139 latepoint_remove_floating_popup();
2140 $popup.offset({top: position.top, left: (position.left + width/2)});
2141 jQuery('body').append($popup);
2142 $this.addClass('os-showing-popup');
2143
2144 var route = $this.data('route');
2145 var params = $this.data('os-params');
2146 var data = { action: latepoint_helper.route_action, route_name: route, params: params, layout: 'none', return_format: 'json' };
2147 jQuery.ajax({
2148 type : "post",
2149 dataType : "json",
2150 url : latepoint_timestamped_ajaxurl(),
2151 data : data,
2152 success: function(response){
2153 if(response.status === latepoint_helper.response_status.success){
2154 jQuery('body').find('.os-floating-popup').html(response.message).removeClass('os-loading');
2155 latepoint_init_customer_donut_chart();
2156 jQuery('.os-floating-popup .os-floating-popup-close').on('click', function(){
2157 latepoint_remove_floating_popup();
2158 return false;
2159 });
2160 }else{
2161
2162 }
2163 }
2164 });
2165 }
2166 return false;
2167 });
2168 }
2169
2170 function latepoint_init_tiny_mce(element_id){
2171 // TODO CHECK IF wp.editor is defined
2172 if(typeof wp !== 'undefined' && typeof wp.editor !== 'undefined' && jQuery('#'+ element_id).length){
2173 wp.editor.remove(element_id);
2174 wp.editor.initialize(element_id,
2175 {
2176 tinymce: {
2177 wpautop: false,
2178 toolbar1: 'formatselect alignjustify forecolor | bold italic underline strikethrough | bullist numlist | blockquote hr | alignleft aligncenter alignright | link unlink | pastetext removeformat | outdent indent | undo redo',
2179 height : "480",
2180 },
2181 quicktags: true,
2182 mediaButtons: true,
2183 }
2184 );
2185 }
2186 }
2187
2188 function latepoint_init_reminder_form(){
2189 latepoint_init_tiny_mce(jQuery('.os-reminder-form:last-child textarea').attr('id'));
2190 }
2191
2192
2193 function latepoint_filter_table($table, $filter_elem, reset_page = true){
2194 $filter_elem.addClass('os-loading');
2195 var filter_params = $table.find('.os-table-filter').serialize();
2196 var $table_w = $table.closest('.table-with-pagination-w');
2197 if(reset_page){
2198 $table_w.find('select.pagination-page-select').val(1);
2199 }else{
2200 filter_params+= '&page_number='+$table_w.find('select.pagination-page-select').val();
2201 }
2202 var route = $table.data('route');
2203 var data = { action: latepoint_helper.route_action, route_name: route, params: filter_params, layout: 'none', return_format: 'json' };
2204 jQuery.ajax({
2205 type : "post",
2206 dataType : "json",
2207 url : latepoint_timestamped_ajaxurl(),
2208 data : data,
2209 success: function(data){
2210 $filter_elem.removeClass('os-loading');
2211 if(data.status === "success"){
2212 $table.find('tbody').html(data.message);
2213 if(data.total_pages && reset_page){
2214 var options = '';
2215 for(var i = 1; i <= data.total_pages; i++){
2216 options+= '<option>'+ i +'</option>';
2217 }
2218 $table_w.find('select.pagination-page-select').html(options);
2219 }
2220 $table_w.find('.os-pagination-from').text(data.showing_from);
2221 $table_w.find('.os-pagination-to').text(data.showing_to);
2222 $table_w.find('.os-pagination-total').text(data.total_records);
2223 latepoint_init_clickable_cells();
2224 }else{
2225 // console.log(data.message);
2226 }
2227 }
2228 });
2229 }
2230
2231 function latepoint_init_service_duration_box($duration_box){
2232 latepoint_init_input_masks(jQuery('.service-duration-box:last-child'));
2233 }
2234
2235 function latepoint_init_wizard_content(){
2236 latepoint_init_input_masks(jQuery('.os-wizard-step-content'));
2237 }
2238
2239 function latepoint_init_input_masks($scoped_element = false){
2240 let $wrapper = $scoped_element ? $scoped_element : jQuery('body');
2241 latepoint_mask_timefield($wrapper.find('.os-mask-time'));
2242
2243 $wrapper.find('.os-mask-phone').each(function(){
2244 latepoint_mask_phone(jQuery(this));
2245 });
2246
2247 latepoint_mask_money($wrapper.find('.os-mask-money'));
2248 latepoint_mask_date($wrapper.find('.os-mask-date'));
2249 latepoint_mask_minutes($wrapper.find('.os-mask-minutes'));
2250
2251 $wrapper.trigger('latepoint:initInputMasks');
2252 }
2253
2254
2255 function latepoint_init_quick_agent_form(){
2256 let $agent_form_wrapper = jQuery('.quick-agent-form-w');
2257 latepoint_init_input_masks($agent_form_wrapper);
2258
2259
2260 $agent_form_wrapper.find('.agent-quick-edit-form').on('submit', function(e){
2261 if(jQuery(this).find('button[type="submit"]').hasClass('os-loading')) return false;
2262 e.preventDefault();
2263 latepoint_submit_quick_agent_form();
2264 });
2265
2266
2267 $agent_form_wrapper.find('.quick-agent-form-view-log-btn').on('click', function(){
2268 let $trigger_elem = jQuery(this);
2269 $trigger_elem.addClass('os-loading');
2270 let route = $trigger_elem.data('route');
2271 let data = { action: 'latepoint_route_call', route_name: route, params: {agent_id: $trigger_elem.data('agent-id')}, return_format: 'json' }
2272 jQuery.ajax({
2273 type : "post",
2274 dataType : "json",
2275 url : latepoint_timestamped_ajaxurl(),
2276 data : data,
2277 success: function(response){
2278 $trigger_elem.removeClass('os-loading');
2279 if(response.status === "success"){
2280 latepoint_display_in_side_sub_panel(response.message);
2281 jQuery('body').addClass('has-side-sub-panel');
2282 }else{
2283 alert(response.message, 'error');
2284 }
2285 }
2286 });
2287 return false;
2288 });
2289 }
2290
2291 /*
2292 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
2293 */
2294
2295 function latepoint_init_quick_customer_form(){
2296 let $customer_form_wrapper = jQuery('.quick-customer-form-w');
2297 latepoint_init_input_masks($customer_form_wrapper);
2298
2299
2300 $customer_form_wrapper.find('.customer-quick-edit-form').on('submit', function(e){
2301 if(jQuery(this).find('button[type="submit"]').hasClass('os-loading')) return false;
2302 e.preventDefault();
2303 latepoint_submit_quick_customer_form();
2304 });
2305
2306
2307 $customer_form_wrapper.find('.quick-customer-form-view-log-btn').on('click', function(){
2308 var $trigger_elem = jQuery(this);
2309 $trigger_elem.addClass('os-loading');
2310 var route = $trigger_elem.data('route');
2311 var data = { action: 'latepoint_route_call', route_name: route, params: {customer_id: $trigger_elem.data('customer-id')}, return_format: 'json' }
2312 jQuery.ajax({
2313 type : "post",
2314 dataType : "json",
2315 url : latepoint_timestamped_ajaxurl(),
2316 data : data,
2317 success: function(response){
2318 $trigger_elem.removeClass('os-loading');
2319 if(response.status === "success"){
2320 latepoint_display_in_side_sub_panel(response.message);
2321 jQuery('body').addClass('has-side-sub-panel');
2322 }else{
2323 alert(response.message, 'error');
2324 }
2325 }
2326 });
2327 return false;
2328 });
2329 }
2330
2331
2332 function latepoint_submit_quick_customer_form(){
2333 let $quick_edit_form = jQuery('form.customer-quick-edit-form');
2334
2335 let errors = latepoint_validate_form($quick_edit_form);
2336 if(errors.length){
2337 let error_messages = errors.map(error => error.message ).join(', ');
2338 latepoint_add_notification(error_messages, 'error');
2339 return false;
2340 }
2341
2342 $quick_edit_form.find('button[type="submit"]').addClass('os-loading');
2343 jQuery.ajax({
2344 type: "post",
2345 dataType: "json",
2346 processData: false,
2347 contentType: false,
2348 url: latepoint_timestamped_ajaxurl(),
2349 data: latepoint_create_form_data($quick_edit_form),
2350 success: function (response) {
2351 $quick_edit_form.find('button[type="submit"]').removeClass('os-loading');
2352 if(response.form_values_to_update){
2353 jQuery.each(response.form_values_to_update, function(name, value){
2354 $quick_edit_form.find('[name="'+ name +'"]').val(value);
2355 });
2356 }
2357 if (response.status === "success") {
2358 latepoint_add_notification(response.message);
2359 latepoint_reload_after_customer_save();
2360 }else{
2361 latepoint_add_notification(response.message, 'error');
2362 }
2363 }
2364 });
2365
2366 }
2367
2368
2369
2370 function latepoint_reload_after_customer_save(){
2371 latepoint_reload_calendar_view();
2372
2373 jQuery('.os-widget').each(function(){
2374 latepoint_reload_widget(jQuery(this));
2375 });
2376 if(jQuery('table.os-reload-on-booking-update').length) latepoint_filter_table(jQuery('table.os-reload-on-booking-update'), jQuery('table.os-reload-on-booking-update'));
2377 latepoint_close_side_panel();
2378 }
2379
2380 function latepoint_init_customers_import() {
2381
2382 jQuery('body.latepoint').on('submit', '.import-customers-form', async function (e) {
2383 e.preventDefault();
2384 let $form = jQuery(this);
2385
2386 if($form.hasClass('os-loading')) return false;
2387
2388 $form.addClass('os-loading');
2389 $form.find('button[type="submit"]').addClass('os-loading');
2390
2391 try {
2392 let response = await jQuery.ajax({
2393 type: "post",
2394 dataType: "json",
2395 processData: false,
2396 contentType: false,
2397 url: latepoint_timestamped_ajaxurl(),
2398 data: latepoint_create_form_data($form)
2399 });
2400
2401 $form.removeClass('os-loading').find('.os-loading').removeClass('os-loading');
2402
2403 if (response.status === 'success') {
2404 $form.find('.latepoint-lightbox-content').html(response.message);
2405
2406 latepoint_import_customers_set_next_btn($form);
2407 latepoint_import_customers_set_step($form);
2408
2409 } else {
2410 latepoint_add_notification(response.message || 'Error', 'error');
2411 return false;
2412 }
2413 } catch (e) {
2414 $form.removeClass('os-loading').find('.os-loading').removeClass('os-loading');
2415 console.log(e);
2416 }
2417 });
2418 }
2419
2420 function latepoint_import_customers_set_next_btn($form) {
2421 let step_form = $form.find('.customer-csv-step');
2422 if (step_form.data('hide-next-btn')) {
2423 $form.find('.latepoint-lightbox-footer').hide();
2424 } else {
2425 let btn_label = step_form.data('customer-csv-next-btn');
2426 if (btn_label) {
2427 $form.find('.latepoint-csv-next-btn').text(btn_label);
2428 }
2429 }
2430 }
2431
2432 function latepoint_import_customers_set_step($form) {
2433 let step = $form.find('.customer-csv-step').data('customer-csv-step');
2434 if (step) {
2435 $form.find('input[name="step"]').val(step);
2436 }
2437 }
2438
2439 /*
2440 * Copyright (c) 2023 LatePoint LLC. All rights reserved.
2441 */
2442
2443
2444 function latepoint_init_daily_bookings_chart() {
2445 if (typeof Chart === 'undefined' || !jQuery('#chartDailyBookings').length) return
2446
2447 let $dailyBookingsChart = jQuery('#chartDailyBookings');
2448 let dailyBookingsLabels = $dailyBookingsChart.data('chart-labels').toString().split(',');
2449 let dailyBookingsValues = $dailyBookingsChart.data('chart-values').toString().split(',').map(Number);
2450 let dailyBookingsChartMax = Math.max.apply(Math, dailyBookingsValues);
2451 // calculate max Y to have space for a tooltip
2452 let canvasHeight = 200
2453 let spaceForTooltip = 160
2454 let maxValue = dailyBookingsChartMax + spaceForTooltip * dailyBookingsChartMax / canvasHeight + 1
2455
2456
2457 var fontFamily = latepoint_helper.body_font_family;
2458
2459 Chart.Tooltip.positioners.top = function (items) {
2460 const pos = Chart.Tooltip.positioners.average(items);
2461
2462 // Happens when nothing is found
2463 if (pos === false) {
2464 return false;
2465 }
2466
2467 const chart = this.chart;
2468
2469 return {
2470 x: pos.x,
2471 y: chart.chartArea.top,
2472 xAlign: 'center',
2473 yAlign: 'bottom',
2474 };
2475 };
2476
2477 Chart.defaults.defaultFontFamily = fontFamily;
2478 Chart.defaults.defaultFontSize = 18;
2479 Chart.defaults.defaultFontStyle = '400';
2480 Chart.defaults.plugins.tooltip.titleFont = {
2481 family: fontFamily,
2482 size: 14,
2483 color: 'rgba(255,255,255,0.6)',
2484 style: 'normal',
2485 weight: 400
2486 }
2487
2488 Chart.defaults.plugins.tooltip.titleFont = {family: fontFamily, size: 14, weight: 400};
2489 Chart.defaults.plugins.tooltip.titleColor = 'rgba(255,255,255,0.6)';
2490 Chart.defaults.plugins.tooltip.backgroundColor = '#000';
2491 Chart.defaults.plugins.tooltip.titleMarginBottom = 5;
2492 Chart.defaults.plugins.tooltip.bodyFont = {family: fontFamily, size: 24, weight: 700, lineHeight: 0.8};
2493 Chart.defaults.plugins.tooltip.displayColors = false;
2494 Chart.defaults.plugins.tooltip.padding = 10;
2495 Chart.defaults.plugins.tooltip.yAlign = 'bottom';
2496 Chart.defaults.plugins.tooltip.xAlign = 'center';
2497 Chart.defaults.plugins.tooltip.cornerRadius = 14;
2498 Chart.defaults.plugins.tooltip.caretSize = 5;
2499 Chart.defaults.plugins.tooltip.position = 'top';
2500
2501 var ctx = $dailyBookingsChart[0].getContext("2d");
2502 var gradientStroke = ctx.createLinearGradient(500, 0, 100, 0);
2503 gradientStroke.addColorStop(0, '#219ff8');
2504 gradientStroke.addColorStop(1, '#219ff8');
2505
2506
2507 let gradientFill = ctx.createLinearGradient(0, 0, 0, 140);
2508 gradientFill.addColorStop(0, 'rgba(195, 229, 253, 0.9)');
2509 gradientFill.addColorStop(1, 'rgba(195, 229, 253, 0.1)');
2510
2511 // line chart data
2512 var chartDailyBookingsData = {
2513 labels: dailyBookingsLabels,
2514 datasets: [{
2515 backgroundColor: gradientFill,
2516 borderColor: gradientStroke,
2517 label: "",
2518 fill: true,
2519 lineTension: 0.3,
2520 borderWidth: 2,
2521 borderCapStyle: 'butt',
2522 borderDash: [],
2523 borderDashOffset: 0.0,
2524 borderJoinStyle: 'miter',
2525 pointBorderColor: "#fff",
2526 pointBackgroundColor: "#219ff8",
2527 pointRadius: 3,
2528 pointBorderWidth: 2,
2529 pointHoverRadius: 6,
2530 pointHoverBorderWidth: 4,
2531 pointHoverBackgroundColor: "#219ff8",
2532 pointHoverBorderColor: "#fff",
2533 pointHitRadius: 20,
2534 spanGaps: false,
2535 data: dailyBookingsValues,
2536 }]
2537 };
2538
2539
2540 let options = {
2541 animation: false,
2542 layout: {
2543 padding: {
2544 top: 0
2545 }
2546 },
2547 interaction: {
2548 mode: 'index',
2549 intersect: false,
2550 },
2551 maintainAspectRatio: false,
2552 plugins: {
2553 verticalLiner: {},
2554 legend: {
2555 display: false
2556 },
2557 },
2558 scales: {
2559 x: {
2560 display: true,
2561 ticks: {
2562 fontFamily: fontFamily,
2563 maxRotation: 0,
2564 color: '#788291',
2565 font: {
2566 size: 10,
2567 family: fontFamily
2568 },
2569 callback: function (value, index, ticks) {
2570 if(ticks.length){
2571 return ((index + 2) % Math.round(ticks.length/8)) ? '' : this.getLabelForValue(value)
2572 }else{
2573 return this.getLabelForValue(value)
2574 }
2575 }
2576 },
2577 grid: {
2578 borderDash: [1, 5],
2579 color: 'rgba(0,0,0,0.35)',
2580 zeroLineColor: 'rgba(0,0,0,0.15)',
2581 },
2582 },
2583 y: {
2584 max: maxValue,
2585 grid: {
2586 color: 'rgba(0,0,0,0.05)',
2587 zeroLineColor: 'rgba(0,0,0,0.05)',
2588 },
2589 display: false,
2590 ticks: {
2591 beginAtZero: true,
2592 fontSize: '10',
2593 fontColor: '#000'
2594 }
2595 }
2596
2597 }
2598 }
2599
2600 const plugin = {
2601 id: 'verticalLiner',
2602 afterInit: (chart, args, opts) => {
2603 chart.verticalLiner = {}
2604 },
2605 afterEvent: (chart, args, options) => {
2606 const {inChartArea} = args
2607 chart.verticalLiner = {draw: inChartArea}
2608 },
2609 beforeTooltipDraw: (chart, args, options) => {
2610 const {draw} = chart.verticalLiner
2611 if (!draw) return
2612
2613 const {ctx} = chart
2614 const {top, bottom} = chart.chartArea
2615 const {tooltip} = args
2616 const x = tooltip.caretX
2617 if (!x) return
2618
2619 ctx.save()
2620
2621 ctx.beginPath()
2622 ctx.moveTo(x, top)
2623 ctx.lineTo(x, bottom)
2624 ctx.stroke()
2625
2626 ctx.restore()
2627 }
2628 }
2629
2630 // line chart init
2631 let chartDailyBookings = new Chart($dailyBookingsChart, {
2632 type: 'line',
2633 data: chartDailyBookingsData,
2634 options: options,
2635 plugins: [plugin],
2636 });
2637 }
2638
2639
2640 function latepoint_init_customer_donut_chart() {
2641 if (typeof Chart !== 'undefined' && jQuery('.os-customer-donut-chart').length) {
2642 var fontFamily = latepoint_helper.body_font_family;
2643 // set defaults
2644 Chart.defaults.defaultFontFamily = fontFamily;
2645 Chart.defaults.defaultFontSize = 16;
2646 Chart.defaults.defaultFontStyle = '400';
2647
2648 Chart.defaults.plugins.tooltip.titleFont = {family: fontFamily, size: 14, weight: 400};
2649 Chart.defaults.plugins.tooltip.titleColor = 'rgba(255,255,255,0.6)';
2650 Chart.defaults.plugins.tooltip.backgroundColor = '#000';
2651 Chart.defaults.plugins.tooltip.titleMarginBottom = 1;
2652 Chart.defaults.plugins.tooltip.bodyFont = {family: fontFamily, size: 18, weight: 500};
2653 Chart.defaults.plugins.tooltip.displayColors = false;
2654 Chart.defaults.plugins.tooltip.padding = 5;
2655 Chart.defaults.plugins.tooltip.yAlign = 'bottom';
2656 Chart.defaults.plugins.tooltip.xAlign = 'center';
2657 Chart.defaults.plugins.tooltip.cornerRadius = 4;
2658 Chart.defaults.plugins.tooltip.intersect = false;
2659 jQuery('.os-customer-donut-chart').each(function (index) {
2660 var chart_colors = jQuery(this).data('chart-colors').toString().split(',');
2661 var chart_labels = jQuery(this).data('chart-labels').toString().split(',');
2662 var chart_values = jQuery(this).data('chart-values').toString().split(',').map(Number);
2663 var $chart_canvas = jQuery(this);
2664 var chartDonut = new Chart($chart_canvas, {
2665 type: 'doughnut',
2666 data: {
2667 labels: chart_labels,
2668 datasets: [{
2669 data: chart_values,
2670 backgroundColor: chart_colors,
2671 hoverBackgroundColor: chart_colors,
2672 borderWidth: 0,
2673 hoverBorderColor: 'transparent'
2674 }]
2675 },
2676 options: {
2677 layout: {
2678 padding: {
2679 top: 10,
2680 bottom: 10,
2681 left: 10,
2682 right: 10
2683 }
2684 },
2685 plugins: {
2686 legend: {
2687 display: false
2688 },
2689 tooltip: {
2690 callbacks: {
2691 title: function (tooltipItem) {
2692 return tooltipItem[0].label;
2693 },
2694 label: function (tooltipItem) {
2695 return tooltipItem.parsed;
2696 },
2697 }
2698 },
2699 },
2700 animation: {
2701 animateRotate: false
2702 },
2703 cutout: "90%",
2704 responsive: false,
2705 maintainAspectRatio: true,
2706 }
2707 });
2708 });
2709 }
2710 }
2711
2712 function latepoint_init_donut_charts() {
2713 if (typeof Chart !== 'undefined' && jQuery('.os-donut-chart').length) {
2714 var fontFamily = latepoint_helper.body_font_family;
2715 // set defaults
2716 Chart.defaults.defaultFontFamily = fontFamily;
2717 Chart.defaults.defaultFontSize = 18;
2718 Chart.defaults.defaultFontStyle = '400';
2719
2720 Chart.defaults.plugins.tooltip.titleFont.family = fontFamily;
2721 Chart.defaults.plugins.tooltip.titleFont.size = 14;
2722 Chart.defaults.plugins.tooltip.titleColor = 'rgba(255,255,255,0.6)';
2723 Chart.defaults.plugins.tooltip.backgroundColor = '#000';
2724 Chart.defaults.plugins.tooltip.titleFont.style = '400';
2725 Chart.defaults.plugins.tooltip.titleMarginBottom = 1;
2726 Chart.defaults.plugins.tooltip.bodyFont.family = fontFamily;
2727 Chart.defaults.plugins.tooltip.bodyFont.size = 24;
2728 Chart.defaults.plugins.tooltip.bodyFont.style = '500';
2729 Chart.defaults.plugins.tooltip.displayColors = false;
2730 Chart.defaults.plugins.tooltip.padding.x = 10;
2731 Chart.defaults.plugins.tooltip.padding.y = 8;
2732 Chart.defaults.plugins.tooltip.yAlign = 'bottom';
2733 Chart.defaults.plugins.tooltip.xAlign = 'center';
2734 Chart.defaults.plugins.tooltip.cornerRadius = 8;
2735 Chart.defaults.plugins.tooltip.intersect = false;
2736 jQuery('.os-donut-chart').each(function (index) {
2737 var chart_colors = jQuery(this).data('chart-colors').toString().split(',');
2738 var chart_labels = jQuery(this).data('chart-labels').toString().split(',');
2739 var chart_values = jQuery(this).data('chart-values').toString().split(',').map(Number);
2740 var $chart_canvas = jQuery(this);
2741 var chartDonut = new Chart($chart_canvas, {
2742 type: 'doughnut',
2743 data: {
2744 labels: chart_labels,
2745 datasets: [{
2746 data: chart_values,
2747 backgroundColor: chart_colors,
2748 hoverBackgroundColor: chart_colors,
2749 borderWidth: 0,
2750 hoverBorderColor: 'transparent'
2751 }]
2752 },
2753 options: {
2754 layout: {
2755 padding: {
2756 top: 40
2757 }
2758 },
2759 plugins: {
2760 legend: {
2761 display: false
2762 },
2763 tooltip: {
2764 callbacks: {
2765 title: function (tooltipItem, data) {
2766 return data['labels'][tooltipItem[0]['index']];
2767 },
2768 label: function (tooltipItem, data) {
2769 return data['datasets'][0]['data'][tooltipItem['index']];
2770 }
2771 }
2772 }
2773 },
2774 animation: {
2775 animateScale: true
2776 },
2777 cutoutPercentage: 96,
2778 responsive: false,
2779 maintainAspectRatio: true,
2780 }
2781 });
2782 });
2783 }
2784 }
2785
2786
2787 function latepoint_init_circles_charts() {
2788 jQuery('.circle-chart').each(function (index) {
2789 var chart_elem_id = jQuery(this).prop('id');
2790 var max_value = jQuery(this).data('max-value');
2791 var chart_value = jQuery(this).data('chart-value');
2792 var chart_color = jQuery(this).data('chart-color');
2793 var chart_color_fade = jQuery(this).data('chart-color-fade');
2794 var myCircle = Circles.create({
2795 id: chart_elem_id,
2796 radius: 25,
2797 value: chart_value,
2798 maxValue: max_value,
2799 width: 2,
2800 text: function (value) {
2801 return Math.round(value);
2802 },
2803 colors: [chart_color, chart_color_fade],
2804 duration: 200,
2805 wrpClass: 'circles-wrp',
2806 textClass: 'circles-text',
2807 valueStrokeClass: 'circles-valueStroke',
2808 maxValueStrokeClass: 'circles-maxValueStroke',
2809 styleWrapper: true,
2810 styleText: true
2811 });
2812
2813 });
2814
2815
2816 }
2817
2818
2819 /*
2820 * Copyright (c) 2023 LatePoint LLC. All rights reserved.
2821 */
2822
2823 function latepoint_check_horizontal_calendar_scroll(){
2824 if(jQuery('.daily-availability-calendar.horizontal-calendar').length){
2825 if(jQuery('.daily-availability-calendar.horizontal-calendar').width() < 700){
2826 jQuery('.daily-availability-calendar.horizontal-calendar').scrollLeft(jQuery('.os-day.selected').index() * jQuery('.os-day.selected').width());
2827 }
2828 }
2829 }
2830
2831 function latepoint_calendar_custom_period_created(){
2832 latepoint_reload_calendar_view();
2833 latepoint_lightbox_close();
2834 }
2835
2836 function latepoint_init_calendar_quick_actions(){
2837 latepoint_init_input_masks(jQuery('.quick-calendar-action-settings'));
2838
2839 jQuery('.quick-calendar-action-day-off').on('click', function(){
2840 jQuery('.quick-calendar-actions-wrapper').addClass('showing-settings');
2841 jQuery('.quick-calendar-actions').hide();
2842 jQuery('.quick-calendar-action-settings').removeClass('setting-slot-off').addClass('setting-day-off');
2843 jQuery('.quick-calendar-action-settings input[name="blocked_period_settings[full_day_off]"]').val('yes');
2844 jQuery('.quick-calendar-action-toggle.selected').removeClass('selected');
2845 jQuery('.quick-calendar-action-toggle[data-period-type="full"]').addClass('selected');
2846
2847 return false;
2848 });
2849 jQuery('.quick-calendar-action-slot-off').on('click', function(){
2850 jQuery('.quick-calendar-actions-wrapper').addClass('showing-settings');
2851 jQuery('.quick-calendar-actions').hide();
2852 jQuery('.quick-calendar-action-settings').removeClass('setting-day-off').addClass('setting-slot-off');
2853 jQuery('.quick-calendar-action-settings input[name="blocked_period_settings[full_day_off]"]').val('no');
2854 jQuery('.quick-calendar-action-toggle.selected').removeClass('selected');
2855 jQuery('.quick-calendar-action-toggle[data-period-type="partial"]').addClass('selected');
2856 return false;
2857 });
2858
2859 jQuery('.quick-calendar-action-toggle').on('click', function(){
2860 if(jQuery(this).data('period-type') === 'full'){
2861 jQuery('.quick-calendar-action-day-off').trigger('click');
2862 }else{
2863 jQuery('.quick-calendar-action-slot-off').trigger('click');
2864 }
2865 return false;
2866 });
2867 }
2868
2869 function latepoint_init_calendars(){
2870 latepoint_check_horizontal_calendar_scroll();
2871 jQuery('.os-calendar-settings-extra .latecheckbox').lateCheckbox();
2872
2873
2874
2875 jQuery('.os-calendar-view-toggle').on('click', '.os-calendar-view-option', function(){
2876 jQuery(this).closest('.os-calendar-view-toggle').find('.os-calendar-view-option.os-selected').removeClass('os-selected')
2877 jQuery(this).addClass('os-selected');
2878 jQuery('input[name="' + jQuery(this).closest('.os-calendar-view-toggle').data('update-element-by-name') + '"]').val(jQuery(this).data('value')).trigger('change');
2879 return false;
2880 });
2881
2882 jQuery('.calendar-settings-toggler').on('click', function(){
2883 jQuery('.os-calendar-settings-form').toggleClass('show-extra-settings');
2884 return false;
2885 });
2886
2887 jQuery('.os-calendar-settings-form').on('change', 'input[name="calendar_settings[view]"]', function(){
2888 jQuery(this).closest('.calendar-wrapper').attr('data-view', jQuery(this).val());
2889 });
2890
2891 jQuery('.os-calendar-settings-form').on('change', 'select, input, .latecheckbox ', function(){
2892 latepoint_reload_calendar_view();
2893 });
2894
2895
2896 jQuery('.calendar-view-wrapper').on('click', '.weekly-calendar-agent-selector', function(){
2897 jQuery('.weekly-calendar-agent-selector.selected').removeClass('selected');
2898 jQuery(this).addClass('selected');
2899 jQuery('.os-calendar-settings-form input[name="calendar_settings[selected_agent_id]"]').val(jQuery(this).data('agent-id'));
2900 jQuery('.agent-weekly-calendar.selected').removeClass('selected');
2901 jQuery('.agent-weekly-calendar[data-agent-id="'+jQuery(this).data('agent-id')+'"]').addClass('selected');
2902 return false;
2903 });
2904
2905 jQuery('.calendar-view-wrapper').on('click', '.daily-calendar-action-navigation-btn', function(){
2906 jQuery(this).addClass('os-loading');
2907 jQuery('input[name="calendar_settings[target_date_string]"]').val(jQuery(this).data('target-date')).trigger('change');
2908 return false;
2909 });
2910
2911 jQuery('.calendar-view-wrapper').on('click', '.daily-availability-calendar .os-day', function(){
2912 jQuery('.os-monthly-calendar-days-w .os-day.selected').removeClass('selected');
2913 jQuery(this).addClass('selected');
2914 jQuery('input[name="calendar_settings[target_date_string]"]').val(jQuery(this).data('date')).trigger('change');
2915 return false;
2916 });
2917
2918
2919 jQuery('.os-calendar-today-btn').on('click', function(){
2920 jQuery(this).addClass('os-loading');
2921 jQuery('input[name="calendar_settings[target_date_string]"]').val(jQuery(this).data('target-date')).trigger('change');
2922 return false;
2923 });
2924
2925 jQuery('.os-calendar-prev-btn').on('click', function(){
2926 jQuery(this).addClass('os-loading');
2927 jQuery('input[name="calendar_settings[target_date_string]"]').val(jQuery('input[name="prev_target_date"]').val()).trigger('change');
2928 return false;
2929 });
2930
2931 jQuery('.os-calendar-next-btn').on('click', function(){
2932 jQuery(this).addClass('os-loading');
2933 jQuery('input[name="calendar_settings[target_date_string]"]').val(jQuery('input[name="next_target_date"]').val()).trigger('change');
2934 return false;
2935 });
2936 }
2937
2938 function latepoint_reload_calendar_view(){
2939 let $calendar_wrapper = jQuery('.calendar-view-wrapper');
2940 if(!$calendar_wrapper.length) return;
2941 $calendar_wrapper.addClass('os-loading');
2942
2943 let calendar_settings = new FormData(jQuery('form.os-calendar-settings-form')[0]);
2944
2945 let data = new FormData();
2946 data.append('params', latepoint_formdata_to_url_encoded_string(calendar_settings));
2947 data.append('action', latepoint_helper.route_action);
2948 data.append('route_name', $calendar_wrapper.data('route'));
2949 data.append('return_format', 'json');
2950
2951 jQuery.ajax({
2952 type: "post",
2953 dataType: "json",
2954 processData: false,
2955 contentType: false,
2956 url: latepoint_timestamped_ajaxurl(),
2957 data: data,
2958 success: function (response) {
2959 if (response.status === "success") {
2960 $calendar_wrapper.html(response.message).removeClass('os-loading');
2961 jQuery('.os-calendar-today-btn, .os-calendar-prev-btn, .os-calendar-next-btn').removeClass('os-loading');
2962 jQuery('.os-current-month-label .current-month').text(response.top_date_label);
2963 jQuery('.os-current-month-label .current-year').text(response.top_date_year);
2964 latepoint_check_horizontal_calendar_scroll();
2965 }
2966 }
2967 });
2968
2969 }
2970
2971 /*
2972 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
2973 */
2974
2975 function latepoint_process_updated() {
2976 location.reload();
2977 }
2978
2979 function latepoint_process_action_removed($elem) {
2980 $elem.closest('.os-form-block').remove();
2981 }
2982
2983 function latepoint_replace_process_condition_element($trigger, params, $target, callback = null) {
2984 $trigger.closest('.sub-section-content').addClass('os-loading');
2985 let route_name = $trigger.data('route');
2986 let data = {action: latepoint_helper.route_action, route_name: route_name, params: params, return_format: 'json'}
2987 jQuery.ajax({
2988 type: 'post',
2989 dataType: "json",
2990 url: latepoint_timestamped_ajaxurl(),
2991 data: data,
2992 success: (response) => {
2993 if (response.status === latepoint_helper.response_status.success) {
2994 $target.html(response.message);
2995 latepoint_init_process_conditions_form();
2996 $trigger.closest('.sub-section-content').removeClass('os-loading');
2997 if (typeof callback === 'function') {
2998 callback();
2999 }
3000 } else {
3001 alert("Error!");
3002 }
3003 }
3004 });
3005 }
3006
3007
3008 function latepoint_init_process_forms() {
3009 latepoint_init_process_conditions_form();
3010
3011 jQuery('.os-processes-w').on('latepoint:initProcessActionForm latepoint:initProcessActionTypeSettings', '.process-action-form', async function () {
3012 if (jQuery(this).find('.latepoint-whatsapp-templates-loader').length) {
3013 let $loader = jQuery(this).find('.latepoint-whatsapp-templates-loader');
3014 let $settings = jQuery(this).find('.process-action-settings');
3015 let $holder = jQuery(this).find('.latepoint-whatsapp-templates-holder');
3016 $settings.addClass('os-loading');
3017
3018 let data = {
3019 action: latepoint_helper.route_action,
3020 route_name: $loader.data('route'),
3021 params: {
3022 template_id: $loader.data('selected-template-id'),
3023 action_id: $loader.data('process-action-id'),
3024 process_id: $loader.data('process-id')
3025 },
3026 layout: 'none',
3027 return_format: 'json'
3028 }
3029 try {
3030 let response = await jQuery.ajax({
3031 type: "post",
3032 dataType: "json",
3033 url: latepoint_timestamped_ajaxurl(),
3034 data: data
3035 });
3036 $settings.removeClass('os-loading');
3037 if (response.status === 'success') {
3038 $loader.remove();
3039 $holder.html(response.message);
3040 } else {
3041 throw new Error(response.message);
3042 }
3043 } catch (e) {
3044 $settings.removeClass('os-loading');
3045 console.log(e);
3046 alert(e);
3047 }
3048 }
3049 });
3050
3051 jQuery('.os-processes-w').on('click', '.os-run-process', function () {
3052 let $btn = jQuery(this);
3053 $btn.addClass('os-loading');
3054 let $process_form = $btn.closest('.os-process-form');
3055 // remove previously assigned class on other forms
3056 jQuery('.os-process-form.prepared-to-run').removeClass('prepared-to-run');
3057 // add class so we know which form is about to be processed
3058 $process_form.addClass('prepared-to-run');
3059
3060
3061 let form_data = new FormData($process_form[0]);
3062 form_data.set('process_event_type', $process_form.closest('.os-process-form').find('.process-event-type-selector').val());
3063
3064
3065 let data = new FormData();
3066 data.append('params', latepoint_formdata_to_url_encoded_string(form_data));
3067 data.append('action', latepoint_helper.route_action);
3068 data.append('route_name', $btn.data('route'));
3069 data.append('return_format', 'json');
3070
3071 jQuery.ajax({
3072 type: "post",
3073 dataType: "json",
3074 processData: false,
3075 contentType: false,
3076 url: latepoint_timestamped_ajaxurl(),
3077 data: data,
3078 success: function (data) {
3079 latepoint_show_data_in_side_panel(data.message, 'width-600');
3080 latepoint_init_process_test_form();
3081 $btn.removeClass('os-loading');
3082 }
3083 });
3084 return false;
3085 });
3086
3087 jQuery('.os-processes-w').find('.process-action-form').each(function (index) {
3088 latepoint_init_process_action_form(jQuery(this));
3089 });
3090
3091 jQuery('.os-processes-w').on('click', '.pe-remove-condition', (event) => {
3092 if (jQuery(event.currentTarget).closest('.pe-conditions').find('.pe-condition').length > 1) {
3093 jQuery(event.currentTarget).closest('.pe-condition').remove();
3094 } else {
3095 alert('You need to have at least one condition if your custom field is set to be conditional.')
3096 }
3097 return false;
3098 });
3099
3100
3101 jQuery('.os-processes-w').on('change', 'select.process-condition-operator-selector', (event) => {
3102 let $select = jQuery(event.currentTarget);
3103 if ($select.val() == 'changed' || $select.val() == 'not_changed') {
3104 $select.closest('.pe-condition').find('.process-condition-values-w').hide();
3105 } else {
3106 $select.closest('.pe-condition').find('.process-condition-values-w').show();
3107 }
3108 });
3109
3110 jQuery('.os-processes-w').on('change', 'select.process-event-type-selector', (event) => {
3111 let $select = jQuery(event.currentTarget);
3112 latepoint_replace_process_condition_element($select, {event_type: $select.val()}, $select.closest('.os-form-block').find('.process-event-condition-wrapper'));
3113 });
3114
3115 jQuery('.os-processes-w').on('change', 'select.process-condition-object-selector', (event) => {
3116 let $select = jQuery(event.currentTarget);
3117 let $property_selector = $select.closest('.pe-condition').find('.process-condition-properties-w select');
3118 latepoint_replace_process_condition_element($select, {object_code: $select.val()}, $property_selector, () => {
3119 $property_selector.trigger('change');
3120 });
3121 });
3122
3123 jQuery('.os-processes-w').on('change', 'select.process-condition-property-selector', (event) => {
3124 let $select = jQuery(event.currentTarget);
3125 let $operator_selector = $select.closest('.pe-condition').find('.process-condition-operators-w select');
3126 latepoint_replace_process_condition_element($select, {property: $select.val()}, $operator_selector, () => {
3127 $operator_selector.trigger('change');
3128 });
3129 });
3130
3131 jQuery('.os-processes-w').on('change', 'select.process-condition-operator-selector', (event) => {
3132 let $select = jQuery(event.currentTarget);
3133 latepoint_replace_process_condition_element($select, {
3134 property: $select.closest('.pe-condition').find('select.process-condition-property-selector').val(),
3135 trigger_condition_id: $select.closest('.pe-condition').data('condition-id'),
3136 operator: $select.val()
3137 }, $select.closest('.pe-condition').find('.process-condition-values-w'));
3138 });
3139
3140 }
3141
3142 function latepoint_init_process_conditions_form() {
3143 jQuery('.os-late-select').lateSelect();
3144 }
3145
3146 function latepoint_add_process_condition($btn, response) {
3147 $btn.closest('.pe-condition').after(response.message);
3148 latepoint_init_process_conditions_form();
3149 }
3150
3151 function latepoint_init_added_process_action_form($trigger) {
3152 let $action_form = $trigger.prev('.process-action-form');
3153 $action_form.addClass('is-editing').trigger('latepoint:initProcessActionForm');
3154 latepoint_init_process_action_form($action_form);
3155 }
3156
3157 function latepoint_init_process_test_form() {
3158
3159 jQuery('.latepoint-run-process-btn').on('click', function () {
3160 let $btn = jQuery(this);
3161 if ($btn.hasClass('os-loading')) return false;
3162 $btn.addClass('os-loading');
3163 let $test_action_form = jQuery('.latepoint-side-panel-w .action-settings-wrapper');
3164
3165
3166 let form_data = new FormData(jQuery('.os-process-form.prepared-to-run')[0]);
3167
3168 // set data sources
3169 jQuery('.process-test-data-source-selector').each(function () {
3170 form_data.set(jQuery(this).prop('name'), jQuery(this).val());
3171 });
3172
3173 // set selected actions
3174 jQuery('.process-test-data-source-selector').each(function () {
3175 form_data.set(jQuery(this).prop('name'), jQuery(this).val());
3176 });
3177
3178 let action_ids_to_run = [];
3179 jQuery('.action-to-run input[type="hidden"]').each(function () {
3180 if (jQuery(this).val() == 'on') action_ids_to_run.push(jQuery(this).closest('.action-to-run').data('id'));
3181 });
3182 form_data.set('action_ids', action_ids_to_run.join(','));
3183
3184
3185 let data = new FormData();
3186 data.append('params', latepoint_formdata_to_url_encoded_string(form_data));
3187 data.append('action', latepoint_helper.route_action);
3188 data.append('route_name', $btn.data('route'));
3189 data.append('return_format', 'json');
3190
3191 jQuery.ajax({
3192 type: "post",
3193 dataType: "json",
3194 processData: false,
3195 contentType: false,
3196 url: latepoint_timestamped_ajaxurl(),
3197 data: data,
3198 success: function (data) {
3199 $btn.removeClass('os-loading');
3200 if (data.status == 'success') {
3201 latepoint_add_notification(data.message);
3202 } else {
3203 latepoint_add_notification(data.message, 'error');
3204 }
3205 }
3206 });
3207 });
3208
3209 jQuery('.process-action-test-data-source-selector').on('change', function () {
3210 // TODO add call to server to check if selected data sources matches conditions of this process
3211 });
3212 }
3213
3214
3215 function latepoint_init_process_action_test_form() {
3216
3217 latepoint_init_json_view(jQuery('.action-preview-wrapper.type-trigger_webhook pre'));
3218
3219 jQuery('.latepoint-run-action-btn').on('click', function () {
3220 let $btn = jQuery(this);
3221 if ($btn.hasClass('os-loading')) return false;
3222 $btn.addClass('os-loading');
3223 let $test_action_form = jQuery('.latepoint-side-panel-w .action-settings-wrapper');
3224
3225 let action_data = new FormData();
3226
3227
3228 action_data.append('params', $test_action_form.find('select, textarea, input').serialize());
3229 action_data.append('action', latepoint_helper.route_action);
3230 action_data.append('route_name', $btn.data('route'));
3231 action_data.append('return_format', 'json');
3232
3233 jQuery.ajax({
3234 type: "post",
3235 dataType: "json",
3236 processData: false,
3237 contentType: false,
3238 url: latepoint_timestamped_ajaxurl(),
3239 data: action_data,
3240 success: function (data) {
3241 $btn.removeClass('os-loading');
3242 if (data.status == 'success') {
3243 latepoint_add_notification(data.message);
3244 } else {
3245 latepoint_add_notification(data.message, 'error');
3246 }
3247 }
3248 });
3249 });
3250
3251 jQuery('.process-action-test-data-source-selector').on('change', function () {
3252 let $select = jQuery(this);
3253 jQuery('.action-preview-wrapper').addClass('os-loading');
3254 let $test_action_form = $select.closest('.action-settings-wrapper');
3255
3256 let action_data = new FormData();
3257
3258
3259 action_data.append('params', $test_action_form.find('select, textarea, input').serialize());
3260 action_data.append('action', latepoint_helper.route_action);
3261 action_data.append('route_name', $select.data('route'));
3262 action_data.append('return_format', 'json');
3263
3264 jQuery.ajax({
3265 type: "post",
3266 dataType: "json",
3267 processData: false,
3268 contentType: false,
3269 url: latepoint_timestamped_ajaxurl(),
3270 data: action_data,
3271 success: function (data) {
3272 jQuery('.action-preview-wrapper').html(data.message).removeClass('os-loading');
3273 latepoint_init_json_view(jQuery('.action-preview-wrapper.type-trigger_webhook pre'));
3274 }
3275 });
3276 });
3277 }
3278
3279 function latepoint_init_process_action_form($action_form) {
3280 $action_form.on('click', '.os-run-process-action', function () {
3281 let $btn = jQuery(this);
3282 $btn.addClass('os-loading');
3283 let $action_form = $btn.closest('.process-action-form');
3284
3285 if (window.tinyMCE !== undefined) window.tinyMCE.triggerSave();
3286
3287 let action_data = new FormData();
3288 let params = latepoint_create_form_data_from_non_form_element($action_form);
3289
3290 params.set('process_event_type', $action_form.closest('.os-process-form').find('.process-event-type-selector').val());
3291
3292 action_data.append('params', latepoint_formdata_to_url_encoded_string(params));
3293 action_data.append('action', latepoint_helper.route_action);
3294 action_data.append('route_name', $btn.data('route'));
3295 action_data.append('return_format', 'json');
3296
3297 jQuery.ajax({
3298 type: "post",
3299 dataType: "json",
3300 processData: false,
3301 contentType: false,
3302 url: latepoint_timestamped_ajaxurl(),
3303 data: action_data,
3304 success: function (data) {
3305 latepoint_show_data_in_side_panel(data.message, 'width-800');
3306 latepoint_init_process_action_test_form();
3307 $btn.removeClass('os-loading');
3308 }
3309 });
3310 return false;
3311 });
3312 $action_form.on('click', '.process-action-heading', function () {
3313 let $action_form = jQuery(this).closest('.process-action-form');
3314 if (!$action_form.hasClass('is-editing')) $action_form.trigger('latepoint:initProcessActionForm')
3315 $action_form.toggleClass('is-editing');
3316 return false;
3317 });
3318
3319 $action_form.find('textarea.os-wp-editor-textarea').each(function (index) {
3320 latepoint_init_tiny_mce(jQuery(this).attr('id'));
3321 });
3322 $action_form.on('click', '.os-remove-process-action', function () {
3323 if (confirm(jQuery(this).data('os-prompt'))) {
3324 jQuery(this).closest('.process-action-form').remove();
3325 }
3326 return false;
3327 });
3328
3329 $action_form.on('change', '.process-action-type-whatsapp-template-selector', async function () {
3330 let $select = jQuery(this);
3331 let $preview_holder = $select.closest('.process-action-settings').find('.latepoint-whatsapp-template-preview-holder');
3332 $preview_holder.addClass('os-loading');
3333
3334 let data = {
3335 action: latepoint_helper.route_action,
3336 route_name: $select.data('route'),
3337 params: {
3338 template_id: $select.val(),
3339 action_id: $select.data('action-id')
3340 },
3341 layout: 'none',
3342 return_format: 'json'
3343 }
3344 try {
3345 let response = await jQuery.ajax({
3346 type: "post",
3347 dataType: "json",
3348 url: latepoint_timestamped_ajaxurl(),
3349 data: data
3350 });
3351 $preview_holder.removeClass('os-loading');
3352 if (response.status === 'success') {
3353 $preview_holder.html(response.message);
3354 } else {
3355 throw new Error(response.message);
3356 }
3357 } catch (e) {
3358 $preview_holder.removeClass('os-loading');
3359 console.log(e);
3360 alert(e);
3361 }
3362 return false;
3363 });
3364
3365 $action_form.on('change', '.process-action-type', function () {
3366 let $select = jQuery(this);
3367 jQuery(this).closest('.process-action-form').find('.process-action-name').text($select.find('option:selected').text());
3368 let action_type = $select.val();
3369 let action_id = $select.data('action-id');
3370 let route_name = $select.data('route');
3371 let $action_settings = $select.closest('.process-action-content').find('.process-action-settings');
3372 $action_settings.addClass('os-loading');
3373 let data = {
3374 action: latepoint_helper.route_action,
3375 route_name: route_name,
3376 params: {
3377 action_type: action_type,
3378 action_id: action_id
3379 },
3380 layout: 'none',
3381 return_format: 'json'
3382 }
3383 jQuery.ajax({
3384 type: "post",
3385 dataType: "json",
3386 url: latepoint_timestamped_ajaxurl(),
3387 data: data,
3388 success: function (data) {
3389 $action_settings.html(data.message).removeClass('os-loading');
3390 let $action_form = $select.closest('.process-action-form');
3391 latepoint_init_input_masks($action_form);
3392 $action_form.trigger('latepoint:initProcessActionTypeSettings');
3393 }
3394 });
3395 return false;
3396 });
3397 }
3398
3399 /*
3400 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
3401 */
3402
3403
3404 function latepoint_preview_init_step_category_items(step_code){
3405 jQuery('.booking-form-preview .os-item-category-info').on('click', function(){
3406 var $booking_form_element = jQuery(this).closest('.booking-form-preview');
3407 jQuery(this).closest('.latepoint-step-content').addClass('selecting-item-category');
3408 var $category_wrapper = jQuery(this).closest('.os-item-category-w');
3409 var $main_parent = jQuery(this).closest('.os-item-categories-main-parent');
3410 if($category_wrapper.hasClass('selected')){
3411 $category_wrapper.removeClass('selected');
3412 if($category_wrapper.parent().closest('.os-item-category-w').length){
3413 $category_wrapper.parent().closest('.os-item-category-w').addClass('selected');
3414 }else{
3415 $main_parent.removeClass('show-selected-only');
3416 }
3417 }else{
3418 $main_parent.find('.os-item-category-w.selected').removeClass('selected');
3419 $main_parent.addClass('show-selected-only');
3420 $category_wrapper.addClass('selected');
3421 }
3422 return false;
3423 });
3424 }
3425
3426 function latepoint_booking_form_discard_changes(){
3427
3428 let form_data = new FormData(jQuery('.booking-form-preview-settings')[0]);
3429
3430 var data = {
3431 action: latepoint_helper.route_action,
3432 route_name: jQuery('.booking-form-preview-settings').data('route-name'),
3433 params: latepoint_formdata_to_url_encoded_string(form_data),
3434 layout: 'none',
3435 return_format: 'json'
3436 }
3437
3438 jQuery.ajax({
3439 type : "post",
3440 dataType : "json",
3441 url : latepoint_timestamped_ajaxurl(),
3442 data : data,
3443 success: function(data){
3444 if(data.status === "success"){
3445 jQuery('.booking-form-preview-inner').html(data.booking_form_html);
3446 latepoint_init_booking_form_preview();
3447 }else{
3448 latepoint_add_notification(data.message, 'error');
3449 }
3450 }
3451 });
3452 }
3453
3454 function latepoint_booking_form_save_changes(){
3455
3456 let form_data = new FormData(jQuery('.booking-form-preview-settings')[0]);
3457
3458 jQuery('.editable-setting').each(function(){
3459 form_data.set('steps_settings' + jQuery(this).data('setting-key'), jQuery(this).html());
3460 });
3461
3462
3463 form_data.set('steps_settings' + jQuery('.bf-side-media-picker-trigger').find('.os-image-id-holder').prop('name'), jQuery('.bf-side-media-picker-trigger').find('.os-image-id-holder').val());
3464
3465
3466 var data = {
3467 action: latepoint_helper.route_action,
3468 route_name: jQuery('.booking-form-preview-settings').data('route-name'),
3469 params: latepoint_formdata_to_url_encoded_string(form_data),
3470 layout: 'none',
3471 return_format: 'json'
3472 }
3473
3474 jQuery.ajax({
3475 type : "post",
3476 dataType : "json",
3477 url : latepoint_timestamped_ajaxurl(),
3478 data : data,
3479 success: function(data){
3480 jQuery('.booking-form-preview-settings').removeClass('os-loading');
3481 if(data.status === "success"){
3482 jQuery('.bf-preview-step-settings').html(data.step_settings_html);
3483 jQuery('.booking-form-preview-inner').html(data.booking_form_html);
3484 jQuery('#latepoint-main-admin-inline-css').html(data.css_variables);
3485 latepoint_init_booking_form_preview();
3486 }else{
3487 latepoint_add_notification(data.message, 'error');
3488 }
3489 }
3490 });
3491 }
3492
3493 function latepoint_init_booking_form_preview(){
3494
3495 latepoint_preview_init_step_category_items();
3496 latepoint_booking_form_preview_init_datepicker();
3497
3498
3499 jQuery('.booking-form-preview-wrapper').on('click', '.os-step-tab', function(){
3500 let $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
3501 jQuery(this).closest('.os-step-tabs').find('.os-step-tab').removeClass('active');
3502 jQuery(this).addClass('active');
3503 var target = jQuery(this).data('target');
3504 jQuery(this).closest('.os-step-tabs-w').find('.os-step-tab-content').hide();
3505 jQuery(target).show();
3506 if(jQuery(this).data('auth-action')){
3507 $booking_form_element.find('input[name="auth[action]"]').val(jQuery(this).data('auth-action'));
3508 }
3509 });
3510
3511
3512 jQuery('.bf-save-btn').on('click', function(){
3513 jQuery(this).addClass('os-loading');
3514 latepoint_booking_form_save_changes();
3515 return false;
3516 });
3517
3518 jQuery('.bf-cancel-save-btn').on('click', function(){
3519 jQuery(this).addClass('os-loading');
3520 latepoint_booking_form_discard_changes();
3521 return false;
3522 });
3523
3524
3525 jQuery('.booking-form-preview .bf-next-btn').on('click', function(){
3526 jQuery(this).addClass('os-loading');
3527 jQuery("#selected_step_code > option:selected")
3528 .prop("selected", false)
3529 .next()
3530 .prop("selected", true).trigger('change');
3531 });
3532
3533 jQuery('.booking-form-preview .bf-prev-btn').on('click', function(){
3534 jQuery(this).addClass('os-loading');
3535 jQuery("#selected_step_code > option:selected")
3536 .prop("selected", false)
3537 .prev()
3538 .prop("selected", true).trigger('change');
3539 });
3540
3541
3542 jQuery('.booking-form-preview .os-image-selector-trigger').on('click', function(){
3543 jQuery('.booking-form-preview').addClass('has-changes');
3544 });
3545
3546 jQuery('.booking-form-preview .editable-setting').on('focus', function(){
3547 jQuery('.booking-form-preview').addClass('has-changes');
3548 });
3549
3550
3551 let editor = new MediumEditor('.booking-form-preview .os-editable', {toolbar: {
3552 buttons: [
3553 {
3554 name: 'bold',
3555 classList: ['latepoint-icon', 'latepoint-icon-format_bold'],
3556 },
3557 {
3558 name: 'anchor',
3559 classList: ['latepoint-icon', 'latepoint-icon-format_link'],
3560 },
3561 {
3562 name: 'h3',
3563 classList: ['latepoint-icon', 'latepoint-icon-format_h3'],
3564 },
3565 {
3566 name: 'h4',
3567 classList: ['latepoint-icon', 'latepoint-icon-format_h4'],
3568 },
3569 {
3570 name: 'h5',
3571 classList: ['latepoint-icon', 'latepoint-icon-format_h5'],
3572 },
3573
3574 ]
3575 }
3576 });
3577 let editor_basic = new MediumEditor('.booking-form-preview .os-editable-basic', {toolbar: {
3578 buttons: [
3579 {
3580 name: 'bold',
3581 classList: ['latepoint-icon', 'latepoint-icon-format_bold'],
3582 },
3583 {
3584 name: 'italic',
3585 classList: ['latepoint-icon', 'latepoint-icon-format_italic'],
3586 },
3587 {
3588 name: 'underline',
3589 classList: ['latepoint-icon', 'latepoint-icon-format_underlined'],
3590 },
3591 {
3592 name: 'anchor',
3593 classList: ['latepoint-icon', 'latepoint-icon-format_link'],
3594 },
3595
3596 ]
3597 }
3598 });
3599 }
3600
3601 function latepoint_reload_booking_form_preview(){
3602 latepoint_booking_form_save_changes();
3603 }
3604
3605 function latepoint_init_steps_settings(){
3606
3607 jQuery('.booking-form-preview-settings').on('change', ' select, input[type="hidden"]', function(){
3608 jQuery('.booking-form-preview-settings').addClass('os-loading');
3609 latepoint_reload_booking_form_preview();
3610 });
3611
3612 jQuery('.trigger-custom-color-save').on('click', function(){
3613 jQuery('.booking-form-preview-settings').addClass('os-loading');
3614 latepoint_booking_form_save_changes();
3615 return false;
3616 });
3617
3618 jQuery('.bf-color-scheme-color-trigger').on('click', function(){
3619 jQuery('.bf-color-scheme-color-trigger.is-selected').removeClass('is-selected');
3620 jQuery(this).addClass('is-selected');
3621 let color_scheme = jQuery(this).data('color-code');
3622 jQuery('.os-color-scheme-selector-wrapper select').val(color_scheme).trigger('change');
3623 if(color_scheme == 'custom'){
3624 jQuery('.os-custom-color-selector-wrapper').removeClass('is-hidden');
3625 }else{
3626 jQuery('.os-custom-color-selector-wrapper').addClass('is-hidden');
3627 }
3628 return false;
3629 });
3630
3631 jQuery('.os-section-collapsible-trigger').on('click', function(){
3632 jQuery(this).closest('.os-section-collapsible-wrapper').toggleClass('is-open');
3633 return false;
3634 })
3635 }
3636
3637
3638 function latepoint_booking_form_preview_init_timeslots($booking_form_element = false){
3639 if(!$booking_form_element) return;
3640 $booking_form_element.on('click', '.dp-timepicker-trigger', function(){
3641 if(jQuery(this).hasClass('is-booked') || jQuery(this).hasClass('is-off')){
3642 // Show error message that you cant select a booked period
3643 }else{
3644 if(jQuery(this).hasClass('selected')){
3645 jQuery(this).removeClass('selected');
3646 jQuery(this).find('.dp-success-label').remove();
3647 }else{
3648 $booking_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove();
3649 var selected_timeslot_time = jQuery(this).find('.dp-label-time').html();
3650 jQuery(this).addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>');
3651
3652 var minutes = parseInt(jQuery(this).data('minutes'));
3653 var start_date = new Date($booking_form_element.find('.os-day.selected').data('date'));
3654 $booking_form_element.find('.latepoint_start_date').val(start_date.toISOString().split('T')[0])
3655 latepoint_trigger_next_btn($booking_form_element);
3656 }
3657 }
3658 return false;
3659 });
3660 }
3661
3662
3663 function latepoint_booking_form_preview_day_timeslots($day){
3664 let $wrapper_element = jQuery('.booking-form-preview');
3665 $day.addClass('selected');
3666
3667 var service_duration = $day.data('service-duration');
3668 var interval = $day.data('interval');
3669 var work_start_minutes = $day.data('work-start-time');
3670 var work_end_minutes = $day.data('work-end-time');
3671 var total_work_minutes = $day.data('total-work-minutes');
3672 var bookable_minutes = [];
3673 var available_capacities_of_bookable_minute = [];
3674 if($day.attr('data-bookable-minutes')){
3675 if($day.data('bookable-minutes').toString().indexOf(':') > -1){
3676 // has capacity information embedded into bookable minutes string
3677 let bookable_minutes_with_capacity = $day.data('bookable-minutes').toString().split(',');
3678 for(let i = 0; i < bookable_minutes_with_capacity.length; i++){
3679 bookable_minutes.push(parseInt(bookable_minutes_with_capacity[i].split(':')[0]));
3680 available_capacities_of_bookable_minute.push(parseInt(bookable_minutes_with_capacity[i].split(':')[1]));
3681 }
3682 }else{
3683 bookable_minutes = $day.data('bookable-minutes').toString().split(',').map(Number);
3684 }
3685 }
3686 var work_minutes = $day.data('work-minutes').toString().split(',').map(Number);
3687
3688 var $timeslots = $wrapper_element.find('.timeslots');
3689 $timeslots.html('');
3690
3691 if(total_work_minutes > 0 && bookable_minutes.length && work_minutes.length){
3692 var prev_minutes = false;
3693 work_minutes.forEach(function(current_minutes){
3694 var ampm = latepoint_am_or_pm(current_minutes);
3695
3696 var timeslot_class = 'dp-timepicker-trigger';
3697 var timeslot_available_capacity = 0;
3698 if($wrapper_element.find('.os-dates-w').data('time-pick-style') == 'timeline'){
3699 timeslot_class+= ' dp-timeslot';
3700 }else{
3701 timeslot_class+= ' dp-timebox';
3702 }
3703
3704 if(prev_minutes !== false && ((current_minutes - prev_minutes) > service_duration)){
3705 // show interval that is off between two work periods
3706 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);
3707 var off_width = (((current_minutes - prev_minutes - service_duration) / total_work_minutes) * 100);
3708 $timeslots.append('<div class="'+ timeslot_class +' is-off" style="max-width:'+ off_width +'%; width:'+ off_width +'%"><span class="dp-label">' + off_label + '</span></div>');
3709 }
3710
3711 if(!bookable_minutes.includes(current_minutes)){
3712 timeslot_class+= ' is-booked';
3713 }else{
3714 if(available_capacities_of_bookable_minute.length) timeslot_available_capacity = available_capacities_of_bookable_minute[bookable_minutes.indexOf(current_minutes)];
3715 }
3716 var tick_html = '';
3717 var capacity_label = '';
3718 var capacity_label_html = '';
3719 var capacity_internal_label_html = '';
3720
3721 if(((current_minutes % 60) == 0) || (interval >= 60)){
3722 timeslot_class+= ' with-tick';
3723 tick_html = '<span class="dp-tick"><strong>'+latepoint_minutes_to_hours_preferably(current_minutes)+'</strong>'+' '+ampm+'</span>';
3724 }
3725 var timeslot_label = latepoint_minutes_to_hours_and_minutes(current_minutes)+' '+ampm;
3726 if(latepoint_show_booking_end_time()){
3727 var end_minutes = current_minutes + service_duration;
3728 if(end_minutes > 1440) end_minutes = end_minutes - 1440;
3729 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
3730 timeslot_label+= ' - <span class="dp-label-end-time">' + latepoint_minutes_to_hours_and_minutes(end_minutes)+' '+end_minutes_ampm + '</span>';
3731 }
3732 if(timeslot_available_capacity){
3733 var spaces_message = timeslot_available_capacity > 1 ? latepoint_helper.many_spaces_message : latepoint_helper.single_space_message;
3734 capacity_label = timeslot_available_capacity + ' ' + spaces_message;
3735 capacity_label_html = '<span class="dp-capacity">' + capacity_label + '</span>';
3736 capacity_internal_label_html = '<span class="dp-label-capacity">' + capacity_label + '</span>';
3737 }
3738 timeslot_label = timeslot_label.trim();
3739 $timeslots.removeClass('slots-not-available').append('<div 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>');
3740 prev_minutes = current_minutes;
3741 });
3742 }else{
3743 // No working hours this day
3744 $timeslots.addClass('slots-not-available').append('<div class="not-working-message">' + latepoint_helper.msg_not_available + "</div>");
3745 }
3746 jQuery('.times-header-label span').text($day.data('nice-date'));
3747 $wrapper_element.find('.time-selector-w').slideDown(200);
3748 }
3749
3750 function latepoint_booking_form_preview_init_monthly_calendar_navigation($booking_form_element){
3751
3752 if(!$booking_form_element) return;
3753 $booking_form_element.on('click', '.os-month-next-btn', function(){
3754 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
3755 var next_month_route_name = jQuery(this).data('route');
3756 if($booking_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length){
3757 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
3758 latepoint_booking_form_preview_calendar_set_month_label($booking_form_element);
3759 }else{
3760 alert('Disabled in preview');
3761 }
3762 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
3763 return false;
3764 });
3765 $booking_form_element.on('click', '.os-month-prev-btn', function(){
3766 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
3767 if($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length){
3768 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active');
3769 latepoint_booking_form_preview_calendar_set_month_label($booking_form_element);
3770 }
3771 return false;
3772 });
3773 }
3774
3775
3776 function latepoint_booking_form_preview_calendar_set_month_label(){
3777 jQuery('.os-current-month-label .current-month').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-month-label'));
3778 jQuery('.os-current-month-label .current-year').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-year'));
3779 }
3780
3781
3782
3783 function latepoint_booking_form_preview_init_datepicker(){
3784 let $booking_form_element = jQuery('.latepoint-booking-form-element');
3785 latepoint_booking_form_preview_init_timeslots($booking_form_element);
3786 latepoint_booking_form_preview_init_monthly_calendar_navigation($booking_form_element);
3787 $booking_form_element.on('click', '.os-months .os-day', function(){
3788 if(jQuery(this).hasClass('os-day-passed')) return false;
3789 if(jQuery(this).hasClass('os-not-in-allowed-period')) return false;
3790 if(jQuery(this).hasClass('os-month-prev')) return false;
3791 if(jQuery(this).hasClass('os-month-next')) return false;
3792 if(jQuery(this).closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')){
3793
3794 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT
3795 if(jQuery(this).hasClass('os-not-available')){
3796 // clicked on a day that has no available timeslots
3797 // do nothing
3798 }else{
3799 $booking_form_element.find('.os-day.selected').removeClass('selected');
3800 jQuery(this).addClass('selected');
3801 // set date
3802 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date'));
3803 if(jQuery(this).hasClass('os-one-slot-only')){
3804 // clicked on a day that has only one slot available
3805 var bookable_minutes = jQuery(this).data('bookable-minutes').toString().split(':')[0];
3806 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number(jQuery(this).data('service-duration')));
3807 $booking_form_element.find('.time-selector-w').slideUp(200);
3808 }else{
3809 // regular day with more than 1 timeslots available
3810 // build timeslots
3811 latepoint_booking_form_preview_day_timeslots(jQuery(this));
3812 // clear time and hide next btn
3813 }
3814 }
3815 }else{
3816 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT
3817 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date'));
3818 $booking_form_element.find('.os-day.selected').removeClass('selected');
3819 jQuery(this).addClass('selected');
3820
3821 // build timeslots
3822 latepoint_booking_form_preview_day_timeslots(jQuery(this));
3823 // clear time and hide next btn
3824 }
3825
3826
3827 return false;
3828 });
3829 }
3830
3831
3832
3833 /*
3834 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
3835 */
3836
3837 function latepoint_submit_quick_order_form(){
3838 let $quick_edit_form = jQuery('form.order-quick-edit-form');
3839
3840 let errors = latepoint_validate_form($quick_edit_form);
3841 if(errors.length){
3842 let error_messages = errors.map(error => error.message ).join(', ');
3843 latepoint_add_notification(error_messages, 'error');
3844 return false;
3845 }
3846
3847 $quick_edit_form.find('button[type="submit"]').addClass('os-loading');
3848 jQuery.ajax({
3849 type: "post",
3850 dataType: "json",
3851 processData: false,
3852 contentType: false,
3853 url: latepoint_timestamped_ajaxurl(),
3854 data: latepoint_create_form_data($quick_edit_form),
3855 success: function (response) {
3856 if(response.fields_to_update){
3857 for (const [key, value] of Object.entries(response.fields_to_update)) {
3858 $quick_edit_form.find('input[name="' + key + '"]').val(value)
3859 }
3860 }
3861 $quick_edit_form.find('button[type="submit"]').removeClass('os-loading');
3862 if(response.form_values_to_update){
3863 jQuery.each(response.form_values_to_update, function(name, value){
3864 $quick_edit_form.find('[name="'+ name +'"]').val(value);
3865 });
3866 }
3867 if (response.status === "success") {
3868 latepoint_add_notification(response.message);
3869 latepoint_reload_after_order_save();
3870 }else{
3871 latepoint_add_notification(response.message, 'error');
3872 }
3873 }
3874 });
3875
3876 }
3877
3878 function latepoint_apply_agent_selector_change(){
3879 if(jQuery('.quick-availability-per-day-w').length){
3880
3881 let booking_form_id = jQuery('.quick-availability-per-day-w').data('trigger-form-booking-id');
3882 let $trigger_btn = jQuery('.order-item-booking-data-form-wrapper[data-booking-id="' + booking_form_id + '"]').find('.trigger-quick-availability');
3883
3884 latepoint_load_quick_availability($trigger_btn);
3885 }
3886 }
3887
3888 function latepoint_apply_service_selector_change($form){
3889 let field_base_name = 'order_items[' + $form.data('order-item-id') +'][bookings][' + $form.data('booking-id') +']';
3890
3891 var $selected_service = $form.find('.os-services-select-field-w .service-option-selected');
3892 var service_id = $selected_service.data('id');
3893 var buffer_before = $selected_service.data('buffer-before');
3894 var buffer_after = $selected_service.data('buffer-after');
3895 var default_duration = $selected_service.data('duration');
3896 var default_duration_name = $selected_service.data('duration-name');
3897 var min_capacity = $selected_service.data('capacity-min');
3898 var max_capacity = $selected_service.data('capacity-max');
3899
3900 var extra_durations = $selected_service.data('extra-durations');
3901
3902 $form.find('input[name="'+field_base_name+'[buffer_before]"]').val(buffer_before).trigger('change').closest('.os-form-group').addClass('has-value');
3903 $form.find('input[name="'+field_base_name+'[buffer_after]"]').val(buffer_after).trigger('change').closest('.os-form-group').addClass('has-value');
3904 $form.find('input[name="'+field_base_name+'[service_id]"]').val(service_id).trigger('change').closest('.os-form-group').addClass('has-value');
3905
3906 var duration_name = default_duration_name ? default_duration_name : (default_duration + ' ' + latepoint_helper.string_minutes);
3907 var options = '<option value="'+ default_duration +'">' + duration_name + '</option>';
3908 if(extra_durations.length){
3909 jQuery.each(extra_durations, function(index, value){
3910 var duration_name = value.name ? value.name : value.duration + ' ' + latepoint_helper.string_minutes;
3911 options+= '<option value="'+ value.duration +'">' + duration_name + '</option>';
3912 });
3913 $form.find('.os-service-durations').show();
3914 }else{
3915 $form.find('.os-service-durations').hide();
3916 }
3917
3918 $form.find('.booking-total-attendees-selector-w .capacity-info strong').text(max_capacity);
3919 var attendees_options_html = '';
3920 for(var i=1;i<=max_capacity;i++){
3921 attendees_options_html+= '<option value="' + i + '">' + i + '</option>';
3922 }
3923 var selected_attendees = Math.min(jQuery('.booking-total-attendees-selector-w select').val(), max_capacity);
3924 $form.find('.booking-total-attendees-selector-w select').html(attendees_options_html).val(selected_attendees);
3925 if(max_capacity > 1){
3926 $form.find('.booking-total-attendees-selector-w').show();
3927 }else{
3928 $form.find('.booking-total-attendees-selector-w').hide();
3929 }
3930
3931 $form.find('.os-service-durations select').html(options);
3932
3933 latepoint_set_booking_end_time($form);
3934 if(jQuery('.quick-availability-per-day-w').length){
3935 latepoint_load_quick_availability($form.find('.trigger-quick-availability'));
3936 }
3937
3938 latepoint_init_input_masks($form);
3939 }
3940
3941 function latepoint_reload_balance_and_payments(){
3942 let $wrapper = jQuery('.balance-payment-info');
3943 $wrapper.closest('.balance-payment-wrapper').addClass('os-loading');
3944 let route_name = $wrapper.data('route');
3945 let $quick_edit_form = $wrapper.closest('form.order-quick-edit-form');
3946 let form_data = new FormData($quick_edit_form[0]);
3947
3948 let data = { action: latepoint_helper.route_action, route_name: route_name, params: latepoint_formdata_to_url_encoded_string(form_data), return_format: 'json' }
3949 jQuery.ajax({
3950 type : "post",
3951 dataType : "json",
3952 url : latepoint_timestamped_ajaxurl(),
3953 data : data,
3954 success: function(response){
3955 $wrapper.closest('.balance-payment-wrapper').removeClass('os-loading');
3956 if(response.status === "success"){
3957 jQuery('.balance-payment-wrapper').html(response.message);
3958 latepoint_init_input_masks(jQuery('.balance-payment-wrapper'));
3959 latepoint_init_daterangepicker(jQuery('.balance-payment-wrapper .os-date-range-picker'));
3960 latepoint_init_payment_request_form(jQuery('.quick-order-form-w'));
3961 }else{
3962 alert(response.message);
3963 }
3964 }
3965 });
3966 }
3967
3968
3969
3970 function latepoint_cancel_adding_new_order_item_to_quick_edit_form(){
3971 jQuery('.order-items-list').removeClass('is-blurred');
3972 jQuery('.new-order-item-list-bundles-wrapper').removeClass('is-open');
3973 jQuery('.new-order-item-variant-selector-wrapper').removeClass('is-open');
3974 jQuery('.order-form-add-item-btn').removeClass('is-cancelling').find('span').text(jQuery('.order-form-add-item-btn').data('add-label'));
3975 }
3976
3977 function latepoint_build_new_booking_order_item(){
3978 jQuery('.order-form-add-item-btn').addClass('os-loading');
3979 latepoint_cancel_adding_new_order_item_to_quick_edit_form();
3980 let params = {}
3981
3982 var data = {
3983 action: 'latepoint_route_call',
3984 route_name: jQuery('.order-form-add-item-btn').data('booking-form-route-name'),
3985 params: params,
3986 return_format: 'json'
3987 }
3988 jQuery.ajax({
3989 type : "post",
3990 dataType : "json",
3991 url : latepoint_timestamped_ajaxurl(),
3992 data : data,
3993 success: function(response){
3994 if(response.status === "success"){
3995 let $form = jQuery(response.message);
3996 jQuery('.order-items-list').prepend($form);
3997 jQuery('.order-form-add-item-btn').removeClass('os-loading');
3998 latepoint_init_booking_data_form(jQuery('.order-item-booking-data-form-wrapper[data-order-item-id="' + $form.data('order-item-id') + '"]'));
3999 // new item added, trigger change event
4000 latepoint_quick_order_items_changed();
4001 }else{
4002 alert(response.message, 'error');
4003 }
4004 }
4005 });
4006 }
4007
4008 function latepoint_build_booking_data_form_for_bundle($slot_for_booking){
4009 $slot_for_booking.addClass('os-loading');
4010 latepoint_cancel_adding_new_order_item_to_quick_edit_form();
4011 let params = {}
4012
4013 let is_booked = $slot_for_booking.hasClass('is-booked');
4014
4015 var data = {
4016 action: 'latepoint_route_call',
4017 route_name: jQuery('.order-form-add-item-btn').data('booking-form-route-name'),
4018 params: {
4019 order_item_id: $slot_for_booking.data('order-item-id'),
4020 order_item_variant: $slot_for_booking.data('order-item-variant'),
4021 booking_id: $slot_for_booking.data('booking-id'),
4022 booking_item_data: is_booked ? $slot_for_booking.find('.booking_item_data').val() : $slot_for_booking.find('.unscheduled_booking_item_data').val()
4023 },
4024 return_format: 'json'
4025 }
4026 jQuery.ajax({
4027 type : "post",
4028 dataType : "json",
4029 url : latepoint_timestamped_ajaxurl(),
4030 data : data,
4031 success: function(response){
4032 if(response.status === "success"){
4033 let $form = jQuery(response.message);
4034 $slot_for_booking.removeClass('os-loading');
4035 if($slot_for_booking){
4036 $slot_for_booking.find('.scheduled-bundle-booking').html($form).closest('.order-item-variant-bundle-booking ').addClass('is-booked');
4037 }else{
4038 jQuery('.order-items-list').prepend($form);
4039 }
4040 latepoint_init_booking_data_form(jQuery('.order-item-booking-data-form-wrapper[data-order-item-id="' + $form.data('order-item-id') + '"][data-booking-id="' + $form.data('booking-id') + '"]'));
4041 // new item added, trigger change event
4042 if(!$slot_for_booking) latepoint_quick_order_items_changed();
4043 }else{
4044 alert(response.message, 'error');
4045 }
4046 }
4047 });
4048 }
4049
4050 function latepoint_bundle_added_to_quick_order(){
4051 latepoint_quick_order_items_changed();
4052 latepoint_cancel_adding_new_order_item_to_quick_edit_form();
4053 }
4054
4055 function latepoint_quick_order_items_changed(){
4056 latepoint_reload_price_breakdown();
4057 }
4058
4059
4060 function latepoint_fold_booking_data_form_in_order_quick_edit($booking_data_form){
4061 if(!$booking_data_form.length) return false;
4062 latepoint_close_quick_availability_form();
4063 latepoint_show_all_order_items();
4064 let order_item_id = $booking_data_form.data('order-item-id');
4065 let booking_id = $booking_data_form.data('booking-id');
4066 let order_item_variant = $booking_data_form.data('order-item-variant');
4067
4068
4069 $booking_data_form.addClass('is-loading');
4070
4071 let form_data = new FormData(jQuery('.order-quick-edit-form')[0]);
4072 form_data.set('order_item_id', order_item_id);
4073 form_data.set('booking_id', booking_id);
4074 var data = {
4075 action: 'latepoint_route_call',
4076 route_name: jQuery('.order-form-add-item-btn').data('fold-booking-data-route-name'),
4077 params: latepoint_formdata_to_url_encoded_string(form_data),
4078 return_format: 'json'
4079 }
4080 jQuery.ajax({
4081 type : "post",
4082 dataType : "json",
4083 url : latepoint_timestamped_ajaxurl(),
4084 data : data,
4085 success: function(response){
4086 if(response.status === "success"){
4087 $booking_data_form.removeClass('is-loading').removeClass('is-unfolded').addClass('is-folded');
4088 if(order_item_variant == latepoint_helper.order_item_variant_bundle){
4089 $booking_data_form.closest('.order-item-variant-bundle-booking').addClass('is-booked');
4090 $booking_data_form.find('.bundle-booking-item-pill').replaceWith(response.message);
4091 }else{
4092 $booking_data_form.find('.order-item-pill').replaceWith(response.message);
4093 }
4094 }else{
4095 alert(response.message, 'error');
4096 }
4097 }
4098 });
4099 }
4100
4101
4102 function latepoint_init_booking_data_form($booking_data_form){
4103 latepoint_init_input_masks($booking_data_form);
4104
4105 $booking_data_form.find('.fold-order-item-booking-data-form-btn').on('click', function(){
4106 latepoint_fold_booking_data_form_in_order_quick_edit($booking_data_form);
4107 return false;
4108 });
4109
4110 $booking_data_form.find('.quick-booking-form-view-log-btn').on('click', function(){
4111 var $trigger_elem = jQuery(this);
4112 $trigger_elem.addClass('os-loading');
4113 var route = $trigger_elem.data('route');
4114 var data = { action: 'latepoint_route_call', route_name: route, params: {booking_id: $trigger_elem.data('booking-id')}, return_format: 'json' }
4115 jQuery.ajax({
4116 type : "post",
4117 dataType : "json",
4118 url : latepoint_timestamped_ajaxurl(),
4119 data : data,
4120 success: function(response){
4121 $trigger_elem.removeClass('os-loading');
4122 if(response.status === "success"){
4123 latepoint_display_in_side_sub_panel(response.message);
4124 jQuery('body').addClass('has-side-sub-panel');
4125 }else{
4126 alert(response.message, 'error');
4127 }
4128 }
4129 });
4130 return false;
4131 });
4132
4133
4134 $booking_data_form.find('.os-late-select').lateSelect();
4135
4136 $booking_data_form.find('.trigger-quick-availability').on('click', function(){
4137 latepoint_load_quick_availability(jQuery(this));
4138 return false;
4139 });
4140
4141 let field_base_name = 'order_items[' + $booking_data_form.data('order-item-id') +'][bookings][' + $booking_data_form.data('booking-id') +']';
4142
4143 $booking_data_form.find('input[name="' + field_base_name +'[start_time][formatted_value]"]').on('change', function(){
4144 latepoint_set_booking_end_time($booking_data_form);
4145 });
4146 $booking_data_form.find('input[name="' + field_base_name +'[end_time][formatted_value]"]').on('change', function(){
4147 latepoint_is_next_day($booking_data_form);
4148 });
4149
4150
4151
4152 $booking_data_form.on('change', '.agent-selector', function(){
4153 latepoint_apply_agent_selector_change($booking_data_form);
4154 });
4155 $booking_data_form.on('change', '.location-selector', function(){
4156 latepoint_apply_agent_selector_change($booking_data_form);
4157 });
4158 $booking_data_form.on('change', 'select[name="booking[location_id]"]', function(){
4159 latepoint_apply_agent_selector_change($booking_data_form);
4160 });
4161 $booking_data_form.on('change', 'select[name="booking[total_attendees]"]', function(){
4162 latepoint_apply_agent_selector_change($booking_data_form);
4163 });
4164
4165 $booking_data_form.on('change', '.os-affects-duration', function(){
4166 latepoint_set_booking_end_time($booking_data_form);
4167 if(jQuery('.quick-availability-per-day-w').length){
4168 latepoint_load_quick_availability($booking_data_form.find('.trigger-quick-availability'));
4169 }
4170 });
4171
4172 $booking_data_form.on('change', '.os-affects-price', function(){
4173 latepoint_reload_price_breakdown();
4174 });
4175
4176 $booking_data_form.on('change', '.os-affects-balance', function(){
4177 latepoint_reload_balance_and_payments();
4178 });
4179 $booking_data_form.on('keyup', '.os-affects-balance', function(event){
4180 if(event.keyCode == 13) {
4181 latepoint_reload_balance_and_payments();
4182 }
4183 });
4184
4185
4186 $booking_data_form.on('click', '.services-options-list .service-option', function(){
4187 var selected_option_html = jQuery(this).html();
4188 var $selected_option = jQuery(this).closest('.os-services-select-field-w').find('.service-option-selected');
4189 $selected_option.html(selected_option_html)
4190 .data('id', jQuery(this).data('id'))
4191 .data('duration', jQuery(this).data('duration'))
4192 .data('duration-name', jQuery(this).data('duration-name'))
4193 .data('buffer-before', jQuery(this).data('buffer-before'))
4194 .data('buffer-after', jQuery(this).data('buffer-after'))
4195 .data('capacity-min', jQuery(this).data('capacity-min'))
4196 .data('capacity-max', jQuery(this).data('capacity-max'))
4197 .data('extra-durations', jQuery(this).data('extra-durations'));
4198 jQuery(this).closest('.os-services-select-field-w').find('.service-option.selected').removeClass('selected');
4199 jQuery(this).addClass('selected').closest('.os-services-select-field-w').removeClass('active');
4200 latepoint_apply_service_selector_change($booking_data_form);
4201 return false;
4202 });
4203
4204 $booking_data_form.trigger('latepoint:initBookingDataForm');
4205
4206 }
4207
4208 function latepoint_init_payment_request_form($quick_order_form){
4209 $quick_order_form.find('select[name="payment_request[portion]"]').on('change', function(){
4210 if(jQuery(this).val() == 'custom'){
4211 $quick_order_form.find('.custom-charge-amount-wrapper').show();
4212 }else{
4213 $quick_order_form.find('.custom-charge-amount-wrapper').hide();
4214 }
4215 })
4216 }
4217
4218 function latepoint_show_all_order_items(){
4219 let $quick_order_form = jQuery('.quick-order-form-w');
4220 $quick_order_form.find('.order-items-info-w').removeClass('show-preselected-only');
4221 $quick_order_form.find('.holds-preselected-booking').removeClass('holds-preselected-booking');
4222 }
4223
4224 function latepoint_init_quick_order_form(){
4225 let $quick_order_form = jQuery('.quick-order-form-w');
4226 $quick_order_form.trigger('latepoint:initOrderEditForm');
4227
4228 $quick_order_form.on('change', '.os-affects-balance', function(){
4229 latepoint_reload_balance_and_payments();
4230 });
4231 $quick_order_form.on('keyup', '.os-affects-balance', function(event){
4232 if(event.keyCode == 13) {
4233 latepoint_reload_balance_and_payments();
4234 }
4235 });
4236
4237 latepoint_init_customer_inline_edit_form($quick_order_form.find('.customer-info-w'));
4238 $quick_order_form.find('.order-item-booking-data-form-wrapper').each(function(){
4239 latepoint_init_booking_data_form(jQuery(this));
4240 });
4241
4242 latepoint_lightbox_close();
4243 latepoint_remove_floating_popup();
4244 latepoint_init_input_masks($quick_order_form);
4245 latepoint_init_daterangepicker($quick_order_form.find('.os-date-range-picker'));
4246 latepoint_init_payment_request_form($quick_order_form);
4247
4248 // Transactions
4249
4250 $quick_order_form.on('click', '.transaction-refund-settings-button', function(){
4251 jQuery(this).closest('.quick-add-transaction-box-w').addClass('show-refund-settings');
4252 });
4253 $quick_order_form.on('click', '.transaction-refund-submit-button', function(){
4254 let $trigger_elem = jQuery(this);
4255 if(confirm(jQuery(this).data('os-prompt'))){
4256 $trigger_elem.addClass('os-loading');
4257 let route = $trigger_elem.data('route');
4258 let data = { action: 'latepoint_route_call', route_name: route, params: $trigger_elem.closest('.refund-settings-fields').find('input, textarea, select').serialize(), return_format: 'json' }
4259 jQuery.ajax({
4260 type : "post",
4261 dataType : "json",
4262 url : latepoint_timestamped_ajaxurl(),
4263 data : data,
4264 success: function(response){
4265 $trigger_elem.removeClass('os-loading');
4266 if(response.status === "success"){
4267 $trigger_elem.closest('.quick-add-transaction-box-w').replaceWith(response.message);
4268 latepoint_reload_balance_and_payments();
4269 }else{
4270 alert(response.message, 'error');
4271 }
4272 }
4273 });
4274 return false;
4275 }
4276 });
4277
4278 $quick_order_form.on('click', '.refund-settings-close', function(){
4279 jQuery(this).closest('.quick-add-transaction-box-w').removeClass('show-refund-settings');
4280 });
4281 $quick_order_form.on('change', '.refund-portion-selector', function(){
4282 if(jQuery(this).val() == 'full'){
4283 jQuery(this).closest('.refund-settings-fields').find('.custom-charge-amount-wrapper').hide();
4284 }else{
4285 jQuery(this).closest('.refund-settings-fields').find('.custom-charge-amount-wrapper').show();
4286 }
4287 });
4288
4289 // Log
4290
4291 $quick_order_form.find('.quick-order-form-view-log-btn').on('click', function(){
4292 var $trigger_elem = jQuery(this);
4293 $trigger_elem.addClass('os-loading');
4294 var route = $trigger_elem.data('route');
4295 var data = { action: 'latepoint_route_call', route_name: route, params: {order_id: $trigger_elem.data('order-id')}, return_format: 'json' }
4296 jQuery.ajax({
4297 type : "post",
4298 dataType : "json",
4299 url : latepoint_timestamped_ajaxurl(),
4300 data : data,
4301 success: function(response){
4302 $trigger_elem.removeClass('os-loading');
4303 if(response.status === "success"){
4304 latepoint_display_in_side_sub_panel(response.message);
4305 jQuery('body').addClass('has-side-sub-panel');
4306 }else{
4307 alert(response.message, 'error');
4308 }
4309 }
4310 });
4311 return false;
4312 });
4313
4314
4315 $quick_order_form.find('.new-order-item-variant-bundle').on('click', function(){
4316 $quick_order_form.find('.new-order-item-list-bundles-wrapper').toggleClass('is-open');
4317 $quick_order_form.find('.new-order-item-variant-selector-wrapper').toggleClass('is-open');
4318 return false;
4319 });
4320
4321
4322
4323
4324 $quick_order_form.find('.hidden-order-items-notice-link, .hidden-bundle-items-notice-link').on('click', function(e){
4325 latepoint_show_all_order_items();
4326 return false;
4327 });
4328
4329 $quick_order_form.find('.order-quick-edit-form').on('submit', function(e){
4330 if(jQuery(this).find('button[type="submit"]').hasClass('os-loading')) return false;
4331 e.preventDefault();
4332 latepoint_submit_quick_order_form();
4333 });
4334
4335 $quick_order_form.on("keydown", ":input:not(textarea):not(:submit)", function(event) {
4336 if (event.key == "Enter") {
4337 event.preventDefault();
4338 }
4339 });
4340
4341 $quick_order_form.find('.order-items-list').on('click', '.remove-order-item-btn', function(){
4342 latepoint_close_quick_availability_form();
4343 if(confirm(jQuery(this).data('os-prompt'))){
4344 if(jQuery(this).closest('.order-item-variant-bundle-booking-wrapper').length){
4345 // it's a bundle booking
4346 // need to figure out how to remove it when bundle
4347 jQuery(this).closest('.order-item-variant-bundle-booking').removeClass('is-booked').find('.scheduled-bundle-booking').html('');
4348 }else{
4349 jQuery(this).closest('.order-item').remove();
4350 jQuery(this).closest('.order-item-booking-data-form-wrapper').remove();
4351
4352 }
4353 latepoint_quick_order_items_changed();
4354 }
4355 return false;
4356 });
4357
4358 $quick_order_form.find('.new-order-item-variant-booking').on('click', function(){
4359 latepoint_fold_all_open_booking_data_forms();
4360 latepoint_build_new_booking_order_item();
4361 });
4362
4363 $quick_order_form.on('click', '.order-item-pill.order-item-pill-variant-booking', function(){
4364 jQuery(this).closest('.order-item-booking-data-form-wrapper').removeClass('is-folded').addClass('is-unfolded');
4365 return false;
4366 });
4367
4368 $quick_order_form.on('click', '.bundle-booking-item-pill', function(){
4369 jQuery(this).closest('.order-item-booking-data-form-wrapper').removeClass('is-folded').addClass('is-unfolded');
4370 return false;
4371 });
4372
4373 $quick_order_form.on('click', '.unscheduled-bundle-booking', function(){
4374 latepoint_build_booking_data_form_for_bundle(jQuery(this).closest('.order-item-variant-bundle-booking'));
4375 });
4376
4377
4378 $quick_order_form.find('.order-form-add-item-btn').on('click', function(){
4379 let $booking_data_forms = jQuery('.order-item-booking-data-form-wrapper');
4380 $booking_data_forms.each(function(){
4381 latepoint_fold_booking_data_form_in_order_quick_edit(jQuery(this));
4382 });
4383 if(jQuery(this).hasClass('is-cancelling')){
4384 latepoint_cancel_adding_new_order_item_to_quick_edit_form();
4385 }else{
4386 if(jQuery('.new-order-item-variant-selector-wrapper').length){
4387 jQuery('.order-items-list').addClass('is-blurred');
4388 jQuery('.new-order-item-variant-selector-wrapper').addClass('is-open');
4389 jQuery(this).addClass('is-cancelling').find('span').text(jQuery(this).data('cancel-label'));
4390 }else{
4391 // no bundles exist, create booking form
4392 latepoint_cancel_adding_new_order_item_to_quick_edit_form();
4393 latepoint_build_new_booking_order_item();
4394 }
4395 }
4396 return false;
4397 });
4398
4399
4400 $quick_order_form.on('click', '.order-item-variant-bundle .bundle-icon', function(){
4401 jQuery(this).closest('.order-item-variant-bundle').toggleClass('is-open');
4402 return false;
4403 });
4404
4405 $quick_order_form.find('.reload-price-breakdown').on('click', function(){
4406 latepoint_reload_price_breakdown();
4407 return false;
4408 });
4409
4410 $quick_order_form.on('click', '.trigger-remove-transaction-btn', function(){
4411 jQuery(this).closest('.quick-add-transaction-box-w').remove();
4412 return false;
4413 });
4414
4415
4416 $quick_order_form.trigger('latepoint:initQuickOrderForm');
4417 }
4418
4419 function latepoint_fold_all_open_booking_data_forms(){
4420 let $booking_data_forms = jQuery('.order-item-booking-data-form-wrapper');
4421 $booking_data_forms.each(function(){
4422 latepoint_fold_booking_data_form_in_order_quick_edit(jQuery(this));
4423 });
4424 }
4425
4426 function latepoint_init_customer_inline_edit_form($customer_form){
4427
4428 latepoint_init_input_masks($customer_form);
4429
4430 $customer_form.find('.customers-selector-search-input').on('keyup',function(){
4431 var $queryInput = jQuery(this);
4432 var query = $queryInput.val().toLowerCase();
4433 if(query == $queryInput.data('current-query')) return;
4434
4435 // Search
4436 $queryInput.closest('.customers-selector-search-w').addClass('os-loading');
4437 $queryInput.data('searching-query', query);
4438 setTimeout(function(){
4439 if(query != jQuery('.customers-selector-search-input').data('searching-query')) return;
4440 var data = { action: latepoint_helper.route_action, route_name: $queryInput.data('route'), params: {query: query}, return_format: 'json' }
4441 jQuery.ajax({
4442 type : "post",
4443 dataType : "json",
4444 url : latepoint_timestamped_ajaxurl(),
4445 data : data,
4446 success: function(response){
4447 if($queryInput.data('searching-query') != query) return;
4448 $queryInput.closest('.customers-selector-search-w').removeClass('os-loading');
4449 if(response.status === "success"){
4450 $queryInput.data('current-query', query);
4451 jQuery('.quick-order-form-w .customers-options-list').html(response.message);
4452 }else{
4453 // console.log(response.message);
4454 }
4455 }
4456 });
4457 }, 300, query, $queryInput);
4458 });
4459
4460 }
4461
4462
4463 function latepoint_load_quick_availability($trigger_elem, custom_agent_id = false, start_date = false, load_more_days = false, load_prev_days = false){
4464 $trigger_elem.addClass('os-loading');
4465
4466 let $booking_form = $trigger_elem.closest('.order-item-booking-data-form-wrapper');
4467 var route = $booking_form.find('.trigger-quick-availability').data('route');
4468 var $quick_order_form = jQuery('.quick-order-form-w');
4469
4470 if(custom_agent_id) $quick_order_form.find('.agent-selector').val(custom_agent_id);
4471 if(!$quick_order_form.find('.service-selector').val() || $quick_order_form.find('.service-selector').val() == '0'){
4472 $quick_order_form.find('.os-services-select-field-w .service-option:first').trigger('click');
4473 }
4474
4475 let form_data = new FormData($quick_order_form.find('form')[0]);
4476
4477
4478 form_data.set('trigger_form_booking_id', $booking_form.data('booking-id'));
4479 form_data.set('trigger_form_order_item_id', $booking_form.data('order-item-id'));
4480
4481 if(start_date) form_data.set('start_date', start_date);
4482 if(load_more_days || load_prev_days) form_data.set('show_days_only', true);
4483 if(load_prev_days) form_data.set('previous_days', true);
4484
4485 var data = {
4486 action: latepoint_helper.route_action,
4487 route_name: route,
4488 params: latepoint_formdata_to_url_encoded_string(form_data),
4489 return_format: 'json'
4490 }
4491
4492 jQuery.ajax({
4493 type : "post",
4494 dataType : "json",
4495 url : latepoint_timestamped_ajaxurl(),
4496 data : data,
4497 success: function(response){
4498 $trigger_elem.removeClass('os-loading');
4499 if(response.status === "success"){
4500 if(load_more_days){
4501 jQuery('.latepoint-side-panel-w .quick-availability-per-day-w').html(response.message);
4502 jQuery('.latepoint-side-panel-w .os-availability-days').scrollTop(52);
4503 }else if(load_prev_days){
4504 jQuery('.latepoint-side-panel-w .quick-availability-per-day-w').html(response.message);
4505 jQuery('.latepoint-side-panel-w .os-availability-days').scrollTop(jQuery('.latepoint-side-panel-w .os-availability-days')[0].scrollHeight - jQuery('.latepoint-side-panel-w .os-availability-days')[0].clientHeight - 50);
4506 }else{
4507 latepoint_display_in_side_sub_panel(response.message);
4508 jQuery('.latepoint-side-panel-w .os-availability-days').scrollTop(52);
4509 jQuery('body').addClass('has-side-sub-panel');
4510 latepoint_init_quick_availability_form();
4511 }
4512 }else{
4513 alert(response.message, 'error');
4514 }
4515 }
4516 });
4517 }
4518
4519 function latepoint_create_field_base_name(order_item_id, booking_id){
4520 return 'order_items['+order_item_id+'][bookings]['+booking_id+']';
4521 }
4522
4523 function latepoint_close_quick_availability_form(){
4524 jQuery('.quick-availability-per-day-w').remove();
4525 jQuery('body').removeClass('has-side-sub-panel');
4526 }
4527
4528 function latepoint_init_quick_availability_form(){
4529 // TODO set booking ID
4530 let $quick_availability_wrapper = jQuery('.quick-availability-per-day-w');
4531
4532 let trigger_form_order_item_id = $quick_availability_wrapper.data('trigger-form-order-item-id');
4533 let trigger_form_booking_id = $quick_availability_wrapper.data('trigger-form-booking-id');
4534
4535 let field_base_name = latepoint_create_field_base_name(trigger_form_order_item_id, trigger_form_booking_id);
4536
4537 let $booking_data_form = jQuery('.quick-order-form-w .order-item-booking-data-form-wrapper[data-booking-id="'+trigger_form_booking_id+'"]');
4538
4539 var selected_start_date = $booking_data_form.find('input[name="'+field_base_name+'[start_date_formatted]"').val();
4540 var selected_start_time = $booking_data_form.find('input[name="'+field_base_name+'[start_time][formatted_value]"]').val();
4541 var selected_start_time_ampm = $booking_data_form.find('input[name="'+field_base_name+'[start_time][ampm]"]').val();
4542
4543
4544 var selected_start_time_minutes = latepoint_hours_and_minutes_to_minutes(selected_start_time, selected_start_time_ampm);
4545 $quick_availability_wrapper.find('.os-availability-days').find('.agent-timeslot[data-formatted-date="'+ selected_start_date +'"][data-minutes="' + selected_start_time_minutes + '"]').addClass('selected');
4546 $quick_availability_wrapper.on('click', '.load-more-quick-availability', function(){
4547 jQuery(this).addClass('os-loading');
4548 let booking_form_id = jQuery(this).closest('.quick-availability-per-day-w').data('trigger-form-booking-id');
4549 let $trigger_btn = jQuery('.order-item-booking-data-form-wrapper[data-booking-id="' + booking_form_id + '"]').find('.trigger-quick-availability');
4550 latepoint_load_quick_availability($trigger_btn, false, jQuery(this).data('start-date'), true);
4551 return false;
4552 });
4553 $quick_availability_wrapper.on('click', '.load-prev-quick-availability', function(){
4554 jQuery(this).addClass('os-loading');
4555 let booking_form_id = jQuery(this).closest('.quick-availability-per-day-w').data('trigger-form-booking-id');
4556 let $trigger_btn = jQuery('.order-item-booking-data-form-wrapper[data-booking-id="' + booking_form_id + '"]').find('.trigger-quick-availability');
4557 latepoint_load_quick_availability($trigger_btn, false, jQuery(this).data('start-date'), false, true);
4558 return false;
4559 });
4560 $quick_availability_wrapper.find('select[name="booking[agent_id]"]').on('change', function(){
4561 latepoint_load_quick_availability(jQuery('.trigger-quick-availability'), jQuery(this).val());
4562 });
4563 jQuery('.os-time-group label').on('click', function(){
4564 jQuery(this).closest('.os-time-group').find('.os-form-control').trigger('focus');
4565 });
4566 $quick_availability_wrapper.on('click', '.fill-booking-time', function(){
4567 jQuery('.os-availability-days .agent-timeslot.selected').removeClass('selected');
4568 jQuery(this).addClass('selected');
4569 var formatted_date = jQuery(this).data('formatted-date');
4570 var minutes = jQuery(this).data('minutes');
4571 $booking_data_form.find('input[name="'+field_base_name+'[start_date_formatted]"]').val(formatted_date);
4572 var start_minutes = minutes;
4573 var start_hours_and_minutes = latepoint_minutes_to_hours_and_minutes(start_minutes);
4574
4575 if(start_minutes >= 720){
4576 $booking_data_form.find('.quick-start-time-w .time-pm').trigger('click');
4577 }else{
4578 $booking_data_form.find('.quick-start-time-w .time-am').trigger('click');
4579 }
4580
4581 $booking_data_form.find('input[name="'+field_base_name+'[start_time][formatted_value]"]').val(start_hours_and_minutes);
4582 latepoint_set_booking_end_time($booking_data_form);
4583 $booking_data_form.find('.ws-period, .as-period').addClass('animate-filled-in');
4584 setTimeout(function(){
4585 $booking_data_form.find('.ws-period, .as-period').removeClass('animate-filled-in');
4586 }, 500)
4587 });
4588 }
4589
4590
4591 function latepoint_reload_after_order_save(){
4592 latepoint_reload_calendar_view();
4593
4594 jQuery('.os-widget').each(function(){
4595 latepoint_reload_widget(jQuery(this));
4596 });
4597 if(jQuery('table.os-reload-on-booking-update').length) latepoint_filter_table(jQuery('table.os-reload-on-booking-update'), jQuery('table.os-reload-on-booking-update'));
4598 latepoint_close_side_panel();
4599 }
4600
4601 /*
4602 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
4603 */
4604
4605 class LatepointStripeConnectAdmin {
4606
4607 // Init
4608 constructor(){
4609 this.ready();
4610 }
4611
4612 ready() {
4613 jQuery(document).ready(() => {
4614 jQuery('.stripe-connect-status-wrapper').on('click', '.payment-start-connecting', function(){
4615 let $link = jQuery(this);
4616 $link.addClass('os-loading');
4617 var data = {
4618 action: 'latepoint_route_call',
4619 route_name: $link.data('route-name'),
4620 params: { env: $link.data('env') },
4621 layout: 'none',
4622 return_format: 'json'
4623 }
4624 jQuery.ajax({
4625 type : "post",
4626 dataType : "json",
4627 url : latepoint_timestamped_ajaxurl(),
4628 data : data,
4629 success: (data) => {
4630 window.location.href = data.url;
4631 }
4632 });
4633 return false;
4634 });
4635
4636 if(jQuery('.stripe-connect-status-wrapper').length){
4637 jQuery('.stripe-connect-status-wrapper').each((index, elem) => {
4638 let $wrapper = jQuery(elem);
4639 var data = {
4640 action: 'latepoint_route_call',
4641 route_name: $wrapper.data('route-name'),
4642 params: { env: $wrapper.data('env') },
4643 layout: 'none',
4644 return_format: 'json'
4645 }
4646 jQuery.ajax({
4647 type : "post",
4648 dataType : "json",
4649 url : latepoint_timestamped_ajaxurl(),
4650 data : data,
4651 success: (data) => {
4652 this.reload_connect_status_wrapper($wrapper, data);
4653 }
4654 });
4655 })
4656 }
4657 });
4658 }
4659
4660
4661 reload_connect_status_wrapper($elem, data){
4662 if(data.status === 'success'){
4663 if($elem.hasClass('.stripe-connect-status-wrapper')){
4664 $elem.html(data.message);
4665 }else{
4666 $elem.closest('.stripe-connect-status-wrapper').html(data.message);
4667 }
4668 }else{
4669 alert(data.message);
4670 }
4671 }
4672
4673
4674 }
4675
4676
4677 window.latepointStripeConnectAdmin = new LatepointStripeConnectAdmin();
4678
4679 /*
4680 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
4681 */
4682
4683 // @codekit-prepend "bin/time.js";
4684 // @codekit-prepend "bin/lateselect.js";
4685 // @codekit-prepend "bin/latecheckbox.js";
4686 // @codekit-prepend "bin/actions.js";
4687 // @codekit-prepend "bin/notifications.js";
4688 // @codekit-prepend "bin/shared.js";
4689 // @codekit-prepend "bin/admin/updates.js";
4690 // @codekit-prepend "bin/admin/main.js";
4691 // @codekit-prepend "bin/admin/_agents.js";
4692 // @codekit-prepend "bin/admin/_customers.js";
4693 // @codekit-prepend "bin/admin/_customers_import.js";
4694 // @codekit-prepend "bin/admin/_chart.js";
4695 // @codekit-prepend "bin/admin/_calendar.js";
4696 // @codekit-prepend "bin/admin/_processes.js";
4697 // @codekit-prepend "bin/admin/_steps.js";
4698 // @codekit-prepend "bin/admin/_orders.js";
4699 // @codekit-prepend "bin/admin/_stripe_connect.js";
4700
4701
4702
4703 // DOCUMENT READY
4704 jQuery(document).ready(function( $ ) {
4705
4706
4707 // DASHBOARD
4708 latepoint_init_calendars();
4709 latepoint_init_circles_charts();
4710 latepoint_init_donut_charts();
4711 latepoint_init_daily_bookings_chart();
4712 latepoint_init_element_togglers();
4713 latepoint_init_daterangepicker(jQuery('.os-date-range-picker'));
4714 latepoint_init_monthly_view();
4715 latepoint_init_form_blocks();
4716 latepoint_init_reminders_form();
4717 latepoint_init_coupons_form();
4718 latepoint_init_copy_on_click_elements();
4719 latepoint_init_side_menu();
4720 latepoint_init_color_picker();
4721 latepoint_init_clickable_cells();
4722 latepoint_init_input_masks();
4723 latepoint_init_process_forms();
4724 latepoint_init_sticky_side_menu();
4725 latepoint_init_sortable_columns();
4726 latepoint_init_accordions();
4727 latepoint_init_default_form_fields_settings();
4728 latepoint_init_steps_settings();
4729 latepoint_init_booking_form_preview();
4730 latepoint_init_sticky_side_nav();
4731 latepoint_init_version5_intro();
4732
4733 jQuery(document).on({
4734 mouseenter: function () {
4735 let $elem = jQuery(this);
4736 let offset = $elem.offset();
4737 jQuery('body > .late-tooltip').remove();
4738 let $popup = jQuery('<div/>').addClass('late-tooltip').text($elem.data('late-tooltip')).appendTo(jQuery('body'));
4739 $popup.css('top', offset.top - 2);
4740 $popup.css('left', offset.left + $elem.outerWidth() / 2);
4741 return false;
4742 },
4743 mouseleave: function () {
4744 jQuery('body > .late-tooltip').remove();
4745 }
4746 }, "[data-late-tooltip]");
4747
4748 jQuery('body').on('click', '.disabled-items-open-trigger', function(){
4749 jQuery('.disabled-items-wrapper').toggleClass('is-open');
4750 return false;
4751 });
4752
4753 jQuery('body').on('click', '.latepoint-side-panel-close', function(){
4754 jQuery('.side-sub-panel-wrapper').remove();
4755 return false;
4756 });
4757
4758 jQuery('#settings_list_of_phone_countries').on('change', function(){
4759 if(jQuery(this).val() == latepoint_helper.value_all){
4760 jQuery('.select-phone-countries-wrapper').hide();
4761 }else{
4762 jQuery('.select-phone-countries-wrapper').show();
4763 }
4764 });
4765
4766
4767 jQuery('.os-select-all-toggler').on('change', function(){
4768 var $connection_wrappers = jQuery(this).closest('.white-box').find('.os-complex-connections-selector .connection');
4769 if(jQuery(this).is(':checked')){
4770 latepoint_complex_selector_select($connection_wrappers);
4771 }else{
4772 latepoint_complex_selector_deselect($connection_wrappers);
4773 }
4774 return false;
4775 });
4776
4777
4778 jQuery('.os-main-location-selector').on('change', function(){
4779 var route = jQuery(this).data('route');
4780 var params = 'id=' + jQuery(this).val();
4781 var data = { action: latepoint_helper.route_action, route_name: route, params: params, layout: 'none', return_format: 'json' };
4782 jQuery('.latepoint-content-w').addClass('os-loading');
4783 jQuery.ajax({
4784 type : "post",
4785 dataType : "json",
4786 url : latepoint_timestamped_ajaxurl(),
4787 data : data,
4788 success: function(data){
4789 location.reload();
4790 }
4791 });
4792 });
4793
4794 jQuery('.os-service-durations-w').on('click', '.os-remove-duration', function(){
4795 jQuery(this).closest('.duration-box').slideUp(300, function(){
4796 jQuery(this).remove();
4797 });
4798 return false;
4799 });
4800
4801
4802 jQuery('.menu-color-toggler').on('click', function(){
4803 jQuery('.latepoint-side-menu-w').toggleClass('dark');
4804 return false;
4805 });
4806
4807
4808 jQuery('.latepoint-mobile-top-menu-trigger').on('click', function(){
4809 jQuery(this).closest('.latepoint-all-wrapper').toggleClass('os-show-mobile-menu');
4810 if(jQuery(this).closest('.latepoint-all-wrapper').hasClass('os-show-mobile-menu')){
4811 jQuery('.latepoint-side-menu-w ul.side-menu > li.has-children > a').on('click', function(){
4812 jQuery(this).closest('li').toggleClass('menu-item-sub-open-mobile');
4813 return false;
4814 });
4815 }else{
4816 jQuery('.latepoint-side-menu-w ul.side-menu > li.has-children > a').off('click');
4817 }
4818 return false;
4819 });
4820
4821 jQuery('.latepoint-mobile-top-search-trigger-cancel').on('click', function(){
4822 jQuery(this).closest('.latepoint-all-wrapper').removeClass('os-show-mobile-search');
4823 return false;
4824 });
4825
4826 jQuery('.latepoint-mobile-top-search-trigger').on('click', function(){
4827 jQuery(this).closest('.latepoint-all-wrapper').toggleClass('os-show-mobile-search');
4828 if(jQuery(this).closest('.latepoint-all-wrapper').hasClass('os-show-mobile-search')){
4829 jQuery('.latepoint-top-search').trigger('focus');
4830 }
4831 return false;
4832 });
4833
4834
4835 jQuery('.latepoint-top-bar-w').on('click', '.top-user-info-toggler', function(){
4836 jQuery('.latepoint-user-info-dropdown').toggleClass('os-visible');
4837 return false;
4838 });
4839
4840 jQuery('.latepoint-content').on('click', '.mobile-calendar-actions-trigger', function(){
4841 jQuery(this).closest('.calendar-mobile-controls').toggleClass('os-show-actions');
4842 return false;
4843 });
4844
4845 jQuery('.latepoint-content').on('click', '.os-widget-header-actions-trigger', function(){
4846 jQuery(this).closest('.os-widget-header').toggleClass('os-show-actions');
4847 return false;
4848 });
4849
4850 jQuery('.latepoint-content').on('click', '.mobile-table-actions-trigger', function(){
4851 jQuery(this).closest('.os-pagination-w').toggleClass('os-show-actions');
4852 return false;
4853 });
4854
4855
4856
4857
4858
4859
4860 jQuery('.download-csv-with-filters').on('click', function(){
4861 var filter_params = jQuery(this).closest('.table-with-pagination-w').find('.os-table-filter').serialize();
4862 filter_params+= '&download=csv';
4863 jQuery(this).attr('href', this.href + '&' + filter_params);
4864 });
4865
4866 jQuery('select.pagination-page-select').on('change', function(){
4867 latepoint_filter_table(jQuery(this).closest('.table-with-pagination-w').find('table'), jQuery(this).closest('.pagination-page-select-w'), false);
4868 });
4869
4870 jQuery('select.os-table-filter').on('change', function(){
4871 latepoint_filter_table(jQuery(this).closest('table'), jQuery(this).closest('.os-form-group'));
4872 });
4873
4874 jQuery('input.os-table-filter').on('keyup', function(){
4875 latepoint_filter_table(jQuery(this).closest('table'), jQuery(this).closest('.os-form-group'));
4876 });
4877
4878
4879 jQuery('.customize-connection-btn').on('click', function(){
4880 jQuery(this).closest('.connection').toggleClass('show-customize-box');
4881 return false;
4882 });
4883
4884 jQuery('.connection-children-list').on('click', 'li', function(){
4885 if(jQuery(this).hasClass('active')){
4886 jQuery(this).removeClass('active');
4887 jQuery(this).find('input.connection-child-is-connected').val('no');
4888 }else{
4889 jQuery(this).addClass('active');
4890 jQuery(this).find('input.connection-child-is-connected').val('yes');
4891 }
4892 latepoint_count_active_connections(jQuery(this).closest('.connection'));
4893 return false;
4894 });
4895
4896 jQuery('.display-toggler-control').on('change', function(){
4897 let group = jQuery(this).data('toggler-group');
4898 let key = jQuery(this).val();
4899 jQuery('.display-toggler-target[data-toggler-group="' + group + '"]').hide();
4900 jQuery('.display-toggler-target[data-toggler-group="' + group + '"][data-toggler-key="'+ key +'"]').show();
4901 return false;
4902 });
4903
4904 jQuery('.add-item-category-trigger').on('click', function(){
4905 jQuery('.add-item-category-box').toggle();
4906 jQuery('.os-new-item-category-form-w').toggle();
4907 return false;
4908 });
4909
4910 jQuery('.latepoint-top-search').on('keyup', function(event){
4911 var $wrapper = jQuery(this).closest('.latepoint-top-search-w');
4912 $wrapper.addClass('os-loading');
4913 var query = jQuery(this).val();
4914 if(event.keyCode == 27){
4915 $wrapper.removeClass('typing');
4916 jQuery('.latepoint-top-search-results-w').html('');
4917 jQuery(this).val('');
4918 $wrapper.removeClass('os-loading');
4919 return;
4920 }
4921 if(query == ''){
4922 $wrapper.removeClass('typing');
4923 jQuery('.latepoint-top-search-results-w').html('');
4924 $wrapper.removeClass('os-loading');
4925 return;
4926 }
4927 var route = jQuery(this).data('route');
4928 var params = 'query=' + query;
4929 var data = { action: latepoint_helper.route_action, route_name: route, params: params, layout: 'none', return_format: 'json' };
4930 $wrapper.addClass('typing');
4931 jQuery.ajax({
4932 type : "post",
4933 dataType : "json",
4934 url : latepoint_timestamped_ajaxurl(),
4935 data : data,
4936 success: function(data){
4937 if(!$wrapper.hasClass('typing')) return;
4938 $wrapper.removeClass('os-loading');
4939 if(data.status === "success"){
4940 jQuery('.latepoint-top-search-results-w').html(data.message);
4941 }else{
4942 // console.log(data.message);
4943 }
4944 }
4945 });
4946 });
4947
4948
4949 jQuery('.appointment-status-selector').on('click', function(e){
4950 e.stopPropagation();
4951 });
4952
4953 jQuery('.latepoint-show-license-details').on('click', function(e){
4954 jQuery(this).closest('.active-license-info').find('.license-info-w').slideToggle(200);
4955 return false;
4956 });
4957
4958 jQuery('.aba-button-w').on('click', function(e){
4959 e.stopPropagation();
4960 var confirm_message = (jQuery(this).hasClass('aba-approve')) ? latepoint_helper.approve_confirm : latepoint_helper.reject_confirm;
4961 if(confirm(confirm_message)){
4962 var $box = jQuery(this).closest('.appointment-box-large');
4963 $box.find('.appointment-status-selector select').val(jQuery(this).data('status')).trigger('change');
4964 }
4965 return false;
4966 });
4967
4968
4969
4970 jQuery('.appointment-status-selector select').on('change', function(e){
4971 var $wrapper = jQuery(this).closest('.appointment-status-selector');
4972 var route = $wrapper.data('route');
4973 var nonce = $wrapper.data('wp-nonce');
4974 var booking_id = $wrapper.data('booking-id');
4975 var status = jQuery(this).val();
4976 jQuery(this).closest('.appointment-box-large').attr('class', 'appointment-box-large status-' + status);
4977 var params = 'id=' + booking_id + '&status=' + status + '&_wpnonce=' + nonce;
4978 var data = { action: latepoint_helper.route_action, route_name: route, params: params, layout: 'none', return_format: 'json' };
4979 jQuery.ajax({
4980 type : "post",
4981 dataType : "json",
4982 url : latepoint_timestamped_ajaxurl(),
4983 data : data,
4984 success: function(data){
4985 if(data.status === "success"){
4986 latepoint_add_notification(data.message);
4987 }else{
4988 latepoint_add_notification(data.message, 'error');
4989 // console.log(data.message);
4990 }
4991 }
4992 });
4993 });
4994
4995 jQuery('body').on('click', '.open-template-variables-panel', function(){
4996 jQuery('.latepoint-template-variables').toggleClass('is-visible');
4997 return false;
4998 });
4999
5000 jQuery('body').on('click', '.close-template-variables-panel', function(){
5001 jQuery('.latepoint-template-variables').removeClass('is-visible');
5002 return false;
5003 });
5004
5005 jQuery('body').on('click', '.open-layout-template-variables-panel', function(){
5006 jQuery('.latepoint-layout-template-variables').toggleClass('is-visible');
5007 return false;
5008 });
5009
5010 jQuery('body').on('click', '.close-layout-template-variables-panel', function(){
5011 jQuery('.latepoint-layout-template-variables').removeClass('is-visible');
5012 return false;
5013 });
5014
5015 jQuery('body').on('click', '.os-notifications .os-notification-close', function(){
5016 jQuery(this).closest('.item').remove();
5017 return false;
5018 });
5019
5020
5021 jQuery('body').on('keyup', '.os-form-group .os-form-control', function(){
5022 if(jQuery(this).val()){
5023 jQuery(this).closest('.os-form-group').addClass('has-value');
5024 }else{
5025 jQuery(this).closest('.os-form-group').removeClass('has-value');
5026 }
5027 });
5028
5029
5030
5031 jQuery('.os-wizard-setup-w, .latepoint-settings-w, .custom-schedule-wrapper').on('click', '.ws-head', function(){
5032 var $schedule_wrapper = jQuery(this).closest('.weekday-schedule-w');
5033 $schedule_wrapper.toggleClass('is-editing').removeClass('day-off');
5034 $schedule_wrapper.find('.os-toggler').removeClass('off');
5035 $schedule_wrapper.find('input.is-active').val(1);
5036 });
5037
5038
5039 jQuery('body.latepoint').on('click', '.wizard-add-edit-item-trigger', function(e){
5040 jQuery(this).addClass('os-loading');
5041 var add_item_route_name = jQuery(this).data('route');
5042 var item_info = { };
5043 if(jQuery(this).data('id')){
5044 item_info.id = jQuery(this).data('id');
5045 }
5046 var data = { action: latepoint_helper.route_action, route_name: add_item_route_name, params: item_info, layout: 'none', return_format: 'json' };
5047 jQuery.ajax({
5048 type : "post",
5049 dataType : "json",
5050 url : latepoint_timestamped_ajaxurl(),
5051 data : data,
5052 success: function(data){
5053 jQuery('.wizard-add-edit-item-trigger.os-loading').removeClass('os-loading');
5054 if(data.status === "success"){
5055 jQuery('.os-wizard-step-content-i').html(data.message);
5056 jQuery('.os-wizard-setup-w').addClass('is-sub-editing');
5057 jQuery('.os-wizard-footer').hide();
5058 latepoint_init_wizard_content();
5059 }else{
5060 // console.log(data.message);
5061 }
5062 }
5063 });
5064 });
5065
5066
5067
5068
5069 jQuery('body.latepoint').on('click', '.os-wizard-trigger-next-btn', function(){
5070 var $next_btn = jQuery(this);
5071 $next_btn.addClass('os-loading');
5072 var current_step_code = jQuery('#wizard_current_step_code').val();
5073 var params = 'current_step_code='+current_step_code;
5074
5075 // work periods step
5076 if(jQuery('.os-wizard-setup-w form.weekday-schedules-w').length){
5077 params+= '&'+ jQuery('.os-wizard-setup-w form.weekday-schedules-w .weekday-schedule-w:not(.day-off) input').serialize();
5078 }
5079 // agent/notifications step
5080 if(jQuery('.os-wizard-default-agent-form').length){
5081 params+= '&'+ jQuery('.os-wizard-default-agent-form input').serialize();
5082
5083 var $form = $('.os-wizard-default-agent-form');
5084 var form_data = new FormData($form[0]);
5085 form_data.set('current_step_code', current_step_code);
5086
5087 if (('lp_intlTelInputGlobals' in window) && ('lp_intlTelInputUtils' in window)) {
5088 // Get e164 formatted number from phone fields when form is submitted
5089 $form.find('input.os-mask-phone').each(function () {
5090 let telInstance = window.lp_intlTelInputGlobals.getInstance(this);
5091 if(telInstance){
5092 const phoneInputName = this.getAttribute('name');
5093 const phoneInputValue = window.lp_intlTelInputGlobals.getInstance(this).getNumber(window.lp_intlTelInputUtils.numberFormat.E164);
5094 form_data.set(phoneInputName, phoneInputValue);
5095 }
5096 });
5097 }
5098 params = latepoint_formdata_to_url_encoded_string(form_data);
5099 }
5100
5101 var data = {
5102 action: latepoint_helper.route_action,
5103 route_name: jQuery(this).data('route-name'),
5104 params: params,
5105 layout: 'none',
5106 return_format: 'json'};
5107 jQuery.ajax({
5108 type : "post",
5109 dataType : "json",
5110 url : latepoint_timestamped_ajaxurl(),
5111 data : data,
5112 success: function(data){
5113 $next_btn.removeClass('os-loading');
5114 if(data.status === "success"){
5115 jQuery('#wizard_current_step_code').val(data.step_code);
5116 jQuery('.os-wizard-setup-w').attr('class', 'os-wizard-setup-w step-' + data.step_code);
5117 jQuery('.os-wizard-step-content').html(data.message);
5118 latepoint_init_wizard_content();
5119 if(data.show_prev_btn){
5120 jQuery('.os-wizard-prev-btn').show();
5121 }else{
5122 jQuery('.os-wizard-prev-btn').hide();
5123 }
5124 if(data.show_next_btn){
5125 jQuery('.os-wizard-next-btn').show();
5126 }else{
5127 jQuery('.os-wizard-next-btn').hide();
5128 }
5129 if(!data.show_next_btn && !data.show_prev_btn){
5130 jQuery('.os-wizard-footer').hide();
5131 }else{
5132 jQuery('.os-wizard-footer').show();
5133 }
5134 }
5135 }
5136 });
5137 return false;
5138 });
5139
5140 // WIZARD PREV BUTTON CLICK LOGIC
5141 jQuery('body.latepoint').on('click', '.os-wizard-trigger-prev-btn', function(){
5142 var $prev_btn = jQuery(this);
5143 $prev_btn.addClass('os-loading');
5144 var current_step_code = jQuery('#wizard_current_step_code').val();
5145 var params = 'current_step_code='+current_step_code;
5146 var data = { action: latepoint_helper.route_action, route_name: jQuery(this).data('route-name'), params: params, layout: 'none', return_format: 'json'};
5147 jQuery.ajax({
5148 type : "post",
5149 dataType : "json",
5150 url : latepoint_timestamped_ajaxurl(),
5151 data : data,
5152 success: function(data){
5153 $prev_btn.removeClass('os-loading');
5154 if(data.status === "success"){
5155 jQuery('#wizard_current_step_code').val(data.step_code);
5156 jQuery('.os-wizard-setup-w').attr('class', 'os-wizard-setup-w step-' + data.step_code);
5157 jQuery('.os-wizard-step-content').html(data.message);
5158 latepoint_init_wizard_content();
5159 if(data.show_prev_btn){
5160 jQuery('.os-wizard-prev-btn').show();
5161 }else{
5162 jQuery('.os-wizard-prev-btn').hide();
5163 }
5164 if(data.show_next_btn){
5165 jQuery('.os-wizard-next-btn').show();
5166 }else{
5167 jQuery('.os-wizard-next-btn').hide();
5168 }
5169 if(!data.show_next_btn && !data.show_prev_btn){
5170 jQuery('.os-wizard-footer').hide();
5171 }else{
5172 jQuery('.os-wizard-footer').show();
5173 }
5174 }
5175 }
5176 });
5177 return false;
5178 });
5179
5180 jQuery('.latepoint-content-w').on('change', '.os-widget .os-trigger-reload-widget', function(){
5181 latepoint_reload_widget(jQuery(this).closest('.os-widget'));
5182 });
5183
5184 jQuery('.latepoint-content-w').on('click', '.os-widget .timeline-type-toggle .timeline-type-option', function(){
5185 jQuery(this).closest('.timeline-type-toggle').find('.timeline-type-option.active').removeClass('active');
5186 jQuery(this).addClass('active');
5187 jQuery('.timeline-and-availability-contents').removeClass('shows-appointments shows-availability').addClass('shows-' + jQuery(this).data('value'));
5188 jQuery('#' + jQuery(this).closest('.timeline-type-toggle').data('value-holder-id')).val(jQuery(this).data('value'));
5189 });
5190
5191
5192 dragula([].slice.apply(document.querySelectorAll('.os-categories-ordering-w .os-category-children')), {
5193 moves: function (el, container, handle) {
5194 return (handle.classList.contains('os-category-drag') || handle.classList.contains('os-category-item-drag'));
5195 },
5196 }).on('drop', function(el){
5197 var $categories_wrapper = jQuery('.os-categories-ordering-w');
5198 var category_datas = [];
5199 var item_datas = [];
5200
5201 $categories_wrapper.find('.os-category-parent-w').each(function(index){
5202 var order_number = jQuery(this).index() + 1;
5203 var parent_id = jQuery(this).parent().closest('.os-category-parent-w').data('id') || 0;
5204 category_datas.push({id: jQuery(this).data('id'), order_number: order_number, parent_id: parent_id});
5205 });
5206 $categories_wrapper.find('.item-in-category-w').each(function(index){
5207 var item_order_number = jQuery(this).index() + 1;
5208 var category_id = jQuery(this).closest('.os-category-parent-w').data('id') || 0;
5209 item_datas.push({id: jQuery(this).data('id'), order_number: item_order_number, category_id: category_id});
5210 });
5211 latepoint_recalculate_items_count_in_category();
5212 var data = { action: latepoint_helper.route_action, route_name: $categories_wrapper.data('category-order-update-route'), params: {category_datas: category_datas, item_datas: item_datas}, return_format: 'json' }
5213 $categories_wrapper.addClass('os-loading');
5214 jQuery.ajax({
5215 type : "post",
5216 dataType : "json",
5217 url : latepoint_timestamped_ajaxurl(),
5218 data : data,
5219 success: function(response){
5220 $categories_wrapper.removeClass('os-loading');
5221 if(response.status === "success"){
5222 // latepoint_add_notification(response.message);
5223 }else{
5224 alert(response.message);
5225 }
5226 }
5227 });
5228 });
5229
5230
5231 // Universal re-ordering dragging for form blocks
5232 dragula([jQuery('.os-draggable-form-blocks')[0]], {
5233 moves: function (el, container, handle) {
5234 return handle.classList.contains('os-form-block-drag');
5235 },
5236 }).on('drop', function(el){
5237 var blocks_order_data = {};
5238 var $draggable_form_blocks_wrapper = jQuery('.os-draggable-form-blocks');
5239 $draggable_form_blocks_wrapper.find('.os-form-block').each(function(index){
5240 var new_order_number = jQuery(this).index() + 1;
5241 var $block_model_id = jQuery(this).find('.os-form-block-id');
5242 if($block_model_id.length && $block_model_id.val()) blocks_order_data[$block_model_id.val()] = new_order_number;
5243 });
5244 var data = { action: latepoint_helper.route_action,
5245 route_name: $draggable_form_blocks_wrapper.data('order-update-route'),
5246 params: {ordered_fields: blocks_order_data,
5247 fields_for: $draggable_form_blocks_wrapper.data('fields-for')},
5248 return_format: 'json' }
5249 $draggable_form_blocks_wrapper.addClass('os-loading');
5250 jQuery.ajax({
5251 type : "post",
5252 dataType : "json",
5253 url : latepoint_timestamped_ajaxurl(),
5254 data : data,
5255 success: function(response){
5256 $draggable_form_blocks_wrapper.removeClass('os-loading');
5257 }
5258 });
5259 });
5260
5261
5262 jQuery('body.latepoint-admin').on('click', '.os-category-edit-btn, .os-category-edit-cancel-btn, .os-category-w .os-category-name', function(){
5263 jQuery(this).closest('.os-category-w').toggleClass('editing');
5264 return false;
5265 });
5266
5267 jQuery('body.latepoint-admin').on('click', '.step-edit-btn, .step-edit-cancel-btn, .step-w .step-head', function(){
5268 jQuery(this).closest('.step-w').toggleClass('editing');
5269 return false;
5270 });
5271
5272 jQuery('body.latepoint-admin').on('click', '.agent-info-change-agent-btn', function(){
5273 jQuery(this).closest('.agent-info-w').removeClass('selected').addClass('selecting');
5274 return false;
5275 });
5276
5277 jQuery('body.latepoint-admin').on('click', '.agent-info-change-agent-btn', function(){
5278 jQuery(this).closest('.agent-info-w').removeClass('selected').addClass('selecting');
5279 return false;
5280 });
5281
5282
5283 jQuery('body.latepoint-admin').on('click', '.customer-info-create-btn', function(){
5284 jQuery(this).closest('.customer-info-w').removeClass('selecting').addClass('selected');
5285 return false;
5286 });
5287
5288 jQuery('body.latepoint-admin').on('click', '.customer-info-load-btn', function(){
5289 jQuery(this).closest('.customer-info-w').removeClass('selected').addClass('selecting').find('.customers-selector-search-input').trigger('focus');
5290 return false;
5291 });
5292
5293 jQuery('body.latepoint-admin').on('click', '.customers-selector-cancel', function(){
5294 jQuery(this).closest('.customer-info-w').removeClass('selecting').addClass('selected ');
5295 jQuery('.customers-options-list .customer-option').show();
5296 jQuery('.customers-selector-search-input').val('');
5297 return false;
5298 });
5299
5300 // CUSTOMER SELECTOR
5301
5302 // SERVICES SELECTOR
5303 jQuery('body.latepoint-admin').on('click', '.service-option-selected', function(){
5304 var $select = jQuery(this).closest('.os-services-select-field-w');
5305 if($select.hasClass('active')){
5306 $select.removeClass('active');
5307 }else{
5308 $select.addClass('active').find('input').trigger('focus');
5309 }
5310 return false;
5311 });
5312
5313
5314 jQuery('body.latepoint-admin').on('keyup', '.service-options-filter-input', function(){
5315 var $list = jQuery(this).closest('.services-options-list');
5316 var text = jQuery(this).val().toLowerCase();
5317 $list.find('.service-option').hide();
5318
5319 // Search
5320 $list.find('.service-option').each(function(){
5321
5322 if(jQuery(this).text().toLowerCase().indexOf(""+text+"") != -1 ){
5323 jQuery(this).show();
5324 }
5325 });
5326 return false;
5327 });
5328
5329
5330 jQuery('.calendar-week-agent-w').on('click', '.calendar-load-target-date', function(event){
5331 jQuery(this).addClass('os-loading');
5332 latepoint_reload_week_view_calendar(jQuery(this).data('target-date'));
5333 return false;
5334 });
5335
5336 jQuery('.calendar-week-agent-w').on('change', '.cc-availability-toggler #overlay_service_availability', function(event){
5337 if(jQuery(this).val() == 'on'){
5338 jQuery('.calendar-week-agent-w .cc-service-selector').show();
5339 }else{
5340 jQuery('.calendar-week-agent-w .cc-service-selector').hide();
5341 }
5342 latepoint_reload_week_view_calendar();
5343 });
5344
5345
5346 jQuery('.calendar-week-agent-w').on('change', '.trigger-weekly-calendar-reload', function(event){
5347 latepoint_reload_week_view_calendar();
5348 return false;
5349 });
5350
5351 jQuery('.latepoint-admin').on('click', '.os-complex-connections-selector .selector-trigger', function(e){
5352 var $connection_wrapper = jQuery(this).closest('.connection');
5353 if($connection_wrapper.hasClass('active')){
5354 latepoint_complex_selector_deselect($connection_wrapper);
5355 jQuery(this).closest('.white-box').find('.os-select-all-toggler').prop('checked', false);
5356 }else{
5357 latepoint_complex_selector_select($connection_wrapper);
5358 }
5359 return false;
5360 });
5361
5362 jQuery('.latepoint-admin').on('click', '.os-complex-connections-selector .item-quantity-selector', function(e){
5363 let val = parseInt(jQuery(this).closest('.item-quantity-selector-w').find('.item-quantity-selector-input').val());
5364 if(jQuery(this).data('sign') == 'plus'){
5365 val = val + 1;
5366 }else{
5367 val = val - 1;
5368 }
5369 val = (val > 0) ? val : 0;
5370 jQuery(this).closest('.item-quantity-selector-w').find('.item-quantity-selector-input').val(val).trigger('change');
5371 return false;
5372 });
5373
5374 jQuery('.latepoint-admin').on('change', '.os-complex-connections-selector .item-quantity-selector-input', function(e){
5375 let $this = jQuery(this);
5376 let $connection_wrapper = jQuery(this).closest('.connection');
5377 if($this.val() > 0){
5378 latepoint_complex_selector_select($connection_wrapper, $this.val());
5379 }else{
5380 latepoint_complex_selector_deselect($connection_wrapper);
5381 }
5382 return false;
5383 });
5384
5385 jQuery('.latepoint-admin').on('click', '.os-agents-selector .agent', function(){
5386 if(jQuery(this).hasClass('active')){
5387 jQuery(this).removeClass('active');
5388 jQuery(this).find('.connection-child-is-connected').val('no');
5389 }else{
5390 jQuery(this).addClass('active');
5391 jQuery(this).find('.connection-child-is-connected').val('yes');
5392 }
5393 return false;
5394 });
5395
5396 jQuery('.latepoint-admin').on('click', '.os-services-selector .service', function(){
5397 if(jQuery(this).hasClass('active')){
5398 jQuery(this).removeClass('active');
5399 jQuery(this).find('.connection-child-is-connected').val('no');
5400 }else{
5401 jQuery(this).addClass('active');
5402 jQuery(this).find('.connection-child-is-connected').val('yes');
5403 }
5404 return false;
5405 });
5406
5407 jQuery('.latepoint-admin').on( 'click', '.os-form-toggler-group', function( event ){
5408 jQuery(this).find('.os-toggler').trigger('click');
5409 return false;
5410 });
5411
5412 jQuery('.latepoint-admin').on( 'click', '.os-toggler', function( event ){
5413 let $toggler = jQuery(this);
5414 if($toggler.data('confirm')){
5415 if(!confirm($toggler.data('confirm'))) return false;
5416 }
5417 if($toggler.hasClass('on')){
5418 $toggler.removeClass('on').addClass('off');
5419 }else{
5420 $toggler.removeClass('off').addClass('on');
5421 }
5422 if($toggler.data('for')){
5423 if($toggler.hasClass('os-toggler-radio')){
5424 // radio
5425 // uncheck all radio buttons with the same name
5426 let $radio = jQuery('#' + $toggler.data('for'));
5427 jQuery('input[type="radio"][name="'+ $radio.prop('name') + '"]:checked').each(function(index){
5428 let toggle_content_id = jQuery(this).prop('checked', false).closest('.os-toggler-w').find('.os-toggler.on').removeClass('on').addClass('off').data('controlled-toggle-id');
5429 jQuery('#'+ toggle_content_id).hide();
5430 });
5431 $radio.prop('checked', !$toggler.hasClass('off'));
5432 }else{
5433 var $hiddenInput = jQuery('input[type="hidden"]#' + $toggler.data('for'));
5434 if($hiddenInput.length){
5435 // hidden input
5436 if($toggler.data('is-string-value')){
5437 $hiddenInput.val($toggler.hasClass('off') ? 'off' : 'on').trigger('change');
5438 }else{
5439 $hiddenInput.val($toggler.hasClass('off') ? 0 : 1).trigger('change');
5440 }
5441
5442 if($toggler.data('os-instant-update')){
5443 let data = new FormData();
5444
5445 let params = $hiddenInput.serialize();
5446 if($toggler.data('nonce')) params+= '&_wpnonce='+$toggler.data('nonce');
5447 data.append('params', params);
5448 data.append('action', latepoint_helper.route_action);
5449 data.append('route_name', $toggler.data('os-instant-update'));
5450 data.append('return_format', 'json');
5451
5452 jQuery.ajax({
5453 type: "post",
5454 dataType: "json",
5455 processData: false,
5456 contentType: false,
5457 url: latepoint_timestamped_ajaxurl(),
5458 data: data,
5459 success: function (response) {
5460
5461 }
5462 });
5463 }
5464 }else{
5465 // checkbox
5466 jQuery('#' + $toggler.data('for')).prop('checked', !$toggler.hasClass('off'));
5467 }
5468 }
5469 }
5470 if($toggler.data('controlled-toggle-id')){
5471 if($toggler.hasClass('off')){
5472 jQuery('#' + $toggler.data('controlled-toggle-id')).hide();
5473 }else{
5474 jQuery('#' + $toggler.data('controlled-toggle-id')).show();
5475 }
5476 }
5477 if($toggler.data('negative-controlled-toggle-id')){
5478 if($toggler.hasClass('off')){
5479 jQuery('#' + $toggler.data('negative-controlled-toggle-id')).show();
5480 }else{
5481 jQuery('#' + $toggler.data('negative-controlled-toggle-id')).hide();
5482 }
5483 }
5484 $toggler.trigger('ostoggler:toggle');
5485 return false;
5486 });
5487
5488
5489
5490 // UPLOAD/REMOVE IMAGE LINK LOGIC
5491 jQuery('.latepoint-admin').on( 'click', '.os-image-selector-trigger', function( event ){
5492 var frame;
5493
5494 event.preventDefault();
5495
5496 var $image_uploader_trigger = jQuery(this);
5497 var $image_selector_w = jQuery(this).closest('.os-image-selector-w');
5498 var $image_container = $image_selector_w.find('.os-image-container');
5499 var $image_id_holder = $image_selector_w.find('.os-image-id-holder');
5500
5501 let is_avatar = $image_selector_w.hasClass('is-avatar');
5502
5503 var image_exists = is_avatar ? $image_container.find('.image-self').length : $image_container.find('img').length;
5504
5505 if(image_exists){
5506 $image_id_holder.val('');
5507 $image_selector_w.removeClass('has-image');
5508 $image_container.html('');
5509 $image_uploader_trigger.find('.os-text-holder').text($image_uploader_trigger.data('label-set-str'));
5510 }else{
5511 // If the media frame already exists, reopen it.
5512 if ( frame ) {
5513 frame.open();
5514 return false;
5515 }
5516
5517 // Create a new media frame
5518 frame = wp.media({
5519 title: 'Select or Upload Media',
5520 button: { text: 'Use this media' },
5521 multiple: false
5522 });
5523
5524 frame.on( 'select', function() {
5525 var attachment = frame.state().get('selection').first().toJSON();
5526 if(is_avatar){
5527 $image_container.html( '<div class="image-self" style="background-image: url('+attachment.url+')"></div>' );
5528 }else{
5529 $image_container.html( '<img src="'+attachment.url+'" alt=""/>' );
5530 }
5531 $image_id_holder.val( attachment.id );
5532 $image_selector_w.addClass('has-image');
5533 $image_uploader_trigger.find('.os-text-holder').text($image_uploader_trigger.data('label-remove-str'));
5534 });
5535
5536 frame.open();
5537 }
5538
5539 return false;
5540 });
5541
5542
5543 jQuery('.latepoint-admin').on('click', '.os-multiple-files-uploader a', function(event) {
5544 event.stopPropagation();
5545 });
5546
5547 jQuery('.latepoint-admin').on('click', '.os-multiple-files-uploader', function(event) {
5548 var frame;
5549 event.preventDefault();
5550
5551 var $uploader_trigger = jQuery(this);
5552 var $uploader_wrapper = $uploader_trigger.closest('.os-multiple-files-uploader');
5553 var $files_list = $uploader_wrapper.find('.os-uploaded-files-list');
5554 var $file_ids_holder = $uploader_wrapper.find('.os-file-ids-holder');
5555
5556 // Create a new media frame
5557 frame = wp.media({
5558 title: 'Select or Upload Files',
5559 button: { text: 'Add selected files' },
5560 multiple: 'add' // Allows to select multiple files
5561 });
5562
5563 // When files are selected...
5564 frame.on('select', function() {
5565 var attachments = frame.state().get('selection').map(function(attachment) {
5566 attachment = attachment.toJSON();
5567 return attachment;
5568 });
5569
5570 var current_ids = $file_ids_holder.val() ? $file_ids_holder.val().split(',') : [];
5571
5572 attachments.forEach(function(attachment) {
5573 // Skip if file already added
5574 if(current_ids.indexOf(attachment.id.toString()) !== -1) return;
5575
5576 // Add to IDs list
5577 current_ids.push(attachment.id);
5578
5579 // Add to files list
5580 var $file_item = jQuery('<div class="os-uploaded-file" data-file-id="'+attachment.id+'">');
5581 $file_item.append('<a class="os-file-link" href="'+attachment.url+'" target="_blank">'+attachment.filename+'</a>');
5582 $file_item.append('<a href="#" class="os-remove-file" title="'+$uploader_trigger.data('label-remove-str')+'"><i class="latepoint-icon latepoint-icon-cross"></i></a>');
5583 $files_list.append($file_item);
5584 });
5585
5586 // Update hidden field with all IDs
5587 $file_ids_holder.val(current_ids.join(','));
5588 });
5589
5590 frame.open();
5591 return false;
5592 });
5593
5594 jQuery('.latepoint-admin').on('click', '.os-remove-file', function(event) {
5595 event.preventDefault();
5596
5597 let $remove_btn = jQuery(this);
5598 const confirm_text = $remove_btn.closest('.os-uploaded-files-list').data('confirm-text') || 'Are you sure you want to remove this file?';
5599 if (confirm(confirm_text)) {
5600 let $file_item = $remove_btn.closest('.os-uploaded-file');
5601 let $file_ids_holder = $file_item.closest('.os-multiple-files-uploader').find('.os-file-ids-holder');
5602
5603 let file_id = $file_item.data('file-id');
5604 let current_ids = $file_ids_holder.val() ? $file_ids_holder.val().split(',') : [];
5605
5606 current_ids = current_ids.filter(function(id) {
5607 return id != file_id;
5608 });
5609
5610 $file_ids_holder.val(current_ids.join(','));
5611 $file_item.remove();
5612 }
5613 });
5614
5615
5616
5617 jQuery('body').on('click', '.latepoint-lightbox-close', function(){
5618 latepoint_lightbox_close();
5619 return false;
5620 });
5621
5622
5623 jQuery('body').on('click', '.latepoint-side-panel-close-trigger', function(){
5624 latepoint_close_side_panel();
5625 return false;
5626 });
5627 jQuery('body').on('click', '.latepoint-side-sub-panel-close-trigger', function(){
5628 jQuery(this).closest('.side-sub-panel-wrapper').remove();
5629 return false;
5630 });
5631
5632
5633
5634 jQuery('body.latepoint-admin').on('click', '.time-ampm-select', function(){
5635 let $form = jQuery(this).closest('.order-item-booking-data-form-wrapper');
5636 jQuery(this).closest('.time-ampm-w').find('.active').removeClass('active');
5637 jQuery(this).addClass('active');
5638 var ampm_value = jQuery(this).data('ampm-value');
5639 jQuery(this).closest('.os-time-group').find('.ampm-value-hidden-holder').val(ampm_value);
5640 if(jQuery(this).closest('.quick-start-time-w').length){
5641 // if called from quick edit form - we need to make sure it accurately changes time to next day if end time is earlier than start time
5642 latepoint_set_booking_end_time($form);
5643 latepoint_is_next_day($form);
5644 }
5645 if(jQuery(this).closest('.quick-end-time-w').length){
5646 latepoint_is_next_day($form);
5647 }
5648 return false;
5649 });
5650
5651
5652 jQuery('body.latepoint-admin').on('click', '.latepoint-lightbox-shadow', function(){
5653 latepoint_lightbox_close();
5654 return false;
5655 });
5656
5657 jQuery('body.latepoint-admin').on('click', '.latepoint-side-panel-shadow', function(){
5658 jQuery('.latepoint-side-panel-w').remove();
5659 return false;
5660 });
5661
5662 // SCHEDULE
5663
5664 jQuery('body.latepoint-admin').on('click', '.ws-period-remove', function(e){
5665 jQuery(this).closest('.ws-period').remove();
5666 return false;
5667 });
5668
5669
5670 jQuery('.latepoint-admin').on( 'click', '.weekday-schedule-w .os-toggler', function( event ){
5671 if(jQuery(this).hasClass('off')){
5672 jQuery(this).closest('.weekday-schedule-w').addClass('day-off').removeClass('is-editing').find('input.is-active').val(0);
5673 }else{
5674 jQuery(this).closest('.weekday-schedule-w').removeClass('day-off').addClass('is-editing').find('input.is-active').val(1);
5675 }
5676 return false;
5677 });
5678
5679
5680
5681 });