PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.7
VikBooking Hotel Booking Engine & PMS v1.6.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 / reminders.php

reminders.php in VikBooking Hotel Booking Engine & PMS 1.6.7, at admin/helpers/widgets/reminders.php

1,415 lines 48.6 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 srl
6 * @copyright Copyright (C) 2022 E4J srl. 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 "reminders".
15 *
16 * @since 1.15.0 (J) - 1.5.0 (WP)
17 */
18 class VikBookingAdminWidgetReminders extends VikBookingAdminWidget
19 {
20 /**
21 * The instance counter of this widget. Since we do not load individual parameters
22 * for each widget's instance, we use a static counter to determine its settings.
23 *
24 * @var int
25 */
26 protected static $instance_counter = -1;
27
28 /**
29 * Default number of reminders per page.
30 *
31 * @var int
32 */
33 protected $reminders_per_page = 6;
34
35 /**
36 * Tells whether VCM is installed.
37 *
38 * @var bool
39 */
40 protected $vcm_exists = false;
41
42 /**
43 * Class constructor will define the widget name and identifier.
44 */
45 public function __construct()
46 {
47 // call parent constructor
48 parent::__construct();
49
50 $this->widgetName = JText::translate('VBO_W_REMINDERS_TITLE');
51 $this->widgetDescr = JText::translate('VBO_W_REMINDERS_DESCR');
52 $this->widgetId = basename(__FILE__, '.php');
53
54 // define widget and icon and style name
55 $this->widgetIcon = '<i class="' . VikBookingIcons::i('bell') . '"></i>';
56 $this->widgetStyleName = 'green';
57
58 // load widget's settings
59 $this->widgetSettings = $this->loadSettings();
60 if (!is_object($this->widgetSettings)) {
61 $this->widgetSettings = new stdClass;
62 }
63
64 // check if VCM is available
65 if (is_file(VCM_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikchannelmanager.php')) {
66 $this->vcm_exists = true;
67 }
68 }
69
70 /**
71 * This widget does not actually need to preload data to be watched for
72 * dispatching notifications, and the reminders due are automatically
73 * scheduled for being dispatched as a browser notification. However,
74 * we make use of this method to periodically check if some reminders
75 * should be automatically created for specific reasons, such as the
76 * Airbnb host-to-guest reviews to remind the host to review the guest.
77 * We also preload the necessary CSS/JS assets and schedule the imminent
78 * reminders for notifications, if any.
79 *
80 * @return void
81 */
82 public function preload()
83 {
84 // declare JS lang vars
85 JText::script('VBO_PLEASE_FILL_FIELDS');
86 JText::script('VBDELCONFIRM');
87 JText::script('VBCONFIGCLOSINGDATEADD');
88 JText::script('VBADMINNOTESUPD');
89
90 // load assets
91 $this->vbo_app->loadDatePicker();
92
93 // check if VCM is available
94 if ($this->vcm_exists) {
95 $today_dt = date('Y-m-d');
96 $yesterday_dt = date('Y-m-d', strtotime('yesterday'));
97
98 // check the last time this check was made
99 $last_check_dt = isset($this->widgetSettings->last_check_dt) ? $this->widgetSettings->last_check_dt : $yesterday_dt;
100
101 if ($last_check_dt != $today_dt) {
102 // update last check date
103 $this->widgetSettings->last_check_dt = $today_dt;
104 $this->updateSettings(json_encode($this->widgetSettings));
105
106 // check for any Channel Manager reservation that requires an auto-reminder
107 $this->scheduleChannelManagerReminders();
108 }
109 }
110
111 // load the 10 next (imminent) reminders
112 $overdue = VBORemindersHelper::getInstance()->getImminents(10);
113 if ($overdue) {
114 // schedule browser notifications for the next reminders
115 VBONotificationScheduler::getInstance()->enqueueReminders($overdue);
116 }
117
118 // nothing should be actually watched, ever
119 return null;
120 }
121
122 /**
123 * Custom method for this widget only to load the reminder records.
124 * The method is called by the admin controller through an AJAX request.
125 * The visibility should be public, it should not exit the process, and
126 * any content sent to output will be returned to the AJAX response.
127 * In this case we return an array because this method requires "return":1.
128 *
129 * It's the actual rendering of the widget which also allows navigation.
130 *
131 * @return array
132 */
133 public function loadReminders()
134 {
135 $offset = VikRequest::getInt('offset', 0, 'request');
136 $length = VikRequest::getInt('length', $this->reminders_per_page, 'request');
137 $completed = VikRequest::getInt('completed', 0, 'request');
138 $expired = VikRequest::getInt('expired', 0, 'request');
139 $bid = VikRequest::getInt('bid', 0, 'request');
140 $wrapper = VikRequest::getString('wrapper', '', 'request');
141
142 // load reminders starting from today at 00:00:00
143 $now_info = getdate();
144 $lim_min_date = date('Y-m-d H:i:s', mktime(0, 0, 0, $now_info['mon'], $now_info['mday'], $now_info['year']));
145
146 // prepare fetch options
147 $fetch = [
148 'after' => $lim_min_date,
149 'completed' => $completed,
150 'expired' => $expired,
151 'idorder' => $bid,
152 ];
153
154 // load reminders
155 $helper = VBORemindersHelper::getInstance();
156 $reminders = $helper->loadReminders($fetch, $offset, $length);
157
158 // check if a next page can be available
159 $has_next_page = (count($reminders) >= $length);
160
161 // compose bookings base URI
162 $bookings_base_uri = VBOFactory::getPlatform()->getUri()->admin('index.php?option=com_vikbooking&task=editorder&cid[]=%d', $xhtml = false);
163
164 // start output buffering
165 ob_start();
166
167 if (!$reminders) {
168 ?>
169 <p class="info"><?php echo JText::translate('VBONORESULTS'); ?></p>
170 <?php
171 } else {
172 // update widget's settings with the lastly used filters
173 $this->widgetSettings->show_completed = $completed;
174 $this->widgetSettings->show_expired = $expired;
175 $this->updateSettings(json_encode($this->widgetSettings));
176 }
177
178 foreach ($reminders as $reminder) {
179 $use_icn_status = $reminder->completed ? 'dot-circle' : 'far fa-circle';
180 $hidden_date = '';
181 $hidden_hours = '';
182 $hidden_minutes = '';
183 if (!empty($reminder->duedate)) {
184 $date_parts = explode(' ', $reminder->duedate);
185 $hidden_date = date($this->df, strtotime($date_parts[0]));
186 if ($reminder->usetime) {
187 $time_parts = explode(':', $date_parts[1]);
188 $hidden_hours = (int)$time_parts[0];
189 $hidden_minutes = (int)$time_parts[1];
190 }
191 }
192 $is_past_reminder = false;
193 if (!empty($reminder->duedate)) {
194 // calculate distance to expiration date from today
195 $diff_data = $helper->relativeDatesDiff($reminder->duedate);
196 $is_past_reminder = $diff_data['past'];
197 }
198
199 // list of extra classes for the reminder
200 $extra_classes = [];
201 if ($is_past_reminder) {
202 $extra_classes[] = 'vbo-reminder-past';
203 } else {
204 $extra_classes[] = 'vbo-reminder-future';
205 }
206 if ($reminder->completed) {
207 $extra_classes[] = 'vbo-reminder-ok';
208 } else {
209 $extra_classes[] = 'vbo-reminder-nok';
210 }
211
212 ?>
213 <div class="vbo-widget-reminders-record <?php echo implode(' ', $extra_classes); ?>" data-reminderid="<?php echo $reminder->id; ?>">
214 <div class="vbo-widget-reminders-record-status">
215 <button type="button" class="vbo-reminder-status-dot" onclick="vboWidgetRemindersComplete('<?php echo $wrapper; ?>', '<?php echo $reminder->id; ?>');"><?php VikBookingIcons::e($use_icn_status); ?></button>
216 <?php
217 if ($reminder->important) {
218 ?>
219 <div class="vbo-widget-reminders-record-important">
220 <?php VikBookingIcons::e('exclamation-triangle'); ?>
221 </div>
222 <?php
223 }
224 ?>
225 </div>
226 <div class="vbo-widget-reminders-record-info">
227 <div class="vbo-widget-reminders-record-txt">
228 <span class="vbo-widget-reminder-title"><?php echo htmlspecialchars($reminder->title); ?></span>
229 <?php
230 if (!empty($reminder->descr)) {
231 ?>
232 <span class="vbo-widget-reminder-descr"><?php echo htmlspecialchars($reminder->descr); ?></span>
233 <?php
234 }
235 ?>
236 </div>
237 <div class="vbo-widget-reminders-record-due">
238 <span class="vbo-widget-reminder-date" style="display: none;"><?php echo $hidden_date; ?></span>
239 <span class="vbo-widget-reminder-hours" style="display: none;"><?php echo $hidden_hours; ?></span>
240 <span class="vbo-widget-reminder-minutes" style="display: none;"><?php echo $hidden_minutes; ?></span>
241 <?php
242 if (!empty($reminder->idorder) && $reminder->idorder > 0) {
243 ?>
244 <span class="vbo-widget-reminder-idorder" style="display: none;"><?php echo $reminder->idorder; ?></span>
245 <div class="vbo-widget-reminders-record-due-booking">
246 <a class="label label-info" href="<?php echo sprintf($bookings_base_uri, $reminder->idorder); ?>" target="_blank"><?php echo $reminder->idorder; ?></a>
247 </div>
248 <?php
249 }
250 if (!empty($reminder->duedate)) {
251 ?>
252 <div class="vbo-widget-reminders-record-due-datetime">
253 <div class="vbo-widget-reminders-record-due-date">
254 <span title="<?php echo $reminder->duedate; ?>"><?php echo $diff_data['relative']; ?></span>
255 </div>
256 <?php
257 if ($reminder->usetime) {
258 ?>
259 <div class="vbo-widget-reminders-record-due-time">
260 <span><?php echo $diff_data['date_a']->format('H:i'); ?></span>
261 </div>
262 <?php
263 }
264 ?>
265 </div>
266 <?php
267 }
268 ?>
269 </div>
270 </div>
271 <div class="vbo-widget-reminders-record-edit">
272 <button type="button" class="vbo-reminder-record-edit" onclick="vboWidgetRemindersEdit('<?php echo $wrapper; ?>', '<?php echo $reminder->id; ?>');"><?php VikBookingIcons::e('edit'); ?></button>
273 </div>
274 </div>
275 <?php
276 }
277
278 // append navigation
279 ?>
280 <div class="vbo-widget-commands vbo-widget-commands-right">
281 <div class="vbo-widget-commands-main">
282 <?php
283 if ($offset > 0) {
284 // show backward navigation button
285 ?>
286 <div class="vbo-widget-command-chevron vbo-widget-command-prev">
287 <span class="vbo-widget-command-chevron-prev" onclick="vboWidgetRemindersNavigate('<?php echo $wrapper; ?>', -1);"><?php VikBookingIcons::e('chevron-left'); ?></span>
288 </div>
289 <?php
290 }
291 if ($has_next_page) {
292 // show forward navigation button
293 ?>
294 <div class="vbo-widget-command-chevron vbo-widget-command-next">
295 <span class="vbo-widget-command-chevron-next" onclick="vboWidgetRemindersNavigate('<?php echo $wrapper; ?>', 1);"><?php VikBookingIcons::e('chevron-right'); ?></span>
296 </div>
297 <?php
298 }
299 ?>
300 </div>
301 </div>
302 <?php
303
304 // get the HTML buffer
305 $html_content = ob_get_contents();
306 ob_end_clean();
307
308 // return an associative array of values
309 return array(
310 'html' => $html_content,
311 'tot_records' => count($reminders),
312 'next_page' => (int)$has_next_page,
313 );
314 }
315
316 /**
317 * Custom method for this widget only.
318 * Creates a new reminder.
319 *
320 * @return array
321 */
322 public function saveReminder()
323 {
324 $title = VikRequest::getString('title', '', 'request');
325 $descr = VikRequest::getString('descr', '', 'request');
326 $date = VikRequest::getString('date', '', 'request');
327 $hours = VikRequest::getInt('hours', 0, 'request');
328 $minutes = VikRequest::getInt('minutes', 0, 'request');
329 $bid = VikRequest::getInt('bid', 0, 'request');
330 $important = VikRequest::getInt('important', 0, 'request');
331
332 // create reminder object
333 $reminder = new stdClass;
334 $reminder->title = $title;
335 $reminder->descr = $descr;
336 $use_time = 0;
337 if (!empty($date)) {
338 if ($hours >= 0) {
339 $use_time = 1;
340 $minutes = $minutes >= 0 ? $minutes : 0;
341 $due_ts = VikBooking::getDateTimestamp($date, $hours, $minutes);
342 } else {
343 $due_ts = VikBooking::getDateTimestamp($date);
344 }
345 $reminder->duedate = date('Y-m-d H:i:s', $due_ts);
346 }
347 $reminder->usetime = $use_time;
348 if (!empty($bid)) {
349 $reminder->idorder = $bid;
350 }
351 $reminder->important = $important;
352
353 if (!VBORemindersHelper::getInstance()->saveReminder($reminder)) {
354 VBOHttpDocument::getInstance()->close(400, 'Could not create the reminder');
355 }
356
357 // compose the notification payload for the newly created reminder
358 $notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);
359
360 return [
361 'status' => true,
362 'notification' => $notif_data,
363 'debug' => print_r($reminder, true)
364 ];
365 }
366
367 /**
368 * Custom method for this widget only.
369 * Updates an existing reminder.
370 *
371 * @return array
372 */
373 public function updateReminder()
374 {
375 $rid = VikRequest::getInt('rid', 0, 'request');
376 $title = VikRequest::getString('title', '', 'request');
377 $descr = VikRequest::getString('descr', '', 'request');
378 $date = VikRequest::getString('date', '', 'request');
379 $hours = VikRequest::getInt('hours', 0, 'request');
380 $minutes = VikRequest::getInt('minutes', 0, 'request');
381 $bid = VikRequest::getInt('bid', 0, 'request');
382 $important = VikRequest::getInt('important', 0, 'request');
383
384 if (empty($rid)) {
385 VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to update');
386 }
387
388 // create reminder object
389 $reminder = new stdClass;
390 $reminder->id = $rid;
391 $reminder->title = $title;
392 $reminder->descr = $descr;
393 $use_time = 0;
394 if (!empty($date)) {
395 if ($hours >= 0) {
396 $use_time = 1;
397 $minutes = $minutes >= 0 ? $minutes : 0;
398 $due_ts = VikBooking::getDateTimestamp($date, $hours, $minutes);
399 } else {
400 $due_ts = VikBooking::getDateTimestamp($date);
401 }
402 $reminder->duedate = date('Y-m-d H:i:s', $due_ts);
403 }
404 $reminder->usetime = $use_time;
405 $reminder->idorder = !empty($bid) ? $bid : 0;
406
407 if (!VBORemindersHelper::getInstance()->updateReminder($reminder)) {
408 VBOHttpDocument::getInstance()->close(400, 'Could not update the reminder');
409 }
410
411 // compose the notification paylod for the newly created reminder
412 $notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);
413
414 return [
415 'status' => true,
416 'notification' => $notif_data,
417 ];
418 }
419
420 /**
421 * Custom method for this widget only.
422 * Toggles the completed status for an existing reminder.
423 *
424 * @return array
425 */
426 public function toggleReminderCompleted()
427 {
428 $rid = VikRequest::getInt('rid', 0, 'request');
429
430 if (empty($rid)) {
431 VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to update');
432 }
433
434 $helper = VBORemindersHelper::getInstance();
435 $reminder = $helper->getReminder($rid);
436 if (!$reminder) {
437 VBOHttpDocument::getInstance()->close(400, 'Record not found');
438 }
439
440 // toggle completed status
441 $reminder->completed = (int) !$reminder->completed;
442
443 if (!$helper->updateReminder($reminder)) {
444 VBOHttpDocument::getInstance()->close(400, 'Could not update the reminder');
445 }
446
447 $notif_data = null;
448 if (!$reminder->completed) {
449 // compose the notification paylod for the uncompleted reminder
450 $notif_data = VBONotificationScheduler::getInstance()->getReminderDataObject($reminder, $max_future_hours = 12);
451 }
452
453 return [
454 'status' => $reminder->completed,
455 'notification' => $notif_data,
456 ];
457 }
458
459 /**
460 * Custom method for this widget only.
461 * Deletes an existing reminder.
462 *
463 * @return bool
464 */
465 public function deleteReminder()
466 {
467 $rid = VikRequest::getInt('rid', 0, 'request');
468
469 if (empty($rid)) {
470 VBOHttpDocument::getInstance()->close(400, 'Missing reminder ID to delete');
471 }
472
473 $helper = VBORemindersHelper::getInstance();
474 $reminder = $helper->getReminder($rid);
475 if (!$reminder) {
476 VBOHttpDocument::getInstance()->close(400, 'Record not found');
477 }
478
479 if (!$helper->deleteReminder($reminder)) {
480 VBOHttpDocument::getInstance()->close(400, 'Could not delete the reminder');
481 }
482
483 return true;
484 }
485
486 /**
487 * Main method to invoke the widget. Contents will be loaded
488 * through AJAX requests, not via PHP when the page loads.
489 *
490 * @param VBOMultitaskData $data multitask data object.
491 *
492 * @return void
493 */
494 public function render(VBOMultitaskData $data = null)
495 {
496 // increase widget's instance counter
497 static::$instance_counter++;
498
499 // check whether the widget is being rendered via AJAX when adding it through the customizer
500 $is_ajax = $this->isAjaxRendering();
501
502 // generate a unique ID for the sticky notes wrapper instance
503 $wrapper_instance = !$is_ajax ? static::$instance_counter : rand();
504 $wrapper_id = 'vbo-widget-reminders-' . $wrapper_instance;
505
506 // default filters
507 $def_completed = 0;
508 $def_expired = 0;
509 $def_duedate = time();
510 $def_duehours = -1;
511 $def_duemins = -1;
512
513 // check multitask data
514 $page_bid = '';
515 $auto_action = '';
516 $js_modal_id = '';
517 if ($data) {
518 // access Multitask data
519 $page_bid = $data->getBookingID();
520 if ($data->isModalRendering()) {
521 // get modal JS identifier
522 $js_modal_id = $data->getModalJsIdentifier();
523 }
524
525 // we allow the page booking ID to be passed as an option as well
526 $page_bid = !$page_bid ? $this->options()->fetchBookingId() : $page_bid;
527
528 // check for options
529 $auto_action = $this->getOption('action', '');
530 $def_completed = (int)$this->getOption('completed', $def_completed);
531 $def_expired = (int)$this->getOption('expired', $def_expired);
532
533 // attempt to define values for this precise booking
534 $booking_info = $page_bid ? VikBooking::getBookingInfoFromID($page_bid) : [];
535 if ($booking_info) {
536 $def_time_info = [];
537 if ($booking_info['checkin'] > $def_duedate) {
538 $def_duedate = $booking_info['checkin'];
539 $def_time_info = getdate($def_duedate);
540 } elseif ($booking_info['checkout'] > $def_duedate) {
541 $def_duedate = $booking_info['checkout'];
542 $def_time_info = getdate($def_duedate);
543 }
544 if ($def_time_info) {
545 $def_duehours = (int)$def_time_info['hours'];
546 $def_duemins = (int)$def_time_info['minutes'];
547 }
548 }
549 } else {
550 // load settings
551 $def_completed = isset($this->widgetSettings->show_completed) ? (int)$this->widgetSettings->show_completed : $def_completed;
552 $def_expired = isset($this->widgetSettings->show_expired) ? (int)$this->widgetSettings->show_expired : $def_expired;
553 }
554
555 ?>
556 <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; ?>">
557 <div class="vbo-admin-widget-head">
558 <div class="vbo-admin-widget-head-inline">
559 <h4><?php echo $this->widgetIcon; ?> <span><?php echo $this->widgetName; ?></span></h4>
560 <div class="vbo-admin-widget-head-commands">
561
562 <div class="vbo-reportwidget-commands">
563 <div class="vbo-reportwidget-commands-main">
564 <div class="vbo-reportwidget-command-add">
565 <span class="vbo-widget-command-addnew" onclick="vboWidgetRemindersAdd('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('plus-circle'); ?></span>
566 </div>
567 </div>
568 <div class="vbo-reportwidget-command-dots">
569 <span class="vbo-widget-command-togglefilters vbo-widget-reminders-togglefilters" onclick="vboWidgetRemindersToggleFilters('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('ellipsis-v'); ?></span>
570 </div>
571 </div>
572 <div class="vbo-reportwidget-filters">
573 <div class="vbo-reportwidget-filter">
574 <label for="show_completed<?php echo $wrapper_instance; ?>-on"><?php echo JText::translate('VBO_SHOW_COMPLETED'); ?></label>
575 <?php echo $this->vbo_app->printYesNoButtons('show_completed' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), $def_completed, 1, 0); ?>
576 </div>
577 <div class="vbo-reportwidget-filter">
578 <label for="show_expired<?php echo $wrapper_instance; ?>-on"><?php echo JText::translate('VBO_SHOW_EXPIRED'); ?></label>
579 <?php echo $this->vbo_app->printYesNoButtons('show_expired' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), $def_expired, 1, 0); ?>
580 </div>
581 <div class="vbo-reportwidget-filter vbo-reportwidget-filter-confirm">
582 <button type="button" class="btn vbo-config-btn" onclick="vboWidgetRemindersChangeParams('<?php echo $wrapper_id; ?>');"><?php echo JText::translate('VBADMINNOTESUPD'); ?></button>
583 </div>
584 </div>
585
586 </div>
587 </div>
588 </div>
589 <div class="vbo-widget-reminders-wrap">
590 <div class="vbo-widget-reminders-inner">
591 <div class="vbo-widget-reminders-manage" style="display: none;">
592
593 <div class="vbo-widget-reminders-goback">
594 <a href="JavaScript: void(0);" onclick="vboWidgetRemindersToggleManage('<?php echo $wrapper_id; ?>');"><?php VikBookingIcons::e('chevron-left'); ?> <?php echo JText::translate('VBBACK'); ?></a>
595 </div>
596
597 <div class="vbo-widget-reminders-manage-wrap">
598 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-title">
599 <input type="text" class="vbo-widget-reminders-ftitle" value="" placeholder="<?php echo htmlspecialchars(JText::translate('VBO_REMINDER_TITLE')); ?>" />
600 </div>
601 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-descr">
602 <textarea class="vbo-widget-reminders-fdescr" placeholder="<?php echo htmlspecialchars(JText::translate('VBPVIEWOPTIONALSTWO')); ?>" maxlength="2000"></textarea>
603 </div>
604 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-booking vbo-toggle-small" style="<?php echo empty($page_bid) ? 'display: none;' : ''; ?>">
605 <span class="vbo-widget-reminders-filter-tobooking">
606 <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>
607 <?php echo $this->vbo_app->printYesNoButtons('assign_booking' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), (!empty($page_bid) ? 1 : 0), 1, 0); ?>
608 </span>
609 <span class="vbo-widget-reminders-filter-importance">
610 <label for="is_important<?php echo $wrapper_instance; ?>-on"><?php VikBookingIcons::e('exclamation-triangle'); ?> <?php echo JText::translate('VBO_IMPORTANT'); ?></label>
611 <?php echo $this->vbo_app->printYesNoButtons('is_important' . $wrapper_instance, JText::translate('VBYES'), JText::translate('VBNO'), 0, 1, 0); ?>
612 </span>
613 </div>
614 <div class="vbo-widget-reminders-filter-datetime">
615 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-date">
616 <div class="vbo-field-calendar">
617 <div class="input-append">
618 <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')); ?>" />
619 <button type="button" class="btn btn-secondary vbo-widget-reminders-caltrigger"><?php VikBookingIcons::e('calendar'); ?></button>
620 </div>
621 </div>
622 </div>
623 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-time">
624 <select class="vbo-widget-reminders-fh">
625 <option value=""><?php echo ucfirst(JText::translate('VBCONFIGONETENEIGHT')); ?></option>
626 <?php
627 for ($i = 0; $i < 24; $i++) {
628 ?>
629 <option value="<?php echo $i; ?>"<?php echo $i == $def_duehours ? ' selected="selected"' : ''; ?>><?php echo $i < 10 ? "0{$i}" : $i; ?></option>
630 <?php
631 }
632 ?>
633 </select>
634 <select class="vbo-widget-reminders-fm">
635 <option value=""><?php echo ucfirst(JText::translate('VBTRKDIFFMINS')); ?></option>
636 <?php
637 for ($i = 0; $i < 60; $i++) {
638 ?>
639 <option value="<?php echo $i; ?>"<?php echo $i == $def_duemins ? ' selected="selected"' : ''; ?>><?php echo $i < 10 ? "0{$i}" : $i; ?></option>
640 <?php
641 }
642 ?>
643 </select>
644 </div>
645 </div>
646 <div class="vbo-widget-reminders-filter vbo-widget-reminders-filter-save">
647 <input type="hidden" class="vbo-widget-reminders-rid" value="" />
648 <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>
649 <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>
650 </div>
651 </div>
652
653 </div>
654 <div class="vbo-widget-reminders-list">
655 <?php
656 for ($i = 0; $i < floor($this->reminders_per_page / 2); $i++) {
657 ?>
658 <div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">
659 <div class="vbo-dashboard-guest-activity-avatar">
660 <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>
661 </div>
662 <div class="vbo-dashboard-guest-activity-content">
663 <div class="vbo-dashboard-guest-activity-content-head">
664 <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>
665 </div>
666 <div class="vbo-dashboard-guest-activity-content-info-msg">
667 <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>
668 </div>
669 </div>
670 </div>
671 <?php
672 }
673 ?>
674 </div>
675 </div>
676 </div>
677 </div>
678 <?php
679
680 if (static::$instance_counter === 0 || $is_ajax) {
681 /**
682 * Print the JS code only once for all instances of this widget.
683 * The real rendering is made through AJAX, not when the page loads.
684 */
685 ?>
686 <script type="text/javascript">
687
688 /**
689 * Display the loading skeletons.
690 */
691 function vboWidgetRemindersSkeletons(wrapper) {
692 var widget_instance = jQuery('#' + wrapper);
693 if (!widget_instance.length) {
694 return false;
695 }
696 widget_instance.find('.vbo-widget-reminders-list').html('');
697 for (var i = 0; i < <?php echo floor($this->reminders_per_page / 2); ?>; i++) {
698 var skeleton = '';
699 skeleton += '<div class="vbo-dashboard-guest-activity vbo-dashboard-guest-activity-skeleton">';
700 skeleton += ' <div class="vbo-dashboard-guest-activity-avatar">';
701 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-avatar"></div>';
702 skeleton += ' </div>';
703 skeleton += ' <div class="vbo-dashboard-guest-activity-content">';
704 skeleton += ' <div class="vbo-dashboard-guest-activity-content-head">';
705 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-title"></div>';
706 skeleton += ' </div>';
707 skeleton += ' <div class="vbo-dashboard-guest-activity-content-info-msg">';
708 skeleton += ' <div class="vbo-skeleton-loading vbo-skeleton-loading-content"></div>';
709 skeleton += ' </div>';
710 skeleton += ' </div>';
711 skeleton += '</div>';
712 // append skeleton
713 jQuery(skeleton).appendTo(widget_instance.find('.vbo-widget-reminders-list'));
714 }
715 }
716
717 /**
718 * Toggles the layout to add or edit a reminder.
719 */
720 function vboWidgetRemindersToggleManage(wrapper) {
721 var widget_instance = jQuery('#' + wrapper);
722 if (!widget_instance.length) {
723 return false;
724 }
725
726 var mng_cont = widget_instance.find('.vbo-widget-reminders-manage');
727 if (mng_cont.is(':visible')) {
728 mng_cont.hide();
729 widget_instance.find('.vbo-widget-reminders-list').show();
730 } else {
731 widget_instance.find('.vbo-widget-reminders-list').hide();
732 mng_cont.show();
733 }
734 }
735
736 /**
737 * Toggle filters.
738 */
739 function vboWidgetRemindersToggleFilters(wrapper) {
740 var widget_instance = jQuery('#' + wrapper);
741 if (!widget_instance.length) {
742 return false;
743 }
744
745 widget_instance.find('.vbo-reportwidget-filters').toggle();
746 }
747
748 /**
749 * Reload records with new params.
750 */
751 function vboWidgetRemindersChangeParams(wrapper) {
752 var widget_instance = jQuery('#' + wrapper);
753 if (!widget_instance.length) {
754 return false;
755 }
756
757 // hide filters when making a new request
758 widget_instance.find('.vbo-reportwidget-filters').hide();
759
760 // reset offset to 0
761 widget_instance.attr('data-offset', 0);
762
763 // show loading skeletons
764 vboWidgetRemindersSkeletons(wrapper);
765
766 // reload the first page
767 vboWidgetRemindersLoad(wrapper);
768 }
769
770 /**
771 * Prepare the layout to add a new reminder.
772 */
773 function vboWidgetRemindersAdd(wrapper) {
774 var widget_instance = jQuery('#' + wrapper);
775 if (!widget_instance.length) {
776 return false;
777 }
778
779 // always reset the reminder id in the hidden input and hide delete
780 widget_instance.find('.vbo-widget-reminders-rid').val('');
781 widget_instance.find('.vbo-widget-reminder-delete').hide();
782 widget_instance.find('.vbo-widget-reminder-confirm span').text(Joomla.JText._('VBCONFIGCLOSINGDATEADD'));
783
784 // check if we need to hide the assign-to-booking option
785 var page_bid = widget_instance.attr('data-pagebid');
786 if (page_bid.length && page_bid > 0) {
787 // show assign-to-booking option and important reminder
788 widget_instance.find('.vbo-widget-reminders-filter-booking-id').text(page_bid);
789 widget_instance.find('input[name^="assign_booking"]').prop('checked', true);
790 widget_instance.find('input[name^="is_important"]').prop('checked', false);
791 widget_instance.find('.vbo-widget-reminders-filter-booking').show();
792 } else {
793 // hide assign-to-booking option and important reminder
794 widget_instance.find('input[name^="assign_booking"]').prop('checked', false);
795 widget_instance.find('input[name^="is_important"]').prop('checked', false);
796 widget_instance.find('.vbo-widget-reminders-filter-booking').hide();
797 }
798
799 // reset the rest of the fields in case of previous editing
800 if (widget_instance.find('.vbo-widget-reminders-ftitle').val() || widget_instance.find('.vbo-widget-reminders-fdescr').val()) {
801 widget_instance.find('.vbo-widget-reminders-ftitle').val('');
802 widget_instance.find('.vbo-widget-reminders-fdescr').val('');
803 widget_instance.find('.vbo-reminders-dtpicker').val('');
804 widget_instance.find('.vbo-widget-reminders-fh').val('');
805 widget_instance.find('.vbo-widget-reminders-fm').val('');
806 }
807
808 // toggle edit mode
809 vboWidgetRemindersToggleManage(wrapper);
810 }
811
812 /**
813 * Prepare the reminder edit mode by populating data.
814 */
815 function vboWidgetRemindersEdit(wrapper, rid) {
816 var widget_instance = jQuery('#' + wrapper);
817 if (!widget_instance.length) {
818 return false;
819 }
820 var reminder_instance = widget_instance.find('[data-reminderid="' + rid + '"]');
821 if (!reminder_instance.length) {
822 return false;
823 }
824
825 // populate fields for edit mode
826 widget_instance.find('.vbo-widget-reminder-confirm span').text(Joomla.JText._('VBADMINNOTESUPD'));
827 widget_instance.find('.vbo-widget-reminder-delete').show();
828 widget_instance.find('.vbo-widget-reminders-rid').val(rid);
829 widget_instance.find('.vbo-widget-reminders-ftitle').val(reminder_instance.find('.vbo-widget-reminder-title').text());
830 widget_instance.find('.vbo-widget-reminders-fdescr').val(reminder_instance.find('.vbo-widget-reminder-descr').text());
831 widget_instance.find('.vbo-reminders-dtpicker').val(reminder_instance.find('.vbo-widget-reminder-date').text());
832 widget_instance.find('.vbo-widget-reminders-fh').val(reminder_instance.find('.vbo-widget-reminder-hours').text());
833 widget_instance.find('.vbo-widget-reminders-fm').val(reminder_instance.find('.vbo-widget-reminder-minutes').text());
834 // handle booking ID assignment
835 var booking_assigned = null;
836 var booking_container = reminder_instance.find('.vbo-widget-reminder-idorder');
837 if (booking_container.length) {
838 booking_assigned = booking_container.text();
839 }
840 if (booking_assigned) {
841 // show assign-to-booking option
842 widget_instance.find('.vbo-widget-reminders-filter-booking-id').text(booking_assigned);
843 widget_instance.find('input[name^="assign_booking"]').prop('checked', true);
844 widget_instance.find('.vbo-widget-reminders-filter-booking').show();
845 } else {
846 // hide assign-to-booking option
847 widget_instance.find('input[name^="assign_booking"]').prop('checked', false);
848 widget_instance.find('.vbo-widget-reminders-filter-booking').hide();
849 }
850
851 // handle important reminder flag
852 if (booking_assigned && reminder_instance.find('.vbo-widget-reminders-record-important').length) {
853 widget_instance.find('input[name^="is_important"]').prop('checked', true);
854 } else {
855 widget_instance.find('input[name^="is_important"]').prop('checked', false);
856 }
857
858 // enter edit mode
859 vboWidgetRemindersToggleManage(wrapper);
860 }
861
862 /**
863 * Toggle reminder completed status.
864 */
865 function vboWidgetRemindersComplete(wrapper, rid) {
866 var widget_instance = jQuery('#' + wrapper);
867 if (!widget_instance.length) {
868 return false;
869 }
870 var reminder_instance = widget_instance.find('[data-reminderid="' + rid + '"]');
871 if (!reminder_instance.length) {
872 return false;
873 }
874
875 // the widget method to call
876 var call_method = 'toggleReminderCompleted';
877
878 // make a request to update the reminder
879 VBOCore.doAjax(
880 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
881 {
882 widget_id: "<?php echo $this->getIdentifier(); ?>",
883 call: call_method,
884 return: 1,
885 rid: rid,
886 wrapper: wrapper,
887 tmpl: "component"
888 },
889 function(response) {
890 try {
891 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
892 if (!obj_res.hasOwnProperty(call_method)) {
893 console.error('Unexpected or invalid JSON response', obj_res);
894 return false;
895 }
896
897 if (obj_res[call_method]['status'] > 0) {
898 // new status is completed
899 reminder_instance
900 .removeClass('vbo-reminder-nok')
901 .addClass('vbo-reminder-ok')
902 .find('.vbo-reminder-status-dot').html('<?php VikBookingIcons::e('dot-circle'); ?>');
903 // check current params
904 var show_completed = widget_instance.find('input[name^="show_completed"]').prop('checked');
905 if (!show_completed) {
906 reminder_instance.fadeOut();
907 }
908 // attempt to unset any scheduled notification for this reminder
909 VBOCore.updateNotification({
910 id: rid,
911 type: "reminder"
912 }, 0);
913 } else {
914 // new status is un-completed
915 reminder_instance
916 .removeClass('vbo-reminder-ok')
917 .addClass('vbo-reminder-nok')
918 .find('.vbo-reminder-status-dot').html('<?php VikBookingIcons::e('far fa-circle'); ?>');
919 if (obj_res[call_method]['notification'] != null) {
920 // attempt to schedule a notification for this reminder
921 VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
922 }
923 }
924 } catch(err) {
925 console.error('could not parse JSON response', err, response);
926 }
927 },
928 function(error) {
929 // log the error and display the message
930 console.error(error);
931 alert(error.responseText);
932 }
933 );
934 }
935
936 /**
937 * Delete one reminder record.
938 */
939 function vboWidgetRemindersDelete(wrapper) {
940 var widget_instance = jQuery('#' + wrapper);
941 if (!widget_instance.length) {
942 return false;
943 }
944
945 var rid = widget_instance.find('.vbo-widget-reminders-rid').val();
946 if (!rid || !rid.length) {
947 return false;
948 }
949
950 if (!confirm(Joomla.JText._('VBDELCONFIRM'))) {
951 return false;
952 }
953
954 // disable delete button
955 var del_btn = widget_instance.find('button.vbo-widget-reminder-delete');
956 del_btn.prop('disabled', true);
957
958 // the widget method to call
959 var call_method = 'deleteReminder';
960
961 // make a request to update the reminder
962 VBOCore.doAjax(
963 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
964 {
965 widget_id: "<?php echo $this->getIdentifier(); ?>",
966 call: call_method,
967 return: 1,
968 rid: rid,
969 wrapper: wrapper,
970 tmpl: "component"
971 },
972 function(response) {
973 try {
974 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
975 if (!obj_res.hasOwnProperty(call_method) || !obj_res[call_method]) {
976 console.error('Unexpected or invalid JSON response', obj_res);
977 return false;
978 }
979
980 // turn flag on
981 vbo_reminders_changed = true;
982
983 // toggle edit mode
984 vboWidgetRemindersToggleManage(wrapper);
985
986 // enable delete button
987 del_btn.prop('disabled', false);
988
989 // reset offset to 0
990 widget_instance.attr('data-offset', 0);
991
992 // show loading skeletons
993 vboWidgetRemindersSkeletons(wrapper);
994
995 // reload the first page
996 vboWidgetRemindersLoad(wrapper);
997
998 // attempt to unset any scheduled notification for this reminder
999 VBOCore.updateNotification({
1000 id: rid,
1001 type: "reminder"
1002 }, 0);
1003 } catch(err) {
1004 console.error('could not parse JSON response', err, response);
1005 }
1006 },
1007 function(error) {
1008 // log the error and display the message
1009 console.error(error);
1010 alert(error.responseText);
1011 // enable delete button
1012 del_btn.prop('disabled', false);
1013 }
1014 );
1015 }
1016
1017 /**
1018 * Perform the request to load the reminders.
1019 */
1020 function vboWidgetRemindersLoad(wrapper) {
1021 var widget_instance = jQuery('#' + wrapper);
1022 if (!widget_instance.length) {
1023 return false;
1024 }
1025
1026 // get vars for making the request
1027 var current_offset = parseInt(widget_instance.attr('data-offset'));
1028 var length_per_page = parseInt(widget_instance.attr('data-length'));
1029 var show_completed = widget_instance.find('input[name^="show_completed"]').prop('checked');
1030 var show_expired = widget_instance.find('input[name^="show_expired"]').prop('checked');
1031 show_completed = show_completed ? 1 : 0;
1032 show_expired = show_expired ? 1 : 0;
1033 var page_bid = widget_instance.attr('data-pagebid');
1034
1035 // the widget method to call
1036 var call_method = 'loadReminders';
1037
1038 // make a request to load the reminder records
1039 VBOCore.doAjax(
1040 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
1041 {
1042 widget_id: "<?php echo $this->getIdentifier(); ?>",
1043 call: call_method,
1044 return: 1,
1045 offset: current_offset,
1046 length: length_per_page,
1047 completed: show_completed,
1048 expired: show_expired,
1049 bid: page_bid,
1050 wrapper: wrapper,
1051 tmpl: "component"
1052 },
1053 (response) => {
1054 try {
1055 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
1056 if (!obj_res.hasOwnProperty(call_method)) {
1057 console.error('Unexpected JSON response', obj_res);
1058 return false;
1059 }
1060
1061 // replace HTML with month-day reservations
1062 widget_instance.find('.vbo-widget-reminders-list').html(obj_res[call_method]['html']);
1063
1064 // check results
1065 var tot_records = obj_res[call_method]['tot_records'] || 0;
1066 if (!isNaN(tot_records) && parseInt(tot_records) < 1) {
1067 // no results can indicate the offset is invalid or too high
1068 if (!isNaN(current_offset) && current_offset > 0) {
1069 // reset offset to 0
1070 widget_instance.attr('data-offset', 0);
1071 // show loading skeletons
1072 vboWidgetRemindersSkeletons(wrapper);
1073 // reload the first page
1074 vboWidgetRemindersLoad(wrapper);
1075 }
1076 }
1077 } catch(err) {
1078 console.error('could not parse JSON response', err, response);
1079 }
1080 },
1081 (error) => {
1082 // remove the skeleton loading
1083 widget_instance.find('.vbo-widget-reminders-list').find('.vbo-dashboard-guest-activity-skeleton').remove();
1084 console.error(error);
1085 }
1086 );
1087 }
1088
1089 /**
1090 * Save a new reminder or update an existing one.
1091 */
1092 function vboWidgetRemindersSaveNew(wrapper) {
1093 var widget_instance = jQuery('#' + wrapper);
1094 if (!widget_instance.length) {
1095 return false;
1096 }
1097
1098 // either save or update
1099 var mode = 'saveReminder';
1100
1101 // collect new reminder details
1102 var r_title = widget_instance.find('.vbo-widget-reminders-ftitle').val();
1103 var r_descr = widget_instance.find('.vbo-widget-reminders-fdescr').val();
1104 var r_date = widget_instance.find('.vbo-reminders-dtpicker').val();
1105 var r_hours = widget_instance.find('.vbo-widget-reminders-fh').val();
1106 var r_mins = widget_instance.find('.vbo-widget-reminders-fm').val();
1107 // adjust time
1108 if (!r_hours.length) {
1109 r_hours = -1;
1110 r_mins = 0;
1111 }
1112 // check if we are editing an existing reminder id
1113 var r_id = widget_instance.find('.vbo-widget-reminders-rid').val();
1114 if (r_id && r_id.length) {
1115 mode = 'updateReminder';
1116 } else {
1117 r_id = 0;
1118 }
1119
1120 if ((!r_title.length && !r_descr.length) || !r_date.length) {
1121 alert(Joomla.JText._('VBO_PLEASE_FILL_FIELDS'));
1122 return false;
1123 }
1124
1125 // check if we are saving/updating a reminder for a booking ID
1126 var r_bid = null;
1127 var assign_to_bid = widget_instance.find('input[name^="assign_booking"]').prop('checked');
1128 if (assign_to_bid) {
1129 // validate the booking id depending on save/update mode
1130 if (mode == 'saveReminder') {
1131 // the booking id must have been set from the current page
1132 var validate_bid = widget_instance.attr('data-pagebid');
1133 if (validate_bid && validate_bid.length) {
1134 // valid
1135 r_bid = validate_bid;
1136 }
1137 } else {
1138 // the booking id must be part of a hidden field
1139 var reminder_instance = widget_instance.find('[data-reminderid="' + r_id + '"]');
1140 if (reminder_instance.length) {
1141 var validate_bid = reminder_instance.find('.vbo-widget-reminder-idorder').text();
1142 if (validate_bid && validate_bid.length) {
1143 // valid
1144 r_bid = validate_bid;
1145 }
1146 }
1147 }
1148 }
1149
1150 // check importance
1151 var is_important = 0;
1152 if (r_bid && widget_instance.find('input[name^="is_important"]').prop('checked')) {
1153 is_important = 1;
1154 }
1155
1156 // disable save button
1157 var save_btn = widget_instance.find('.vbo-widget-reminders-filter-save button');
1158 save_btn.prop('disabled', true);
1159
1160 // the widget method to call
1161 var call_method = mode;
1162
1163 // make a request to save a new reminder or to update it
1164 VBOCore.doAjax(
1165 "<?php echo $this->getExecWidgetAjaxUri(); ?>",
1166 {
1167 widget_id: "<?php echo $this->getIdentifier(); ?>",
1168 call: call_method,
1169 return: 1,
1170 rid: r_id,
1171 bid: r_bid,
1172 title: r_title,
1173 descr: r_descr,
1174 date: r_date,
1175 hours: r_hours,
1176 minutes: r_mins,
1177 important: is_important,
1178 wrapper: wrapper,
1179 tmpl: "component"
1180 },
1181 (response) => {
1182 try {
1183 var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
1184 if (!obj_res.hasOwnProperty(call_method) || !obj_res[call_method]['status']) {
1185 console.error('Unexpected or invalid JSON response', obj_res);
1186 return false;
1187 }
1188
1189 // turn flag on & store booking involved, if any
1190 vbo_reminders_changed = true;
1191 vbo_reminders_changed_bid = r_bid;
1192
1193 // toggle edit mode
1194 vboWidgetRemindersToggleManage(wrapper);
1195
1196 // enable save button
1197 save_btn.prop('disabled', false);
1198
1199 // reset offset to 0
1200 widget_instance.attr('data-offset', 0);
1201
1202 // show loading skeletons
1203 vboWidgetRemindersSkeletons(wrapper);
1204
1205 // reload the first page
1206 vboWidgetRemindersLoad(wrapper);
1207
1208 // handle browser notifications
1209 if (call_method == 'saveReminder') {
1210 if (obj_res[call_method]['notification'] != null) {
1211 // attempt to schedule a notification for the new reminder
1212 VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
1213 }
1214 } else {
1215 if (obj_res[call_method]['notification'] != null) {
1216 // attempt to update the notification scheduling time for this reminder
1217 let updated = VBOCore.updateNotification({
1218 id: r_id,
1219 type: "reminder"
1220 }, obj_res[call_method]['notification']['dtime']);
1221 if (updated !== true) {
1222 // attempt to schedule this anticipated reminder as a new notification
1223 VBOCore.enqueueNotifications(obj_res[call_method]['notification']);
1224 }
1225 } else {
1226 // the notification may have been set to a far-ahead date, delete it
1227 VBOCore.updateNotification({
1228 id: r_id,
1229 type: "reminder"
1230 }, 0);
1231 }
1232 }
1233 } catch(err) {
1234 console.error('could not parse JSON response', err, response);
1235 }
1236 },
1237 (error) => {
1238 // log the error and display the message
1239 console.error(error);
1240 alert(error.responseText);
1241 // enable save button
1242 save_btn.prop('disabled', false);
1243 }
1244 );
1245 }
1246
1247 /**
1248 * Navigate between the various pages of the reminders.
1249 */
1250 function vboWidgetRemindersNavigate(wrapper, direction) {
1251 var widget_instance = jQuery('#' + wrapper);
1252 if (!widget_instance.length) {
1253 return false;
1254 }
1255
1256 // show loading skeletons
1257 vboWidgetRemindersSkeletons(wrapper);
1258
1259 // current offset
1260 var current_offset = parseInt(widget_instance.attr('data-offset'));
1261
1262 // records per page
1263 var steps = parseInt(widget_instance.attr('data-length'));
1264
1265 // check direction and update offsets for nav
1266 if (direction > 0) {
1267 // navigate forward
1268 widget_instance.attr('data-offset', (current_offset + steps));
1269 } else {
1270 // navigate backward
1271 var new_offset = current_offset - steps;
1272 new_offset = new_offset >= 0 ? new_offset : 0;
1273 widget_instance.attr('data-offset', new_offset);
1274 }
1275
1276 // launch navigation
1277 vboWidgetRemindersLoad(wrapper);
1278 }
1279
1280 </script>
1281 <?php
1282 }
1283 ?>
1284
1285 <script type="text/javascript">
1286
1287 // keep track of any changes related to reminders
1288 var vbo_reminders_changed = false;
1289
1290 // keep track of changes to reminders related to a bookind ID
1291 var vbo_reminders_changed_bid = null;
1292
1293 jQuery(function() {
1294
1295 // render datepicker calendar
1296 jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-reminders-dtpicker').datepicker({
1297 minDate: "0",
1298 maxDate: "+5y",
1299 yearRange: "<?php echo date('Y'); ?>:<?php echo (date('Y') + 5); ?>",
1300 changeMonth: true,
1301 changeYear: true,
1302 dateFormat: "<?php echo $this->getDateFormat('jui'); ?>",
1303 defaultDate: "<?php echo date($this->df, $def_duedate); ?>"
1304 });
1305
1306 // triggering for datepicker calendar icons
1307 jQuery('#<?php echo $wrapper_id; ?>').find('.vbo-widget-reminders-caltrigger').click(function() {
1308 var jdp = jQuery(this).parent().find('input.hasDatepicker');
1309 if (jdp.length) {
1310 jdp.focus();
1311 }
1312 });
1313
1314 // when document is ready, load reminders for this widget's instance
1315 vboWidgetRemindersLoad('<?php echo $wrapper_id; ?>');
1316
1317 // subscribe to the multitask-panel-close event to emit the event for the reminders changed
1318 document.addEventListener(VBOCore.multitask_close_event, function() {
1319 if (vbo_reminders_changed) {
1320 // emit the event with data for anyone who is listening to it
1321 VBOCore.emitEvent('vbo_reminders_changed', {
1322 bid: vbo_reminders_changed_bid
1323 });
1324 }
1325 });
1326
1327 <?php
1328 if ($js_modal_id) {
1329 // widget can be dismissed through the modal
1330 ?>
1331 // subscribe to the modal-dismissed event to emit the event for the reminders changed
1332 document.addEventListener(VBOCore.widget_modal_dismissed + '<?php echo $js_modal_id; ?>', function() {
1333 if (vbo_reminders_changed) {
1334 // emit the event with data for anyone who is listening to it
1335 VBOCore.emitEvent('vbo_reminders_changed', {
1336 bid: vbo_reminders_changed_bid
1337 });
1338 }
1339 });
1340 <?php
1341 }
1342
1343 if ($auto_action == 'add_new') {
1344 // injected optinos require to add a new reminder
1345 ?>
1346 setTimeout(() => {
1347 vboWidgetRemindersAdd('<?php echo $wrapper_id; ?>');
1348 }, 300);
1349 <?php
1350 }
1351 ?>
1352
1353 });
1354
1355 </script>
1356
1357 <?php
1358 }
1359
1360 /**
1361 * Checks if any reminders should be automatically scheduled due to
1362 * important events related to reservations downloaded through VCM.
1363 *
1364 * @return int number of reminders that were automatically scheduled.
1365 *
1366 * @since 1.16.3 (J) - 1.6.3 (WP)
1367 */
1368 protected function scheduleChannelManagerReminders()
1369 {
1370 $scheduled = 0;
1371
1372 if (!method_exists('VikChannelManager', 'hostToGuestReviewSupported')) {
1373 // prevent server errors
1374 return $scheduled;
1375 }
1376
1377 // get the reminders helper object
1378 $helper = VBORemindersHelper::getInstance();
1379
1380 // get a list of Airbnb reservations with a proper checkout date
1381 $airbnb_checkouts = $helper->gatherAirbnbReservationsCheckedOut();
1382
1383 // default due-date for the newly added reminders
1384 $def_due_date = date('Y-m-d H:i:s', strtotime("+1 minute"));
1385
1386 // default reminder payload
1387 $payload = [
1388 'airbnb_host_guest_review' => 1,
1389 ];
1390
1391 // parse all eligible reservations
1392 foreach ($airbnb_checkouts as $airbnb_res) {
1393 // make sure this airbnb reservation requires a host-to-guest review
1394 if (!$helper->bookingHasReminder($airbnb_res['id'], $payload) && VikChannelManager::hostToGuestReviewSupported($airbnb_res)) {
1395 // build and schedule an automatic reminder
1396 $reminder = new stdClass;
1397 $reminder->title = JText::translate('VBO_REVIEW_YOUR_GUEST');
1398 $reminder->descr = 'Airbnb - ' . JText::translate('VBDASHBOOKINGID') . ' ' . $airbnb_res['id'];
1399 $reminder->duedate = $def_due_date;
1400 $reminder->usetime = 1;
1401 $reminder->idorder = $airbnb_res['id'];
1402 $reminder->payload = $payload;
1403 $reminder->important = 1;
1404
1405 if ($helper->saveReminder($reminder)) {
1406 // increase counter
1407 $scheduled++;
1408 }
1409 }
1410 }
1411
1412 return $scheduled;
1413 }
1414 }
1415