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>&nbsp;<?=$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>&nbsp;<?=$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