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 / admin / views / calendar / tmpl / default_timeline.php
vikappointments / admin / views / calendar / tmpl Last commit date
default.php 4 days ago default_calendar.php 4 days ago default_filters.php 4 days ago default_reservations.php 4 days ago default_timeline.php 4 days ago index.html 4 days ago
default_timeline.php
349 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 $vik = VAPApplication::getInstance();
15
16 ?>
17
18 <div class="vaptimeline" id="vaptimeline">
19
20 </div>
21
22 <div class="vaptimeline-hover-tip" style="display:none;">
23 <i class="fas fa-life-ring"></i>&nbsp;
24 <?php echo JText::translate('VAPTIMELINEHOVERTIP'); ?>
25 </div>
26
27 <?php
28 JText::script('VAPCONNECTIONLOSTERROR');
29 JText::script('VAP_N_PEOPLE_1');
30 JText::script('VAP_N_PEOPLE');
31 JText::script('VAPSTATUSCLOSURE');
32 ?>
33
34 <script>
35
36 /* GROUP INFO EVENTS */
37
38 var SLOT_HOVER_TIMEOUT = null;
39 var SLOT_CURRENT_TARGET = null;
40 var SLOT_AJAX_HANDLE = null;
41
42 jQuery(function($) {
43 // attempt to refresh timeline
44 vapGetTimeline();
45
46 // iterate each RED block to support view details action
47 $('#vaptimeline').on('click', '.vaptlblock0', function() {
48 vapViewDetails($(this).data('hour'), $(this).data('min'), this);
49 });
50
51 // implement hover/leave events for time slots with a number of seats
52 $('#vaptimeline').on('mouseenter mouseleave', '.vap-timeline-block[data-seats]', function(event) {
53 let seats = $(this).data('seats');
54
55 if (isNaN(seats) || !seats) {
56 return false;
57 }
58
59 if (event.type == 'mouseenter') {
60 // register timer to load time slots
61 SLOT_HOVER_TIMEOUT = setTimeout(() => {
62 if (this == SLOT_CURRENT_TARGET) {
63 return;
64 }
65
66 openSmartOverlay(this);
67 }, 1000);
68 } else {
69 // reset slot loader
70 clearTimeout(SLOT_HOVER_TIMEOUT);
71 }
72 });
73
74 $(window).on('beforeunload click', () => {
75 // close overlay in order to safely abort any pending
76 // AJAX request before leaving the page
77 closeSmartOverlay();
78 });
79
80 $(window).on('resize', function() {
81 calculateOverlayPosition($('.smart-overlay'));
82 });
83 });
84
85 function vapGetTimeline(date) {
86 if (typeof date === 'undefined') {
87 // recover stored date
88 date = jQuery('#vapdayselected').val();
89
90 if (!date) {
91 // no selected date
92 return false;
93 }
94
95 // auto-select clicked cell
96 jQuery('.vaptdday[data-day="' + date + '"]').addClass('vaptdselected');
97 } else {
98 // register selected date
99 jQuery('#vapdayselected').val(date);
100 }
101
102 // prepare timeline data
103 let data = {
104 day: date,
105 id_emp: <?php echo (int) $this->filters['id_emp']; ?>,
106 id_ser: <?php echo (int) $this->filters['id_ser']; ?>,
107 };
108
109 new Promise((resolve, reject) => {
110 UIAjax.do(
111 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.timelineajax'); ?>',
112 data,
113 (resp) => {
114 resolve(resp);
115 },
116 (err) => {
117 reject(err);
118 }
119 );
120 }).then((resp) => {
121 // file timeline with fetched HTML
122 jQuery('#vaptimeline').html(resp.html);
123 // load appointments list on the selected date
124 getReservationsOnDay(date);
125 }).catch((err) => {
126 // display response error message
127 jQuery('#vaptimeline').html(err.responseText);
128 // unset selected date
129 jQuery('#vapdayselected').val('');
130 }).finally(() => {
131 // animate only in case the timeline is not visible
132 var px_to_scroll = isBoxOutOfMonitor(jQuery('#vaptimeline'), 60);
133
134 if (px_to_scroll !== false) {
135 jQuery('html,body').animate({scrollTop: "+=" + px_to_scroll}, {duration:'normal'});
136 }
137
138 // count slots with number of seats
139 let count = jQuery('.vap-timeline-block[data-seats]');
140
141 if (count.length) {
142 // display "hover" label
143 jQuery('.vaptimeline-hover-tip').show();
144 } else {
145 // hide "hover" label
146 jQuery('.vaptimeline-hover-tip').hide();
147 }
148 });
149 }
150
151 function vapTimeClicked(hour, min, slot)
152 {
153 // inject selected hours and minutes
154 document.adminForm.hour.value = hour;
155 document.adminForm.min.value = min;
156
157 // check whether the employee ID is selected
158 if (!jQuery('select[name="id_emp"]').val()) {
159 // attempt to find parent employee ID
160 const parent = jQuery(slot).closest('.vaptimeline-empblock[data-id]');
161
162 if (parent.length) {
163 // overwrite employee ID with the clicked one
164 jQuery('#adminForm').append('<input type="hidden" name="id_emp" value="' + parent.data('id') + '" />');
165 }
166 }
167
168 // submit task
169 Joomla.submitbutton('reservation.add');
170 }
171
172 function vapViewDetails(hour, min, slot) {
173 let id_emp = parseInt(jQuery('select[name="id_emp"]').val());
174
175 // check whether the employee ID is selected
176 if (isNaN(id_emp) || !id_emp) {
177 // attempt to find parent employee ID
178 id_emp = jQuery(slot).closest('.vaptimeline-empblock[data-id]').data('id');
179 }
180
181 let date = jQuery('#vapdayselected').val();
182
183 UIAjax.do(
184 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.appointmentsajax'); ?>',
185 {
186 id_emp: id_emp,
187 date: date,
188 hour: hour,
189 min: min,
190 },
191 (resp) => {
192 // map records to obtain only a list of reservations ID
193 let ids = resp.map((elem) => { return elem.id; });
194
195 // display modal
196 displayDetailsView(ids);
197 },
198 (err) => {
199 alert(err.responseText || Joomla.JText._('VAPCONNECTIONLOSTERROR'));
200 }
201 );
202 }
203
204 function openSmartOverlay(slot) {
205 closeSmartOverlay();
206
207 SLOT_CURRENT_TARGET = slot;
208
209 var html = '<div class="smart-overlay-loading">\n'+
210 '<i class="fas fa-circle-notch fa-spin fa-3x" style="font-size: 32px;"></i>\n'+
211 '</div>';
212
213 jQuery('#adminForm').append('<div class="smart-overlay">' + html + '</div>');
214
215 var overlay = jQuery('.smart-overlay');
216
217 calculateOverlayPosition(overlay);
218
219 overlay.on('click', (event) => {
220 event.preventDefault();
221 event.stopPropagation();
222 });
223
224 loadSmartOverlayData(overlay);
225 }
226
227 function calculateOverlayPosition(overlay) {
228 if (!SLOT_CURRENT_TARGET) {
229 return;
230 }
231
232 var offset = jQuery(SLOT_CURRENT_TARGET).offset();
233
234 var left = offset.left;
235
236 if (left + overlay.width() >= jQuery(window).width() - 5) {
237 left = jQuery(window).width() - overlay.width() - 5;
238 }
239
240 overlay.css('top', (offset.top - overlay.height() - 5) + 'px');
241 overlay.css('left', left + 'px');
242 }
243
244 function loadSmartOverlayData(overlay) {
245 var id_emp = <?php echo (int) $this->filters['id_emp']; ?>;
246
247 if (!id_emp) {
248 // fallback to obtain the employee ID from the timeline
249 id_emp = jQuery(SLOT_CURRENT_TARGET).closest('.vaptimeline-empblock').data('id');
250 }
251
252 var date = jQuery('#vapdayselected').val();
253 var hour = jQuery(SLOT_CURRENT_TARGET).data('hour');
254 var min = jQuery(SLOT_CURRENT_TARGET).data('min');
255
256 // get cached record, if any
257 var cache = VAPTempCache.get([id_emp, date, hour, min]);
258
259 if (cache) {
260 // fill smart overlay with cached data
261 fillSmartOverlay(cache, overlay);
262 return;
263 }
264
265 SLOT_AJAX_HANDLE = UIAjax.do(
266 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.appointmentsajax'); ?>',
267 {
268 id_emp: id_emp,
269 date: date,
270 hour: hour,
271 min: min,
272 },
273 (resp) => {
274 fillSmartOverlay(resp, overlay);
275 // cache result for later use
276 VAPTempCache.set([id_emp, date, hour, min], resp);
277 },
278 (err) => {
279 if (err.statusText != 'abort') {
280 console.log(err, err.responseText);
281 alert(Joomla.JText._('VAPCONNECTIONLOSTERROR'));
282 }
283
284 // close overlay on error
285 closeSmartOverlay();
286 }
287 );
288 }
289
290 function fillSmartOverlay(obj, overlay) {
291 // reset overlay HTML
292 overlay.html('');
293
294 var _guest = Joomla.JText._('VAP_N_PEOPLE_1');
295 var _guests = Joomla.JText._('VAP_N_PEOPLE');
296
297 obj.forEach((app) => {
298 // create overlay record
299 let record = jQuery('<div class="overlay-record"></div>');
300
301 // create record ID column
302 let recordId = jQuery('<div class="record-column col-id"></div>').html('#' + app.id);
303 record.append(recordId);
304
305 // create custom name column
306 let recordCust = jQuery('<div class="record-column col-name"></div>');
307 if (app.closure == 1) {
308 recordCust.html(Joomla.JText._('VAPSTATUSCLOSURE').toUpperCase());
309 } else {
310 recordCust.html(app.purchaser_nominative || app.purchaser_phone || app.purchaser_mail);
311 }
312 record.append(recordCust);
313
314 // create last column
315 let recordThird = jQuery('<div class="record-column col-count"></div>');
316
317 if (app.id_service == <?php echo $this->filters['id_ser']; ?>) {
318 // same service, display number of people
319 if (app.people > 1) {
320 recordThird.html(_guests.replace(/%d/, app.people));
321 } else {
322 recordThird.html(_guest);
323 }
324 } else {
325 // display service name
326 recordThird.html(app.service_name);
327 }
328
329 record.append(recordThird);
330
331 // append record to averlay
332 overlay.append(record);
333 });
334
335 calculateOverlayPosition(overlay);
336 }
337
338 function closeSmartOverlay() {
339 jQuery('.smart-overlay').remove();
340 SLOT_CURRENT_TARGET = null;
341
342 if (SLOT_AJAX_HANDLE) {
343 SLOT_AJAX_HANDLE.abort();
344 SLOT_AJAX_HANDLE = null;
345 }
346 }
347
348 </script>
349