File "latest_from_guests.php"
Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/admin/helpers/widgets/latest_from_guests.php
File size: 26.41 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* @package VikBooking
* @subpackage com_vikbooking
* @author Alessio Gaggii - e4j - Extensionsforjoomla.com
* @copyright Copyright (C) 2018 e4j - Extensionsforjoomla.com. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE
* @link https://vikwp.com
*/
defined('ABSPATH') or die('No script kiddies please!');
/**
* Class handler for admin widget "latest from guests".
*
* @since 1.14.0 (J) - 1.4.0 (WP)
*/
class VikBookingAdminWidgetLatestFromGuests extends VikBookingAdminWidget
{
/**
* The instance counter of this widget.
*
* @var int
*/
protected static $instance_counter = -1;
/**
* Number of activities per page. Should be an even number.
*
* @var int
*/
protected $activities_per_page = 6;
/**
* Number of activities per type. Should be half of numer per page.
*
* @var int
*/
protected $activities_per_type = 3;
/**
* Today Y-m-d string
*
* @var string
*/
protected $today_ymd = null;
/**
* The path to the VCM lib to see if it's available.
*
* @var string
*/
protected $vcm_lib_path = '';
/**
* Tells whether VCM is installed and updated.
*
* @var bool
*/
protected $vcm_exists = true;
/**
* List of new guest messages detected.
*
* @var array
*
* @since 1.17.6 (J) - 1.7.6 (WP)
*/
protected $new_guest_messages = [];
/**
* Class constructor will define the widget name and identifier.
*/
public function __construct()
{
// call parent constructor
parent::__construct();
$this->widgetName = JText::translate('VBO_W_LATESTFROMGUESTS_TITLE');
$this->widgetDescr = JText::translate('VBO_W_LATESTFROMGUESTS_DESCR');
$this->widgetId = basename(__FILE__, '.php');
/**
* Define widget and icon and style name.
*
* @since 1.15.0 (J) - 1.5.0 (WP)
*/
$this->widgetIcon = '<i class="' . VikBookingIcons::i('comments') . '"></i>';
$this->widgetStyleName = 'green';
// activities per type is half the total number of activities
$this->activities_per_type = ceil($this->activities_per_page / 2);
// today Y-m-d date
$this->today_ymd = date('Y-m-d');
// the path to the VCM library
$this->vcm_lib_path = VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php';
// whether VCM is available
$this->vcm_exists = true;
if (is_file($this->vcm_lib_path)) {
// require the dependencies
if (!class_exists('VikChannelManager')) {
require_once $this->vcm_lib_path;
}
if (!method_exists('VikChannelManager', 'getLatestFromGuests')) {
// VCM is outdated
$this->vcm_exists = false;
}
} else {
$this->vcm_exists = false;
}
// avoid queries on certain pages, as VCM may not have been activated yet
if (VBOPlatformDetection::isWordPress() && $this->vcm_exists) {
global $pagenow;
$skip_pages = ['update.php', 'plugins.php', 'plugin-install.php'];
if (isset($pagenow) && in_array($pagenow, $skip_pages)) {
$this->vcm_exists = false;
}
}
}
/**
* This widget returns the latest activity information to schedule
* periodic watch data in order to be able to trigger notifications.
* No CSS/JS assets are needed during preloading.
*
* @return void|object
*/
public function preload()
{
if (!$this->vcm_exists) {
return null;
}
// use VCM to load the latest guest activity ids
$latest_activities = [];
try {
$latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
} catch (Exception $e) {
// do nothing
}
if (!is_array($latest_activities) || !$latest_activities) {
return null;
}
// default watch-data values to monitor
$watch_data = new stdClass;
$watch_data->guest_review = 0;
$watch_data->guest_message = '';
$watch_data->message_id = 0;
$watch_data->message_bid = 0;
foreach ($latest_activities as $activity) {
if (isset($activity->id_review) && empty($watch_data->guest_review)) {
// this is a guest review
$watch_data->guest_review = $activity->id_review;
} elseif (!isset($activity->id_review) && empty($watch_data->message_id)) {
// this is a guest message
$watch_data->guest_message = $activity->content;
$watch_data->message_id = $activity->id_message ?? 0;
$watch_data->message_bid = $activity->idorder;
}
}
return $watch_data;
}
/**
* Checks for new notifications by using the previous preloaded watch-data.
*
* @param ?VBONotificationWatchdata $watch_data the preloaded watch-data object.
*
* @return array data object to watch next and notifications array.
*
* @see preload()
*
* @since 1.15.0 (J) - 1.5.0 (WP)
*/
public function getNotifications(?VBONotificationWatchdata $watch_data = null)
{
// default empty values
$watch_next = null;
$notifications = null;
if (!$this->vcm_exists || !$watch_data) {
return [$watch_next, $notifications];
}
// grab latest watch data values
$latest_guest_review = (int)$watch_data->get('guest_review', 0);
$latest_guest_message = $watch_data->get('guest_message', '');
$latest_message_id = (int)$watch_data->get('message_id', 0);
$latest_message_bid = (int)$watch_data->get('message_bid', 0);
// use VCM to load the latest guest activity ids
try {
$latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
} catch (Exception $e) {
// do nothing
$latest_activities = [];
}
if (!$latest_activities) {
return [$watch_next, $notifications];
}
// default watch-data next values to monitor
$watch_next = new stdClass;
$watch_next->guest_review = $latest_guest_review;
$watch_next->guest_message = $latest_guest_message;
$watch_next->message_id = $latest_message_id;
$watch_next->message_bid = $latest_message_bid;
// new notifications pool (if any)
$notifications = [];
foreach ($latest_activities as $activity) {
if (isset($activity->id_review)) {
// this is a guest review
if ($activity->id_review > $latest_guest_review) {
// set the next watch data value
$watch_next->guest_review = $activity->id_review;
// compose the notification(s) to dispatch for the guest review(s)
$review_notifications = VBONotificationScheduler::getInstance()->buildReviewDataObjects([$activity]);
if ($review_notifications) {
$notifications = array_merge($notifications, $review_notifications);
}
}
} else {
// this is a guest message
if (isset($activity->sender_type) && (!strcasecmp($activity->sender_type, 'host') || !strcasecmp($activity->sender_type, 'hotel'))) {
// we don't want threads started by the host/hotel
continue;
}
// make sure this is a more recent activity than the last one
if ($activity->id_message > $latest_message_id && ($activity->idorder != $latest_message_bid || $activity->content != $latest_guest_message)) {
// overwrite properties to watch at the next scheduled interval
$watch_next->guest_message = $activity->content;
$watch_next->message_id = $activity->id_message;
$watch_next->message_bid = $activity->idorder;
// make sure the same message was not previously dispatched through a Push notification
if (!$watch_data->matchPushedGuestMessage($activity)) {
// compose the notification(s) to dispatch for the guest message(s)
$guestmess_notifications = VBONotificationScheduler::getInstance()->buildGuestMessageDataObjects([$activity]);
if ($guestmess_notifications) {
$notifications = array_merge($notifications, $guestmess_notifications);
}
// set the new guest message
$this->new_guest_messages[] = [
'id' => $watch_next->message_id,
'bid' => $watch_next->message_bid,
];
}
}
}
}
return [$watch_next, $notifications];
}
/**
* Checks for new events to be dispatched by using the previous preloaded watch-data.
* This method is called after getNotifications(), so we avoid querying the DB.
*
* @param ?VBONotificationWatchdata $watch_data the preloaded watch-data object.
*
* @return array list of event objects to dispatch, if any.
*
* @see preload()
*
* @since 1.17.6 (J) - 1.7.6 (WP)
*/
public function getNotificationEvents(?VBONotificationWatchdata $watch_data = null)
{
if (!$this->new_guest_messages) {
return [];
}
// return the notification events to dispatch
return [
// propagate the new guest messages
'vbo-new-guest-messages' => [
'messages' => $this->new_guest_messages,
],
// update the admin-dock badge count, if widget available
'vbo-admin-dock-update-badge' => [
'widgetId' => 'guest_messages',
'badgeCount' => count($this->new_guest_messages),
],
];
}
/**
* Custom method for this widget only to load the latest guest activities.
* The method is called by the admin controller through an AJAX request.
* The visibility should be public, it should not exit the process, and
* any content sent to output will be returned to the AJAX response.
*
* It's the actual rendering of the widget which also allows navigation.
*/
public function loadActivities()
{
$offset = VikRequest::getInt('offset', 0, 'request');
$length = VikRequest::getInt('length', $this->activities_per_type, 'request');
$wrapper = VikRequest::getString('wrapper', '', 'request');
if (!$this->vcm_exists) {
echo 'e4j.error.missing or outdated VCM';
return;
}
// load latest activities
$latest_activities = [];
try {
$latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], $offset, $length);
} catch (Exception $e) {
// do nothing
}
foreach ($latest_activities as $activity) {
$activity_type = isset($activity->id_review) ? 'review' : 'message';
$activity_content = $activity->content;
if (empty($activity_content)) {
$activity_content = '.....';
} elseif (strlen($activity_content) > 90) {
if (function_exists('mb_substr')) {
$activity_content = mb_substr($activity_content, 0, 90, 'UTF-8');
} else {
$activity_content = substr($activity_content, 0, 90);
}
$activity_content .= '...';
}
// determine sender type in case of guest message
$sender = 'Hotel';
if ($activity_type == 'message' && isset($activity->sender_type)) {
if (strcasecmp($activity->sender_type, 'Hotel') && strcasecmp($activity->sender_type, 'Host')) {
$sender = 'Guest';
}
}
?>
<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; ?>');">
<div class="vbo-dashboard-guest-activity-avatar">
<?php
if (!empty($activity->guest_avatar)) {
// highest priority goes to the profile picture, not always available
?>
<img class="vbo-dashboard-guest-activity-avatar-profile" src="<?php echo $activity->guest_avatar; ?>" />
<?php
} elseif (!empty($activity->pic)) {
// customer profile picture is not the same as the photo avatar
?>
<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; ?>" />
<?php
} elseif (!empty($activity->channel_logo)) {
// channel logo goes as second option
?>
<img class="vbo-dashboard-guest-activity-avatar-profile" src="<?php echo $activity->channel_logo; ?>" />
<?php
} else {
// we use an icon as fallback
VikBookingIcons::e('user', 'vbo-dashboard-guest-activity-avatar-icon');
}
?>
</div>
<div class="vbo-dashboard-guest-activity-content">
<div class="vbo-dashboard-guest-activity-content-head">
<div class="vbo-dashboard-guest-activity-content-info-details">
<h4><?php echo $activity->first_name . (!empty($activity->last_name) ? ' ' . $activity->last_name : ''); ?></h4>
<div class="vbo-dashboard-guest-activity-content-info-icon">
<?php
if ($activity_type == 'review') {
// we display an icon as well as the score
VikBookingIcons::e('star');
?>
<span class="vbo-dashboard-guest-activity-content-info-rate"><?php echo round(($activity->score / 2), 1); ?></span>
<?php
} else {
// we use just an icon to tell that it's a chat guest message
if (empty($activity->read_dt) && $sender === 'Guest') {
// print also an icon to inform that the message was not read
VikBookingIcons::e('exclamation-circle');
echo ' ';
}
VikBookingIcons::e('comment-dots');
}
?>
</div>
</div>
<div class="vbo-dashboard-guest-activity-content-info-date">
<?php
$activity_ts = strtotime($activity->last_updated);
?>
<span><?php echo date('H:i', $activity_ts); ?></span>
<?php
if (date('Y-m-d', $activity_ts) != $this->today_ymd) {
// format and print the date
?>
<span><?php echo date(str_replace('/', $this->datesep, $this->df), $activity_ts); ?></span>
<?php
} else {
// print "today"
?>
<span><?php echo JText::translate('VBTODAY'); ?></span>
<?php
}
?>
</div>
</div>
<div class="vbo-dashboard-guest-activity-content-info-msg">
<p><?php echo $activity_content; ?></p>
</div>
</div>
</div>
<?php
}
// append navigation
?>
<div class="vbo-guestactivitywidget-commands">
<div class="vbo-guestactivitywidget-commands-main">
<?php
if ($offset > 0) {
// show backward navigation button
?>
<div class="vbo-guestactivitywidget-command-chevron vbo-guestactivitywidget-command-prev">
<span class="vbo-guestactivitywidget-prev" onclick="vboWidgetLatestFromGuestsNavigate('<?php echo $wrapper; ?>', -1);"><?php VikBookingIcons::e('chevron-left'); ?></span>
</div>
<?php
}
?>
<div class="vbo-guestactivitywidget-command-chevron vbo-guestactivitywidget-command-next">
<span class="vbo-guestactivitywidget-next" onclick="vboWidgetLatestFromGuestsNavigate('<?php echo $wrapper; ?>', 1);"><?php VikBookingIcons::e('chevron-right'); ?></span>
</div>
</div>
</div>
<?php
// append the total number of activities displayed, the current offset and the latest activity datetime
$tot_activities = count($latest_activities);
$latest_datetime = $tot_activities > 0 && $offset === 0 ? $latest_activities[0]->last_updated : null;
echo ';' . __FUNCTION__ . ';' . $tot_activities . ';' . __FUNCTION__ . ';' . $offset . ';' . __FUNCTION__ . ';' . $latest_datetime;
}
/**
* Custom method for this widget only to watch the latest guest activities.
* The method is called by the admin controller through an AJAX request.
* The visibility should be public, it should not exit the process, and
* any content sent to output will be returned to the AJAX response.
*
* Outputs the new number of activities found from the latest datetime.
*/
public function watchActivities()
{
$latest_dt = VikRequest::getString('latest_dt', '', 'request');
if (empty($latest_dt)) {
echo '0';
return;
}
if (!$this->vcm_exists) {
echo 'e4j.error.missing or outdated VCM';
return;
}
// load the latest activity (one is sufficient)
$latest_activities = [];
try {
$latest_activities = VikChannelManager::getLatestFromGuests(['messages', 'reviews'], 0, 1);
} catch (Exception $e) {
// do nothing
}
if (!$latest_activities || $latest_activities[0]->last_updated == $latest_dt) {
// no newest activities found
echo '0';
return;
}
// print 1 to indicate that new activities should be reloaded
echo '1';
}
public function render(?VBOMultitaskData $data = null)
{
// increase widget's instance counter
static::$instance_counter++;
// check whether the widget is being rendered via AJAX when adding it through the customizer
$is_ajax = $this->isAjaxRendering();
// generate a unique ID for the latest from guests wrapper instance
$wrapper_instance = !$is_ajax ? static::$instance_counter : rand();
$wrapper_id = 'vbo-widget-latest-from-guests-' . $wrapper_instance;
// this widget will work only if VCM is available and updated, and if permissions are met
$vbo_auth_bookings = JFactory::getUser()->authorise('core.vbo.bookings', 'com_vikbooking');
if (!$this->vcm_exists || !$vbo_auth_bookings) {
return;
}
// multitask data event identifier for intervals
$js_intvals_id = '';
if ($data && $data->isModalRendering()) {
$js_intvals_id = $data->getModalJsIdentifier();
}
?>
<div class="vbo-admin-widget-wrapper">
<div class="vbo-admin-widget-head">
<h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4>
</div>
<div id="<?php echo $wrapper_id; ?>" class="vbo-dashboard-guests-latest" data-offset="0" data-length="<?php echo $this->activities_per_type; ?>" data-latestdt="">
<div class="vbo-dashboard-guest-activities-inner">
<div class="vbo-dashboard-guest-activities-list">
<?php
for ($i = 0; $i < $this->activities_per_page; $i++) {
?>
<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">
<div class="vbo-dashboard-guest-activity-avatar">
<div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>
</div>
<div class="vbo-dashboard-guest-activity-content">
<div class="vbo-dashboard-guest-activity-content-head">
<div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>
</div>
<div class="vbo-dashboard-guest-activity-content-subhead">
<div class="vbo-skeleton-loading vbo-skeleton-loading-subtitle"></div>
</div>
<div class="vbo-dashboard-guest-activity-content-info-msg">
<div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>
</div>
</div>
</div>
<?php
}
?>
</div>
</div>
</div>
</div>
<?php
if (static::$instance_counter === 0 || $is_ajax) {
// HTML helper tag for URL routing and some JS functions should be loaded once per widget instance
$admin_file_base = VBOPlatformDetection::isWordPress() ? 'admin.php' : 'index.php';
?>
<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>
<script type="text/javascript">
/**
* Open the booking details page for the clicked activity
*/
function vboWidgetLatestFromGuestsOpenBooking(id, url_suffix) {
var open_url = jQuery('.vbo-widget-latest-from-guests-basenavuri').first().attr('href');
open_url = open_url.replace('%d', id) + url_suffix;
// navigate
document.location.href = open_url;
}
/**
* Shows the details of either a message or a review.
*/
function vboWidgetLatestFromGuestsShowDetails(type, id) {
if (type === 'message') {
VBOCore.handleDisplayWidgetNotification({
widget_id: 'guest_messages'
}, {
bid: id,
modal_options: {
suffix: 'widget_modal_inner_guest_messages',
}
});
} else if (type === 'review') {
VBOCore.handleDisplayWidgetNotification({
widget_id: 'guest_reviews'
}, {
review_id: id,
modal_options: {
suffix: 'widget_modal_inner_guest_reviews',
}
});
} else {
vboWidgetLatestFromGuestsOpenBooking(id, '');
}
}
/**
* Display the loading skeletons.
*/
function vboWidgetLatestFromGuestsSkeletons(wrapper) {
var widget_instance = jQuery('#' + wrapper);
if (!widget_instance.length) {
return false;
}
widget_instance.find('.vbo-dashboard-guest-activities-list').html('');
for (var i = 0; i < <?php echo $this->activities_per_page; ?>; i++) {
var skeleton = '';
skeleton += '<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">';
skeleton += ' <div class="vbo-dashboard-guest-activity-avatar">';
skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>';
skeleton += ' </div>';
skeleton += ' <div class="vbo-dashboard-guest-activity-content">';
skeleton += ' <div class="vbo-dashboard-guest-activity-content-head">';
skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>';
skeleton += ' </div>';
skeleton += ' <div class="vbo-dashboard-guest-activity-content-subhead">';
skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-subtitle"></div>';
skeleton += ' </div>';
skeleton += ' <div class="vbo-dashboard-guest-activity-content-info-msg">';
skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>';
skeleton += ' </div>';
skeleton += ' </div>';
skeleton += '</div>';
// append skeleton
jQuery(skeleton).appendTo(widget_instance.find('.vbo-dashboard-guest-activities-list'));
}
}
/**
* Perform the request to load the latest activities.
*/
function vboWidgetLatestFromGuestsLoad(wrapper) {
var widget_instance = jQuery('#' + wrapper);
if (!widget_instance.length) {
return false;
}
var current_offset = parseInt(widget_instance.attr('data-offset'));
var length_per_page = parseInt(widget_instance.attr('data-length'));
// the widget method to call
var call_method = 'loadActivities';
// make a request to load the activities
VBOCore.doAjax(
"<?php echo $this->getExecWidgetAjaxUri(); ?>",
{
widget_id: "<?php echo $this->getIdentifier(); ?>",
call: call_method,
offset: current_offset,
length: length_per_page,
wrapper: wrapper,
tmpl: "component"
},
(response) => {
try {
var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
if (!obj_res.hasOwnProperty(call_method)) {
console.error('Unexpected JSON response', obj_res);
return false;
}
// response must contain 4 values separated by ";call_method;"
var activities_data = obj_res[call_method].split(';' + call_method + ';');
if (activities_data.length != 4) {
return;
}
// replace HTML with new activities
widget_instance.find('.vbo-dashboard-guest-activities-list').html(activities_data[0]);
// check if latest datetime is set
if (activities_data[3].length) {
widget_instance.attr('data-latestdt', activities_data[3]);
}
// check results
if (!isNaN(activities_data[1]) && parseInt(activities_data[1]) < 1) {
// no results can indicate the offset is invalid or too high
if (!isNaN(activities_data[2]) && parseInt(activities_data[2]) > 0) {
// reset offset to 0
widget_instance.attr('data-offset', 0);
// show loading skeletons
vboWidgetLatestFromGuestsSkeletons(wrapper);
// reload the first page
vboWidgetLatestFromGuestsLoad(wrapper);
}
}
} catch(err) {
console.error('could not parse JSON response', err, response);
}
},
(error) => {
// remove the skeleton loading
widget_instance.find('.vbo-dashboard-guest-activities-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
console.error(error);
}
);
}
/**
* Navigate between the various pages of the activities.
*/
function vboWidgetLatestFromGuestsNavigate(wrapper, direction) {
var widget_instance = jQuery('#' + wrapper);
if (!widget_instance.length) {
return false;
}
// current offset
var current_offset = parseInt(widget_instance.attr('data-offset'));
// steps per type
var steps = <?php echo $this->activities_per_type; ?>;
// show loading skeletons
vboWidgetLatestFromGuestsSkeletons(wrapper);
// check direction and update offset for next nav
if (direction > 0) {
// navigate forward
widget_instance.attr('data-offset', (current_offset + steps));
} else {
// navigate backward
var new_offset = current_offset - steps;
new_offset = new_offset >= 0 ? new_offset : 0;
widget_instance.attr('data-offset', new_offset);
}
// launch navigation
vboWidgetLatestFromGuestsLoad(wrapper);
}
/**
* Watch periodically if there are new activities to be displayed.
*/
function vboWidgetLatestFromGuestsWatch(wrapper) {
var widget_instance = jQuery('#' + wrapper);
if (!widget_instance.length) {
return false;
}
var latest_dt = widget_instance.attr('data-latestdt');
if (!latest_dt || !latest_dt.length) {
return false;
}
// the widget method to call
var call_method = 'watchActivities';
// make a request to watch the activities
VBOCore.doAjax(
"<?php echo $this->getExecWidgetAjaxUri(); ?>",
{
widget_id: "<?php echo $this->getIdentifier(); ?>",
call: call_method,
latest_dt: latest_dt,
tmpl: "component"
},
(response) => {
try {
var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
if (!obj_res.hasOwnProperty(call_method)) {
console.error('Unexpected JSON response', obj_res);
return false;
}
// response will contain the number of new activities
if (isNaN(obj_res[call_method]) || parseInt(obj_res[call_method]) < 1) {
// do nothing
return;
}
// new activities found, reset the offset and re-load the first page
widget_instance.attr('data-offset', 0);
// show loading skeletons
vboWidgetLatestFromGuestsSkeletons(wrapper);
// reload the first page
vboWidgetLatestFromGuestsLoad(wrapper);
} catch(err) {
console.error('could not parse JSON response', err, response);
}
},
(error) => {
// do nothing
console.error(error);
}
);
}
</script>
<?php
}
?>
<script type="text/javascript">
jQuery(function() {
// when document is ready, load latest activities for this widget's instance
vboWidgetLatestFromGuestsLoad('<?php echo $wrapper_id; ?>');
// set interval for loading new activities automatically
var watch_intv = setInterval(function() {
vboWidgetLatestFromGuestsWatch('<?php echo $wrapper_id; ?>');
}, 60000);
<?php
if ($js_intvals_id) {
// widget can be dismissed through the modal
?>
document.addEventListener(VBOCore.widget_modal_dismissed + '<?php echo $js_intvals_id; ?>', (e) => {
clearInterval(watch_intv);
});
<?php
}
?>
});
</script>
<?php
}
}