PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.7.1
VikBooking Hotel Booking Engine & PMS v1.7.1
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.7.1, at admin/helpers/widgets/latest_from_guests.php

772 lines 25.2 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 ?? 0;
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="vboWidgetLatestFromGuestsShowDetails('<?php echo $activity_type; ?>', '<?php echo $activity_type == 'message' ? $activity->idorder : $activity->id_review; ?>');">
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 (!$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 * Shows the details of either a message or a review.
525 */
526 function vboWidgetLatestFromGuestsShowDetails(type, id) {
527 if (type === 'message') {
528 VBOCore.handleDisplayWidgetNotification({
529 widget_id: 'guest_messages'
530 }, {
531 bid: id,
532 modal_options: {
533 suffix: 'widget_modal_inner_guest_messages',
534 }
535 });
536 } else if (type === 'review') {
537 VBOCore.handleDisplayWidgetNotification({
538 widget_id: 'guest_reviews'
539 }, {
540 review_id: id,
541 modal_options: {
542 suffix: 'widget_modal_inner_guest_reviews',
543 }
544 });
545 } else {
546 vboWidgetLatestFromGuestsOpenBooking(id, '');
547 }
548 }
549
550 /**
551 * Display the loading skeletons.
552 */
553 function vboWidgetLatestFromGuestsSkeletons(wrapper) {
554 var widget_instance = jQuery('#' + wrapper);
555 if (!widget_instance.length) {
556 return false;
557 }
558 widget_instance.find('.vbo-dashboard-guest-activities-list').html('');
559 for (var i = 0; i < <?php echo $this->activities_per_page; ?>; i++) {
560 var skeleton = '';
561 skeleton += '<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">';
562 skeleton += ' <div class="vbo-dashboard-guest-activity-avatar">';
563 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>';
564 skeleton += ' </div>';
565 skeleton += ' <div class="vbo-dashboard-guest-activity-content">';
566 skeleton += ' <div class="vbo-dashboard-guest-activity-content-head">';
567 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>';
568 skeleton += ' </div>';
569 skeleton += ' <div class="vbo-dashboard-guest-activity-content-subhead">';
570 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-subtitle"></div>';
571 skeleton += ' </div>';
572 skeleton += ' <div class="vbo-dashboard-guest-activity-content-info-msg">';
573 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>';
574 skeleton += ' </div>';
575 skeleton += ' </div>';
576 skeleton += '</div>';
577 // append skeleton
578 jQuery(skeleton).appendTo(widget_instance.find('.vbo-dashboard-guest-activities-list'));
579 }
580 }
581
582 /**
583 * Perform the request to load the latest activities.
584 */
585 function vboWidgetLatestFromGuestsLoad(wrapper) {
586 var widget_instance = jQuery('#' + wrapper);
587 if (!widget_instance.length) {
588 return false;
589 }
590 var current_offset = parseInt(widget_instance.attr('data-offset'));
591 var length_per_page = parseInt(widget_instance.attr('data-length'));
592
593 // the widget method to call
594 var call_method = 'loadActivities';
595
596 // make a request to load the activities
597 VBOCore.doAjax(
598 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
599 {
600 widget_id: "<?php echo $this->getIdentifier(); ?>",
601 call: call_method,
602 offset: current_offset,
603 length: length_per_page,
604 wrapper: wrapper,
605 tmpl: "component"
606 },
607 (response) => {
608 try {
609 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
610 if (!obj_res.hasOwnProperty(call_method)) {
611 console.error('Unexpected JSON response', obj_res);
612 return false;
613 }
614 // response must contain 4 values separated by ";call_method;"
615 var activities_data = obj_res[call_method].split(';' + call_method + ';');
616 if (activities_data.length != 4) {
617 return;
618 }
619 // replace HTML with new activities
620 widget_instance.find('.vbo-dashboard-guest-activities-list').html(activities_data[0]);
621 // check if latest datetime is set
622 if (activities_data[3].length) {
623 widget_instance.attr('data-latestdt', activities_data[3]);
624 }
625 // check results
626 if (!isNaN(activities_data[1]) && parseInt(activities_data[1]) < 1) {
627 // no results can indicate the offset is invalid or too high
628 if (!isNaN(activities_data[2]) && parseInt(activities_data[2]) > 0) {
629 // reset offset to 0
630 widget_instance.attr('data-offset', 0);
631 // show loading skeletons
632 vboWidgetLatestFromGuestsSkeletons(wrapper);
633 // reload the first page
634 vboWidgetLatestFromGuestsLoad(wrapper);
635 }
636 }
637 } catch(err) {
638 console.error('could not parse JSON response', err, response);
639 }
640 },
641 (error) => {
642 // remove the skeleton loading
643 widget_instance.find('.vbo-dashboard-guest-activities-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
644 console.error(error);
645 }
646 );
647 }
648
649 /**
650 * Navigate between the various pages of the activities.
651 */
652 function vboWidgetLatestFromGuestsNavigate(wrapper, direction) {
653 var widget_instance = jQuery('#' + wrapper);
654 if (!widget_instance.length) {
655 return false;
656 }
657
658 // current offset
659 var current_offset = parseInt(widget_instance.attr('data-offset'));
660
661 // steps per type
662 var steps = <?php echo $this->activities_per_type; ?>;
663
664 // show loading skeletons
665 vboWidgetLatestFromGuestsSkeletons(wrapper);
666
667 // check direction and update offset for next nav
668 if (direction > 0) {
669 // navigate forward
670 widget_instance.attr('data-offset', (current_offset + steps));
671 } else {
672 // navigate backward
673 var new_offset = current_offset - steps;
674 new_offset = new_offset >= 0 ? new_offset : 0;
675 widget_instance.attr('data-offset', new_offset);
676 }
677
678 // launch navigation
679 vboWidgetLatestFromGuestsLoad(wrapper);
680 }
681
682 /**
683 * Watch periodically if there are new activities to be displayed.
684 */
685 function vboWidgetLatestFromGuestsWatch(wrapper) {
686 var widget_instance = jQuery('#' + wrapper);
687 if (!widget_instance.length) {
688 return false;
689 }
690
691 var latest_dt = widget_instance.attr('data-latestdt');
692 if (!latest_dt || !latest_dt.length) {
693 return false;
694 }
695
696 // the widget method to call
697 var call_method = 'watchActivities';
698
699 // make a request to watch the activities
700 VBOCore.doAjax(
701 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
702 {
703 widget_id: "<?php echo $this->getIdentifier(); ?>",
704 call: call_method,
705 latest_dt: latest_dt,
706 tmpl: "component"
707 },
708 (response) => {
709 try {
710 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
711 if (!obj_res.hasOwnProperty(call_method)) {
712 console.error('Unexpected JSON response', obj_res);
713 return false;
714 }
715 // response will contain the number of new activities
716 if (isNaN(obj_res[call_method]) || parseInt(obj_res[call_method]) < 1) {
717 // do nothing
718 return;
719 }
720 // new activities found, reset the offset and re-load the first page
721 widget_instance.attr('data-offset', 0);
722 // show loading skeletons
723 vboWidgetLatestFromGuestsSkeletons(wrapper);
724 // reload the first page
725 vboWidgetLatestFromGuestsLoad(wrapper);
726 } catch(err) {
727 console.error('could not parse JSON response', err, response);
728 }
729 },
730 (error) => {
731 // do nothing
732 console.error(error);
733 }
734 );
735 }
736
737 </script>
738 <?php
739 }
740 ?>
741
742 <script type="text/javascript">
743
744 jQuery(function() {
745
746 // when document is ready, load latest activities for this widget's instance
747 vboWidgetLatestFromGuestsLoad('<?php echo $wrapper_id; ?>');
748
749 // set interval for loading new activities automatically
750 var watch_intv = setInterval(function() {
751 vboWidgetLatestFromGuestsWatch('<?php echo $wrapper_id; ?>');
752 }, 60000);
753
754 <?php
755 if ($js_intvals_id) {
756 // widget can be dismissed through the modal
757 ?>
758 document.addEventListener(VBOCore.widget_modal_dismissed + '<?php echo $js_intvals_id; ?>', (e) => {
759 clearInterval(watch_intv);
760 });
761 <?php
762 }
763 ?>
764
765 });
766
767 </script>
768
769 <?php
770 }
771 }
772