From 24100d66cfa558b89f9dd663e7b2f1546c6f1b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Maa=C3=9F?= <mathias.maass@uni-leipzig.de> Date: Thu, 23 Feb 2023 13:36:21 +0100 Subject: [PATCH] refs #23260 [finc] * add ajax handler to retrieve count of ill requests * move menu.phtml from finc-accessibitily to finc and and update menu.phtml to contain all possible menu items. * add sub menu "prefences" to menu.phtml * add translation strings for use in browser * override vufinds account_ajax.js to meet fincs account menu needs * guard menu against missing route exception * hide ill count if number of ill requests is zero * add doc header and comments to account_ajax.js * remove duplicated item in menu.phtml --- module/finc/config/module.config.php | 4 + .../AjaxHandler/GetUserILLRequestsStats.php | 65 ++++ themes/finc/js/account_ajax.js | 294 ++++++++++++++++++ themes/finc/templates/layout/layout.phtml | 4 +- .../templates/myresearch/menu.phtml | 95 ++++-- 5 files changed, 434 insertions(+), 28 deletions(-) create mode 100644 module/finc/src/finc/AjaxHandler/GetUserILLRequestsStats.php create mode 100644 themes/finc/js/account_ajax.js rename themes/{finc-accessibility => finc}/templates/myresearch/menu.phtml (65%) diff --git a/module/finc/config/module.config.php b/module/finc/config/module.config.php index eaabdac9936..d72bbb6a4d1 100644 --- a/module/finc/config/module.config.php +++ b/module/finc/config/module.config.php @@ -92,6 +92,8 @@ $config = [ 'finc\AjaxHandler\GetResolverLinksFactory', 'finc\AjaxHandler\GetRecordCover' => 'finc\AjaxHandler\GetRecordCoverFactory', + 'finc\AjaxHandler\GetUserILLRequestsStats' => + 'VuFind\AjaxHandler\AbstractIlsAndUserActionFactory', 'finc\AjaxHandler\GetUserMediaReadyToPickup' => 'VuFind\AjaxHandler\AbstractIlsAndUserActionFactory', 'finc\AjaxHandler\GetUserPermanentLoans' => @@ -108,6 +110,8 @@ $config = [ 'finc\AjaxHandler\GetResolverLinks', 'getRecordCover' => 'finc\AjaxHandler\GetRecordCover', + 'getUserILLRequestsStats' => + 'finc\AjaxHandler\GetUserILLRequestsStats', 'getUserMediaReadyToPickup' => 'finc\AjaxHandler\GetUserMediaReadyToPickup', 'getUserPermanentLoans' => diff --git a/module/finc/src/finc/AjaxHandler/GetUserILLRequestsStats.php b/module/finc/src/finc/AjaxHandler/GetUserILLRequestsStats.php new file mode 100644 index 00000000000..33c73a42225 --- /dev/null +++ b/module/finc/src/finc/AjaxHandler/GetUserILLRequestsStats.php @@ -0,0 +1,65 @@ +<?php +/** + * PHP version 7 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace finc\AjaxHandler; + +use Zend\Mvc\Controller\Plugin\Params; + +/** + * AJAX handler to get statistics (e.g. counts) of users interlibrary loans. + * + * @category VuFind + * @package AJAX + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GetUserILLRequestsStats extends \VuFind\AjaxHandler\AbstractUserRequestAction +{ + /** + * Handle a request. + * + * @param Params $params Parameter helper from controller + * + * @return array [response data, internal status code, HTTP status code] + */ + public function handleRequest(Params $params) + { + $this->disableSessionWrites(); // avoid session write timing bug + $patron = $this->ilsAuthenticator->storedCatalogLogin(); + if (!$patron) { + return $this->formatResponse('', self::STATUS_HTTP_NEED_AUTH, 401); + } + if (!$this->ils->checkCapability('getMyTransactions')) { + return $this->formatResponse('', self::STATUS_HTTP_ERROR, 405); + } + $items = $this->ils->getMyILLRequests($patron); + $stats = [ + 'total' => count($items) + ]; + + return $this->formatResponse($stats); + } +} diff --git a/themes/finc/js/account_ajax.js b/themes/finc/js/account_ajax.js new file mode 100644 index 00000000000..decb403f86c --- /dev/null +++ b/themes/finc/js/account_ajax.js @@ -0,0 +1,294 @@ +/** + * origin: {vufind} + * called by view helper/controller: + * usage: {} + * modified for finc: + * - Add handler for menu items "permanent loan" and "ready to pickup" + * - Change handler for "ill requests" to show total items count + *configured in: {} + */ + +/*global userIsLoggedIn, VuFind */ +VuFind.register('account', function Account() { + // Retrieved statuses + var LOADING = -1 * Math.PI; // waiting for request + var MISSING = -2 * Math.PI; // no data available + var INACTIVE = -3 * Math.PI; // status element missing + var _statuses = {}; + + // Account Icons + var ICON_LEVELS = { + "NONE": 0, + "GOOD": 1, + "WARNING": 2, + "DANGER": 3 + }; + var _accountIcons = {}; + _accountIcons[ICON_LEVELS.NONE] = "fa fa-user-circle"; + _accountIcons[ICON_LEVELS.GOOD] = "fa fa-bell text-success"; + _accountIcons[ICON_LEVELS.WARNING] = "fa fa-bell text-warning"; + _accountIcons[ICON_LEVELS.DANGER] = "fa fa-exclamation-triangle text-danger"; + + var _submodules = []; + + var _sessionDataPrefix = "vf-account-status-"; + var _save = function _save(module) { + sessionStorage.setItem( + _sessionDataPrefix + module, + JSON.stringify(_statuses[module]) + ); + }; + + // Clearing save forces AJAX update next page load + var clearCache = function clearCache(name) { + if (typeof name === "undefined") { + for (var sub in _submodules) { + if (Object.prototype.hasOwnProperty.call(_submodules, sub)) { + clearCache(sub); + } + } + } else { + sessionStorage.removeItem(_sessionDataPrefix + name); + } + }; + + var _getStatus = function _getStatus(module) { + return (typeof _statuses[module] === "undefined") ? LOADING : _statuses[module]; + }; + + var _render = function _render() { + var accountStatus = ICON_LEVELS.NONE; + for (var sub in _submodules) { + if (Object.prototype.hasOwnProperty.call(_submodules, sub)) { + var $element = $(_submodules[sub].selector); + if (!$element) { + _statuses[sub] = INACTIVE; + continue; + } + var status = _getStatus(sub); + if (status === MISSING) { + $element.addClass('hidden'); + } else { + $element.removeClass('hidden'); + if (status === LOADING) { + $element.html('<i class="fa fa-spin fa-spinner"></i>'); + } else { + var moduleStatus = _submodules[sub].render($element, _statuses[sub], ICON_LEVELS); + if (moduleStatus > accountStatus) { + accountStatus = moduleStatus; + } + } + } + } + } + $("#account-icon").attr("class", _accountIcons[accountStatus]); + if (accountStatus > ICON_LEVELS.NONE) { + $("#account-icon") + .attr("data-toggle", "tooltip") + .attr("data-placement", "bottom") + .attr("title", VuFind.translate("account_has_alerts")) + .tooltip(); + } else { + $("#account-icon").tooltip("destroy"); + } + }; + var _ajaxLookup = function _ajaxLookup(module) { + $.ajax({ + url: VuFind.path + '/AJAX/JSON?method=' + _submodules[module].ajaxMethod, + dataType: 'json' + }) + .done(function ajaxLookupDone(response) { + _statuses[module] = response.data; + }) + .fail(function ajaxLookupFail() { + _statuses[module] = MISSING; + }) + .always(function ajaxLookupAlways() { + _save(module); + _render(); + }); + }; + + var _load = function _load(module) { + var $element = $(_submodules[module].selector); + if (!$element) { + _statuses[module] = INACTIVE; + } else { + var json = sessionStorage.getItem(_sessionDataPrefix + module); + var session = typeof json === "undefined" ? null : JSON.parse(json); + if ( + session === null || + session === LOADING || + session === MISSING + ) { + _statuses[module] = LOADING; + _ajaxLookup(module); + } else { + _statuses[module] = session; + } + _render(); + } + }; + + var init = function init() { + // Update information when certain actions are performed + $("[data-clear-account-cache]").submit(function dataClearCache() { + clearCache($(this).attr("data-clear-account-cache")); + }); + $("#library_card").change(function clearChangeLibraryCard() { + clearCache(/* all */); + }); + }; + + var register = function register(name, module) { + if (typeof _submodules[name] === "undefined") { + _submodules[name] = typeof module == 'function' ? module() : module; + } + var $el = $(_submodules[name].selector); + if ($el.length > 0) { + $el.removeClass("hidden"); + _statuses[name] = LOADING; + _load(name); + } else { + _statuses[name] = INACTIVE; + } + }; + + return { + init: init, + clearCache: clearCache, + // if user is logged out, clear cache instead of register + register: userIsLoggedIn ? register : clearCache + }; +}); + +$(document).ready(function registerAccountAjax() { + + VuFind.account.register("fines", { + selector: ".fines-status", + ajaxMethod: "getUserFines", + render: function render($element, status, ICON_LEVELS) { + if (status.value === 0) { + $element.addClass("hidden"); + return ICON_LEVELS.NONE; + } + $element.html('<span class="badge overdue">' + status.display + '</span>'); + return ICON_LEVELS.DANGER; + } + }); + + VuFind.account.register("checkedOut", { + selector: ".checkedout-status", + ajaxMethod: "getUserTransactions", + render: function render($element, status, ICON_LEVELS) { + var html = ''; + var level = ICON_LEVELS.NONE; + if (status.ok > 0) { + html += '<span class="badge ok" data-toggle="tooltip" title="' + VuFind.translate('Checked Out Items') + '">' + status.ok + '</span>'; + } + if (status.warn > 0) { + html += '<span class="badge warn" data-toggle="tooltip" title="' + VuFind.translate('renew_item_due_tooltip') + '">' + status.warn + '</span>'; + level = ICON_LEVELS.WARNING; + } + if (status.overdue > 0) { + html += '<span class="badge overdue" data-toggle="tooltip" title="' + VuFind.translate('renew_item_overdue_tooltip') + '">' + status.overdue + '</span>'; + level = ICON_LEVELS.DANGER; + } + $element.html(html); + $('[data-toggle="tooltip"]', $element).tooltip(); + return level; + } + }); + + // finc: add handler for "media ready to pickup" #23285 + VuFind.account.register("mediareadytopickup", { + selector: ".mediareadytopickup-status", + ajaxMethod: "getUserMediaReadyToPickup", + render: function render($element, status, ICON_LEVELS) { + var level = ICON_LEVELS.NONE; + if (status.available > 0) { + $element.html('<i class="fa fa-bell text-success" data-toggle="tooltip" title="' + VuFind.translate('hold_available') + '"></i>'); + level = ICON_LEVELS.GOOD; + } else if (status.in_transit > 0) { + $element.html('<i class="fa fa-clock-o text-warning" data-toggle="tooltip" title="' + VuFind.translate('request_in_transit') + '"></i>'); + } else { + $element.addClass("holds-status hidden"); + } + $('[data-toggle="tooltip"]', $element).tooltip(); + return level; + } + }); + + // finc: add handler for permanent loans #23285 + VuFind.account.register("permanentLoans", { + selector: ".permanentloans-status", + ajaxMethod: "getUserPermanentLoans", + render: function render($element, status, ICON_LEVELS) { + var html = ''; + var level = ICON_LEVELS.NONE; + if (status.ok > 0) { + html += '<span class="badge ok" data-toggle="tooltip" title="' + VuFind.translate('Permanent Checked Out Items') + '">' + status.ok + '</span>'; + } + if (status.warn > 0) { + html += '<span class="badge warn" data-toggle="tooltip" title="' + VuFind.translate('renew_item_due_tooltip') + '">' + status.warn + '</span>'; + level = ICON_LEVELS.WARNING; + } + if (status.overdue > 0) { + html += '<span class="badge overdue" data-toggle="tooltip" title="' + VuFind.translate('renew_item_overdue_tooltip') + '">' + status.overdue + '</span>'; + level = ICON_LEVELS.DANGER; + } + $element.html(html); + $('[data-toggle="tooltip"]', $element).tooltip(); + return level; + } + }); + + VuFind.account.register("holds", { + selector: ".holds-status", + ajaxMethod: "getUserHolds", + render: function render($element, status, ICON_LEVELS) { + var level = ICON_LEVELS.NONE; + if (status.available > 0) { + $element.html('<i class="fa fa-bell text-success" data-toggle="tooltip" title="' + VuFind.translate('hold_available') + '"></i>'); + level = ICON_LEVELS.GOOD; + } else if (status.in_transit > 0) { + $element.html('<i class="fa fa-clock-o text-warning" data-toggle="tooltip" title="' + VuFind.translate('request_in_transit') + '"></i>'); + } else { + $element.addClass("holds-status hidden"); + } + $('[data-toggle="tooltip"]', $element).tooltip(); + return level; + } + }); + + VuFind.account.register("storageRetrievalRequests", { + selector: ".storageretrievalrequests-status", + ajaxMethod: "getUserStorageRetrievalRequests", + render: function render($element, status, ICON_LEVELS) { + var level = ICON_LEVELS.NONE; + if (status.available > 0) { + $element.html('<i class="fa fa-bell text-success" data-toggle="tooltip" title="' + VuFind.translate('hold_available') + '"></i>'); + level = ICON_LEVELS.GOOD; + } else if (status.in_transit > 0) { + $element.html('<i class="fa fa-clock-o text-warning" data-toggle="tooltip" title="' + VuFind.translate('request_in_transit') + '"></i>'); + } else { + $element.addClass("holds-status hidden"); + } + $('[data-toggle="tooltip"]', $element).tooltip(); + return level; + } + }); + + // finc: show total count of ill request items #23285 + VuFind.account.register("illRequests", { + selector: ".illrequests-status", + ajaxMethod: "getUserILLRequestsStats", + render: function render($element, stats, ICON_LEVELS) { + var html = stats.total > 0 + ? '<span class="badge ok" data-toggle="tooltip" title="' + VuFind.translate('Interlibrary Loan Requests') + '">' + stats.total + '</span>' + : '' + $element.html(html) + return ICON_LEVELS.GOOD; + } + }); +}); diff --git a/themes/finc/templates/layout/layout.phtml b/themes/finc/templates/layout/layout.phtml index 88bdc236b6a..35cef794a56 100644 --- a/themes/finc/templates/layout/layout.phtml +++ b/themes/finc/templates/layout/layout.phtml @@ -149,7 +149,9 @@ 'renew_item_due_tooltip' => 'renew_item_due_tooltip', 'renew_item_overdue_tooltip' => 'renew_item_overdue_tooltip', 'request_in_transit' => 'request_in_transit', - 'storage_retrieval_request_available' => 'storage_retrieval_request_available' + 'storage_retrieval_request_available' => 'storage_retrieval_request_available', + 'Interlibrary Loan Requests' => 'Interlibrary Loan Requests', + 'Permanent Checked Out Items' => 'Permanent Checked Out Items' ] ); } diff --git a/themes/finc-accessibility/templates/myresearch/menu.phtml b/themes/finc/templates/myresearch/menu.phtml similarity index 65% rename from themes/finc-accessibility/templates/myresearch/menu.phtml rename to themes/finc/templates/myresearch/menu.phtml index cd4def5af7a..1de7bdfae6a 100644 --- a/themes/finc-accessibility/templates/myresearch/menu.phtml +++ b/themes/finc/templates/myresearch/menu.phtml @@ -17,6 +17,15 @@ $patron = $user ? $this->auth()->getILSPatron() : false; $capabilityParams = $patron ? ['patron' => $patron] : []; $ilsOnline = ('ils-none' !== $this->ils()->getOfflineMode()); + + $routeExists = function($route) { + try { + $this->url($route); + return true; + } catch (Exception $e) { + return false; + } + }; ?> <?php /* finc change btn-link to btn-default */ ?> <button class="close-offcanvas btn btn-default" data-toggle="offcanvas"><?=$this->transEsc('navigate_back') ?></button> @@ -28,13 +37,6 @@ <?php /* finc: myreasearch menu as list #19734 */ ?> <?php /* finc: specify current page menu entry in following elements #19941 */ ?> <ul class="myresearch-menu account-menu facet-group"> - <?php if ($this->userlist()->getMode() !== 'disabled'): ?> - <li class="facet"> - <a href="<?=$this->url('myresearch-favorites')?>"<?=$this->active == 'favorites' ? ' class="active" aria-current="page"' : ''?>> - <i class="fa fa-fw fa-star" aria-hidden="true"></i> <?=$this->transEsc('Favorites')?> - </a> - </li> - <?php endif; ?> <?php if ($ilsOnline && $this->ils()->checkCapability('getMyTransactions', $capabilityParams)): ?> <li class="facet"> <a href="<?=$this->url('myresearch-checkedout')?>" class="flex checkedout<?=$this->active == 'checkedout' ? ' active' : ''?>" @@ -45,9 +47,32 @@ </a> </li> <?php endif; ?> - <?php if ($ilsOnline && $this->ils()->checkFunction('getMyTransactionHistory', $capabilityParams)): ?> + <?php /* finc: adds media ready to pickup */ ?> + <?php if ($ilsOnline && $this->ils()->checkCapability('getMyMediaReadyToPickup', $capabilityParams) && $routeExists('myresearch-mediareadytopickup')): ?> <li class="facet"> - <a href="<?=$this->url('myresearch-historicloans')?>"<?=$this->active == 'historicloans' ? ' class="active" aria-current="page"' : ''?>> + <a href="<?=$this->url('myresearch-mediareadytopickup')?>" class="flex <?=$this->active == 'mediareadytopickup' ? ' active' : ''?>" + <?=$this->active == 'mediareadytopickup' ? ' aria-current="page"' : ''?> + > + <span class="flex-col"><i class="fa fa-fw fa-book" aria-hidden="true"></i> <?=$this->transEsc('Ready For Collection')?></span> + <span class="mediareadytopickup-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span> + </a> + </li> + <?php endif; ?> + <?php /* finc: adds permanent loans */ ?> + <?php if ($ilsOnline && $this->ils()->checkCapability('getMyPermanentLoans', $capabilityParams) && $routeExists('myresearch-permanentloans')): ?> + <li class="facet"> + <a href="<?=$this->url('myresearch-permanentloans')?>" class="flex <?=$this->active == 'permanentloans' ? ' active' : ''?>" + <?=$this->active == 'permanent' ? ' aria-current="page"' : ''?> + > + <span class="flex-col"><i class="fa fa-fw fa-book" aria-hidden="true"></i> <?=$this->transEsc('Permanent Checked Out Items')?></span> + <span class="permanentloans-status status hidden"><i class="fa fa-spin fa-spinner" aria-hidden="true"></i></span> + </a> + </li> + <?php endif; ?> + <?php /* finc: adds historic loans */ ?> + <?php if ($ilsOnline && $this->ils()->checkCapability('getMyLoanHistory', $capabilityParams) && $routeExists('myresearch-loanhistory')): ?> + <li class="facet"> + <a href="<?=$this->url('myresearch-loanhistory')?>"<?=$this->active == 'loanhistory' ? ' class="active" aria-current="page"' : ''?>> <i class="fa fa-fw fa-history" aria-hidden="true"></i> <?=$this->transEsc('Loan History')?> </a> </li> @@ -72,7 +97,7 @@ </a> </li> <?php endif; ?> - <?php if ($ilsOnline && $this->ils()->checkFunction('ILLRequests', $capabilityParams)): ?> + <?php if ($ilsOnline && $this->ils()->checkCapability('getMyILLRequests', $capabilityParams)): ?> <li class="facet"> <a href="<?=$this->url('myresearch-illrequests')?>" class="flex<?=$this->active == 'ILLRequests' ? ' active' : ''?>" <?=$this->active == 'ILLRequests' ? ' aria-current="page"' : ''?> @@ -92,18 +117,6 @@ </a> </li> <?php endif; ?> - <li class="facet"> - <a href="<?=$this->url('myresearch-profile')?>"<?=$this->active == 'profile' ? ' class="active" aria-current="page"' : ''?>> - <i class="fa fa-fw fa-user" aria-hidden="true"></i> <?=$this->transEsc('Profile')?> - </a> - </li> - <?php if ($ilsOnline && $user && $user->libraryCardsEnabled()): ?> - <li class="facet"> - <a href="<?=$this->url('librarycards-home')?>"<?=$this->active == 'librarycards' ? ' class="active" aria-current="page"' : ''?>> - <i class="fa fa-fw fa-barcode" aria-hidden="true"></i> <?=$this->transEsc('Library Cards')?> - </a> - </li> - <?php endif; ?> <?php if ($this->overdrive()->showMyContentLink()):?> <li class="facet"> <a href="<?=$this->url('overdrive-mycontent')?>"<?=$this->active == 'dgcontent' ? ' class="active"' : ''?>> @@ -118,14 +131,42 @@ </a> </li> <?php endif; ?> - <?php if ($user): ?> +</ul> + +<?php /* finc: adds prefences sub menu with items "profile", "change password", "change pin" and "logout" */ ?> +<?php if ($this->auth()->isLoggedIn()): ?> + <h3><?=$this->transEsc('Preferences')?></h3> + <ul class="myresearch-menu account-menu facet-group"> <li class="facet"> - <a href="<?=$this->url('myresearch-logout')?>"> - <i class="fa fa-fw fa-sign-out" aria-hidden="true"></i> <?=$this->transEsc("Log Out")?> + <a href="<?=$this->url('myresearch-profile')?>"<?=$this->active == 'profile' ? ' class="active" aria-current="page"' : ''?>> + <i class="fa fa-fw fa-user" aria-hidden="true"></i> + <?=$this->transEsc('Profile')?> </a> </li> - <?php endif; ?> -</ul> + <?php if ($this->auth()->getManager()->supportsPasswordChange() && $routeExists('myresearch-changepassword')): ?> + <li class="facet"> + <a href="<?=$this->url('myresearch-changepassword')?>" class="text<?=$this->active == 'newpassword' ? ' active' : ''?>"> + <i class="fa fa-fw fa-lock" aria-hidden="true"></i> + <?=$this->transEsc('Change Password')?> + </a> + </li> + <?php endif; ?> + <?php if ($this->ils()->checkCapability('changeUserPin') && $routeExists('myresearch-setpin')): ?> + <li class="facet"> + <a href="<?=$this->url('myresearch-setpin')?>" class="text<?=$this->active == 'setpin' ? ' active' : ''?>"> + <i class="fa fa-fw fa-key" aria-hidden="true"></i> + <?=$this->transEsc('LiberoAccount::change_user_pin')?> + </a> + </li> + <?php endif; ?> + <li class="facet"> + <a href="<?=$this->url('myresearch-logout')?>" class="text action"> + <i class="fa fa-fw fa-sign-out" aria-hidden="true"></i> + <?=$this->transEsc("Log Out")?> + </a> + </li> + </ul> +<?php endif; ?> <?php if ($user && $this->userlist()->getMode() !== 'disabled'): ?> <?php /* finc adds '.lists-heading' for styling purposes */ ?> -- GitLab