File "reminders.php"

Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/admin/helpers/widgets/reminders.php
File size: 49.56 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * @package     VikBooking
 * @subpackage  com_vikbooking
 * @author      Alessio Gaggii - E4J srl
 * @copyright   Copyright (C) 2022 E4J srl. 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 "reminders".
 * 
 * @since 	1.15.0 (J) - 1.5.0 (WP)
 */
class VikBookingAdminWidgetReminders extends VikBookingAdminWidget
{
	/**
	 * The instance counter of this widget. Since we do not load individual parameters
	 * for each widget's instance, we use a static counter to determine its settings.
	 *
	 * @var 	int
	 */
	protected static $instance_counter = -1;

	/**
	 * Default number of reminders per page.
	 * 
	 * @var 	int
	 */
	protected $reminders_per_page = 6;

	/**
	 * Tells whether VCM is installed.
	 * 
	 * @var 	bool
	 */
	protected $vcm_exists = false;

	/**
	 * Class constructor will define the widget name and identifier.
	 */
	public function __construct()
	{
		// call parent constructor
		parent::__construct();

		$this->widgetName = JText::translate('VBO_W_REMINDERS_TITLE');
		$this->widgetDescr = JText::translate('VBO_W_REMINDERS_DESCR');
		$this->widgetId = basename(__FILE__, '.php');

		// define widget and icon and style name
		$this->widgetIcon = '<i class="' . VikBookingIcons::i('bell') . '"></i>';
		$this->widgetStyleName = 'green';

		// load widget's settings
		$this->widgetSettings = $this->loadSettings();
		if (!is_object($this->widgetSettings)) {
			$this->widgetSettings = new stdClass;
		}

		// check if VCM is available
		if (is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php')) {
			$this->vcm_exists = true;
		}
	}

	/**
	 * This widget does not actually need to preload data to be watched for
	 * dispatching notifications, and the reminders due are automatically
	 * scheduled for being dispatched as a browser notification. However,
	 * we make use of this method to periodically check if some reminders
	 * should be automatically created for specific reasons, such as the
	 * Airbnb host-to-guest reviews to remind the host to review the guest.
	 * We also preload the necessary CSS/JS assets and schedule the imminent
	 * reminders for notifications, if any.
	 * 
	 * @return 	void
	 */
	public function preload()
	{
		// declare JS lang vars
		JText::script('VBO_PLEASE_FILL_FIELDS');
		JText::script('VBDELCONFIRM');
		JText::script('VBCONFIGCLOSINGDATEADD');
		JText::script('VBADMINNOTESUPD');

		// load assets
		$this->vbo_app->loadDatePicker();

		// check if VCM is available
		if ($this->vcm_exists) {
			$today_dt 	  = date('Y-m-d');
			$yesterday_dt = date('Y-m-d', strtotime('yesterday'));

			// check the last time this check was made
			$last_check_dt = isset($this->widgetSettings->last_check_dt) ? $this->widgetSettings->last_check_dt : $yesterday_dt;

			if ($last_check_dt != $today_dt) {
				// update last check date
				$this->widgetSettings->last_check_dt = $today_dt;
				$this->updateSettings(json_encode($this->widgetSettings));

				// check for any Channel Manager reservation that requires an auto-reminder
				$this->scheduleChannelManagerReminders();
			}
		}

		// load the 10 next (imminent) reminders
		$overdue = VBORemindersHelper::getInstance()->getImminents(10);
		if ($overdue) {
			// schedule browser notifications for the next reminders
			VBONotificationScheduler::getInstance()->enqueueReminders($overdue);
		}

		// nothing should be actually watched, ever
		return null;
	}

	/**
	 * Custom method for this widget only to load the reminder records.
	 * 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.
	 * In this case we return an array because this method requires "return":1.
	 * 
	 * It's the actual rendering of the widget which also allows navigation.
	 * 
	 * @return 	array
	 */
	public function loadReminders()
	{
		$offset = VikRequest::getInt('offset', 0, 'request');
		$length = VikRequest::getInt('length', $this->reminders_per_page, 'request');
		$completed = VikRequest::getInt('completed', 0, 'request');
		$expired = VikRequest::getInt('expired', 0, 'request');
		$bid = VikRequest::getInt('bid', 0, 'request');
		$reminder_id = VikRequest::getInt('reminder_id', 0, 'request');
		$wrapper = VikRequest::getString('wrapper', '', 'request');

		// load reminders starting from today at 00:00:00
		$now_info = getdate();
		$lim_min_date = date('Y-m-d H:i:s', mktime(0, 0, 0, $now_info['mon'], $now_info['mday'], $now_info['year']));

		// prepare fetch options
		$fetch = [
			'after' 	=> $lim_min_date,
			'completed' => $completed,
			'expired' 	=> $expired,
			'idorder' 	=> $bid,
		];

		// load reminders
		$helper = VBORemindersHelper::getInstance();
		$reminders = $helper->loadReminders($fetch, $offset, $length);

		// check if a next page can be available
		$has_next_page = (count($reminders) >= $length);

		// compose bookings base URI
		$bookings_base_uri = VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=%d', $xhtml = false);

		// check if a specific reminder ID was requested
		if ($reminder_id) {
			// check if the requested ID was found among the most recent ones
			$reminder_found = false;
			foreach ($reminders as $reminder) {
				if ($reminder->id == $reminder_id) {
					$reminder_found = true;
					break;
				}
			}

			if (!$reminder_found) {
				// fetch the record by ID
				$reminder_record = $helper->getReminder($reminder_id);

				if ($reminder_record) {
					// prepend element to the list
					array_unshift($reminders, $reminder_record);
				}
			}
		}

		// start output buffering
		ob_start();

		if (!$reminders) {
			?>
		<p class="info"><?php echo JText::translate('VBONORESULTS'); ?></p>
			<?php
		} else {
			// update widget's settings with the lastly used filters
			$this->widgetSettings->show_completed = $completed;
			$this->widgetSettings->show_expired   = $expired;
			$this->updateSettings(json_encode($this->widgetSettings));
		}

		foreach ($reminders as $reminder) {
			$use_icn_status = $reminder->completed ? 'dot-circle' : 'far fa-circle';
			$hidden_date = '';
			$hidden_hours = '';
			$hidden_minutes = '';
			if (!empty($reminder->duedate)) {
				$date_parts = explode(' ', $reminder->duedate);
				$hidden_date = date($this->df, strtotime($date_parts[0]));
				if ($reminder->usetime) {
					$time_parts = explode(':', $date_parts[1]);
					$hidden_hours = (int)$time_parts[0];
					$hidden_minutes = (int)$time_parts[1];
				}
			}
			$is_past_reminder = false;
			if (!empty($reminder->duedate)) {
				// calculate distance to expiration date from today
				$diff_data = $helper->relativeDatesDiff($reminder->duedate);
				$is_past_reminder = $diff_data['past'];
			}

			// list of extra classes for the reminder
			$extra_classes = [];
			if ($is_past_reminder) {
				$extra_classes[] = 'vbo-reminder-past';
			} else {
				$extra_classes[] = 'vbo-reminder-future';
			}
			if ($reminder->completed) {
				$extra_classes[] = 'vbo-reminder-ok';
			} else {
				$extra_classes[] = 'vbo-reminder-nok';
			}

			?>
		<div class="vbo-widget-reminders-record <?php echo implode(' ', $extra_classes); ?>" data-reminderid="<?php echo $reminder->id; ?>">
			<div class="vbo-widget-reminders-record-status">
				<button type="button" class="vbo-reminder-status-dot" onclick="vboWidgetRemindersComplete('<?php echo $wrapper; ?>', '<?php echo $reminder->id; ?>');"><?php VikBookingIcons::e($use_icn_status); ?></button>
			<?php
			if ($reminder->important) {
				?>
				<div class="vbo-widget-reminders-record-important">
					<?php VikBookingIcons::e('exclamation-triangle'); ?>
				</div>
				<?php
			}
			?>
			</div>
			<div class="vbo-widget-reminders-record-info">
				<div class="vbo-widget-reminders-record-txt">
					<span class="vbo-widget-reminder-title"><?php echo htmlspecialchars($reminder->title); ?></span>
					<?php
					if (!empty($reminder->descr)) {
						?>
					<span class="vbo-widget-reminder-descr"><?php echo htmlspecialchars($reminder->descr); ?></span>
						<?php
					}
					?>
				</div>
				<div class="vbo-widget-reminders-record-due">
					<span class="vbo-widget-reminder-date" style="display: none;"><?php echo $hidden_date; ?></span>
					<span class="vbo-widget-reminder-hours" style="display: none;"><?php echo $hidden_hours; ?></span>
					<span class="vbo-widget-reminder-minutes" style="display: none;"><?php echo $hidden_minutes; ?></span>
				<?php
				if (!empty($reminder->idorder) && $reminder->idorder > 0) {
					?>
					<span class="vbo-widget-reminder-idorder" style="display: none;"><?php echo $reminder->idorder; ?></span>
					<div class="vbo-widget-reminders-record-due-booking">
						<a class="label label-info" href="<?php echo sprintf($bookings_base_uri, $reminder->idorder); ?>" target="_blank"><?php echo $reminder->idorder; ?></a>
					</div>
					<?php
				}
				if (!empty($reminder->duedate)) {
					?>
					<div class="vbo-widget-reminders-record-due-datetime">
						<div class="vbo-widget-reminders-record-due-date">
							<span title="<?php echo $reminder->duedate; ?>"><?php echo $diff_data['relative']; ?></span>
						</div>
					<?php
					if ($reminder->usetime) {
						?>
						<div class="vbo-widget-reminders-record-due-time">
							<span><?php echo $diff_data['date_a']->format('H:i'); ?></span>
						</div>
						<?php
					}
					?>
					</div>
					<?php
				}
				?>
				</div>
			</div>
			<div class="vbo-widget-reminders-record-edit">
				<button type="button" class="vbo-reminder-record-edit" onclick="vboWidgetRemindersEdit('<?php echo $wrapper; ?>', '<?php echo $reminder->id; ?>');"><?php VikBookingIcons::e('edit'); ?></button>
			</div>
		</div>
			<?php
		}

		// append navigation
		?>
		<div class="vbo-widget-commands vbo-widget-commands-right">
			<div class="vbo-widget-commands-main">
			<?php
			if ($offset > 0) {
				// show backward navigation button
				?>
				<div class="vbo-widget-command-chevron vbo-widget-command-prev">
					<span class="vbo-widget-command-chevron-prev" onclick="vboWidgetRemindersNavigate('<?php echo $wrapper; ?>', -1);"><?php VikBookingIcons::e('chevron-left'); ?></span>
				</div>
				<?php
			}
			if ($has_next_page) {
				// show forward navigation button
				?>
				<div class="vbo-widget-command-chevron vbo-widget-command-next">
					<span class="vbo-widget-command-chevron-next" onclick="vboWidgetRemindersNavigate('<?php echo $wrapper; ?>', 1);"><?php VikBookingIcons::e('chevron-right'); ?></span>
				</div>
			<?php
			}
			?>
			</div>
		</div>
		<?php

		if ($reminder_id) {
			?>
		<script type="text/javascript">
			setTimeout(() => {
				vboWidgetRemindersEdit('<?php echo $wrapper; ?>', '<?php echo $reminder_id; ?>');
			}, 200);
		</script>
			<?php
		}

		// get the HTML buffer
		$html_content = ob_get_contents();
		ob_end_clean();

		// return an associative array of values
		return array(
			'html' 		  => $html_content,
			'tot_records' => count($reminders),
			'next_page'   => (int)$has_next_page,
		);
	}

	/**
	 * Custom method for this widget only.
	 * Creates a new reminder.
	 * 
	 * @return 	array
	 */
	public function saveReminder()
	{
		$title 	   = VikRequest::getString('title', '', 'request');
		$descr 	   = VikRequest::getString('descr', '', 'request');
		$date 	   = VikRequest::getString('date', '', 'request');
		$hours 	   = VikRequest::getInt('hours', 0, 'request');
		$minutes   = VikRequest::getInt('minutes', 0, 'request');
		$bid 	   = VikRequest::getInt('bid', 0, 'request');
		$important = VikRequest::getInt('important', 0, 'request');

		// create reminder object
		$reminder = new stdClass;
		$reminder->title = $title;
		$reminder->descr = $descr;
		$use_time = 0;
		if (!empty($date)) {
			if ($hours >= 0) {
				$use_time = 1;
				$minutes = $minutes >= 0 ? $minutes : 0;
				$due_ts = VikBooking::getDateTimestamp($date, $hours, $minutes);
			} else {
				$due_ts = VikBooking::getDateTimestamp($date);
			}
			$reminder->duedate = date('Y-m-d H:i:s', $due_ts);
		}
		$reminder->usetime = $use_time;
		if (!empty($bid)) {
			$reminder->idorder = $bid;
		}
		$reminder->important = $important;

		if (!VBORemindersHelper::getInstance()->saveReminder($reminder)) {
			VBOHttpDocument::getInstance()->close(400, 'Could not create the reminder');
		}

		// compose the notification payload for the newly created reminder
		$notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);

		return [
			'status' 	   => true,
			'notification' => $notif_data,
			'debug' => print_r($reminder, true)
		];
	}

	/**
	 * Custom method for this widget only.
	 * Updates an existing reminder.
	 * 
	 * @return 	array
	 */
	public function updateReminder()
	{
		$rid 	   = VikRequest::getInt('rid', 0, 'request');
		$title 	   = VikRequest::getString('title', '', 'request');
		$descr 	   = VikRequest::getString('descr', '', 'request');
		$date 	   = VikRequest::getString('date', '', 'request');
		$hours 	   = VikRequest::getInt('hours', 0, 'request');
		$minutes   = VikRequest::getInt('minutes', 0, 'request');
		$bid 	   = VikRequest::getInt('bid', 0, 'request');
		$important = VikRequest::getInt('important', 0, 'request');

		if (empty($rid)) {
			VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to update');
		}

		// create reminder object
		$reminder = new stdClass;
		$reminder->id = $rid;
		$reminder->title = $title;
		$reminder->descr = $descr;
		$use_time = 0;
		if (!empty($date)) {
			if ($hours >= 0) {
				$use_time = 1;
				$minutes = $minutes >= 0 ? $minutes : 0;
				$due_ts = VikBooking::getDateTimestamp($date, $hours, $minutes);
			} else {
				$due_ts = VikBooking::getDateTimestamp($date);
			}
			$reminder->duedate = date('Y-m-d H:i:s', $due_ts);
		}
		$reminder->usetime = $use_time;
		$reminder->idorder = !empty($bid) ? $bid : 0;

		if (!VBORemindersHelper::getInstance()->updateReminder($reminder)) {
			VBOHttpDocument::getInstance()->close(400, 'Could not update the reminder');
		}

		// compose the notification paylod for the newly created reminder
		$notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);

		return [
			'status' 	   => true,
			'notification' => $notif_data,
		];
	}

	/**
	 * Custom method for this widget only.
	 * Toggles the completed status for an existing reminder.
	 * 
	 * @return 	array
	 */
	public function toggleReminderCompleted()
	{
		$rid = VikRequest::getInt('rid', 0, 'request');

		if (empty($rid)) {
			VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to update');
		}

		$helper = VBORemindersHelper::getInstance();
		$reminder = $helper->getReminder($rid);
		if (!$reminder) {
			VBOHttpDocument::getInstance()->close(400, 'Record not found');
		}

		// toggle completed status
		$reminder->completed = (int) !$reminder->completed;

		if (!$helper->updateReminder($reminder)) {
			VBOHttpDocument::getInstance()->close(400, 'Could not update the reminder');
		}

		$notif_data = null;
		if (!$reminder->completed) {
			// compose the notification paylod for the uncompleted reminder
			$notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);
		}

		return [
			'status' 	   => $reminder->completed,
			'notification' => $notif_data,
		];
	}

	/**
	 * Custom method for this widget only.
	 * Deletes an existing reminder.
	 * 
	 * @return 	bool
	 */
	public function deleteReminder()
	{
		$rid = VikRequest::getInt('rid', 0, 'request');

		if (empty($rid)) {
			VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to delete');
		}

		$helper = VBORemindersHelper::getInstance();
		$reminder = $helper->getReminder($rid);
		if (!$reminder) {
			VBOHttpDocument::getInstance()->close(400, 'Record not found');
		}

		if (!$helper->deleteReminder($reminder)) {
			VBOHttpDocument::getInstance()->close(400, 'Could not delete the reminder');
		}

		return true;
	}

	/**
	 * Main method to invoke the widget. Contents will be loaded
	 * through AJAX requests, not via PHP when the page loads.
	 * 
	 * @param 	?VBOMultitaskData 	$data 	multitask data object.
	 * 
	 * @return 	void
	 */
	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 sticky notes wrapper instance
		$wrapper_instance = !$is_ajax ? static::$instance_counter : rand();
		$wrapper_id = 'vbo-widget-reminders-' . $wrapper_instance;

		// default filters
		$reminder_id   = 0;
		$def_completed = 0;
		$def_expired   = 0;
		$def_duedate   = time();
		$def_duehours  = -1;
		$def_duemins   = -1;

		// check multitask data
		$page_bid 	 = '';
		$auto_action = '';
		$js_modal_id = '';
		if ($data) {
			// access Multitask data
			$page_bid = $data->getBookingID();
			if ($data->isModalRendering()) {
				// get modal JS identifier
				$js_modal_id = $data->getModalJsIdentifier();
			}

			// we allow the page booking ID to be passed as an option as well
			$page_bid = !$page_bid ? $this->options()->fetchBookingId() : $page_bid;

			// check for options
			$reminder_id   = (int) $this->getOption('reminder_id', 0);
			$auto_action   = $this->getOption('action', '');
			$def_completed = (int) $this->getOption('completed', $def_completed);
			$def_expired   = (int) $this->getOption('expired', $def_expired);

			// attempt to define values for this precise booking
			$booking_info = $page_bid ? VikBooking::getBookingInfoFromID($page_bid) : [];
			if ($booking_info) {
				$def_time_info = [];
				if ($booking_info['checkin'] > $def_duedate) {
					$def_duedate   = $booking_info['checkin'];
					$def_time_info = getdate($def_duedate);
				} elseif ($booking_info['checkout'] > $def_duedate) {
					$def_duedate   = $booking_info['checkout'];
					$def_time_info = getdate($def_duedate);
				}
				if ($def_time_info) {
					$def_duehours = (int)$def_time_info['hours'];
					$def_duemins  = (int)$def_time_info['minutes'];
				}
			}
		} else {
			// load settings
			$def_completed = isset($this->widgetSettings->show_completed) ? (int)$this->widgetSettings->show_completed : $def_completed;
			$def_expired   = isset($this->widgetSettings->show_expired) ? (int)$this->widgetSettings->show_expired : $def_expired;
		}

		?>
		<div id="<?php echo $wrapper_id; ?>" class="vbo-admin-widget-wrapper" data-instance="<?php echo $wrapper_instance; ?>" data-offset="0" data-pagebid="<?php echo $page_bid; ?>" data-length="<?php echo $this->reminders_per_page; ?>">
			<div class="vbo-admin-widget-head">
				<div class="vbo-admin-widget-head-inline">
					<h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4>
					<div class="vbo-admin-widget-head-commands">

						<div class="vbo-reportwidget-commands">
							<div class="vbo-reportwidget-commands-main">
								<div class="vbo-reportwidget-command-add">
									<span class="vbo-widget-command-addnew" onclick="vboWidgetRemindersAdd('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('plus-circle'); ?></span>
								</div>
							</div>
							<div class="vbo-reportwidget-command-dots">
								<span class="vbo-widget-command-togglefilters vbo-widget-reminders-togglefilters" onclick="vboWidgetRemindersToggleFilters('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('ellipsis-v'); ?></span>
							</div>
						</div>
						<div class="vbo-reportwidget-filters">
							<div class="vbo-reportwidget-filter">
								<label for="show_completed<?php echo $wrapper_instance; ?>-on"><?php echo JText::translate('VBO_SHOW_COMPLETED'); ?></label>
								<?php echo $this->vbo_app->printYesNoButtons('show_completed' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), $def_completed, 1, 0); ?>
							</div>
							<div class="vbo-reportwidget-filter">
								<label for="show_expired<?php echo $wrapper_instance; ?>-on"><?php echo JText::translate('VBO_SHOW_EXPIRED'); ?></label>
								<?php echo $this->vbo_app->printYesNoButtons('show_expired' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), $def_expired, 1, 0); ?>
							</div>
							<div class="vbo-reportwidget-filter vbo-reportwidget-filter-confirm">
								<button type="button" class="btn vbo-config-btn" onclick="vboWidgetRemindersChangeParams('<?php echo $wrapper_id; ?>');"><?php echo JText::translate('VBADMINNOTESUPD'); ?></button>
							</div>
						</div>

					</div>
				</div>
			</div>
			<div class="vbo-widget-reminders-wrap">
				<div class="vbo-widget-reminders-inner">
					<div class="vbo-widget-reminders-manage" style="display: none;">

						<div class="vbo-widget-reminders-goback">
							<a href="JavaScript: void(0);" onclick="vboWidgetRemindersToggleManage('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('chevron-left'); ?> <?php echo JText::translate('VBBACK'); ?></a>
						</div>

						<div class="vbo-widget-reminders-manage-wrap">
							<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-title">
								<input type="text" class="vbo-widget-reminders-ftitle" value="" placeholder="<?php echo htmlspecialchars(JText::translate('VBO_REMINDER_TITLE')); ?>" />
							</div>
							<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-descr">
								<textarea class="vbo-widget-reminders-fdescr" placeholder="<?php echo htmlspecialchars(JText::translate('VBPVIEWOPTIONALSTWO')); ?>" maxlength="2000"></textarea>
							</div>
							<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-booking vbo-toggle-small" style="<?php echo empty($page_bid) ? 'display: none;' : ''; ?>">
								<span class="vbo-widget-reminders-filter-tobooking">
									<label for="assign_booking<?php echo $wrapper_instance; ?>-on"><span class="label label-info vbo-widget-reminders-filter-booking-id"><?php echo $page_bid; ?></span> <?php echo JText::translate('VBO_ASSIGN_TO_BOOKING'); ?></label>
									<?php echo $this->vbo_app->printYesNoButtons('assign_booking' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), (!empty($page_bid) ? 1 : 0), 1, 0); ?>
								</span>
								<span class="vbo-widget-reminders-filter-importance">
									<label for="is_important<?php echo $wrapper_instance; ?>-on"><?php VikBookingIcons::e('exclamation-triangle'); ?> <?php echo JText::translate('VBO_IMPORTANT'); ?></label>
									<?php echo $this->vbo_app->printYesNoButtons('is_important' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), 0, 1, 0); ?>
								</span>
							</div>
							<div class="vbo-widget-reminders-filter-datetime">
								<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-date">
									<div class="vbo-field-calendar">
										<div class="input-append">
											<input type="text" class="vbo-reminders-dtpicker" value="<?php echo date($this->df, $def_duedate); ?>" placeholder="<?php echo htmlspecialchars(JText::translate('VBO_REMINDER_DUE_DATE')); ?>" />
											<button type="button" class="btn btn-secondary vbo-widget-reminders-caltrigger"><?php VikBookingIcons::e('calendar'); ?></button>
										</div>
									</div>
								</div>
								<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-time">
									<select class="vbo-widget-reminders-fh">
										<option value=""><?php echo ucfirst(JText::translate('VBCONFIGONETENEIGHT')); ?></option>
									<?php
									for ($i = 0; $i < 24; $i++) { 
										?>
										<option value="<?php echo $i; ?>"<?php echo $i == $def_duehours ? ' selected="selected"' : ''; ?>><?php echo $i < 10 ? "0{$i}" : $i; ?></option>
										<?php
									}
									?>
									</select>
									<select class="vbo-widget-reminders-fm">
										<option value=""><?php echo ucfirst(JText::translate('VBTRKDIFFMINS')); ?></option>
									<?php
									for ($i = 0; $i < 60; $i++) { 
										?>
										<option value="<?php echo $i; ?>"<?php echo $i == $def_duemins ? ' selected="selected"' : ''; ?>><?php echo $i < 10 ? "0{$i}" : $i; ?></option>
										<?php
									}
									?>
									</select>
								</div>
							</div>
							<div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-save">
								<input type="hidden" class="vbo-widget-reminders-rid" value="" />
								<button type="button" class="btn btn-success vbo-widget-reminder-confirm" onclick="vboWidgetRemindersSaveNew('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('bell'); ?> <span><?php echo JText::translate('VBCONFIGCLOSINGDATEADD'); ?></span></button>
								<button type="button" class="btn btn-danger vbo-widget-reminder-delete" onclick="vboWidgetRemindersDelete('<?php echo $wrapper_id; ?>');" style="display: none;"><?php VikBookingIcons::e('trash'); ?> <?php echo JText::translate('VBELIMINA'); ?></button>
							</div>
						</div>

					</div>
					<div class="vbo-widget-reminders-list">
					<?php
					for ($i = 0; $i < floor($this->reminders_per_page / 2); $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-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) {
			/**
			 * Print the JS code only once for all instances of this widget.
			 * The real rendering is made through AJAX, not when the page loads.
			 */
			?>
		<script type="text/javascript">

			/**
			 * Display the loading skeletons.
			 */
			function vboWidgetRemindersSkeletons(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}
				widget_instance.find('.vbo-widget-reminders-list').html('');
				for (var i = 0; i < <?php echo floor($this->reminders_per_page / 2); ?>; 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-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-widget-reminders-list'));
				}
			}

			/**
			 * Toggles the layout to add or edit a reminder.
			 */
			function vboWidgetRemindersToggleManage(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				var mng_cont = widget_instance.find('.vbo-widget-reminders-manage');
				if (mng_cont.is(':visible')) {
					mng_cont.hide();
					widget_instance.find('.vbo-widget-reminders-list').show();
				} else {
					widget_instance.find('.vbo-widget-reminders-list').hide();
					mng_cont.show();
				}
			}

			/**
			 * Toggle filters.
			 */
			function vboWidgetRemindersToggleFilters(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				widget_instance.find('.vbo-reportwidget-filters').toggle();
			}

			/**
			 * Reload records with new params.
			 */
			function vboWidgetRemindersChangeParams(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// hide filters when making a new request
				widget_instance.find('.vbo-reportwidget-filters').hide();

				// reset offset to 0
				widget_instance.attr('data-offset', 0);

				// show loading skeletons
				vboWidgetRemindersSkeletons(wrapper);

				// reload the first page
				vboWidgetRemindersLoad(wrapper);
			}

			/**
			 * Prepare the layout to add a new reminder.
			 */
			function vboWidgetRemindersAdd(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// always reset the reminder id in the hidden input and hide delete
				widget_instance.find('.vbo-widget-reminders-rid').val('');
				widget_instance.find('.vbo-widget-reminder-delete').hide();
				widget_instance.find('.vbo-widget-reminder-confirm span').text(Joomla.JText._('VBCONFIGCLOSINGDATEADD'));

				// check if we need to hide the assign-to-booking option
				var page_bid = widget_instance.attr('data-pagebid');
				if (page_bid.length && page_bid > 0) {
					// show assign-to-booking option and important reminder
					widget_instance.find('.vbo-widget-reminders-filter-booking-id').text(page_bid);
					widget_instance.find('input[name^="assign_booking"]').prop('checked', true);
					widget_instance.find('input[name^="is_important"]').prop('checked', false);
					widget_instance.find('.vbo-widget-reminders-filter-booking').show();
				} else {
					// hide assign-to-booking option and important reminder
					widget_instance.find('input[name^="assign_booking"]').prop('checked', false);
					widget_instance.find('input[name^="is_important"]').prop('checked', false);
					widget_instance.find('.vbo-widget-reminders-filter-booking').hide();
				}

				// reset the rest of the fields in case of previous editing
				if (widget_instance.find('.vbo-widget-reminders-ftitle').val() || widget_instance.find('.vbo-widget-reminders-fdescr').val()) {
					widget_instance.find('.vbo-widget-reminders-ftitle').val('');
					widget_instance.find('.vbo-widget-reminders-fdescr').val('');
					widget_instance.find('.vbo-reminders-dtpicker').val('');
					widget_instance.find('.vbo-widget-reminders-fh').val('');
					widget_instance.find('.vbo-widget-reminders-fm').val('');
				}

				// toggle edit mode
				vboWidgetRemindersToggleManage(wrapper);
			}

			/**
			 * Prepare the reminder edit mode by populating data.
			 */
			function vboWidgetRemindersEdit(wrapper, rid) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}
				var reminder_instance = widget_instance.find('[data-reminderid="' + rid + '"]');
				if (!reminder_instance.length) {
					return false;
				}

				// populate fields for edit mode
				widget_instance.find('.vbo-widget-reminder-confirm span').text(Joomla.JText._('VBADMINNOTESUPD'));
				widget_instance.find('.vbo-widget-reminder-delete').show();
				widget_instance.find('.vbo-widget-reminders-rid').val(rid);
				widget_instance.find('.vbo-widget-reminders-ftitle').val(reminder_instance.find('.vbo-widget-reminder-title').text());
				widget_instance.find('.vbo-widget-reminders-fdescr').val(reminder_instance.find('.vbo-widget-reminder-descr').text());
				widget_instance.find('.vbo-reminders-dtpicker').val(reminder_instance.find('.vbo-widget-reminder-date').text());
				widget_instance.find('.vbo-widget-reminders-fh').val(reminder_instance.find('.vbo-widget-reminder-hours').text());
				widget_instance.find('.vbo-widget-reminders-fm').val(reminder_instance.find('.vbo-widget-reminder-minutes').text());
				// handle booking ID assignment
				var booking_assigned = null;
				var booking_container = reminder_instance.find('.vbo-widget-reminder-idorder');
				if (booking_container.length) {
					booking_assigned = booking_container.text();
				}
				if (booking_assigned) {
					// show assign-to-booking option
					widget_instance.find('.vbo-widget-reminders-filter-booking-id').text(booking_assigned);
					widget_instance.find('input[name^="assign_booking"]').prop('checked', true);
					widget_instance.find('.vbo-widget-reminders-filter-booking').show();
				} else {
					// hide assign-to-booking option
					widget_instance.find('input[name^="assign_booking"]').prop('checked', false);
					widget_instance.find('.vbo-widget-reminders-filter-booking').hide();
				}

				// handle important reminder flag
				if (booking_assigned && reminder_instance.find('.vbo-widget-reminders-record-important').length) {
					widget_instance.find('input[name^="is_important"]').prop('checked', true);
				} else {
					widget_instance.find('input[name^="is_important"]').prop('checked', false);
				}

				// enter edit mode
				vboWidgetRemindersToggleManage(wrapper);
			}

			/**
			 * Toggle reminder completed status.
			 */
			function vboWidgetRemindersComplete(wrapper, rid) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}
				var reminder_instance = widget_instance.find('[data-reminderid="' + rid + '"]');
				if (!reminder_instance.length) {
					return false;
				}

				// the widget method to call
				var call_method = 'toggleReminderCompleted';

				// make a request to update the reminder
				VBOCore.doAjax(
					"<?php echo $this->getExecWidgetAjaxUri(); ?>",
					{
						widget_id: "<?php echo $this->getIdentifier(); ?>",
						call: call_method,
						return: 1,
						rid: rid,
						wrapper: wrapper,
						tmpl: "component"
					},
					function(response) {
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method)) {
								console.error('Unexpected or invalid JSON response', obj_res);
								return false;
							}

							if (obj_res[call_method]['status'] > 0) {
								// new status is completed
								reminder_instance
									.removeClass('vbo-reminder-nok')
									.addClass('vbo-reminder-ok')
									.find('.vbo-reminder-status-dot').html('<?php VikBookingIcons::e('dot-circle'); ?>');
								// check current params
								var show_completed = widget_instance.find('input[name^="show_completed"]').prop('checked');
								if (!show_completed) {
									reminder_instance.fadeOut();
								}
								// attempt to unset any scheduled notification for this reminder
								VBOCore.updateNotification({
									id: rid,
									type: "reminder"
								}, 0);
							} else {
								// new status is un-completed
								reminder_instance
									.removeClass('vbo-reminder-ok')
									.addClass('vbo-reminder-nok')
									.find('.vbo-reminder-status-dot').html('<?php VikBookingIcons::e('far fa-circle'); ?>');
								if (obj_res[call_method]['notification'] != null) {
									// attempt to schedule a notification for this reminder
									VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
								}
							}
						} catch(err) {
							console.error('could not parse JSON response', err, response);
						}
					},
					function(error) {
						// log the error and display the message
						console.error(error);
						alert(error.responseText);
					}
				);
			}

			/**
			 * Delete one reminder record.
			 */
			function vboWidgetRemindersDelete(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				var rid = widget_instance.find('.vbo-widget-reminders-rid').val();
				if (!rid || !rid.length) {
					return false;
				}

				if (!confirm(Joomla.JText._('VBDELCONFIRM'))) {
					return false;
				}

				// disable delete button
				var del_btn = widget_instance.find('button.vbo-widget-reminder-delete');
				del_btn.prop('disabled', true);

				// the widget method to call
				var call_method = 'deleteReminder';

				// make a request to update the reminder
				VBOCore.doAjax(
					"<?php echo $this->getExecWidgetAjaxUri(); ?>",
					{
						widget_id: "<?php echo $this->getIdentifier(); ?>",
						call: call_method,
						return: 1,
						rid: rid,
						wrapper: wrapper,
						tmpl: "component"
					},
					function(response) {
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method) || !obj_res[call_method]) {
								console.error('Unexpected or invalid JSON response', obj_res);
								return false;
							}

							// turn flag on
							vbo_reminders_changed = true;

							// toggle edit mode
							vboWidgetRemindersToggleManage(wrapper);

							// enable delete button
							del_btn.prop('disabled', false);

							// reset offset to 0
							widget_instance.attr('data-offset', 0);

							// show loading skeletons
							vboWidgetRemindersSkeletons(wrapper);

							// reload the first page
							vboWidgetRemindersLoad(wrapper);

							// attempt to unset any scheduled notification for this reminder
							VBOCore.updateNotification({
								id: rid,
								type: "reminder"
							}, 0);
						} catch(err) {
							console.error('could not parse JSON response', err, response);
						}
					},
					function(error) {
						// log the error and display the message
						console.error(error);
						alert(error.responseText);
						// enable delete button
						del_btn.prop('disabled', false);
					}
				);
			}

			/**
			 * Perform the request to load the reminders.
			 */
			function vboWidgetRemindersLoad(wrapper, reminder_id) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// get vars for making the request
				var current_offset  = parseInt(widget_instance.attr('data-offset'));
				var length_per_page = parseInt(widget_instance.attr('data-length'));
				var show_completed = widget_instance.find('input[name^="show_completed"]').prop('checked');
				var show_expired = widget_instance.find('input[name^="show_expired"]').prop('checked');
				show_completed = show_completed ? 1 : 0;
				show_expired = show_expired ? 1 : 0;
				var page_bid = widget_instance.attr('data-pagebid');

				// the widget method to call
				var call_method = 'loadReminders';

				// make a request to load the reminder records
				VBOCore.doAjax(
					"<?php echo $this->getExecWidgetAjaxUri(); ?>",
					{
						widget_id: "<?php echo $this->getIdentifier(); ?>",
						call: call_method,
						return: 1,
						offset: current_offset,
						length: length_per_page,
						completed: show_completed,
						expired: show_expired,
						bid: page_bid,
						reminder_id: reminder_id,
						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;
							}

							// replace HTML with month-day reservations
							widget_instance.find('.vbo-widget-reminders-list').html(obj_res[call_method]['html']);

							// check results
							var tot_records = obj_res[call_method]['tot_records'] || 0;
							if (!isNaN(tot_records) && parseInt(tot_records) < 1) {
								// no results can indicate the offset is invalid or too high
								if (!isNaN(current_offset) && current_offset > 0) {
									// reset offset to 0
									widget_instance.attr('data-offset', 0);
									// show loading skeletons
									vboWidgetRemindersSkeletons(wrapper);
									// reload the first page
									vboWidgetRemindersLoad(wrapper);
								}
							}
						} catch(err) {
							console.error('could not parse JSON response', err, response);
						}
					},
					(error) => {
						// remove the skeleton loading
						widget_instance.find('.vbo-widget-reminders-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
						console.error(error);
					}
				);
			}

			/**
			 * Save a new reminder or update an existing one.
			 */
			function vboWidgetRemindersSaveNew(wrapper) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// either save or update
				var mode = 'saveReminder';

				// collect new reminder details
				var r_title = widget_instance.find('.vbo-widget-reminders-ftitle').val();
				var r_descr = widget_instance.find('.vbo-widget-reminders-fdescr').val();
				var r_date  = widget_instance.find('.vbo-reminders-dtpicker').val();
				var r_hours = widget_instance.find('.vbo-widget-reminders-fh').val();
				var r_mins  = widget_instance.find('.vbo-widget-reminders-fm').val();
				// adjust time
				if (!r_hours.length) {
					r_hours = -1;
					r_mins  = 0;
				}
				// check if we are editing an existing reminder id
				var r_id = widget_instance.find('.vbo-widget-reminders-rid').val();
				if (r_id && r_id.length) {
					mode = 'updateReminder';
				} else {
					r_id = 0;
				}

				if ((!r_title.length && !r_descr.length) || !r_date.length) {
					alert(Joomla.JText._('VBO_PLEASE_FILL_FIELDS'));
					return false;
				}

				// check if we are saving/updating a reminder for a booking ID
				var r_bid = null;
				var assign_to_bid = widget_instance.find('input[name^="assign_booking"]').prop('checked');
				if (assign_to_bid) {
					// validate the booking id depending on save/update mode
					if (mode == 'saveReminder') {
						// the booking id must have been set from the current page
						var validate_bid = widget_instance.attr('data-pagebid');
						if (validate_bid && validate_bid.length) {
							// valid
							r_bid = validate_bid;
						}
					} else {
						// the booking id must be part of a hidden field
						var reminder_instance = widget_instance.find('[data-reminderid="' + r_id + '"]');
						if (reminder_instance.length) {
							var validate_bid = reminder_instance.find('.vbo-widget-reminder-idorder').text();
							if (validate_bid && validate_bid.length) {
								// valid
								r_bid = validate_bid;
							}
						}
					}
				}

				// check importance
				var is_important = 0;
				if (r_bid && widget_instance.find('input[name^="is_important"]').prop('checked')) {
					is_important = 1;
				}

				// disable save button
				var save_btn = widget_instance.find('.vbo-widget-reminders-filter-save button');
				save_btn.prop('disabled', true);

				// the widget method to call
				var call_method = mode;

				// make a request to save a new reminder or to update it
				VBOCore.doAjax(
					"<?php echo $this->getExecWidgetAjaxUri(); ?>",
					{
						widget_id: "<?php echo $this->getIdentifier(); ?>",
						call: call_method,
						return: 1,
						rid: r_id,
						bid: r_bid,
						title: r_title,
						descr: r_descr,
						date: r_date,
						hours: r_hours,
						minutes: r_mins,
						important: is_important,
						wrapper: wrapper,
						tmpl: "component"
					},
					(response) => {
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method) || !obj_res[call_method]['status']) {
								console.error('Unexpected or invalid JSON response', obj_res);
								return false;
							}

							// turn flag on & store booking involved, if any
							vbo_reminders_changed = true;
							vbo_reminders_changed_bid = r_bid;

							// toggle edit mode
							vboWidgetRemindersToggleManage(wrapper);

							// enable save button
							save_btn.prop('disabled', false);

							// reset offset to 0
							widget_instance.attr('data-offset', 0);

							// show loading skeletons
							vboWidgetRemindersSkeletons(wrapper);

							// reload the first page
							vboWidgetRemindersLoad(wrapper);

							// handle browser notifications
							if (call_method == 'saveReminder') {
								if (obj_res[call_method]['notification'] != null) {
									// attempt to schedule a notification for the new reminder
									VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
								}
							} else {
								if (obj_res[call_method]['notification'] != null) {
									// attempt to update the notification scheduling time for this reminder
									let updated = VBOCore.updateNotification({
										id: r_id,
										type: "reminder"
									}, obj_res[call_method]['notification']['dtime']);
									if (updated !== true) {
										// attempt to schedule this anticipated reminder as a new notification
										VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
									}
								} else {
									// the notification may have been set to a far-ahead date, delete it
									VBOCore.updateNotification({
										id: r_id,
										type: "reminder"
									}, 0);
								}
							}
						} catch(err) {
							console.error('could not parse JSON response', err, response);
						}
					},
					(error) => {
						// log the error and display the message
						console.error(error);
						alert(error.responseText);
						// enable save button
						save_btn.prop('disabled', false);
					}
				);
			}

			/**
			 * Navigate between the various pages of the reminders.
			 */
			function vboWidgetRemindersNavigate(wrapper, direction) {
				var widget_instance = jQuery('#' + wrapper);
				if (!widget_instance.length) {
					return false;
				}

				// show loading skeletons
				vboWidgetRemindersSkeletons(wrapper);

				// current offset
				var current_offset = parseInt(widget_instance.attr('data-offset'));

				// records per page
				var steps = parseInt(widget_instance.attr('data-length'));

				// check direction and update offsets for 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
				vboWidgetRemindersLoad(wrapper);
			}
			
		</script>
			<?php
		}
		?>

		<script type="text/javascript">

			// keep track of any changes related to reminders
			var vbo_reminders_changed = false;

			// keep track of changes to reminders related to a bookind ID
			var vbo_reminders_changed_bid = null;

			jQuery(function() {

				// render datepicker calendar
				jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-reminders-dtpicker').datepicker({
					minDate: "0",
					maxDate: "+5y",
					yearRange: "<?php echo date('Y'); ?>:<?php echo (date('Y') + 5); ?>",
					changeMonth: true,
					changeYear: true,
					dateFormat: "<?php echo $this->getDateFormat('jui'); ?>",
					defaultDate: "<?php echo date($this->df, $def_duedate); ?>"
				});

				// triggering for datepicker calendar icons
				jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-widget-reminders-caltrigger').click(function() {
					var jdp = jQuery(this).parent().find('input.hasDatepicker');
					if (jdp.length) {
						jdp.focus();
					}
				});

				// when document is ready, load reminders for this widget's instance
				vboWidgetRemindersLoad('<?php echo $wrapper_id; ?>', <?php echo $reminder_id; ?>);

				// subscribe to the multitask-panel-close event to emit the event for the reminders changed
				document.addEventListener(VBOCore.multitask_close_event, function() {
					if (vbo_reminders_changed) {
						// emit the event with data for anyone who is listening to it
						VBOCore.emitEvent('vbo_reminders_changed', {
							bid: vbo_reminders_changed_bid
						});
					}
				});

			<?php
			if ($js_modal_id) {
				// widget can be dismissed through the modal
				?>
				// subscribe to the modal-dismissed event to emit the event for the reminders changed
				document.addEventListener(VBOCore.widget_modal_dismissed + '<?php echo $js_modal_id; ?>', function() {
					if (vbo_reminders_changed) {
						// emit the event with data for anyone who is listening to it
						VBOCore.emitEvent('vbo_reminders_changed', {
							bid: vbo_reminders_changed_bid
						});
					}
				});
				<?php
			}

			if ($auto_action == 'add_new') {
				// injected optinos require to add a new reminder
				?>
				setTimeout(() => {
					vboWidgetRemindersAdd('<?php echo $wrapper_id; ?>');
				}, 300);
				<?php
			}
			?>

			});
			
		</script>

		<?php
	}

	/**
	 * Checks if any reminders should be automatically scheduled due to
	 * important events related to reservations downloaded through VCM.
	 * 
	 * @return 	int 	number of reminders that were automatically scheduled.
	 * 
	 * @since 	1.16.3 (J) - 1.6.3 (WP)
	 */
	protected function scheduleChannelManagerReminders()
	{
		$scheduled = 0;

		if (!method_exists('VikChannelManager', 'hostToGuestReviewSupported')) {
			// prevent server errors
			return $scheduled;
		}

		// get the reminders helper object
		$helper = VBORemindersHelper::getInstance();

		// get a list of Airbnb reservations with a proper checkout date
		$airbnb_checkouts = $helper->gatherAirbnbReservationsCheckedOut();

		// default due-date for the newly added reminders
		$def_due_date = date('Y-m-d H:i:s', strtotime("+1 minute"));

		// default reminder payload
		$payload = [
			'airbnb_host_guest_review' => 1,
		];

		// parse all eligible reservations
		foreach ($airbnb_checkouts as $airbnb_res) {
			// make sure this airbnb reservation requires a host-to-guest review
			if (!$helper->bookingHasReminder($airbnb_res['id'], $payload) && VikChannelManager::hostToGuestReviewSupported($airbnb_res)) {
				// build and schedule an automatic reminder
				$reminder = new stdClass;
				$reminder->title 	 = JText::translate('VBO_REVIEW_YOUR_GUEST');
				$reminder->descr 	 = 'Airbnb - ' . JText::translate('VBDASHBOOKINGID') . ' ' . $airbnb_res['id'];
				$reminder->duedate 	 = $def_due_date;
				$reminder->usetime 	 = 1;
				$reminder->idorder 	 = $airbnb_res['id'];
				$reminder->payload 	 = $payload;
				$reminder->important = 1;

				if ($helper->saveReminder($reminder)) {
					// increase counter
					$scheduled++;
				}
			}
		}

		return $scheduled;
	}
}