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 / findreservation / tmpl / default_timeline.php
vikappointments / admin / views / findreservation / tmpl Last commit date
default.php 6 days ago default_calendar.php 6 days ago default_filters.php 6 days ago default_timeline.php 6 days ago index.html 6 days ago
default_timeline.php
352 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 id_res: <?php echo (int) $this->filters['id_res']; ?>,
108 people: jQuery('input[name="people"]').val(),
109 };
110
111 new Promise((resolve, reject) => {
112 UIAjax.do(
113 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.timelineajax'); ?>',
114 data,
115 (resp) => {
116 resolve(resp);
117 },
118 (err) => {
119 reject(err);
120 }
121 );
122 }).then((resp) => {
123 // file timeline with fetched HTML
124 jQuery('#vaptimeline').html(resp.html);
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 // fetch task based on reservation ID set in request
169 let task = '<?php echo (int) $this->filters['id_res'] ? 'edit' : 'add'; ?>';
170
171 // submit task
172 Joomla.submitbutton('reservation.' + task);
173 }
174
175 function vapViewDetails(hour, min, slot) {
176 let id_emp = parseInt(jQuery('select[name="id_emp"]').val());
177
178 // check whether the employee ID is selected
179 if (isNaN(id_emp) || !id_emp) {
180 // attempt to find parent employee ID
181 id_emp = jQuery(slot).closest('.vaptimeline-empblock[data-id]').data('id');
182 }
183
184 let date = jQuery('#vapdayselected').val();
185
186 UIAjax.do(
187 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.appointmentsajax'); ?>',
188 {
189 id_emp: id_emp,
190 date: date,
191 hour: hour,
192 min: min,
193 },
194 (resp) => {
195 // map records to obtain only a list of reservations ID
196 let ids = resp.map((elem) => { return elem.id; });
197
198 // display modal
199 displayDetailsView(ids);
200 },
201 (err) => {
202 alert(err.responseText || Joomla.JText._('VAPCONNECTIONLOSTERROR'));
203 }
204 );
205 }
206
207 function openSmartOverlay(slot) {
208 closeSmartOverlay();
209
210 SLOT_CURRENT_TARGET = slot;
211
212 var html = '<div class="smart-overlay-loading">\n'+
213 '<i class="fas fa-circle-notch fa-spin fa-3x" style="font-size: 32px;"></i>\n'+
214 '</div>';
215
216 jQuery('#adminForm').append('<div class="smart-overlay">' + html + '</div>');
217
218 var overlay = jQuery('.smart-overlay');
219
220 calculateOverlayPosition(overlay);
221
222 overlay.on('click', (event) => {
223 event.preventDefault();
224 event.stopPropagation();
225 });
226
227 loadSmartOverlayData(overlay);
228 }
229
230 function calculateOverlayPosition(overlay) {
231 if (!SLOT_CURRENT_TARGET) {
232 return;
233 }
234
235 var offset = jQuery(SLOT_CURRENT_TARGET).offset();
236
237 var left = offset.left;
238
239 if (left + overlay.width() >= jQuery(window).width() - 5) {
240 left = jQuery(window).width() - overlay.width() - 5;
241 }
242
243 overlay.css('top', (offset.top - overlay.height() - 5) + 'px');
244 overlay.css('left', left + 'px');
245 }
246
247 function loadSmartOverlayData(overlay) {
248 var id_emp = <?php echo (int) $this->filters['id_emp']; ?>;
249
250 if (!id_emp) {
251 // fallback to obtain the employee ID from the timeline
252 id_emp = jQuery(SLOT_CURRENT_TARGET).closest('.vaptimeline-empblock').data('id');
253 }
254
255 var date = jQuery('#vapdayselected').val();
256 var hour = jQuery(SLOT_CURRENT_TARGET).data('hour');
257 var min = jQuery(SLOT_CURRENT_TARGET).data('min');
258
259 // get cached record, if any
260 var cache = VAPTempCache.get([id_emp, date, hour, min]);
261
262 if (cache) {
263 // fill smart overlay with cached data
264 fillSmartOverlay(cache, overlay);
265 return;
266 }
267
268 SLOT_AJAX_HANDLE = UIAjax.do(
269 '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=findreservation.appointmentsajax'); ?>',
270 {
271 id_emp: id_emp,
272 date: date,
273 hour: hour,
274 min: min,
275 },
276 (resp) => {
277 fillSmartOverlay(resp, overlay);
278 // cache result for later use
279 VAPTempCache.set([id_emp, date, hour, min], resp);
280 },
281 (err) => {
282 if (err.statusText != 'abort') {
283 console.log(err, err.responseText);
284 alert(Joomla.JText._('VAPCONNECTIONLOSTERROR'));
285 }
286
287 // close overlay on error
288 closeSmartOverlay();
289 }
290 );
291 }
292
293 function fillSmartOverlay(obj, overlay) {
294 // reset overlay HTML
295 overlay.html('');
296
297 var _guest = Joomla.JText._('VAP_N_PEOPLE_1');
298 var _guests = Joomla.JText._('VAP_N_PEOPLE');
299
300 obj.forEach((app) => {
301 // create overlay record
302 let record = jQuery('<div class="overlay-record"></div>');
303
304 // create record ID column
305 let recordId = jQuery('<div class="record-column col-id"></div>').html('#' + app.id);
306 record.append(recordId);
307
308 // create custom name column
309 let recordCust = jQuery('<div class="record-column col-name"></div>');
310 if (app.closure == 1) {
311 recordCust.html(Joomla.JText._('VAPSTATUSCLOSURE').toUpperCase());
312 } else {
313 recordCust.html(app.purchaser_nominative || app.purchaser_phone || app.purchaser_mail);
314 }
315 record.append(recordCust);
316
317 // create last column
318 let recordThird = jQuery('<div class="record-column col-count"></div>');
319
320 if (app.id_service == <?php echo $this->filters['id_ser']; ?>) {
321 // same service, display number of people
322 if (app.people > 1) {
323 recordThird.html(_guests.replace(/%d/, app.people));
324 } else {
325 recordThird.html(_guest);
326 }
327 } else {
328 // display service name
329 recordThird.html(app.service_name);
330 }
331
332 record.append(recordThird);
333
334 // append record to averlay
335 overlay.append(record);
336 });
337
338 calculateOverlayPosition(overlay);
339 }
340
341 function closeSmartOverlay() {
342 jQuery('.smart-overlay').remove();
343 SLOT_CURRENT_TARGET = null;
344
345 if (SLOT_AJAX_HANDLE) {
346 SLOT_AJAX_HANDLE.abort();
347 SLOT_AJAX_HANDLE = null;
348 }
349 }
350
351 </script>
352