calendar
5 days ago
login
5 days ago
payment
5 days ago
alert.php
5 days ago
carttotals.php
5 days ago
checkout.php
5 days ago
couponform.php
5 days ago
index.html
5 days ago
login.php
5 days ago
options.php
5 days ago
paymentmethods.php
5 days ago
quickcontact.php
5 days ago
reviews.php
5 days ago
timeline.php
5 days ago
waitlist.php
5 days ago
reviews.php
476 lines
| 1 | <?php |
| 2 | /** |
| 3 | * @package VikAppointments |
| 4 | * @subpackage core |
| 5 | * @author E4J s.r.l. |
| 6 | * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved. |
| 7 | * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL |
| 8 | * @link https://vikwp.com |
| 9 | */ |
| 10 | |
| 11 | // No direct access |
| 12 | defined('ABSPATH') or die('No script kiddies please!'); |
| 13 | |
| 14 | $reviews = isset($displayData['reviews']) ? $displayData['reviews'] : array(); |
| 15 | $can_leave = isset($displayData['canLeave']) ? $displayData['canLeave'] : false; |
| 16 | $ordering_links = isset($displayData['orderingLinks']) ? $displayData['orderingLinks'] : false; |
| 17 | $id_service = isset($displayData['id_service']) ? $displayData['id_service'] : 0; |
| 18 | $id_employee = isset($displayData['id_employee']) ? $displayData['id_employee'] : 0; |
| 19 | $rev_sub_title = isset($displayData['subtitle']) ? $displayData['subtitle'] : ''; |
| 20 | $dt_format = isset($displayData['datetime_format']) ? $displayData['datetime_format'] : ''; |
| 21 | $itemid = isset($displayData['itemid']) ? $displayData['itemid'] : null; |
| 22 | |
| 23 | if ($id_service) |
| 24 | { |
| 25 | // reviews for a service |
| 26 | $col_name = 'id_service'; |
| 27 | $col_value = $id_service; |
| 28 | $controller = 'servicesearch'; |
| 29 | } |
| 30 | else |
| 31 | { |
| 32 | // reviews for an employee |
| 33 | $col_name = 'id_employee'; |
| 34 | $col_value = $id_employee; |
| 35 | $controller = 'employeesearch'; |
| 36 | } |
| 37 | |
| 38 | if (is_null($itemid)) |
| 39 | { |
| 40 | // item id not provided, get the current one (if set) |
| 41 | $itemid = JFactory::getApplication()->input->getInt('Itemid'); |
| 42 | } |
| 43 | |
| 44 | $config = VAPFactory::getConfig(); |
| 45 | |
| 46 | /** |
| 47 | * Returns the mode used to load the reviews: |
| 48 | * - [1] on scroll down |
| 49 | * - [2] button click |
| 50 | */ |
| 51 | $reviews_load_mode = $config->getUint('revloadmode'); |
| 52 | |
| 53 | $MIN_COMMENT_LENGTH = $config->getUint('revminlength'); |
| 54 | $MAX_COMMENT_LENGTH = $config->getUint('revmaxlength'); |
| 55 | $REVIEW_COMMENT_REQUIRED = $config->getBool('revcommentreq'); |
| 56 | |
| 57 | $vik = VAPApplication::getInstance(); |
| 58 | |
| 59 | $reviews->rows = isset($reviews->rows) ? $reviews->rows : array(); |
| 60 | $reviews->size = isset($reviews->size) ? $reviews->size : 0; |
| 61 | |
| 62 | ?> |
| 63 | |
| 64 | <div class="vap-allreviews-intro"> |
| 65 | |
| 66 | <div class="vap-allreviews-title"> |
| 67 | <h2><?php echo JText::translate('VAPREVIEWSTITLE'); ?></h2> |
| 68 | <span><?php echo $rev_sub_title; ?></span> |
| 69 | </div> |
| 70 | |
| 71 | <div class="vap-allreviews-actions"> |
| 72 | <?php |
| 73 | foreach ($ordering_links as $link) |
| 74 | { |
| 75 | ?> |
| 76 | <a href="<?php echo JRoute::rewrite($link['uri']); ?>" class="vap-btn dark-gray vap-revord-link <?php echo ($link['active'] ? 'active' : ''); ?>"> |
| 77 | <i class="fas fa-<?php echo $link['mode'] == 'ASC' ? 'sort-amount-up-alt' : 'sort-amount-down'; ?>"></i> |
| 78 | <span><?php echo $link['name']; ?></span> |
| 79 | </a> |
| 80 | <?php |
| 81 | } |
| 82 | ?> |
| 83 | </div> |
| 84 | </div> |
| 85 | |
| 86 | <?php if ($can_leave) { ?> |
| 87 | |
| 88 | <div class="vap-postreview-block"> |
| 89 | |
| 90 | <div class="vap-postreview-form" style="display: none;"> |
| 91 | <form action="<?php echo JRoute::rewrite('index.php?option=com_vikappointments&task=' . $controller . '.leavereview' . ($itemid ? '&Itemid=' . $itemid : '')); ?>" method="post" id="vaprevformpost"> |
| 92 | |
| 93 | <div class="vap-postreview-top"> |
| 94 | |
| 95 | <!-- Rating --> |
| 96 | <div class="vap-postreview-ratingwrap"> |
| 97 | <div class="vap-postreview-label review-rating"><?php echo JText::translate('VAPPOSTREVIEWLBLRATING'); ?>*</div> |
| 98 | <div class="vap-postreview-field"> |
| 99 | <div class="vap-rating-field"> |
| 100 | <?php for ($i = 1; $i <= 5; $i++) { ?> |
| 101 | <div class="vap-rating-box rating-nostar" id="vaprating<?php echo $i; ?>"></div> |
| 102 | <?php } ?> |
| 103 | </div> |
| 104 | <input type="hidden" name="rating" value="" class="required" id="vapreviewrating" /> |
| 105 | </div> |
| 106 | </div> |
| 107 | |
| 108 | <!-- Title --> |
| 109 | <div class="vap-postreview-titlewrap"> |
| 110 | <div class="vap-postreview-label review-title"><?php echo JText::translate('VAPPOSTREVIEWLBLTITLE'); ?>*</div> |
| 111 | <div class="vap-postreview-field"> |
| 112 | <input type="text" name="title" value="" maxlength="64" size="32" class="required" id="vapreviewtitle" /> |
| 113 | </div> |
| 114 | </div> |
| 115 | |
| 116 | </div> |
| 117 | |
| 118 | <!-- Comment --> |
| 119 | <div class="vap-postreview-label review-comment"> |
| 120 | <?php echo JText::translate('VAPPOSTREVIEWLBLCOMMENT'); ?> |
| 121 | <?php echo ($REVIEW_COMMENT_REQUIRED ? '*' : ''); ?> |
| 122 | </div> |
| 123 | |
| 124 | <div class="vap-postreview-field"> |
| 125 | <div class="vap-postreview-commentarea"> |
| 126 | |
| 127 | <textarea maxlength="<?php echo $MAX_COMMENT_LENGTH; ?>" name="comment" class="<?php echo $REVIEW_COMMENT_REQUIRED ? 'required' : ''; ?>" id="vapreviewcomment"></textarea> |
| 128 | |
| 129 | <div class="vap-postreview-charsleft"> |
| 130 | <span><?php echo JText::translate('VAPPOSTREVIEWCHARSLEFT'); ?> </span> |
| 131 | <span id="vapcommentchars"><?php echo $MAX_COMMENT_LENGTH; ?></span> |
| 132 | </div> |
| 133 | |
| 134 | <?php if ($MIN_COMMENT_LENGTH > 0) { ?> |
| 135 | <div class="vap-postreview-minchars"> |
| 136 | <span><?php echo JText::translate('VAPPOSTREVIEWMINCHARS'); ?> </span> |
| 137 | <span id="vapcommentminchars"><?php echo $MIN_COMMENT_LENGTH; ?></span> |
| 138 | </div> |
| 139 | <?php } ?> |
| 140 | </div> |
| 141 | </div> |
| 142 | |
| 143 | <input type="hidden" name="option" value="com_vikappointments" /> |
| 144 | <input type="hidden" name="task" value="<?php echo $controller; ?>.leavereview" /> |
| 145 | <input type="hidden" name="<?php echo $col_name; ?>" value="<?php echo $col_value; ?>" /> |
| 146 | </form> |
| 147 | </div> |
| 148 | |
| 149 | <div class="vap-postreview-bottom"> |
| 150 | <button type="button" class="vap-btn blue" onClick="vapLeaveReview(this);"><?php echo JText::translate('VAPLEAVEREVIEWLINK'); ?></button> |
| 151 | </div> |
| 152 | |
| 153 | </div> |
| 154 | |
| 155 | <?php } ?> |
| 156 | |
| 157 | <div class="vap-reviews-cont"> |
| 158 | <div class="vap-reviews-list"> |
| 159 | |
| 160 | <?php |
| 161 | foreach ($reviews->rows as $review) |
| 162 | { |
| 163 | $data = array( |
| 164 | /** |
| 165 | * An object containing the review details. |
| 166 | * |
| 167 | * @var object |
| 168 | */ |
| 169 | 'review' => $review, |
| 170 | |
| 171 | /** |
| 172 | * The date time format used to display when the review was created. |
| 173 | * If not provided, it will be used the default one (military format). |
| 174 | * |
| 175 | * @var string |
| 176 | */ |
| 177 | 'datetime_format' => $dt_format, |
| 178 | ); |
| 179 | |
| 180 | /** |
| 181 | * The review block is displayed from the layout below: |
| 182 | * /components/com_vikappointments/layouts/review/default.php |
| 183 | * |
| 184 | * If you need to change something from this layout, just create |
| 185 | * an override of this layout by following the instructions below: |
| 186 | * - open the back-end of your Joomla |
| 187 | * - visit the Extensions > Templates > Templates page |
| 188 | * - edit the active template |
| 189 | * - access the "Create Overrides" tab |
| 190 | * - select Layouts > com_vikappointments > review |
| 191 | * - start editing the default.php file on your template to create your own layout |
| 192 | * |
| 193 | * @since 1.6 |
| 194 | */ |
| 195 | echo JLayoutHelper::render('review.default', $data); |
| 196 | } |
| 197 | ?> |
| 198 | |
| 199 | </div> |
| 200 | </div> |
| 201 | |
| 202 | <?php |
| 203 | if ($reviews_load_mode == 2 && $reviews->size > count($reviews->rows)) |
| 204 | { |
| 205 | // AJAX disabled, load reviews with the apposite buttons |
| 206 | ?> |
| 207 | <div class="vap-reviews-load-wrap"> |
| 208 | <button class="vap-btn blue" onClick="loadMoreReviews();"> |
| 209 | <?php echo JText::translate('VAPREVIEWLOADMOREBTN'); ?> |
| 210 | </button> |
| 211 | </div> |
| 212 | <?php |
| 213 | } |
| 214 | ?> |
| 215 | |
| 216 | <div id="vap-reviews-limit"></div> |
| 217 | |
| 218 | <?php |
| 219 | JText::script('VAPREVIEWCOMMENTSHOWLESS'); |
| 220 | JText::script('VAPREVIEWCOMMENTSHOWMORE'); |
| 221 | JText::script('VAPSUBMITREVIEWLINK'); |
| 222 | ?> |
| 223 | |
| 224 | <script> |
| 225 | |
| 226 | var LOAD_REVIEWS = true; |
| 227 | var REVIEWS_START_LIM = <?php echo count($reviews->rows); ?>; |
| 228 | var ALL_LOADED = <?php echo ($reviews->size > count($reviews->rows) ? 0 : 1); ?>; |
| 229 | |
| 230 | var reviewsValidator = null; |
| 231 | |
| 232 | jQuery(function($) { |
| 233 | if (document.location.search.indexOf('revordby') != -1) { |
| 234 | $('html,body').animate({ |
| 235 | scrollTop: $('.vap-allreviews-title').first().offset().top - 5, |
| 236 | }, { |
| 237 | duration: 'normal', |
| 238 | }); |
| 239 | } |
| 240 | |
| 241 | // create reviews form validator |
| 242 | reviewsValidator = new VikFormValidator('#vaprevformpost', 'vap-reviewfield-required'); |
| 243 | reviewsValidator.setLabel($('#vapreviewrating'), $('.vap-postreview-label.review-rating')); |
| 244 | reviewsValidator.setLabel($('#vapreviewtitle'), $('.vap-postreview-label.review-title')); |
| 245 | reviewsValidator.setLabel($('#vapreviewcomment'), $('.vap-postreview-label.review-comment')); |
| 246 | // validate comment length |
| 247 | reviewsValidator.addCallback(() => { |
| 248 | const comment = $('#vapreviewcomment'); |
| 249 | |
| 250 | if (REVIEW_COMMENT_REQUIRED && comment.hasClass('vap-reviewfield-required')) { |
| 251 | // do not neet to validate comment again |
| 252 | return false; |
| 253 | } |
| 254 | |
| 255 | let val = comment.val(); |
| 256 | |
| 257 | // make sure the user specified at least the minimum number of characters |
| 258 | if (val.length > 0 && val.length < MIN_COMMENT_LENGTH) { |
| 259 | reviewsValidator.setInvalid(comment); |
| 260 | return false; |
| 261 | } |
| 262 | |
| 263 | reviewsValidator.unsetInvalid(comment); |
| 264 | return true; |
| 265 | }); |
| 266 | |
| 267 | <?php |
| 268 | if ($reviews_load_mode == 1) |
| 269 | { |
| 270 | ?> |
| 271 | // load the reviews via AJAX when the scrollbar touches the limit |
| 272 | $(window).scrollStopped(function() { |
| 273 | if (LOAD_REVIEWS && isReviewsLimitReached()) { |
| 274 | loadMoreReviews(); |
| 275 | } |
| 276 | }); |
| 277 | <?php |
| 278 | } |
| 279 | ?> |
| 280 | }); |
| 281 | |
| 282 | function showMoreLessDescription(action, id) { |
| 283 | var app = jQuery('#vaprevcomment' + id).text(); |
| 284 | jQuery('#vaprevcomment' + id).text(jQuery('#vaprevcomfull'+id).val()); |
| 285 | jQuery('#vaprevcomfull' + id).val(app); |
| 286 | |
| 287 | if (jQuery('#vaprevcomtype' + id).val() == 'more') { |
| 288 | jQuery(action).text(Joomla.JText._('VAPREVIEWCOMMENTSHOWLESS')); |
| 289 | jQuery('#vaprevcomtype' + id).val('less'); |
| 290 | } else { |
| 291 | jQuery(action).text(Joomla.JText._('VAPREVIEWCOMMENTSHOWMORE')); |
| 292 | jQuery('#vaprevcomtype' + id).val('more'); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | function loadMoreReviews(attempt) { |
| 297 | if (ALL_LOADED) { |
| 298 | return; |
| 299 | } |
| 300 | |
| 301 | if (!attempt) { |
| 302 | attempt = 1; |
| 303 | } |
| 304 | |
| 305 | LOAD_REVIEWS = false; |
| 306 | |
| 307 | UIAjax.do( |
| 308 | '<?php echo $vik->ajaxUrl('index.php?option=com_vikappointments&task=' . $controller . '.loadreviews' . ($itemid ? '&Itemid=' . $itemid : '')); ?>', |
| 309 | { |
| 310 | <?php echo $col_name; ?>: <?php echo $col_value; ?>, |
| 311 | start: REVIEWS_START_LIM, |
| 312 | }, |
| 313 | (resp) => { |
| 314 | resp.reviews.forEach((rev) => { |
| 315 | jQuery('.vap-reviews-list').append(rev); |
| 316 | }); |
| 317 | |
| 318 | REVIEWS_START_LIM += resp.reviews.length |
| 319 | ALL_LOADED = (REVIEWS_START_LIM >= resp.size); |
| 320 | |
| 321 | if (ALL_LOADED) { |
| 322 | jQuery('.vap-reviews-load-wrap').hide(); |
| 323 | } |
| 324 | |
| 325 | LOAD_REVIEWS = true; |
| 326 | }, |
| 327 | (err) => { |
| 328 | // enable reviews again |
| 329 | LOAD_REVIEWS = true; |
| 330 | } |
| 331 | ); |
| 332 | } |
| 333 | |
| 334 | function isReviewsLimitReached() { |
| 335 | var rev_limit_y = jQuery('#vap-reviews-limit').offset().top; |
| 336 | var scroll = jQuery(window).scrollTop(); |
| 337 | var screen_height = jQuery(window).height(); |
| 338 | |
| 339 | if (rev_limit_y - scroll - 150 > screen_height) { |
| 340 | return false; |
| 341 | } |
| 342 | |
| 343 | return true; |
| 344 | } |
| 345 | |
| 346 | jQuery.fn.scrollStopped = function(callback) { |
| 347 | var elem = jQuery(this), self = this; |
| 348 | elem.scroll(function() { |
| 349 | if (elem.data('scrollTimeout')) { |
| 350 | clearTimeout(elem.data('scrollTimeout')); |
| 351 | } |
| 352 | elem.data('scrollTimeout', setTimeout(callback, 250, self)); |
| 353 | }); |
| 354 | }; |
| 355 | |
| 356 | // SUBMIT REVIEW |
| 357 | |
| 358 | function vapLeaveReview(action) { |
| 359 | var form = jQuery('.vap-postreview-form'); |
| 360 | if (!form.is(':visible')) { |
| 361 | form.slideDown(); |
| 362 | jQuery(action).text(Joomla.JText._('VAPSUBMITREVIEWLINK')); |
| 363 | return; |
| 364 | } |
| 365 | |
| 366 | if (reviewsValidator.validate()) { |
| 367 | jQuery('#vaprevformpost').submit(); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | function vapValidatesReviewFields() { |
| 372 | var input = ['title', 'rating']; |
| 373 | |
| 374 | var resp = true; |
| 375 | jQuery.each(input, function(i,v){ |
| 376 | var elem = jQuery('#vapreview'+v); |
| 377 | if (elem.val().length > 0) { |
| 378 | elem.parent().prev().removeClass('vap-reviewfield-required'); |
| 379 | } else { |
| 380 | elem.parent().prev().addClass('vap-reviewfield-required'); |
| 381 | resp = false; |
| 382 | } |
| 383 | }); |
| 384 | |
| 385 | if (resp && REVIEW_COMMENT_REQUIRED) { |
| 386 | var elem = jQuery('#vapreviewcomment'); |
| 387 | if (elem.val().length > 0) { |
| 388 | elem.parent().parent().prev().removeClass('vap-reviewfield-required'); |
| 389 | } else { |
| 390 | elem.parent().parent().prev().addClass('vap-reviewfield-required'); |
| 391 | resp = false; |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | if (resp) { |
| 396 | var comment = jQuery('#vapreviewcomment'); |
| 397 | if (comment.val().length > 0 && comment.val().length < MIN_COMMENT_LENGTH) { |
| 398 | comment.parent().parent().prev().addClass('vap-reviewfield-required'); |
| 399 | jQuery('.vap-postreview-minchars').addClass('vap-reviewfield-required'); |
| 400 | resp = false; |
| 401 | } else { |
| 402 | comment.parent().prev().removeClass('vap-reviewfield-required'); |
| 403 | jQuery('.vap-postreview-minchars').removeClass('vap-reviewfield-required'); |
| 404 | } |
| 405 | } |
| 406 | |
| 407 | return resp; |
| 408 | } |
| 409 | |
| 410 | var TO_RATE = true; |
| 411 | var MAX_COMMENT_LENGTH = <?php echo $MAX_COMMENT_LENGTH; ?>; |
| 412 | var MIN_COMMENT_LENGTH = <?php echo $MIN_COMMENT_LENGTH; ?>; |
| 413 | var REVIEW_COMMENT_REQUIRED = <?php echo $REVIEW_COMMENT_REQUIRED ? 1 : 0; ?>; |
| 414 | |
| 415 | jQuery(function() { |
| 416 | |
| 417 | jQuery('.vap-rating-box').on('click', function() { |
| 418 | var id = jQuery(this).attr('id').split('vaprating')[1]; |
| 419 | |
| 420 | jQuery('.vap-rating-box').removeClass('rating-nostar rating-hoverstar rating-yesstar'); |
| 421 | |
| 422 | if (TO_RATE) { |
| 423 | jQuery(this).addClass('rating-yesstar'); |
| 424 | jQuery(this).siblings().each(function() { |
| 425 | if (jQuery(this).attr('id').split('vaprating')[1] < id) { |
| 426 | jQuery(this).addClass('rating-yesstar'); |
| 427 | } else { |
| 428 | jQuery(this).addClass('rating-nostar'); |
| 429 | } |
| 430 | }); |
| 431 | |
| 432 | jQuery('#vapreviewrating').val(id); |
| 433 | } else { |
| 434 | jQuery(this).addClass('rating-hoverstar'); |
| 435 | jQuery(this).siblings().each(function(){ |
| 436 | if (jQuery(this).attr('id').split('vaprating')[1] < id) { |
| 437 | jQuery(this).addClass('rating-hoverstar'); |
| 438 | } else { |
| 439 | jQuery(this).addClass('rating-nostar'); |
| 440 | } |
| 441 | }); |
| 442 | |
| 443 | jQuery('#vapreviewrating').val(''); |
| 444 | } |
| 445 | |
| 446 | TO_RATE = !TO_RATE |
| 447 | }); |
| 448 | |
| 449 | jQuery('.vap-rating-box').hover(function() { |
| 450 | var id = jQuery(this).attr('id').split('vaprating')[1]; |
| 451 | |
| 452 | if (TO_RATE) { |
| 453 | jQuery('.vap-rating-box').removeClass('rating-nostar rating-hoverstar rating-yesstar'); |
| 454 | |
| 455 | jQuery(this).addClass('rating-hoverstar'); |
| 456 | jQuery(this).siblings().each(function(){ |
| 457 | if (jQuery(this).attr('id').split('vaprating')[1] < id) { |
| 458 | jQuery(this).addClass('rating-hoverstar'); |
| 459 | } else { |
| 460 | jQuery(this).addClass('rating-nostar'); |
| 461 | } |
| 462 | }); |
| 463 | } |
| 464 | |
| 465 | }, function() { |
| 466 | |
| 467 | }); |
| 468 | |
| 469 | jQuery('#vapreviewcomment').on('keyup', function(e) { |
| 470 | jQuery('#vapcommentchars').text((MAX_COMMENT_LENGTH - jQuery(this).val().length)); |
| 471 | }); |
| 472 | |
| 473 | }); |
| 474 | |
| 475 | </script> |
| 476 |