PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.1.3
LatePoint – Calendar Booking Plugin for Appointments and Events v5.1.3
5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / assets / javascripts / bin / admin / _steps.js
latepoint / lib / assets / javascripts / bin / admin Last commit date
_agents.js 1 year ago _calendar.js 1 year ago _chart.js 1 year ago _customers.js 1 year ago _orders.js 1 year ago _processes.js 1 year ago _steps.js 1 year ago _stripe_connect.js 1 year ago main.js 1 year ago updates.js 1 year ago
_steps.js
439 lines
1 /*
2 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
3 */
4
5
6 function latepoint_preview_init_step_category_items(step_code){
7 jQuery('.booking-form-preview .os-item-category-info').on('click', function(){
8 var $booking_form_element = jQuery(this).closest('.booking-form-preview');
9 jQuery(this).closest('.latepoint-step-content').addClass('selecting-item-category');
10 var $category_wrapper = jQuery(this).closest('.os-item-category-w');
11 var $main_parent = jQuery(this).closest('.os-item-categories-main-parent');
12 if($category_wrapper.hasClass('selected')){
13 $category_wrapper.removeClass('selected');
14 if($category_wrapper.parent().closest('.os-item-category-w').length){
15 $category_wrapper.parent().closest('.os-item-category-w').addClass('selected');
16 }else{
17 $main_parent.removeClass('show-selected-only');
18 }
19 }else{
20 $main_parent.find('.os-item-category-w.selected').removeClass('selected');
21 $main_parent.addClass('show-selected-only');
22 $category_wrapper.addClass('selected');
23 }
24 return false;
25 });
26 }
27
28 function latepoint_booking_form_discard_changes(){
29
30 let form_data = new FormData(jQuery('.booking-form-preview-settings')[0]);
31
32 var data = {
33 action: latepoint_helper.route_action,
34 route_name: jQuery('.booking-form-preview-settings').data('route-name'),
35 params: latepoint_formdata_to_url_encoded_string(form_data),
36 layout: 'none',
37 return_format: 'json'
38 }
39
40 jQuery.ajax({
41 type : "post",
42 dataType : "json",
43 url : latepoint_timestamped_ajaxurl(),
44 data : data,
45 success: function(data){
46 if(data.status === "success"){
47 jQuery('.booking-form-preview-inner').html(data.booking_form_html);
48 latepoint_init_booking_form_preview();
49 }else{
50 latepoint_add_notification(data.message, 'error');
51 }
52 }
53 });
54 }
55
56 function latepoint_booking_form_save_changes(){
57
58 let form_data = new FormData(jQuery('.booking-form-preview-settings')[0]);
59
60 jQuery('.editable-setting').each(function(){
61 form_data.set('steps_settings' + jQuery(this).data('setting-key'), jQuery(this).html());
62 });
63
64
65 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());
66
67
68 var data = {
69 action: latepoint_helper.route_action,
70 route_name: jQuery('.booking-form-preview-settings').data('route-name'),
71 params: latepoint_formdata_to_url_encoded_string(form_data),
72 layout: 'none',
73 return_format: 'json'
74 }
75
76 jQuery.ajax({
77 type : "post",
78 dataType : "json",
79 url : latepoint_timestamped_ajaxurl(),
80 data : data,
81 success: function(data){
82 jQuery('.booking-form-preview-settings').removeClass('os-loading');
83 if(data.status === "success"){
84 jQuery('.bf-preview-step-settings').html(data.step_settings_html);
85 jQuery('.booking-form-preview-inner').html(data.booking_form_html);
86 jQuery('#latepoint-main-admin-inline-css').html(data.css_variables);
87 latepoint_init_booking_form_preview();
88 }else{
89 latepoint_add_notification(data.message, 'error');
90 }
91 }
92 });
93 }
94
95 function latepoint_init_booking_form_preview(){
96
97 latepoint_preview_init_step_category_items();
98 latepoint_booking_form_preview_init_datepicker();
99
100
101 jQuery('.booking-form-preview-wrapper').on('click', '.os-step-tab', function(){
102 jQuery(this).closest('.os-step-tabs').find('.os-step-tab').removeClass('active');
103 jQuery(this).addClass('active');
104 var target = jQuery(this).data('target');
105 jQuery(this).closest('.os-step-tabs-w').find('.os-step-tab-content').hide();
106 jQuery(target).show();
107 });
108
109
110 jQuery('.bf-save-btn').on('click', function(){
111 jQuery(this).addClass('os-loading');
112 latepoint_booking_form_save_changes();
113 return false;
114 });
115
116 jQuery('.bf-cancel-save-btn').on('click', function(){
117 jQuery(this).addClass('os-loading');
118 latepoint_booking_form_discard_changes();
119 return false;
120 });
121
122
123 jQuery('.booking-form-preview .bf-next-btn').on('click', function(){
124 jQuery(this).addClass('os-loading');
125 jQuery("#selected_step_code > option:selected")
126 .prop("selected", false)
127 .next()
128 .prop("selected", true).trigger('change');
129 });
130
131 jQuery('.booking-form-preview .bf-prev-btn').on('click', function(){
132 jQuery(this).addClass('os-loading');
133 jQuery("#selected_step_code > option:selected")
134 .prop("selected", false)
135 .prev()
136 .prop("selected", true).trigger('change');
137 });
138
139
140 jQuery('.booking-form-preview .os-image-selector-trigger').on('click', function(){
141 jQuery('.booking-form-preview').addClass('has-changes');
142 });
143
144 jQuery('.booking-form-preview .editable-setting').on('focus', function(){
145 jQuery('.booking-form-preview').addClass('has-changes');
146 });
147
148
149 let editor = new MediumEditor('.booking-form-preview .os-editable', {toolbar: {
150 buttons: [
151 {
152 name: 'bold',
153 classList: ['latepoint-icon', 'latepoint-icon-format_bold'],
154 },
155 {
156 name: 'anchor',
157 classList: ['latepoint-icon', 'latepoint-icon-format_link'],
158 },
159 {
160 name: 'h3',
161 classList: ['latepoint-icon', 'latepoint-icon-format_h3'],
162 },
163 {
164 name: 'h4',
165 classList: ['latepoint-icon', 'latepoint-icon-format_h4'],
166 },
167 {
168 name: 'h5',
169 classList: ['latepoint-icon', 'latepoint-icon-format_h5'],
170 },
171
172 ]
173 }
174 });
175 let editor_basic = new MediumEditor('.booking-form-preview .os-editable-basic', {toolbar: {
176 buttons: [
177 {
178 name: 'bold',
179 classList: ['latepoint-icon', 'latepoint-icon-format_bold'],
180 },
181 {
182 name: 'italic',
183 classList: ['latepoint-icon', 'latepoint-icon-format_italic'],
184 },
185 {
186 name: 'underline',
187 classList: ['latepoint-icon', 'latepoint-icon-format_underlined'],
188 },
189 {
190 name: 'anchor',
191 classList: ['latepoint-icon', 'latepoint-icon-format_link'],
192 },
193
194 ]
195 }
196 });
197 }
198
199 function latepoint_reload_booking_form_preview(){
200 latepoint_booking_form_save_changes();
201 }
202
203 function latepoint_init_steps_settings(){
204
205 jQuery('.booking-form-preview-settings').on('change', ' select, input[type="hidden"]', function(){
206 jQuery('.booking-form-preview-settings').addClass('os-loading');
207 latepoint_reload_booking_form_preview();
208 });
209
210 jQuery('.trigger-custom-color-save').on('click', function(){
211 jQuery('.booking-form-preview-settings').addClass('os-loading');
212 latepoint_booking_form_save_changes();
213 return false;
214 });
215
216 jQuery('.bf-color-scheme-color-trigger').on('click', function(){
217 jQuery('.bf-color-scheme-color-trigger.is-selected').removeClass('is-selected');
218 jQuery(this).addClass('is-selected');
219 let color_scheme = jQuery(this).data('color-code');
220 jQuery('.os-color-scheme-selector-wrapper select').val(color_scheme).trigger('change');
221 if(color_scheme == 'custom'){
222 jQuery('.os-custom-color-selector-wrapper').removeClass('is-hidden');
223 }else{
224 jQuery('.os-custom-color-selector-wrapper').addClass('is-hidden');
225 }
226 return false;
227 });
228
229 jQuery('.os-section-collapsible-trigger').on('click', function(){
230 jQuery(this).closest('.os-section-collapsible-wrapper').toggleClass('is-open');
231 return false;
232 })
233 }
234
235
236 function latepoint_booking_form_preview_init_timeslots($booking_form_element = false){
237 if(!$booking_form_element) return;
238 $booking_form_element.on('click', '.dp-timepicker-trigger', function(){
239 if(jQuery(this).hasClass('is-booked') || jQuery(this).hasClass('is-off')){
240 // Show error message that you cant select a booked period
241 }else{
242 if(jQuery(this).hasClass('selected')){
243 jQuery(this).removeClass('selected');
244 jQuery(this).find('.dp-success-label').remove();
245 }else{
246 $booking_form_element.find('.dp-timepicker-trigger.selected').removeClass('selected').find('.dp-success-label').remove();
247 var selected_timeslot_time = jQuery(this).find('.dp-label-time').html();
248 jQuery(this).addClass('selected').find('.dp-label').prepend('<span class="dp-success-label">' + latepoint_helper.datepicker_timeslot_selected_label + '</span>');
249
250 var minutes = parseInt(jQuery(this).data('minutes'));
251 var timeshift_minutes = parseInt($booking_form_element.find('.latepoint_timeshift_minutes').val());
252 // we substract timeshift minutes because its timeshift minutes that the business is running in, in opposite of what we do when we generate a calendar for a client
253 if(timeshift_minutes) minutes = minutes - timeshift_minutes;
254 var start_date = new Date($booking_form_element.find('.os-day.selected').data('date'));
255 if(minutes < 0){
256 // business minutes are in previous day
257 minutes = 24*60 + minutes;
258 // move start date back 1 day
259 start_date.setDate(start_date.getDate() - 1);
260 }else if(minutes >= 24*60){
261 // business minutes are in next day
262 minutes = minutes - 24*60;
263 start_date.setDate(start_date.getDate() + 1);
264 }
265 $booking_form_element.find('.latepoint_start_date').val(start_date.toISOString().split('T')[0])
266 latepoint_trigger_next_btn($booking_form_element);
267 }
268 }
269 return false;
270 });
271 }
272
273
274 function latepoint_booking_form_preview_day_timeslots($day){
275 let $wrapper_element = jQuery('.booking-form-preview');
276 $day.addClass('selected');
277
278 var service_duration = $day.data('service-duration');
279 var interval = $day.data('interval');
280 var work_start_minutes = $day.data('work-start-time');
281 var work_end_minutes = $day.data('work-end-time');
282 var total_work_minutes = $day.data('total-work-minutes');
283 var bookable_minutes = [];
284 var available_capacities_of_bookable_minute = [];
285 if($day.attr('data-bookable-minutes')){
286 if($day.data('bookable-minutes').toString().indexOf(':') > -1){
287 // has capacity information embedded into bookable minutes string
288 let bookable_minutes_with_capacity = $day.data('bookable-minutes').toString().split(',');
289 for(let i = 0; i < bookable_minutes_with_capacity.length; i++){
290 bookable_minutes.push(parseInt(bookable_minutes_with_capacity[i].split(':')[0]));
291 available_capacities_of_bookable_minute.push(parseInt(bookable_minutes_with_capacity[i].split(':')[1]));
292 }
293 }else{
294 bookable_minutes = $day.data('bookable-minutes').toString().split(',').map(Number);
295 }
296 }
297 var work_minutes = $day.data('work-minutes').toString().split(',').map(Number);
298
299 var $timeslots = $wrapper_element.find('.timeslots');
300 $timeslots.html('');
301
302 if(total_work_minutes > 0 && bookable_minutes.length && work_minutes.length){
303 var prev_minutes = false;
304 work_minutes.forEach(function(current_minutes){
305 var ampm = latepoint_am_or_pm(current_minutes);
306
307 var timeslot_class = 'dp-timepicker-trigger';
308 var timeslot_available_capacity = 0;
309 if($wrapper_element.find('.os-dates-w').data('time-pick-style') == 'timeline'){
310 timeslot_class+= ' dp-timeslot';
311 }else{
312 timeslot_class+= ' dp-timebox';
313 }
314
315 if(prev_minutes !== false && ((current_minutes - prev_minutes) > service_duration)){
316 // show interval that is off between two work periods
317 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);
318 var off_width = (((current_minutes - prev_minutes - service_duration) / total_work_minutes) * 100);
319 $timeslots.append('<div class="'+ timeslot_class +' is-off" style="max-width:'+ off_width +'%; width:'+ off_width +'%"><span class="dp-label">' + off_label + '</span></div>');
320 }
321
322 if(!bookable_minutes.includes(current_minutes)){
323 timeslot_class+= ' is-booked';
324 }else{
325 if(available_capacities_of_bookable_minute.length) timeslot_available_capacity = available_capacities_of_bookable_minute[bookable_minutes.indexOf(current_minutes)];
326 }
327 var tick_html = '';
328 var capacity_label = '';
329 var capacity_label_html = '';
330 var capacity_internal_label_html = '';
331
332 if(((current_minutes % 60) == 0) || (interval >= 60)){
333 timeslot_class+= ' with-tick';
334 tick_html = '<span class="dp-tick"><strong>'+latepoint_minutes_to_hours_preferably(current_minutes)+'</strong>'+' '+ampm+'</span>';
335 }
336 var timeslot_label = latepoint_minutes_to_hours_and_minutes(current_minutes)+' '+ampm;
337 if(latepoint_show_booking_end_time()){
338 var end_minutes = current_minutes + service_duration;
339 if(end_minutes > 1440) end_minutes = end_minutes - 1440;
340 var end_minutes_ampm = latepoint_am_or_pm(end_minutes);
341 timeslot_label+= ' - <span class="dp-label-end-time">' + latepoint_minutes_to_hours_and_minutes(end_minutes)+' '+end_minutes_ampm + '</span>';
342 }
343 if(timeslot_available_capacity){
344 var spaces_message = timeslot_available_capacity > 1 ? latepoint_helper.many_spaces_message : latepoint_helper.single_space_message;
345 capacity_label = timeslot_available_capacity + ' ' + spaces_message;
346 capacity_label_html = '<span class="dp-capacity">' + capacity_label + '</span>';
347 capacity_internal_label_html = '<span class="dp-label-capacity">' + capacity_label + '</span>';
348 }
349 timeslot_label = timeslot_label.trim();
350 $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>');
351 prev_minutes = current_minutes;
352 });
353 }else{
354 // No working hours this day
355 $timeslots.addClass('slots-not-available').append('<div class="not-working-message">' + latepoint_helper.msg_not_available + "</div>");
356 }
357 jQuery('.times-header-label span').text($day.data('nice-date'));
358 $wrapper_element.find('.time-selector-w').slideDown(200);
359 }
360
361 function latepoint_booking_form_preview_init_monthly_calendar_navigation($booking_form_element){
362
363 if(!$booking_form_element) return;
364 $booking_form_element.on('click', '.os-month-next-btn', function(){
365 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
366 var next_month_route_name = jQuery(this).data('route');
367 if($booking_form_element.find('.os-monthly-calendar-days-w.active + .os-monthly-calendar-days-w').length){
368 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').next('.os-monthly-calendar-days-w').addClass('active');
369 latepoint_booking_form_preview_calendar_set_month_label($booking_form_element);
370 }else{
371 alert('Disabled in preview');
372 }
373 latepoint_calendar_show_or_hide_prev_next_buttons($booking_form_element);
374 return false;
375 });
376 $booking_form_element.on('click', '.os-month-prev-btn', function(){
377 var $booking_form_element = jQuery(this).closest('.latepoint-booking-form-element');
378 if($booking_form_element.find('.os-monthly-calendar-days-w.active').prev('.os-monthly-calendar-days-w').length){
379 $booking_form_element.find('.os-monthly-calendar-days-w.active').removeClass('active').prev('.os-monthly-calendar-days-w').addClass('active');
380 latepoint_booking_form_preview_calendar_set_month_label($booking_form_element);
381 }
382 return false;
383 });
384 }
385
386
387 function latepoint_booking_form_preview_calendar_set_month_label(){
388 jQuery('.os-current-month-label .current-month').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-month-label'));
389 jQuery('.os-current-month-label .current-year').text(jQuery('.os-monthly-calendar-days-w.active').data('calendar-year'));
390 }
391
392
393
394 function latepoint_booking_form_preview_init_datepicker(){
395 let $booking_form_element = jQuery('.latepoint-booking-form-element');
396 latepoint_booking_form_preview_init_timeslots($booking_form_element);
397 latepoint_booking_form_preview_init_monthly_calendar_navigation($booking_form_element);
398 $booking_form_element.on('click', '.os-months .os-day', function(){
399 if(jQuery(this).hasClass('os-day-passed')) return false;
400 if(jQuery(this).hasClass('os-not-in-allowed-period')) return false;
401 if(jQuery(this).closest('.os-monthly-calendar-days-w').hasClass('hide-if-single-slot')){
402
403 // HIDE TIMESLOT IF ONLY ONE TIMEPOINT
404 if(jQuery(this).hasClass('os-not-available')){
405 // clicked on a day that has no available timeslots
406 // do nothing
407 }else{
408 $booking_form_element.find('.os-day.selected').removeClass('selected');
409 jQuery(this).addClass('selected');
410 // set date
411 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date'));
412 if(jQuery(this).hasClass('os-one-slot-only')){
413 // clicked on a day that has only one slot available
414 var bookable_minutes = jQuery(this).data('bookable-minutes').toString().split(':')[0];
415 var selected_timeslot_time = latepoint_format_minutes_to_time(Number(bookable_minutes), Number(jQuery(this).data('service-duration')));
416 $booking_form_element.find('.time-selector-w').slideUp(200);
417 }else{
418 // regular day with more than 1 timeslots available
419 // build timeslots
420 latepoint_booking_form_preview_day_timeslots(jQuery(this));
421 // clear time and hide next btn
422 }
423 }
424 }else{
425 // SHOW TIMESLOTS EVEN IF ONLY ONE TIMEPOINT
426 $booking_form_element.find('.latepoint_start_date').val(jQuery(this).data('date'));
427 $booking_form_element.find('.os-day.selected').removeClass('selected');
428 jQuery(this).addClass('selected');
429
430 // build timeslots
431 latepoint_booking_form_preview_day_timeslots(jQuery(this));
432 // clear time and hide next btn
433 }
434
435
436 return false;
437 });
438 }
439