PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.6
VikBooking Hotel Booking Engine & PMS v1.6.6
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
vikbooking / admin / helpers / widgets / latest_from_guests.php

latest_from_guests.php in VikBooking Hotel Booking Engine & PMS 1.6.6, at admin/helpers/widgets/latest_from_guests.php

745 lines 24.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage com_vikbooking
5 * @author Alessio Gaggii - e4j - Extensionsforjoomla.com
6 * @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
7 * @license GNU General Public License version 2 or later; see LICENSE
8 * @link https://vikwp.com
9 */
10
11 defined('ABSPATH') or die('No script kiddies please!');
12
13 /**
14 * Class handler for admin widget "latest from guests".
15 *
16 * @since 1.14.0 (J) - 1.4.0 (WP)
17 */
18 class VikBookingAdminWidgetLatestFromGuests extends VikBookingAdminWidget
19 {
20 /**
21 * The instance counter of this widget.
22 *
23 * @var int
24 */
25 protected static $instance_counter = -1;
26
27 /**
28 * Number of activities per page. Should be an even number.
29 *
30 * @var int
31 */
32 protected $activities_per_page = 6;
33
34 /**
35 * Number of activities per type. Should be half of numer per page.
36 *
37 * @var int
38 */
39 protected $activities_per_type = 3;
40
41 /**
42 * Today Y-m-d string
43 *
44 * @var string
45 */
46 protected $today_ymd = null;
47
48 /**
49 * The path to the VCM lib to see if it's available.
50 *
51 * @var string
52 */
53 protected $vcm_lib_path = '';
54
55 /**
56 * Tells whether VCM is installed and updated.
57 *
58 * @var bool
59 */
60 protected $vcm_exists = true;
61
62 /**
63 * Class constructor will define the widget name and identifier.
64 */
65 public function __construct()
66 {
67 // call parent constructor
68 parent::__construct();
69
70 $this->widgetName = JText::translate('VBO_W_LATESTFROMGUESTS_TITLE');
71 $this->widgetDescr = JText::translate('VBO_W_LATESTFROMGUESTS_DESCR');
72 $this->widgetId = basename(__FILE__, '.php');
73
74 /**
75 * Define widget and icon and style name.
76 *
77 * @since 1.15.0 (J) - 1.5.0 (WP)
78 */
79 $this->widgetIcon = '<i class="' . VikBookingIcons::i('comments') . '"></i>';
80 $this->widgetStyleName = 'green';
81
82 // activities per type is half the total number of activities
83 $this->activities_per_type = ceil($this->activities_per_page / 2);
84
85 // today Y-m-d date
86 $this->today_ymd = date('Y-m-d');
87
88 // the path to the VCM library
89 $this->vcm_lib_path = VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php';
90
91 // whether VCM is available
92 $this->vcm_exists = true;
93 if (is_file($this->vcm_lib_path)) {
94 // require the dependencies
95 if (!class_exists('VikChannelManager')) {
96 require_once $this->vcm_lib_path;
97 }
98 if (!method_exists('VikChannelManager', 'getLatestFromGuests')) {
99 // VCM is outdated
100 $this->vcm_exists = false;
101 }
102 } else {
103 $this->vcm_exists = false;
104 }
105
106 // avoid queries on certain pages, as VCM may not have been activated yet
107 if (VBOPlatformDetection::isWordPress() && $this->vcm_exists) {
108 global $pagenow;
109 $skip_pages = ['update.php', 'plugins.php', 'plugin-install.php'];
110 if (isset($pagenow) && in_array($pagenow, $skip_pages)) {
111 $this->vcm_exists = false;
112 }
113 }
114 }
115
116 /**
117 * This widget returns the latest activity information to schedule
118 * periodic watch data in order to be able to trigger notifications.
119 * No CSS/JS assets are needed during preloading.
120 *
121 * @return void|object
122 */
123 public function preload()
124 {
125 if (!$this->vcm_exists) {
126 return null;
127 }
128
129 // use VCM to load the latest guest activity ids
130 $latest_activities = [];
131 try {
132 $latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
133 } catch (Exception $e) {
134 // do nothing
135 }
136
137 if (!is_array($latest_activities) || !$latest_activities) {
138 return null;
139 }
140
141 // default watch-data values to monitor
142 $watch_data = new stdClass;
143 $watch_data->guest_review = 0;
144 $watch_data->guest_message = '';
145 $watch_data->message_id = 0;
146 $watch_data->message_bid = 0;
147
148 foreach ($latest_activities as $activity) {
149 if (isset($activity->id_review) && empty($watch_data->guest_review)) {
150 // this is a guest review
151 $watch_data->guest_review = $activity->id_review;
152 } elseif (!isset($activity->id_review) && empty($watch_data->message_id)) {
153 // this is a guest message
154 $watch_data->guest_message = $activity->content;
155 $watch_data->message_id = $activity->id_message;
156 $watch_data->message_bid = $activity->idorder;
157 }
158 }
159
160 return $watch_data;
161 }
162
163 /**
164 * Checks for new notifications by using the previous preloaded watch-data.
165 *
166 * @param VBONotificationWatchdata $watch_data the preloaded watch-data object.
167 *
168 * @return array data object to watch next and notifications array.
169 *
170 * @see preload()
171 *
172 * @since 1.15.0 (J) - 1.5.0 (WP)
173 */
174 public function getNotifications(VBONotificationWatchdata $watch_data = null)
175 {
176 // default empty values
177 $watch_next = null;
178 $notifications = null;
179
180 if (!$this->vcm_exists || !$watch_data) {
181 return [$watch_next, $notifications];
182 }
183
184 // grab latest watch data values
185 $latest_guest_review = (int)$watch_data->get('guest_review', 0);
186 $latest_guest_message = $watch_data->get('guest_message', '');
187 $latest_message_id = (int)$watch_data->get('message_id', 0);
188 $latest_message_bid = (int)$watch_data->get('message_bid', 0);
189
190 // use VCM to load the latest guest activity ids
191 try {
192 $latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
193 } catch (Exception $e) {
194 // do nothing
195 $latest_activities = [];
196 }
197
198 if (!$latest_activities) {
199 return [$watch_next, $notifications];
200 }
201
202 // default watch-data next values to monitor
203 $watch_next = new stdClass;
204 $watch_next->guest_review = $latest_guest_review;
205 $watch_next->guest_message = $latest_guest_message;
206 $watch_next->message_id = $latest_message_id;
207 $watch_next->message_bid = $latest_message_bid;
208
209 // new notifications pool (if any)
210 $notifications = [];
211
212 foreach ($latest_activities as $activity) {
213 if (isset($activity->id_review)) {
214 // this is a guest review
215 if ($activity->id_review > $latest_guest_review) {
216 // set the next watch data value
217 $watch_next->guest_review = $activity->id_review;
218 // compose the notification(s) to dispatch for the guest review(s)
219 $review_notifications = VBONotificationScheduler::getInstance()->buildReviewDataObjects([$activity]);
220 if ($review_notifications) {
221 $notifications = array_merge($notifications, $review_notifications);
222 }
223 }
224 } else {
225 // this is a guest message
226 if (isset($activity->sender_type) && (!strcasecmp($activity->sender_type, 'host') || !strcasecmp($activity->sender_type, 'hotel'))) {
227 // we don't want threads started by the host/hotel
228 continue;
229 }
230
231 // make sure this is a more recent activity than the last one
232 if ($activity->id_message > $latest_message_id && ($activity->idorder != $latest_message_bid || $activity->content != $latest_guest_message)) {
233 // overwrite properties to watch at the next scheduled interval
234 $watch_next->guest_message = $activity->content;
235 $watch_next->message_id = $activity->id_message;
236 $watch_next->message_bid = $activity->idorder;
237
238 // make sure the same message was not previously dispatched through a Push notification
239 if (!$watch_data->matchPushedGuestMessage($activity)) {
240 // compose the notification(s) to dispatch for the guest message(s)
241 $guestmess_notifications = VBONotificationScheduler::getInstance()->buildGuestMessageDataObjects([$activity]);
242 if ($guestmess_notifications) {
243 $notifications = array_merge($notifications, $guestmess_notifications);
244 }
245 }
246 }
247 }
248 }
249
250 return [$watch_next, $notifications];
251 }
252
253 /**
254 * Custom method for this widget only to load the latest guest activities.
255 * The method is called by the admin controller through an AJAX request.
256 * The visibility should be public, it should not exit the process, and
257 * any content sent to output will be returned to the AJAX response.
258 *
259 * It's the actual rendering of the widget which also allows navigation.
260 */
261 public function loadActivities()
262 {
263 $offset = VikRequest::getInt('offset', 0, 'request');
264 $length = VikRequest::getInt('length', $this->activities_per_type, 'request');
265 $wrapper = VikRequest::getString('wrapper', '', 'request');
266
267 if (!$this->vcm_exists) {
268 echo 'e4j.error.missing or outdated VCM';
269 return;
270 }
271
272 // load latest activities
273 $latest_activities = [];
274 try {
275 $latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], $offset, $length);
276 } catch (Exception $e) {
277 // do nothing
278 }
279
280 foreach ($latest_activities as $activity) {
281 $activity_type = isset($activity->id_review) ? 'review' : 'message';
282 $activity_content = $activity->content;
283 if (empty($activity_content)) {
284 $activity_content = '.....';
285 } elseif (strlen($activity_content) > 90) {
286 if (function_exists('mb_substr')) {
287 $activity_content = mb_substr($activity_content, 0, 90, 'UTF-8');
288 } else {
289 $activity_content = substr($activity_content, 0, 90);
290 }
291 $activity_content .= '...';
292 }
293 // determine sender type in case of guest message
294 $sender = 'Hotel';
295 if ($activity_type == 'message' && isset($activity->sender_type)) {
296 if (strcasecmp($activity->sender_type, 'Hotel') && strcasecmp($activity->sender_type, 'Host')) {
297 $sender = 'Guest';
298 }
299 }
300
301 ?>
302 <div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-<?php echo $activity_type; ?>" onclick="vboWidgetLatestFromGuestsOpenBooking('<?php echo $activity->idorder; ?>', '<?php echo $activity_type == 'message' ? '#messaging' : ''; ?>');">
303 <div class="vbo-dashboard-guest-activity-avatar">
304 <?php
305 if (!empty($activity->guest_avatar)) {
306 // highest priority goes to the profile picture, not always available
307 ?>
308 <img class="vbo-dashboard-guest-activity-avatar-profile" src="<?php echo $activity->guest_avatar; ?>" />
309 <?php
310 } elseif (!empty($activity->pic)) {
311 // customer profile picture is not the same as the photo avatar
312 ?>
313 <img class="vbo-dashboard-guest-activity-avatar-profile" src="<?php echo strpos($activity->pic, 'http') === 0 ? $activity->pic : VBO_SITE_URI . 'resources/uploads/' . $activity->pic; ?>" />
314 <?php
315 } elseif (!empty($activity->channel_logo)) {
316 // channel logo goes as second option
317 ?>
318 <img class="vbo-dashboard-guest-activity-avatar-profile" src="<?php echo $activity->channel_logo; ?>" />
319 <?php
320 } else {
321 // we use an icon as fallback
322 VikBookingIcons::e('user', 'vbo-dashboard-guest-activity-avatar-icon');
323 }
324 ?>
325 </div>
326 <div class="vbo-dashboard-guest-activity-content">
327 <div class="vbo-dashboard-guest-activity-content-head">
328 <div class="vbo-dashboard-guest-activity-content-info-details">
329 <h4><?php echo $activity->first_name . (!empty($activity->last_name) ? ' ' . $activity->last_name : ''); ?></h4>
330 <div class="vbo-dashboard-guest-activity-content-info-icon">
331 <?php
332 if ($activity_type == 'review') {
333 // we display an icon as well as the score
334 VikBookingIcons::e('star');
335 ?>
336 <span class="vbo-dashboard-guest-activity-content-info-rate"><?php echo round(($activity->score / 2), 1); ?></span>
337 <?php
338 } else {
339 // we use just an icon to tell that it's a chat guest message
340 if (empty($activity->read_dt) && $sender === 'Guest') {
341 // print also an icon to inform that the message was not read
342 VikBookingIcons::e('exclamation-circle');
343 echo ' ';
344 }
345 VikBookingIcons::e('comment-dots');
346 }
347 ?>
348 </div>
349 </div>
350 <div class="vbo-dashboard-guest-activity-content-info-date">
351 <?php
352 $activity_ts = strtotime($activity->last_updated);
353 ?>
354 <span><?php echo date('H:i', $activity_ts); ?></span>
355 <?php
356 if (date('Y-m-d', $activity_ts) != $this->today_ymd) {
357 // format and print the date
358 ?>
359 <span><?php echo date(str_replace('/', $this->datesep, $this->df), $activity_ts); ?></span>
360 <?php
361 } else {
362 // print "today"
363 ?>
364 <span><?php echo JText::translate('VBTODAY'); ?></span>
365 <?php
366 }
367 ?>
368 </div>
369 </div>
370 <div class="vbo-dashboard-guest-activity-content-info-msg">
371 <p><?php echo $activity_content; ?></p>
372 </div>
373 </div>
374 </div>
375 <?php
376 }
377
378 // append navigation
379 ?>
380 <div class="vbo-guestactivitywidget-commands">
381 <div class="vbo-guestactivitywidget-commands-main">
382 <?php
383 if ($offset > 0) {
384 // show backward navigation button
385 ?>
386 <div class="vbo-guestactivitywidget-command-chevron vbo-guestactivitywidget-command-prev">
387 <span class="vbo-guestactivitywidget-prev" onclick="vboWidgetLatestFromGuestsNavigate('<?php echo $wrapper; ?>', -1);"><?php VikBookingIcons::e('chevron-left'); ?></span>
388 </div>
389 <?php
390 }
391 ?>
392 <div class="vbo-guestactivitywidget-command-chevron vbo-guestactivitywidget-command-next">
393 <span class="vbo-guestactivitywidget-next" onclick="vboWidgetLatestFromGuestsNavigate('<?php echo $wrapper; ?>', 1);"><?php VikBookingIcons::e('chevron-right'); ?></span>
394 </div>
395 </div>
396 </div>
397 <?php
398
399 // append the total number of activities displayed, the current offset and the latest activity datetime
400 $tot_activities = count($latest_activities);
401 $latest_datetime = $tot_activities > 0 && $offset === 0 ? $latest_activities[0]->last_updated : null;
402
403 echo ';' . __FUNCTION__ . ';' . $tot_activities . ';' . __FUNCTION__ . ';' . $offset . ';' . __FUNCTION__ . ';' . $latest_datetime;
404 }
405
406 /**
407 * Custom method for this widget only to watch the latest guest activities.
408 * The method is called by the admin controller through an AJAX request.
409 * The visibility should be public, it should not exit the process, and
410 * any content sent to output will be returned to the AJAX response.
411 *
412 * Outputs the new number of activities found from the latest datetime.
413 */
414 public function watchActivities()
415 {
416 $latest_dt = VikRequest::getString('latest_dt', '', 'request');
417 if (empty($latest_dt)) {
418 echo '0';
419 return;
420 }
421
422 if (!$this->vcm_exists) {
423 echo 'e4j.error.missing or outdated VCM';
424 return;
425 }
426
427 // load the latest activity (one is sufficient)
428 $latest_activities = [];
429 try {
430 $latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
431 } catch (Exception $e) {
432 // do nothing
433 }
434
435 if (!count($latest_activities) || $latest_activities[0]->last_updated == $latest_dt) {
436 // no newest activities found
437 echo '0';
438 return;
439 }
440
441 // print 1 to indicate that new activities should be reloaded
442 echo '1';
443 }
444
445 public function render(VBOMultitaskData $data = null)
446 {
447 // increase widget's instance counter
448 static::$instance_counter++;
449
450 // check whether the widget is being rendered via AJAX when adding it through the customizer
451 $is_ajax = $this->isAjaxRendering();
452
453 // generate a unique ID for the latest from guests wrapper instance
454 $wrapper_instance = !$is_ajax ? static::$instance_counter : rand();
455 $wrapper_id = 'vbo-widget-latest-from-guests-' . $wrapper_instance;
456
457 // this widget will work only if VCM is available and updated, and if permissions are met
458 $vbo_auth_bookings = JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking');
459 if (!$this->vcm_exists || !$vbo_auth_bookings) {
460 return;
461 }
462
463 // multitask data event identifier for intervals
464 $js_intvals_id = '';
465 if ($data && $data->isModalRendering()) {
466 $js_intvals_id = $data->getModalJsIdentifier();
467 }
468
469 ?>
470 <div class="vbo-admin-widget-wrapper">
471 <div class="vbo-admin-widget-head">
472 <h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4>
473 </div>
474 <div id="<?php echo $wrapper_id; ?>" class="vbo-dashboard-guests-latest" data-offset="0" data-length="<?php echo $this->activities_per_type; ?>" data-latestdt="">
475 <div class="vbo-dashboard-guest-activities-inner">
476 <div class="vbo-dashboard-guest-activities-list">
477 <?php
478 for ($i = 0; $i < $this->activities_per_page; $i++) {
479 ?>
480 <div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">
481 <div class="vbo-dashboard-guest-activity-avatar">
482 <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>
483 </div>
484 <div class="vbo-dashboard-guest-activity-content">
485 <div class="vbo-dashboard-guest-activity-content-head">
486 <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>
487 </div>
488 <div class="vbo-dashboard-guest-activity-content-subhead">
489 <div class="vbo-skeleton-loading vbo-skeleton-loading-subtitle"></div>
490 </div>
491 <div class="vbo-dashboard-guest-activity-content-info-msg">
492 <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>
493 </div>
494 </div>
495 </div>
496 <?php
497 }
498 ?>
499 </div>
500 </div>
501 </div>
502 </div>
503
504 <?php
505 if (static::$instance_counter === 0 || $is_ajax) {
506 // HTML helper tag for URL routing and some JS functions should be loaded once per widget instance
507 $admin_file_base = VBOPlatformDetection::isWordPress() ? 'admin.php' : 'index.php';
508 ?>
509 <a class="vbo-widget-latest-from-guests-basenavuri" href="<?php echo $admin_file_base; ?>?option=com_vikbooking&task=editorder&cid[]=%d" style="display: none;"></a>
510
511 <script type="text/javascript">
512
513 /**
514 * Open the booking details page for the clicked activity
515 */
516 function vboWidgetLatestFromGuestsOpenBooking(id, url_suffix) {
517 var open_url = jQuery('.vbo-widget-latest-from-guests-basenavuri').first().attr('href');
518 open_url = open_url.replace('%d', id) + url_suffix;
519 // navigate
520 document.location.href = open_url;
521 }
522
523 /**
524 * Display the loading skeletons.
525 */
526 function vboWidgetLatestFromGuestsSkeletons(wrapper) {
527 var widget_instance = jQuery('#' + wrapper);
528 if (!widget_instance.length) {
529 return false;
530 }
531 widget_instance.find('.vbo-dashboard-guest-activities-list').html('');
532 for (var i = 0; i < <?php echo $this->activities_per_page; ?>; i++) {
533 var skeleton = '';
534 skeleton += '<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">';
535 skeleton += ' <div class="vbo-dashboard-guest-activity-avatar">';
536 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>';
537 skeleton += ' </div>';
538 skeleton += ' <div class="vbo-dashboard-guest-activity-content">';
539 skeleton += ' <div class="vbo-dashboard-guest-activity-content-head">';
540 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>';
541 skeleton += ' </div>';
542 skeleton += ' <div class="vbo-dashboard-guest-activity-content-subhead">';
543 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-subtitle"></div>';
544 skeleton += ' </div>';
545 skeleton += ' <div class="vbo-dashboard-guest-activity-content-info-msg">';
546 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>';
547 skeleton += ' </div>';
548 skeleton += ' </div>';
549 skeleton += '</div>';
550 // append skeleton
551 jQuery(skeleton).appendTo(widget_instance.find('.vbo-dashboard-guest-activities-list'));
552 }
553 }
554
555 /**
556 * Perform the request to load the latest activities.
557 */
558 function vboWidgetLatestFromGuestsLoad(wrapper) {
559 var widget_instance = jQuery('#' + wrapper);
560 if (!widget_instance.length) {
561 return false;
562 }
563 var current_offset = parseInt(widget_instance.attr('data-offset'));
564 var length_per_page = parseInt(widget_instance.attr('data-length'));
565
566 // the widget method to call
567 var call_method = 'loadActivities';
568
569 // make a request to load the activities
570 VBOCore.doAjax(
571 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
572 {
573 widget_id: "<?php echo $this->getIdentifier(); ?>",
574 call: call_method,
575 offset: current_offset,
576 length: length_per_page,
577 wrapper: wrapper,
578 tmpl: "component"
579 },
580 (response) => {
581 try {
582 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
583 if (!obj_res.hasOwnProperty(call_method)) {
584 console.error('Unexpected JSON response', obj_res);
585 return false;
586 }
587 // response must contain 4 values separated by ";call_method;"
588 var activities_data = obj_res[call_method].split(';' + call_method + ';');
589 if (activities_data.length != 4) {
590 return;
591 }
592 // replace HTML with new activities
593 widget_instance.find('.vbo-dashboard-guest-activities-list').html(activities_data[0]);
594 // check if latest datetime is set
595 if (activities_data[3].length) {
596 widget_instance.attr('data-latestdt', activities_data[3]);
597 }
598 // check results
599 if (!isNaN(activities_data[1]) && parseInt(activities_data[1]) < 1) {
600 // no results can indicate the offset is invalid or too high
601 if (!isNaN(activities_data[2]) && parseInt(activities_data[2]) > 0) {
602 // reset offset to 0
603 widget_instance.attr('data-offset', 0);
604 // show loading skeletons
605 vboWidgetLatestFromGuestsSkeletons(wrapper);
606 // reload the first page
607 vboWidgetLatestFromGuestsLoad(wrapper);
608 }
609 }
610 } catch(err) {
611 console.error('could not parse JSON response', err, response);
612 }
613 },
614 (error) => {
615 // remove the skeleton loading
616 widget_instance.find('.vbo-dashboard-guest-activities-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
617 console.error(error);
618 }
619 );
620 }
621
622 /**
623 * Navigate between the various pages of the activities.
624 */
625 function vboWidgetLatestFromGuestsNavigate(wrapper, direction) {
626 var widget_instance = jQuery('#' + wrapper);
627 if (!widget_instance.length) {
628 return false;
629 }
630
631 // current offset
632 var current_offset = parseInt(widget_instance.attr('data-offset'));
633
634 // steps per type
635 var steps = <?php echo $this->activities_per_type; ?>;
636
637 // show loading skeletons
638 vboWidgetLatestFromGuestsSkeletons(wrapper);
639
640 // check direction and update offset for next nav
641 if (direction > 0) {
642 // navigate forward
643 widget_instance.attr('data-offset', (current_offset + steps));
644 } else {
645 // navigate backward
646 var new_offset = current_offset - steps;
647 new_offset = new_offset >= 0 ? new_offset : 0;
648 widget_instance.attr('data-offset', new_offset);
649 }
650
651 // launch navigation
652 vboWidgetLatestFromGuestsLoad(wrapper);
653 }
654
655 /**
656 * Watch periodically if there are new activities to be displayed.
657 */
658 function vboWidgetLatestFromGuestsWatch(wrapper) {
659 var widget_instance = jQuery('#' + wrapper);
660 if (!widget_instance.length) {
661 return false;
662 }
663
664 var latest_dt = widget_instance.attr('data-latestdt');
665 if (!latest_dt || !latest_dt.length) {
666 return false;
667 }
668
669 // the widget method to call
670 var call_method = 'watchActivities';
671
672 // make a request to watch the activities
673 VBOCore.doAjax(
674 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
675 {
676 widget_id: "<?php echo $this->getIdentifier(); ?>",
677 call: call_method,
678 latest_dt: latest_dt,
679 tmpl: "component"
680 },
681 (response) => {
682 try {
683 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
684 if (!obj_res.hasOwnProperty(call_method)) {
685 console.error('Unexpected JSON response', obj_res);
686 return false;
687 }
688 // response will contain the number of new activities
689 if (isNaN(obj_res[call_method]) || parseInt(obj_res[call_method]) < 1) {
690 // do nothing
691 return;
692 }
693 // new activities found, reset the offset and re-load the first page
694 widget_instance.attr('data-offset', 0);
695 // show loading skeletons
696 vboWidgetLatestFromGuestsSkeletons(wrapper);
697 // reload the first page
698 vboWidgetLatestFromGuestsLoad(wrapper);
699 } catch(err) {
700 console.error('could not parse JSON response', err, response);
701 }
702 },
703 (error) => {
704 // do nothing
705 console.error(error);
706 }
707 );
708 }
709
710 </script>
711 <?php
712 }
713 ?>
714
715 <script type="text/javascript">
716
717 jQuery(function() {
718
719 // when document is ready, load latest activities for this widget's instance
720 vboWidgetLatestFromGuestsLoad('<?php echo $wrapper_id; ?>');
721
722 // set interval for loading new activities automatically
723 var watch_intv = setInterval(function() {
724 vboWidgetLatestFromGuestsWatch('<?php echo $wrapper_id; ?>');
725 }, 60000);
726
727 <?php
728 if ($js_intvals_id) {
729 // widget can be dismissed through the modal
730 ?>
731 document.addEventListener(VBOCore.widget_modal_dismissed + '<?php echo $js_intvals_id; ?>', (e) => {
732 clearInterval(watch_intv);
733 });
734 <?php
735 }
736 ?>
737
738 });
739
740 </script>
741
742 <?php
743 }
744 }
745