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

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