PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / site / layouts / blocks / timeline.php
vikappointments / site / layouts / blocks Last commit date
calendar 1 day ago login 1 day ago payment 1 day ago alert.php 1 day ago carttotals.php 1 day ago checkout.php 1 day ago couponform.php 1 day ago index.html 1 day ago login.php 1 day ago options.php 1 day ago paymentmethods.php 1 day ago quickcontact.php 1 day ago reviews.php 1 day ago timeline.php 1 day ago waitlist.php 1 day ago
timeline.php
441 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 $id_service = isset($displayData['id_service']) ? $displayData['id_service'] : 0;
15 $id_employee = isset($displayData['id_employee']) ? $displayData['id_employee'] : 0;
16 $hour = isset($displayData['hour']) ? $displayData['hour'] : null;
17 $min = isset($displayData['min']) ? $displayData['min'] : null;
18 $checkout = isset($displayData['checkout']) ? $displayData['checkout'] : 0;
19 $multi_tz = isset($displayData['multitimezone']) ? $displayData['multitimezone'] : null;
20 $admin = isset($displayData['admin']) ? $displayData['admin'] : false;
21 $id_res = isset($displayData['id_res']) ? $displayData['id_res'] : false;
22
23 $vik = VAPApplication::getInstance();
24
25 $config = VAPFactory::getConfig();
26
27 if (is_null($multi_tz))
28 {
29 // take value from configuration
30 $multi_tz = $config->getBool('multitimezone');
31 }
32
33 /**
34 * In case of multi-timezone, allow the customers to switch timezone.
35 *
36 * @since 1.7
37 */
38 if ($multi_tz)
39 {
40 // get user timezone
41 $tz = VikAppointments::getUserTimezone();
42
43 ?>
44 <div class="vap-user-timezone">
45 <span><?php echo JText::translate('VAP_USER_CHANGE_TIMEZONE'); ?>&nbsp;</span>
46
47 <?php
48 $zones = array();
49
50 foreach (timezone_identifiers_list() as $zone)
51 {
52 $parts = explode('/', $zone);
53
54 $continent = isset($parts[0]) ? $parts[0] : '';
55 $city = (isset($parts[1]) ? $parts[1] : $continent) . (isset($parts[2]) ? '/' . $parts[2] : '');
56 $city = ucwords(str_replace('_', ' ', $city));
57
58 if (!isset($zones[$continent]))
59 {
60 $zones[$continent] = array();
61 }
62
63 $zones[$continent][] = JHtml::fetch('select.option', $zone, $city);
64 }
65
66 $params = array(
67 'id' => 'vap-timezone-sel',
68 'group.items' => null,
69 'list.select' => $tz->getName(),
70 );
71
72 echo JHtml::fetch('select.groupedList', $zones, 'timezone', $params);
73 ?>
74 </div>
75
76 <script>
77 (function($) {
78 $(function() {
79 // render timezone dropdown
80 $('#vap-timezone-sel').select2({
81 allowClear: false,
82 width: 250,
83 });
84
85 // register selected timezone as a cookie
86 $('#vap-timezone-sel').on('change', function() {
87 // store timezone in a cookie for 1 month
88 var date = new Date();
89 date.setMonth(date.getMonth() + 1);
90
91 document.cookie = 'vikappointments.user.timezone=' + $(this).val() + '; expires=' + date.toUTCString() + '; path=/';
92
93 // refresh timeline
94 vapGetTimeline();
95 });
96 });
97 })(jQuery);
98 </script>
99 <?php
100 }
101 ?>
102
103 <div class="vaptimeline" id="vaptimeline">
104
105 </div>
106
107 <?php
108 JText::script('VAPWAITLISTADDED0');
109 ?>
110
111 <script>
112
113 jQuery(function($) {
114 // auto-load timeline in case a date was selected
115 vapGetTimeline();
116 });
117
118 <?php
119 /**
120 * In case of concurrent requests, the confirmation form
121 * may be overwritten when the first request made ends afters
122 * the second one.
123 * So, we should abort any connections every time we request
124 * for a new timeline.
125 *
126 * @since 1.6.2
127 */
128 ?>
129 var TIMELINE_XHR = null;
130
131 function vapGetTimeline(date) {
132 if (TIMELINE_XHR !== null) {
133 // abort previous request
134 TIMELINE_XHR.abort();
135 }
136
137 if (typeof date === 'undefined') {
138 // recover stored date
139 date = jQuery('#vapdayselected').val();
140
141 if (!date) {
142 // no selected date
143 return false;
144 }
145
146 // auto-select clicked cell
147 jQuery('.vaptdday[data-day="' + date + '"]').addClass('vaptdselected');
148 } else {
149 // register selected date
150 jQuery('#vapdayselected').val(date);
151 }
152
153 /**
154 * @see views/employeesearch/tmpl/default.php
155 */
156 LAST_TIMESTAMP_USED = date;
157
158 /**
159 * @see layouts/blocks/checkout.php
160 */
161 isTimeChoosen = false;
162
163 // prepare timeline data
164 let data = {
165 day: date,
166 id_emp: <?php echo (int) $id_employee; ?>,
167 id_ser: <?php echo (int) $id_service; ?>,
168 people: jQuery('#vapserpeopleselect').val(),
169 admin: <?php echo (int) $admin; ?>,
170 id_res: <?php echo (int) $id_res; ?>,
171 locations: [],
172 };
173
174 // unset hours and minutes as the checkin day has changed
175 jQuery('#vapconfhourselected').val('');
176 jQuery('#vapconfminselected').val('');
177
178 // update input hidden holding the selected number of participants
179 jQuery('#vappeopleselected').val(data.people);
180
181 // flag used to check whether all the locations are selected
182 let all = true;
183
184 jQuery('.vap-empsearch-locval').each(function() {
185 if (jQuery(this).is(':checked')) {
186 data.locations.push(jQuery(this).val());
187 } else {
188 // at least one not selected
189 all = false;
190 }
191 });
192
193 if (all) {
194 // all locations are selected, so we can ignore this filter
195 delete data.locations;
196 }
197
198 let error = false, aborted = false;
199
200 new Promise((resolve, reject) => {
201 TIMELINE_XHR = UIAjax.do(
202 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=employeesearch.timelineajax'); ?>',
203 data,
204 (resp) => {
205 resolve(resp);
206 },
207 (err) => {
208 reject(err);
209 }
210 );
211 }).then((resp) => {
212 if (!resp.error) {
213 // render timeline through the helper function
214 vapRenderTimeline(resp.timeline, resp.html, resp.rate, data);
215 } else {
216 // register availability error
217 error = resp.error;
218 }
219 }).catch((err) => {
220 if (err.statusText === 'abort') {
221 aborted = false;
222 } else if (typeof err.responseText !== 'undefined') {
223 // register response HTTP error message
224 error = err.responseText || Joomla.JText._('VAPWAITLISTADDED0');
225 } else {
226 error = true;
227 // we are probably handling an exception
228 console.error(err);
229 }
230 }).finally(() => {
231 TIMELINE_XHR = null;
232
233 // do not go ahead in case we aborted the request
234 if (aborted === true) {
235 return;
236 }
237
238 if (error !== false) {
239 if (typeof error === 'string') {
240 // Fill timeline box with fetched error message.
241 // Wrap error in a <div> for individual styling.
242 jQuery('#vaptimeline').html(
243 jQuery('<div class="timeline-error"></div>').html(error)
244 );
245 }
246
247 // unset selected date on error
248 jQuery('#vapdayselected').val('');
249
250 // hide wait list button
251 jQuery('#vapwaitlistbox').hide();
252 // hide add cart button
253 jQuery('#vapadditembutton').hide();
254 }
255
256 // animate only in case the timeline is not visible
257 var px_to_scroll = isBoxOutOfMonitor(jQuery('#vaptimeline'), 60);
258
259 if (px_to_scroll !== false) {
260 jQuery('html,body').animate({scrollTop: "+=" + px_to_scroll}, {duration:'normal'});
261 }
262 });
263 }
264
265 var HOUR_MIN_SELECTED = false;
266
267 function vapRenderTimeline(timeline, html, newRate, request) {
268 let eventArgs = {
269 timeline: timeline,
270 html: html,
271 newRate: newRate,
272 request: request,
273 };
274
275 // inject received parameters within the event to dispatch
276 var event = jQuery.Event('timeline.beforerender');
277 event.params = eventArgs;
278
279 // trigger event before rendering the timeline
280 jQuery(window).trigger(event);
281
282 // fill timeline with fetched HTML
283 jQuery('#vaptimeline').html(html);
284
285 // update base cost
286 if (newRate && typeof vapUpdateServiceRate !== 'undefined') {
287 /**
288 * @see views/employeesearch/tmpl/default_filterbar.php
289 */
290 vapUpdateServiceRate(newRate);
291 }
292
293 var at_least_one_open = false;
294 var at_least_one_closed = false;
295
296 // iterate timeline levels
297 timeline.forEach((level) => {
298 // iterate level times
299 level.forEach((time) => {
300 at_least_one_open = at_least_one_open || (time.status == 1);
301 at_least_one_closed = at_least_one_closed || (time.status == 0);
302 });
303 });
304
305 // display "add to cart" button only if the timeline
306 // reports at least an available slot
307 if (at_least_one_open) {
308 jQuery('#vapadditembutton').show();
309 } else {
310 jQuery('#vapadditembutton').hide();
311 }
312
313 // display "add to waiting list" button only if the
314 // timeline reports at least an occupied slot
315 if (at_least_one_closed) {
316 jQuery('#vapwaitlistbox').show();
317 } else {
318 jQuery('#vapwaitlistbox').hide();
319 }
320
321 <?php
322 /**
323 * If hours and minutes are set, try to pre-select
324 * the specified block.
325 *
326 * @since 1.6
327 */
328 if (!is_null($hour) && !is_null($min))
329 {
330 ?>
331 if (!HOUR_MIN_SELECTED) {
332
333 var hour = <?php echo (int) $hour; ?>;
334 var min = <?php echo (int) $min; ?>;
335
336 <?php
337 // check whether the check-out selection is supported
338 if ($checkout)
339 {
340 // used for dropdown layout
341 ?>
342 jQuery('#vap-checkin-sel option').each(function() {
343 if (hour == jQuery(this).data('hour') && min == jQuery(this).data('min')) {
344 // trigger click of selected option
345 jQuery('#vap-checkin-sel').val(jQuery(this).val()).trigger('change');
346 return false;
347 }
348 });
349 <?php
350 }
351 else
352 {
353 // used for any other timeline layout
354 ?>
355 jQuery('.vap-timeline-block').each(function() {
356 if (hour == jQuery(this).data('hour') && min == jQuery(this).data('min')) {
357 // invoke vapTimeClicked() function
358 jQuery(this).closest('a').trigger('click');
359 return false;
360 }
361 });
362 <?php
363 }
364 ?>
365
366 // pre-select time block only once
367 HOUR_MIN_SELECTED = true;
368 }
369 <?php
370 }
371 ?>
372
373 // inject received parameters within the event to dispatch
374 var event = jQuery.Event('timeline.afterrender');
375 event.params = eventArgs;
376
377 // trigger event after rendering the timeline
378 jQuery(window).trigger(event);
379 }
380
381 function vapTimeClicked(hour, min, slot)
382 {
383 let eventArgs = {
384 hour: hour,
385 min: min,
386 };
387
388 // inject received parameters within the event to dispatch
389 var event = jQuery.Event('timeline.beforepicktime');
390 event.params = eventArgs;
391
392 // trigger event before picking a time slot
393 jQuery(slot).trigger(event);
394
395 // get new rate as string
396 var newRate = '' + jQuery(slot).find('.vaptlblock1').data('rate');
397
398 if (newRate.length && typeof vapUpdateServiceRate !== 'undefined') {
399 /**
400 * Dispatch rate update only if the data is set.
401 *
402 * @see views/employeesearch/tmpl/default_filterbar.php
403 */
404 vapUpdateServiceRate(parseFloat(newRate));
405 }
406
407 jQuery('#vapconfempselected').val(<?php echo $id_employee; ?>);
408 jQuery('#vapconfserselected').val(<?php echo $id_service; ?>);
409 jQuery('#vapconfdayselected').val(jQuery('#vapdayselected').val());
410 jQuery('#vapconfhourselected').val(hour);
411 jQuery('#vapconfminselected').val(min);
412 jQuery('#vapconfpeopleselected').val(jQuery('#vappeopleselected').val());
413
414 jQuery('.vaptlblock1').removeClass('vaptimeselected');
415 jQuery(slot).find('.vaptlblock1').addClass('vaptimeselected');
416
417 var opt_div = jQuery('.vapseroptionscont');
418
419 if (opt_div.length > 0) {
420 opt_div.slideDown();
421 }
422
423 var rec_div = jQuery('.vaprecurrencediv');
424
425 if (rec_div.length > 0) {
426 rec_div.slideDown();
427 }
428
429 isTimeChoosen = true;
430
431 // inject received parameters within the event to dispatch
432 var event = jQuery.Event('timeline.afterpicktime');
433 event.params = eventArgs;
434
435 // trigger event after picking a time slot
436 jQuery(slot).trigger(event);
437 }
438
439 </script>
440
441