1(function ($) { 2 window.booklyStaffAppointments = function (Options) { 3 let $container = $('.bookly-staff-cabinet-appointments.' + Options.wrapper); 4 if (!$container.length) { 5 return; 6 } 7 let $list = $('.bookly-js-appointments-list', $container), 8 $customerFilter = $('#bookly-filter-customer', $container), 9 $idFilter = $('#bookly-filter-id', $container), 10 $appointmentDateFilter = $('#bookly-filter-date', $container), 11 $creationDateFilter = $('#bookly-filter-creation-date', $container), 12 $statusFilter = $('#bookly-filter-status', $container), 13 $serviceFilter = $('#bookly-filter-service', $container), 14 $locationFilter = $('#bookly-filter-location', $container), 15 $newAppointmentBtn = $('#bookly-new-appointment', $container), 16 isMobile = false, 17 columns = [], 18 order = [], 19 pickers = { 20 dateFormat: 'YYYY-MM-DD', 21 appointmentDate: { 22 startDate: moment().startOf('month'), 23 endDate: moment().endOf('month'), 24 }, 25 creationDate: { 26 startDate: moment(), 27 endDate: moment().add(100, 'years'), 28 }, 29 } 30 ; 31 32 try { 33 document.createEvent('TouchEvent'); 34 isMobile = true; 35 } catch (e) {} 36 37 function onChangeFilter() { 38 dt.ajax.reload(); 39 } 40 41 $statusFilter.booklyDropdown({onChange: onChangeFilter}); 42 43 $('.bookly-js-select', $container).val(null); 44 45 $.each(BooklySCAppointmentsL10n.datatables.appointments.settings.filter, function (field, value) { 46 if (field !== 'status') { 47 if (value != '') { 48 $('#bookly-filter-' + field, $container).val(value); 49 } 50 // check if select has correct values 51 if ($('#bookly-filter-' + field, $container).prop('type') == 'select-one') { 52 if ($('#bookly-filter-' + field + ' option[value="' + value + '"]', $container).length == 0) { 53 $('#bookly-filter-' + field, $container).val(null); 54 } 55 } 56 } 57 }); 58 59 if (BooklySCAppointmentsL10n.datatables.appointments.settings.filter.hasOwnProperty('status')) { 60 $statusFilter.booklyDropdown('setSelected', BooklySCAppointmentsL10n.datatables.appointments.settings.filter.status); 61 } else { 62 $statusFilter.booklyDropdown('selectAll'); 63 } 64 65 /** 66 * Init date range pickers. 67 */ 68 69 let 70 pickerRanges1 = {}, 71 pickerRanges2 = {} 72 ; 73 pickerRanges1[BooklySCAppointmentsL10n.dateRange.anyTime] = [moment().subtract(100, 'years'), moment().add(100, 'years')]; 74 pickerRanges1[BooklySCAppointmentsL10n.dateRange.yesterday] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')]; 75 pickerRanges1[BooklySCAppointmentsL10n.dateRange.today] = [moment(), moment()]; 76 pickerRanges1[BooklySCAppointmentsL10n.dateRange.tomorrow] = [moment().add(1, 'days'), moment().add(1, 'days')]; 77 pickerRanges1[BooklySCAppointmentsL10n.dateRange.last_7] = [moment().subtract(7, 'days'), moment()]; 78 pickerRanges1[BooklySCAppointmentsL10n.dateRange.last_30] = [moment().subtract(30, 'days'), moment()]; 79 pickerRanges1[BooklySCAppointmentsL10n.dateRange.next_7] = [moment(), moment().add(7, 'days')]; 80 pickerRanges1[BooklySCAppointmentsL10n.dateRange.next_30] = [moment(), moment().add(30, 'days')]; 81 pickerRanges1[BooklySCAppointmentsL10n.dateRange.thisMonth] = [moment().startOf('month'), moment().endOf('month')]; 82 pickerRanges1[BooklySCAppointmentsL10n.dateRange.nextMonth] = [moment().add(1, 'month').startOf('month'), moment().add(1, 'month').endOf('month')]; 83 84 pickerRanges2[BooklySCAppointmentsL10n.dateRange.anyTime] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.anyTime]; 85 pickerRanges2[BooklySCAppointmentsL10n.dateRange.yesterday] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.yesterday]; 86 pickerRanges2[BooklySCAppointmentsL10n.dateRange.today] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.today]; 87 pickerRanges2[BooklySCAppointmentsL10n.dateRange.last_7] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.last_7]; 88 pickerRanges2[BooklySCAppointmentsL10n.dateRange.last_30] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.last_30]; 89 pickerRanges2[BooklySCAppointmentsL10n.dateRange.thisMonth] = pickerRanges1[BooklySCAppointmentsL10n.dateRange.thisMonth]; 90 91 if (BooklySCAppointmentsL10n.tasks.enabled) { 92 pickerRanges1[BooklySCAppointmentsL10n.tasks.title] = [moment(), moment().add(1, 'days')]; 93 } 94 95 $appointmentDateFilter.daterangepicker( 96 { 97 parentEl: $appointmentDateFilter.parent(), 98 startDate: pickers.appointmentDate.startDate, 99 endDate: pickers.appointmentDate.endDate, 100 ranges: pickerRanges1, 101 showDropdowns: true, 102 linkedCalendars: false, 103 autoUpdateInput: false, 104 locale: $.extend({}, BooklySCAppointmentsL10n.dateRange, BooklySCAppointmentsL10n.datePicker) 105 }, 106 function (start, end, label) { 107 switch (label) { 108 case BooklySCAppointmentsL10n.tasks.title: 109 $appointmentDateFilter 110 .data('date', 'null') 111 .find('span') 112 .html(BooklySCAppointmentsL10n.tasks.title); 113 break; 114 case BooklySCAppointmentsL10n.dateRange.anyTime: 115 $appointmentDateFilter 116 .data('date', 'any') 117 .find('span') 118 .html(BooklySCAppointmentsL10n.dateRange.anyTime); 119 break; 120 default: 121 $appointmentDateFilter 122 .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat)) 123 .find('span') 124 .html(start.format(BooklySCAppointmentsL10n.dateRange.format) + ' - ' + end.format(BooklySCAppointmentsL10n.dateRange.format)); 125 } 126 } 127 ); 128 129 $creationDateFilter.daterangepicker( 130 { 131 parentEl: $creationDateFilter.parent(), 132 startDate: pickers.creationDate.startDate, 133 endDate: pickers.creationDate.endDate, 134 ranges: pickerRanges2, 135 showDropdowns: true, 136 linkedCalendars: false, 137 autoUpdateInput: false, 138 locale: $.extend(BooklySCAppointmentsL10n.dateRange, BooklySCAppointmentsL10n.datePicker) 139 }, 140 function (start, end, label) { 141 switch (label) { 142 case BooklySCAppointmentsL10n.tasks.title: 143 $creationDateFilter 144 .data('date', 'null') 145 .find('span') 146 .html(BooklySCAppointmentsL10n.tasks.title); 147 break; 148 case BooklySCAppointmentsL10n.dateRange.anyTime: 149 $creationDateFilter 150 .data('date', 'any') 151 .find('span') 152 .html(BooklySCAppointmentsL10n.dateRange.createdAtAnyTime); 153 break; 154 default: 155 $creationDateFilter 156 .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat)) 157 .find('span') 158 .html(start.format(BooklySCAppointmentsL10n.dateRange.format) + ' - ' + end.format(BooklySCAppointmentsL10n.dateRange.format)); 159 } 160 } 161 ); 162 163 /** 164 * Init table columns. 165 */ 166 $.each(BooklySCAppointmentsL10n.datatables.appointments.settings.columns, function (column, show) { 167 if (show) { 168 switch (column) { 169 case 'customer_full_name': 170 columns.push({data: 'customer.full_name', render: $.fn.dataTable.render.text()}); 171 break; 172 case 'customer_phone': 173 columns.push({ 174 data: 'customer.phone', 175 render: function (data, type, row, meta) { 176 if (isMobile) { 177 return '<a href="tel:' + window.booklyIntlTelInput.utils.formatNumber($.fn.dataTable.render.text().display(data), null, window.booklyIntlTelInput.utils.numberFormat.INTERNATIONAL) + '">' + $.fn.dataTable.render.text().display(data) + '</a>'; 178 } else { 179 return data ? '<span style="white-space: nowrap;">' + window.booklyIntlTelInput.utils.formatNumber($.fn.dataTable.render.text().display(data), null, window.booklyIntlTelInput.utils.numberFormat.INTERNATIONAL) + '</span>' : ''; 180 } 181 } 182 }); 183 break; 184 case 'customer_email': 185 columns.push({data: 'customer.email', render: $.fn.dataTable.render.text()}); 186 break; 187 case 'customer_address': 188 columns.push({data: 'customer.address', render: $.fn.dataTable.render.text(), orderable: false}); 189 break; 190 case 'customer_birthday': 191 columns.push({data: 'customer.birthday', render: $.fn.dataTable.render.text()}); 192 break; 193 case 'staff_name':
194 columns.push({data: 'staff.name', render: $.fn.dataTable.render.text()}); 195 break; 196 case 'service_title': 197 columns.push({ 198 data: 'service.title', 199 render: function (data, type, row, meta) { 200 data = $.fn.dataTable.render.text().display(data); 201 if (row.service.extras.length) { 202 var extras = '<ul class="bookly-list list-dots">'; 203 $.each(row.service.extras, function (key, item) { 204 extras += '<li><nobr>' + item.title + '</nobr></li>'; 205 }); 206 extras += '</ul>'; 207 return data + extras; 208 } else { 209 return data; 210 } 211 } 212 }); 213 break; 214 case 'payment': 215 columns.push({ 216 data: 'payment', 217 render: function (data, type, row, meta) { 218 if (row.payment_id) { 219 if (Options.read_only) { 220 return data; 221 } 222 return '<a type="button" data-action="show-payment" class="text-primary" data-payment_id="' + row.payment_id + '">' + data + '</a>'; 223 } 224 return ''; 225 } 226 }); 227 break; 228 case 'service_duration': 229 columns.push({data: 'service.duration'}); 230 break; 231 case 'attachments': 232 columns.push({ 233 data: 'attachment', 234 render: function (data, type, row, meta) { 235 if (data == '1') { 236 if (Options.read_only) { 237 return '<i class="fas fa-fw fa-paperclip"></i>'; 238 } 239 return '<button type="button" class="btn btn-link" data-action="show-attachments" title="' + BooklySCAppointmentsL10n.attachments + '"><i class="fas fa-fw fa-paperclip"></i></button>'; 240 } 241 return ''; 242 } 243 }); 244 break; 245 case 'rating': 246 columns.push({ 247 data: 'rating', 248 render: function (data, type, row, meta) { 249 if (row.rating_comment == null) { 250 return row.rating; 251 } else { 252 return '<a href="#" data-toggle="bookly-popover" data-trigger="hover" data-placement="bottom" data-content="' + $.fn.dataTable.render.text().display(row.rating_comment) + '" data-container="#bookly-appointments-list">' + $.fn.dataTable.render.text().display(row.rating) + '</a>'; 253 } 254 }, 255 }); 256 break; 257 case 'internal_note': 258 case 'locations': 259 case 'notes': 260 case 'number_of_persons': 261 columns.push({data: column, render: $.fn.dataTable.render.text()}); 262 break; 263 case 'online_meeting': 264 columns.push({ 265 data: 'online_meeting_provider', 266 render: function (data, type, row, meta) { 267 switch (data) { 268 case 'zoom': 269 return '<a class="badge badge-primary" href="https://zoom.us/j/' + $.fn.dataTable.render.text().display(row.online_meeting_start_url) + '" target="_blank"><i class="fas fa-video fa-fw"></i> Zoom <i class="fas fa-external-link-alt fa-fw"></i></a>'; 270 case 'google_meet': 271 return '<a class="badge badge-primary" href="' + $.fn.dataTable.render.text().display(row.online_meeting_start_url) + '" target="_blank"><i class="fas fa-video fa-fw"></i> Google Meet <i class="fas fa-external-link-alt fa-fw"></i></a>'; 272 case 'jitsi': 273 return '<a class="badge badge-primary" href="' + $.fn.dataTable.render.text().display(row.online_meeting_start_url) + '" target="_blank"><i class="fas fa-video fa-fw"></i> Jitsi Meet <i class="fas fa-external-link-alt fa-fw"></i></a>'; 274 case 'bbb': 275 return '<a class="badge badge-primary" href="' + $.fn.dataTable.render.text().display(row.online_meeting_start_url) + '" target="_blank"><i class="fas fa-video fa-fw"></i> BigBlueButton <i class="fas fa-external-link-alt fa-fw"></i></a>';
276 case 'teams': 277 return '<a class="badge badge-primary" href="' + $.fn.dataTable.render.text().display(row.online_meeting_start_url) + '" target="_blank"><i class="fas fa-video fa-fw"></i> Microsoft Teams <i class="fas fa-external-link-alt fa-fw"></i></a>'; 278 default: 279 return ''; 280 } 281 }, 282 }); 283 break; 284 default: 285 if (column.startsWith('custom_fields_')) { 286 columns.push({ 287 data: column.replace(/_([^_]*)$/, '.$1'), 288 render: $.fn.dataTable.render.text(), 289 orderable: false 290 }); 291 } else { 292 columns.push({data: column, render: $.fn.dataTable.render.text()}); 293 } 294 break; 295 } 296 } 297 }); 298 299 if (!Options.read_only) { 300 columns.push({ 301 data: null, 302 responsivePriority: 1, 303 orderable: false, 304 width: 120, 305 render: function(data, type, row, meta) { 306 return '<button type="button" class="btn btn-default" data-action="edit"><i class="far fa-fw fa-edit mr-lg-1"></i><span class="d-none d-lg-inline">' + BooklySCAppointmentsL10n.edit + 'â¦</span></button>'; 307 } 308 }); 309 } 310 311 columns[0].responsivePriority = 0; 312 313 $.each(BooklySCAppointmentsL10n.datatables.appointments.settings.order, function (_, value) { 314 const index = columns.findIndex(function (c) { return c.data === value.column; }); 315 if (index !== -1) { 316 order.push([index, value.order]); 317 } 318 }); 319 320 /** 321 * Init DataTables. 322 */ 323 var dt = $list.DataTable({ 324 order: order, 325 info: false, 326 searching: false, 327 lengthChange: false, 328 processing: true, 329 responsive: true, 330 pageLength: 25, 331 pagingType: 'numbers', 332 serverSide: true, 333 drawCallback: function (settings) { 334 $('[data-toggle="bookly-popover"]', $list).on('click', function (e) { 335 e.preventDefault(); 336 }).booklyPopover(); 337 dt.responsive.recalc(); 338 }, 339 ajax: { 340 url: ajaxurl, 341 type: 'POST', 342 data: function (d) { 343 return $.extend({action: 'bookly_staff_cabinet_get_appointments', csrf_token: BooklyL10nGlobal.csrf_token}, { 344 filter: { 345 id: $idFilter.val(), 346 date: $appointmentDateFilter.data('date'), 347 created_date: $creationDateFilter.data('date'), 348 customer: $customerFilter.val(), 349 service: $serviceFilter.val(), 350 status: $statusFilter.booklyDropdown('getSelected'), 351 location: $locationFilter.val() 352 } 353 }, d); 354 } 355 }, 356 columns: columns, 357 language: { 358 zeroRecords: BooklySCAppointmentsL10n.zeroRecords, 359 processing: BooklySCAppointmentsL10n.processing, 360 emptyTable: BooklySCAppointmentsL10n.emptyTable, 361 loadingRecords: BooklySCAppointmentsL10n.loadingRecords 362 }, 363 layout: { 364 bottomStart: 'paging', 365 bottomEnd: null 366 } 367 }); 368 369 dt.on('responsive-display', function (e, datatable, row, showHide, update) { 370 if (showHide) { 371 $('[data-toggle="bookly-popover"]', row.child()).on('click', function (e) { 372 e.preventDefault(); 373 }).booklyPopover(); 374 } 375 }); 376 377 if (!Options.read_only) { 378 $list 379 // Show payment details
380 .on('click', '[data-action=show-payment]', function() { 381 BooklyPaymentDetailsDialog.showDialog({ 382 payment_id: getDTRowData(this).payment_id, 383 done: function(event) { 384 dt.ajax.reload(null, false); 385 } 386 }); 387 }) 388 // Edit appointment. 389 .on('click', '[data-action=edit]', function(e) { 390 e.preventDefault(); 391 BooklyAppointmentDialog.showDialog( 392 getDTRowData(this).id, 393 null, 394 null, 395 function(event) { 396 dt.ajax.reload(null, false); 397 } 398 ) 399 }); 400 401 /** 402 * Add appointment. 403 */ 404 $newAppointmentBtn.on('click', function() { 405 BooklyAppointmentDialog.showDialog( 406 null, 407 null, 408 moment(), 409 function(event) { 410 dt.ajax.reload(null, false); 411 } 412 ) 413 }); 414 } 415 416 /** 417 * On filters change. 418 */ 419 $('.bookly-js-select') 420 .booklySelect2({ 421 width: '100%', 422 theme: 'bootstrap4', 423 dropdownParent: $container, 424 allowClear: true, 425 placeholder: '', 426 language: { 427 noResults: function () { 428 return BooklySCAppointmentsL10n.no_result_found; 429 } 430 }, 431 matcher: function (params, data) { 432 const term = $.trim(params.term).toLowerCase(); 433 if (term === '' || data.text.toLowerCase().indexOf(term) !== -1) { 434 return data; 435 } 436 437 let result = null; 438 const search = $(data.element).data('search'); 439 search && 440 search.find(function (text) { 441 if (result === null && text.toLowerCase().indexOf(term) !== -1) { 442 result = data; 443 } 444 }); 445 446 return result; 447 } 448 }); 449 450 $('.bookly-js-select-ajax') 451 .booklySelect2({ 452 width: '100%', 453 theme: 'bootstrap4', 454 dropdownParent: $container, 455 allowClear: true, 456 placeholder: '', 457 language: { 458 noResults: function () { 459 return BooklySCAppointmentsL10n.no_result_found; 460 }, 461 searching: function () { 462 return BooklySCAppointmentsL10n.searching; 463 } 464 }, 465 ajax: { 466 url: ajaxurl, 467 dataType: 'json', 468 delay: 250, 469 data: function (params) { 470 params.page = params.page || 1; 471 return { 472 action: this.action === undefined ? $(this).data('ajax--action') : this.action, 473 filter: params.term, 474 page: params.page, 475 csrf_token: BooklyL10nGlobal.csrf_token 476 }; 477 } 478 }, 479 }); 480 481 function getDTRowData(element) { 482 let $el = $(element).closest('td'); 483 if ($el.hasClass('child')) { 484 $el = $el.closest('tr').prev(); 485 } 486 return dt.row($el).data(); 487 } 488 489 $idFilter.on('keyup', onChangeFilter); 490 $appointmentDateFilter.on('apply.daterangepicker', onChangeFilter); 491 $creationDateFilter.on('apply.daterangepicker', onChangeFilter); 492 $customerFilter.on('change', onChangeFilter); 493 $serviceFilter.on('change', onChangeFilter); 494 $locationFilter.on('change', onChangeFilter); 495 } 496})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.