From c68d9ab10a996008e8048594ccec51025c302396 Mon Sep 17 00:00:00 2001
From: Owen Leonard <oleonard@myacpl.org>
Date: Thu, 1 Jun 2023 14:16:18 +0000
Subject: [PATCH] Bug 33895: Use template wrapper for tabs: OPAC user summary

This patch updates the OPAC user summary page so that it uses
the new WRAPPER syntax to generate tabs markup.

To test, apply the patch and log in to the OPAC. Check these tabs on
the patron summary page:

  - Checkouts
  - Relatives' checkouts
  - Relatives' charges
  - Overdues
  - Charges
  - Credits
  - Clubs
    - Test enrolling and unenrolling
  - Holds
  - Recalls
  - Article requests
  - Overdrive
    - Test with OverDriveCirculation enabled
    - Logging in, logging out

Signed-off-by: Sam Lau <samalau@gmail.com>
---
 .../bootstrap/en/includes/holds-table.inc     | 428 +++++++++---------
 .../bootstrap/en/modules/clubs/clubs-tab.tt   |   4 +-
 .../bootstrap/en/modules/clubs/enroll.tt      |   4 +-
 .../bootstrap/en/modules/opac-user.tt         | 146 +++---
 koha-tmpl/opac-tmpl/bootstrap/js/overdrive.js |   2 +-
 5 files changed, 293 insertions(+), 291 deletions(-)

diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/holds-table.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/holds-table.inc
index 84fb105751..483f026453 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/holds-table.inc
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/holds-table.inc
@@ -3,234 +3,230 @@
 [% USE KohaDates %]
 [% PROCESS 'i18n.inc' %]
 
-[% IF ( HOLDS.count ) %]
-    <div id="opac-user-holds" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-holds-tab">
-        <table id="holdst" class="table table-bordered table-striped">
-            <caption>Holds <span class="count">([% HOLDS.count | html %] total)</span></caption>
-            <!-- HOLDS TABLE ROWS -->
-            <thead>
+<table id="holdst" class="table table-bordered table-striped">
+    <caption>Holds <span class="count">([% HOLDS.count | html %] total)</span></caption>
+    <!-- HOLDS TABLE ROWS -->
+    <thead>
+        <tr>
+            <th class="anti-the">Title</th>
+            [% IF ( showpriority ) %]
+                <th>Placed on</th>
+            [% ELSE %]
+                <th class="psort">Placed on</th>
+            [% END %]
+            <th>Expires on</th>
+            [% UNLESS( singleBranchMode) %]
+                <th>Pickup location</th>
+            [% END %]
+            [% IF ( showpriority ) %]
+                <th class="psort">Priority</th>
+            [% END %]
+            <th>Status</th>
+            [% IF SuspendHoldsOpac and ! onlyinfo %]
+                    <th class="nosort" >Suspend</th>
+            [% END %]
+            [% IF ! onlyinfo %]
+                <th class="nosort">Modify</th>
+            [% END %]
+            <th></th>
+        </tr>
+    </thead>
+    <tbody>
+        [% SET all_holds_waiting = 1 %]
+        [% FOREACH HOLD IN HOLDS %]
+            [% UNLESS ( HOLD.is_waiting || HOLD.is_in_transit || HOLD.is_in_processing) %]
+                [% SET all_holds_waiting = 0 %]
+            [% END %]
+            [% IF ( HOLD.is_at_destination ) %]
+                <tr class="reserved">
+            [% ELSIF HOLD.is_in_transit %]
+                <tr class="transfered">
+            [% ELSE %]
                 <tr>
-                    <th class="anti-the">Title</th>
-                    [% IF ( showpriority ) %]
-                        <th>Placed on</th>
-                    [% ELSE %]
-                        <th class="psort">Placed on</th>
-                    [% END %]
-                    <th>Expires on</th>
-                    [% UNLESS( singleBranchMode) %]
-                        <th>Pickup location</th>
-                    [% END %]
-                    [% IF ( showpriority ) %]
-                        <th class="psort">Priority</th>
-                    [% END %]
-                    <th>Status</th>
-                    [% IF SuspendHoldsOpac and ! onlyinfo %]
-                            <th class="nosort" >Suspend</th>
-                    [% END %]
+            [% END %]
+                <td class="title">
                     [% IF ! onlyinfo %]
-                        <th class="nosort">Modify</th>
+                        [% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio link=> 1 %]
+                        [% HOLD.item.enumchron | html %]
+                    [% ELSE %]
+                        <strong>
+                            [% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio %]
+                            [% HOLD.item.enumchron | html %]
+                        </strong>
                     [% END %]
-                    <th></th>
-                </tr>
-            </thead>
-            <tbody>
-                [% SET all_holds_waiting = 1 %]
-                [% FOREACH HOLD IN HOLDS %]
-                    [% UNLESS ( HOLD.is_waiting || HOLD.is_in_transit || HOLD.is_in_processing) %]
-                        [% SET all_holds_waiting = 0 %]
+                    [% HOLD.biblio.author | html %]
+                    [% IF HOLD.item_group_id %]
+                        <p>Next available item from item group: <strong>[% HOLD.item_group.description | html %]</strong></p>
                     [% END %]
-                    [% IF ( HOLD.is_at_destination ) %]
-                        <tr class="reserved">
-                    [% ELSIF HOLD.is_in_transit %]
-                        <tr class="transfered">
-                    [% ELSE %]
-                        <tr>
+                    [% IF HOLD.item_level_hold %]
+                        <p class="hint">Item on hold: [% HOLD.item.barcode | html %]</p>
                     [% END %]
-                        <td class="title">
-                            [% IF ! onlyinfo %]
-                                [% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio link=> 1 %]
-                                [% HOLD.item.enumchron | html %]
-                            [% ELSE %]
-                                <strong>
-                                    [% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio %]
-                                    [% HOLD.item.enumchron | html %]
-                                </strong>
-                            [% END %]
-                            [% HOLD.biblio.author | html %]
-                            [% IF HOLD.item_group_id %]
-                               <p>Next available item from item group: <strong>[% HOLD.item_group.description | html %]</strong></p>
-                            [% END %]
-                            [% IF HOLD.item_level_hold %]
-                                <p class="hint">Item on hold: [% HOLD.item.barcode | html %]</p>
-                            [% END %]
-                        </td>
-                        <td class="reservedate" data-order="[% HOLD.reservedate | html %]">
-                            <span class="tdlabel">Hold date:</span>
-                                [% HOLD.reservedate | $KohaDates %]
-                            </span>
-                        </td>
-                        [% IF ! HOLD.found %]
-                            <td class="expirationdate" data-order="[% HOLD.expirationdate | html %]">
-                                [% IF ( HOLD.expirationdate ) %]
-                                    <span class="tdlabel">Expiration:</span>
-                                    [% HOLD.expirationdate | $KohaDates %]
-                                [% ELSE %]
-                                    <span class="tdlabel">Expiration:</span>
-                                    Never expires
-                                [% END %]
+                </td>
+                <td class="reservedate" data-order="[% HOLD.reservedate | html %]">
+                    <span class="tdlabel">Hold date:</span>
+                        [% HOLD.reservedate | $KohaDates %]
+                    </span>
+                </td>
+                [% IF ! HOLD.found %]
+                    <td class="expirationdate" data-order="[% HOLD.expirationdate | html %]">
+                        [% IF ( HOLD.expirationdate ) %]
+                            <span class="tdlabel">Expiration:</span>
+                            [% HOLD.expirationdate | $KohaDates %]
                         [% ELSE %]
-                            <td class="expirationdate" data-order="0000-00-00">
-                                -
+                            <span class="tdlabel">Expiration:</span>
+                            Never expires
                         [% END %]
-                        </td>
-                        [% UNLESS( singleBranchMode) %]
-                            <td class="branch">
-                                <span class="tdlabel">Pickup location:</span>
-                                [% HOLD.branch.branchname | html %]
-                                [% IF ( HOLD.can_update_pickup_location_opac ) %]
-                                    <button type="button" class="btn btn-sm btn-link" data-toggle="modal" data-target="#changePickup[% HOLD.reserve_id | html %]">
-                                        <i class="fa-solid fa-pencil" aria-hidden="true"></i> Change
-                                    </button>
-                                    <!-- Change pickup location modal -->
-                                    <div class="modal" id="changePickup[% HOLD.reserve_id | html %]" tabindex="-1" aria-labelledby="changePickup[% HOLD.reserve_id | html %]Label" aria-hidden="true">
-                                        <div class="modal-dialog">
-                                            <form id="change_branch_form[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
-                                                <div class="modal-content">
-                                                    <div class="modal-header">
-                                                        <h5 class="modal-title" id="changePickup[% HOLD.reserve_id | html %]Label">Change pickup location for <em>[% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio %]</em></h5>
-                                                        <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close">
-                                                            <span aria-hidden="true">&times;</span>
-                                                        </button>
-                                                    </div>
-                                                    <div class="modal-body">
-                                                        <div class="form-group">
-                                                        <label for="new_branch[% HOLD.reserve_id | html %]">New pickup location:</label>
-                                                        <select name="new_pickup_location" id="new_branch[% HOLD.reserve_id | html %]" class="form-control">
-                                                            [% PROCESS options_for_libraries libraries = Branches.pickup_locations({ search_params => { biblio => HOLD.biblionumber, patron => HOLD.borrower }, selected => HOLD.branchcode }) %]
-                                                        </select>
-                                                        </div>
-                                                        <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
-                                                    </div>
-                                                    <div class="modal-footer">
-                                                        <button type="submit" name="change_branch" value="1" class="btn btn-primary"><i class="fa fa-check" aria-hidden="true"></i> Save</button>
-                                                        <button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times" aria-hidden="true"></i> Cancel</button>
-                                                    </div>
-                                                </div> <!-- /.modal-content -->
-                                            </form>
-                                        </div> <!-- /.modal-dialog -->
-                                    </div> <!-- /.modal -->
-                                [% END  %]
-                            </td>
+                [% ELSE %]
+                    <td class="expirationdate" data-order="0000-00-00">
+                        -
+                [% END %]
+                </td>
+                [% UNLESS( singleBranchMode) %]
+                    <td class="branch">
+                        <span class="tdlabel">Pickup location:</span>
+                        [% HOLD.branch.branchname | html %]
+                        [% IF ( HOLD.can_update_pickup_location_opac ) %]
+                            <button type="button" class="btn btn-sm btn-link" data-toggle="modal" data-target="#changePickup[% HOLD.reserve_id | html %]">
+                                <i class="fa fa-pencil-alt" aria-hidden="true"></i> Change
+                            </button>
+                            <!-- Change pickup location modal -->
+                            <div class="modal" id="changePickup[% HOLD.reserve_id | html %]" tabindex="-1" aria-labelledby="changePickup[% HOLD.reserve_id | html %]Label" aria-hidden="true">
+                                <div class="modal-dialog">
+                                    <form id="change_branch_form[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
+                                        <div class="modal-content">
+                                            <div class="modal-header">
+                                                <h5 class="modal-title" id="changePickup[% HOLD.reserve_id | html %]Label">Change pickup location for <em>[% INCLUDE 'biblio-title.inc' biblio=HOLD.biblio %]</em></h5>
+                                                <button type="button" class="closebtn" data-dismiss="modal" aria-label="Close">
+                                                    <span aria-hidden="true">&times;</span>
+                                                </button>
+                                            </div>
+                                            <div class="modal-body">
+                                                <div class="form-group">
+                                                <label for="new_branch[% HOLD.reserve_id | html %]">New pickup location:</label>
+                                                <select name="new_pickup_location" id="new_branch[% HOLD.reserve_id | html %]" class="form-control">
+                                                    [% PROCESS options_for_libraries libraries = Branches.pickup_locations({ search_params => { biblio => HOLD.biblionumber, patron => HOLD.borrower }, selected => HOLD.branchcode }) %]
+                                                </select>
+                                                </div>
+                                                <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
+                                            </div>
+                                            <div class="modal-footer">
+                                                <button type="submit" name="change_branch" value="1" class="btn btn-primary"><i class="fa fa-check" aria-hidden="true"></i> Save</button>
+                                                <button type="button" class="btn btn-secondary" data-dismiss="modal"><i class="fa fa-times" aria-hidden="true"></i> Cancel</button>
+                                            </div>
+                                        </div> <!-- /.modal-content -->
+                                    </form>
+                                </div> <!-- /.modal-dialog -->
+                            </div> <!-- /.modal -->
+                        [% END  %]
+                    </td>
+                [% END %]
+                [% IF ( showpriority ) %]
+                        <td data-order="[% HOLD.priority | html %]" class="priority">
+                        <span class="tdlabel">Priority:</span>
+                        [% HOLD.priority | html %]
+                    </td>
+                [% END %]
+                <td class="status">
+                    <span class="tdlabel">Status:</span>
+                    [% IF ( HOLD.is_waiting ) %]
+                        <i class="fa fa-exclamation-circle text-warning" aria-hidden="true"></i>
+                        [% IF ( HOLD.is_at_destination ) %]
+                            Item waiting at <strong> [% HOLD.branch.branchname | html %]</strong>
+                            [% IF ( HOLD.desk_id ) %], [% HOLD.desk.desk_name | html %],[% END %]
+                            [% IF ( HOLD.waitingdate ) %]
+                                since [% HOLD.waitingdate | $KohaDates %]
+                                [% IF HOLD.expirationdate %]
+                                    until [% HOLD.expirationdate | $KohaDates %]
+                                [% END %]
+                            [% END %]
+                            <input type="hidden" name="pickup" value="[% HOLD.branchcode | html %]" />
+                        [% ELSE %]
+                            Item in transit to <strong> [% Branches.GetName( HOLD.branchcode ) | html %]</strong> <input type="hidden" name="pickup" value="[% HOLD.branchcode | html %]" />
                         [% END %]
-                        [% IF ( showpriority ) %]
-                                <td data-order="[% HOLD.priority | html %]" class="priority">
-                                <span class="tdlabel">Priority:</span>
-                                [% HOLD.priority | html %]
-                            </td>
+                    [% ELSE %]
+                        [% IF ( HOLD.is_in_transit ) %]
+                            [% SET transfer = HOLD.item.get_transfer %]
+                            [% branch_name = BLOCK %]<strong>[% Branches.GetName( transfer.frombranch ) | html %]</strong>[% END %]
+                            <span>Item in transit from [% branch_name| $raw %] since</span>
+                            [% transfer.datesent | $KohaDates %]
+                        [% ELSIF ( HOLD.is_in_processing ) %]
+                            <span>Item in processing</span>
+                        [% ELSIF ( HOLD.suspend ) %]
+                            <span>Suspended</span>[% IF ( HOLD.suspend_until ) %] <span>until</span> [% HOLD.suspend_until | $KohaDates %][% END %]
+                        [% ELSE %]
+                            [% IF HOLD.itemtype %]
+                                <span>Pending for next available item of item type '[% ItemTypes.GetDescription( HOLD.itemtype ) | html %]'</span>
+                            [% ELSE %]
+                                <span>Pending</span>
+                            [% END %]
                         [% END %]
-                        <td class="status">
-                            <span class="tdlabel">Status:</span>
-                            [% IF ( HOLD.is_waiting ) %]
-                                <i class="fa fa-exclamation-circle text-warning" aria-hidden="true"></i>
-                                [% IF ( HOLD.is_at_destination ) %]
-                                    Item waiting at <strong> [% HOLD.branch.branchname | html %]</strong>
-                                    [% IF ( HOLD.desk_id ) %], [% HOLD.desk.desk_name | html %],[% END %]
-                                    [% IF ( HOLD.waitingdate ) %]
-                                        since [% HOLD.waitingdate | $KohaDates %]
-                                        [% IF HOLD.expirationdate %]
-                                            until [% HOLD.expirationdate | $KohaDates %]
-                                        [% END %]
-                                    [% END %]
-                                    <input type="hidden" name="pickup" value="[% HOLD.branchcode | html %]" />
-                                [% ELSE %]
-                                    Item in transit to <strong> [% Branches.GetName( HOLD.branchcode ) | html %]</strong> <input type="hidden" name="pickup" value="[% HOLD.branchcode | html %]" />
-                                [% END %]
+                    [% END %]
+                </td>
+                [% IF SuspendHoldsOpac and ! onlyinfo %]
+                    <td>
+                        [% IF ( HOLD.is_cancelable_from_opac ) %]
+                            [% IF HOLD.suspend %]
+                                <form class="form-inline" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
+                                    <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
+                                    <button class="btn btn-link" type="submit" name="submit"><i class="fa fa-play" aria-hidden="true"></i> Resume</button>
+                                </form>
                             [% ELSE %]
-                                [% IF ( HOLD.is_in_transit ) %]
-                                    [% SET transfer = HOLD.item.get_transfer %]
-                                    [% branch_name = BLOCK %]<strong>[% Branches.GetName( transfer.frombranch ) | html %]</strong>[% END %]
-                                    <span>Item in transit from [% branch_name| $raw %] since</span>
-                                    [% transfer.datesent | $KohaDates %]
-                                [% ELSIF ( HOLD.is_in_processing ) %]
-                                    <span>Item in processing</span>
-                                [% ELSIF ( HOLD.suspend ) %]
-                                    <span>Suspended</span>[% IF ( HOLD.suspend_until ) %] <span>until</span> [% HOLD.suspend_until | $KohaDates %][% END %]
+                                [% IF AutoResumeSuspendedHolds %]
+                                    <a class="btn btn-link suspend_hold js-show" href="#" role="button" data-title="[% HOLD.biblio.title | html %] [% FOREACH subtitle IN HOLD.biblio.subtitle.split(' \| ') %][% IF Koha.Preference('marcflavour')=='UNIMARC' %],[% END %][% subtitle | html %][% END %]" data-reserve_id="[% HOLD.reserve_id | html %]"><i class="fa fa-pause" aria-hidden="true"></i> Suspend</a>
                                 [% ELSE %]
-                                    [% IF HOLD.itemtype %]
-                                        <span>Pending for next available item of item type '[% ItemTypes.GetDescription( HOLD.itemtype ) | html %]'</span>
-                                    [% ELSE %]
-                                        <span>Pending</span>
-                                    [% END %]
-                                [% END %]
-                            [% END %]
-                        </td>
-                        [% IF SuspendHoldsOpac and ! onlyinfo %]
-                            <td>
-                                [% IF ( HOLD.is_cancelable_from_opac ) %]
-                                    [% IF HOLD.suspend %]
-                                        <form class="form-inline" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
-                                            <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
-                                            <button class="btn btn-link" type="submit" name="submit"><i class="fa fa-play" aria-hidden="true"></i> Resume</button>
-                                        </form>
-                                    [% ELSE %]
-                                        [% IF AutoResumeSuspendedHolds %]
-                                            <a class="btn btn-link suspend_hold js-show" href="#" role="button" data-title="[% HOLD.biblio.title | html %] [% FOREACH subtitle IN HOLD.biblio.subtitle.split(' \| ') %][% IF Koha.Preference('marcflavour')=='UNIMARC' %],[% END %][% subtitle | html %][% END %]" data-reserve_id="[% HOLD.reserve_id | html %]"><i class="fa fa-pause" aria-hidden="true"></i> Suspend</a>
-                                        [% ELSE %]
-                                            <form class="form-inline" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
-                                                <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
-                                                <button class="btn btn-link" type="submit" name="submit"><i class="fa fa-pause" aria-hidden="true"></i> Suspend</button>
-                                            </form>
-                                        [% END # / IF AutoResumeSuspendedHolds %]
-                                    [% END # / IF HOLD.suspend %]
-                                [% END # / IF ( HOLD.is_cancelable_from_opac )%]
-                            </td>
-                        [% END # / IF SuspendHoldsOpac %]
-                        [% IF ! onlyinfo %]
-                            <td class="modify">
-                                [% IF ( HOLD.is_cancelable_from_opac ) %]
-                                    <form id="delete_hold_[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
-                                        <input type="hidden" name="biblionumber" value="[% HOLD.biblionumber | html %]" />
-                                        <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
-                                        <button data-title="[% INCLUDE 'biblio-title-head.inc' biblio=HOLD.biblio %]" data-reserve_id="[% HOLD.reserve_id | html %]" type="submit" class="btn btn-sm btn-danger btn-delete-hold"><i class="fa fa-times" aria-hidden="true"></i> [% tp('Cancel hold button', 'Cancel') | html %]</button>
-                                    </form>
-                                [% ELSIF HOLD.is_waiting && HOLD.cancellation_requestable_from_opac %]
-                                    <form id="req_cancel_hold_[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
-                                        <input type="hidden" name="biblionumber" value="[% HOLD.biblionumber | html %]" />
+                                    <form class="form-inline" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
                                         <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
-                                        <input type="hidden" name="cancellation_request" value="1" />
-                                        <button data-title="[% INCLUDE 'biblio-title-head.inc' biblio=HOLD.biblio %]" data-reserve_id="[% HOLD.reserve_id | html %]" type="submit" class="btn btn-sm btn-danger btn-req-delete-hold"><i class="fa fa-times" aria-hidden="true"></i> [% tp('Cancel hold button', 'Cancel') | html %]</button>
+                                        <button class="btn btn-link" type="submit" name="submit"><i class="fa fa-pause" aria-hidden="true"></i> Suspend</button>
                                     </form>
-                                [% END %]
-                            </td>
-                            <td></td>
-                        [% END # / IF onlyinfo %]
-                    </tr>
-                [% END # /FOREACH HOLDS %]
-            </tbody>
-        </table>
+                                [% END # / IF AutoResumeSuspendedHolds %]
+                            [% END # / IF HOLD.suspend %]
+                        [% END # / IF ( HOLD.is_cancelable_from_opac )%]
+                    </td>
+                [% END # / IF SuspendHoldsOpac %]
+                [% IF ! onlyinfo %]
+                    <td class="modify">
+                        [% IF ( HOLD.is_cancelable_from_opac ) %]
+                            <form id="delete_hold_[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
+                                <input type="hidden" name="biblionumber" value="[% HOLD.biblionumber | html %]" />
+                                <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
+                                <button data-title="[% INCLUDE 'biblio-title-head.inc' biblio=HOLD.biblio %]" data-reserve_id="[% HOLD.reserve_id | html %]" type="submit" class="btn btn-sm btn-danger btn-delete-hold"><i class="fa fa-times" aria-hidden="true"></i> [% tp('Cancel hold button', 'Cancel') | html %]</button>
+                            </form>
+                        [% ELSIF HOLD.is_waiting && HOLD.cancellation_requestable_from_opac %]
+                            <form id="req_cancel_hold_[% HOLD.reserve_id | html %]" action="/cgi-bin/koha/opac-modrequest.pl" method="post">
+                                <input type="hidden" name="biblionumber" value="[% HOLD.biblionumber | html %]" />
+                                <input type="hidden" name="reserve_id" value="[% HOLD.reserve_id | html %]" />
+                                <input type="hidden" name="cancellation_request" value="1" />
+                                <button data-title="[% INCLUDE 'biblio-title-head.inc' biblio=HOLD.biblio %]" data-reserve_id="[% HOLD.reserve_id | html %]" type="submit" class="btn btn-sm btn-danger btn-req-delete-hold"><i class="fa fa-times" aria-hidden="true"></i> [% tp('Cancel hold button', 'Cancel') | html %]</button>
+                            </form>
+                        [% END %]
+                    </td>
+                    <td></td>
+                [% END # / IF onlyinfo %]
+            </tr>
+        [% END # /FOREACH HOLDS %]
+    </tbody>
+</table>
 
-        [% IF SuspendHoldsOpac and ! onlyinfo %]
-            [% UNLESS ( all_holds_waiting ) %]
-                <div>
-                    <form class="form-inline" id="suspend_all_holds" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
-                        <button type="submit" id="suspend_all_submit" class="btn btn-primary"><i class="fa fa-pause" aria-hidden="true"></i> Suspend all holds</button>
-                        <input type="hidden" name="suspend" value="1" />
+[% IF SuspendHoldsOpac and ! onlyinfo %]
+    [% UNLESS ( all_holds_waiting ) %]
+        <div>
+            <form class="form-inline" id="suspend_all_holds" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
+                <button type="submit" id="suspend_all_submit" class="btn btn-primary"><i class="fa fa-pause" aria-hidden="true"></i> Suspend all holds</button>
+                <input type="hidden" name="suspend" value="1" />
 
-                        [% IF AutoResumeSuspendedHolds %]
-                            <label for="suspend_until"> until </label>
-                            <input type="text" name="suspend_until" id="suspend_until" class="flatpickr futuredate" size="10" />
-                            <p><a href="#" class="clear-flatpickr" data-fp="suspend_until">Clear date to suspend indefinitely</a></p>
-                        [% END %]
-                    </form>
-                </div>
-                <br/>
-                <div>
-                    <form id="resume_all_holds" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
-                        <button type="submit" id="resume_all_submit" class="btn btn-primary"><i class="fa fa-play" aria-hidden="true"></i> Resume all suspended holds</button>
-                        <input type="hidden" name="suspend" value="0" />
-                    </form>
-                </div>
-            [% END %]
-        [% END %]
-    </div> <!-- / #opac-user-holds -->
-[% END # / #HOLDS.count %]
+                [% IF AutoResumeSuspendedHolds %]
+                    <label for="suspend_until"> until </label>
+                    <input type="text" name="suspend_until" id="suspend_until" class="flatpickr futuredate" size="10" />
+                    <p><a href="#" class="clear-flatpickr" data-fp="suspend_until">Clear date to suspend indefinitely</a></p>
+                [% END %]
+            </form>
+        </div>
+        <br/>
+        <div>
+            <form id="resume_all_holds" action="/cgi-bin/koha/opac-modrequest-suspend.pl" method="post">
+                <button type="submit" id="resume_all_submit" class="btn btn-primary"><i class="fa fa-play" aria-hidden="true"></i> Resume all suspended holds</button>
+                <input type="hidden" name="suspend" value="0" />
+            </form>
+        </div>
+    [% END %]
+[% END %]
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt
index c084ae304f..8e0f99659d 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/clubs-tab.tt
@@ -76,7 +76,7 @@
 <script>
 function loadEnrollmentForm( id ) {
     $("body").css("cursor", "progress");
-    $('#opac-user-clubs').load('/cgi-bin/koha/clubs/enroll.pl?borrowernumber=[% borrower.borrowernumber | html %]&id=' + id, function() {
+    $('#opac-user-clubs_panel').load('/cgi-bin/koha/clubs/enroll.pl?borrowernumber=[% borrower.borrowernumber | html %]&id=' + id, function() {
         $("body").css("cursor", "default");
     });
 
@@ -91,7 +91,7 @@ function cancelEnrollment( id ) {
         data: { id: id },
         success: function( data ) {
             if ( data.success ) {
-                $('#opac-user-clubs').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrower.borrowernumber | html %]', function() {
+                $('#opac-user-clubs_panel').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrower.borrowernumber | html %]', function() {
                     $("body").css("cursor", "default");
                 });
             } else {
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/enroll.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/enroll.tt
index b83e1e3156..88939b10e5 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/enroll.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/clubs/enroll.tt
@@ -44,7 +44,7 @@ function addEnrollment() {
         data: $( "#patron-enrollment-form" ).serialize(),
         success: function( data ) {
             if ( data.success ) {
-                $('#opac-user-clubs').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]&id=[% club.id | html %]', function() {
+                $('#opac-user-clubs_panel').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]&id=[% club.id | html %]', function() {
                     $("body").css("cursor", "default");
                 });
             } else {
@@ -58,7 +58,7 @@ function addEnrollment() {
 
 function showClubs() {
     $("body").css("cursor", "progress");
-    $('#opac-user-clubs').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]&id=[% club.id | html %]', function() {
+    $('#opac-user-clubs_panel').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]&id=[% club.id | html %]', function() {
         $("body").css("cursor", "default");
     });
 }
diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt
index 2a82506693..4e801d55b8 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt
+++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt
@@ -251,73 +251,72 @@
                     </form>
                     [% END %]
 
-                    <div id="opac-user-views" class="toptabs">
-                        <ul class="nav nav-tabs" role="tablist">
-                            <li class="nav-item" role="presentation">
-                                <a class="nav-link active" id="opac-user-checkouts-tab" data-toggle="tab" role="tab" aria-controls="opac-user-checkouts" aria-selected="true"  href="#opac-user-checkouts">Checked out ([% issues_count | html %])</a>
-                            </li>
+                    [% WRAPPER tabs id= "opac-user-views" %]
+                        [% WRAPPER tabs_nav %]
+                            [% WRAPPER tab_item tabname= "opac-user-checkouts" %]
+                                <span>Checked out ([% issues_count | html %])</span>
+                            [% END %]
                             [% IF relatives %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-relative-issues-tab" data-toggle="tab" role="tab" aria-controls="opac-user-relative-issues" aria-selected="false" href="#opac-user-relative-issues">Relatives' checkouts</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-relative-issues" %]
+                                    <span>Relatives' checkouts</span>
+                                [% END %]
                             [% END %]
                             [% IF ( overdues_count ) %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-overdues-tab" data-toggle="tab" role="tab" aria-controls="opac-user-overdues" aria-selected="false" href="#opac-user-overdues">Overdue ([% overdues_count | html %])</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-overdues" %]
+                                    <span>Overdue ([% overdues_count | html %])</span>
+                                [% END %]
                             [% END %]
                             [% IF ( OPACFinesTab ) %]
                                 [% IF ( amountoutstanding > 0 ) %]
-                                    <li class="nav-item" role="presentation">
-                                        <a class="nav-link" id="opac-user-fines-tab" data-toggle="tab" role="tab" aria-controls="opac-user-fines" aria-selected="false" href="#opac-user-fines">Charges ([% amountoutstanding | $Price %])</a>
-                                    </li>
+                                    [% WRAPPER tab_item tabname= "opac-user-fines" %]
+                                        <span>Charges ([% amountoutstanding | $Price %])</span>
+                                    [% END %]
                                 [% END %]
                                 [% IF ( amountoutstanding < 0 ) %]
-                                    <li class="nav-item" role="presentation">
-                                        <a class="nav-link" id="opac-user-fines-tab" data-toggle="tab" role="tab" aria-controls="opac-user-fines" aria-selected="false" href="#opac-user-fines">Credits ([% amountoutstanding * -1 | $Price %])</a>
-                                    </li>
+                                    [% WRAPPER tab_item tabname= "opac-user-fines" %]
+                                        <span>Credits ([% amountoutstanding * -1 | $Price %])</span>
+                                    [% END %]
                                 [% END %]
                                 [% IF relatives_with_fines %]
-                                    <li class="nav-item" role="presentation">
-                                        <a class="nav-link" id="opac-user-relative-fines-tab" data-toggle="tab" role="tab" aria-controls="opac-user-relative-fines" aria-selected="false" href="#opac-user-relative-fines">Relatives' charges</a>
-                                    </li>
+                                    [% WRAPPER tab_item tabname= "opac-user-relative-fines" %]
+                                        <span>Relatives' charges</span>
+                                    [% END %]
                                 [% END %]
                             [% END %]
 
                             [% IF borrower_club_enrollments.count || borrower_enrollable_clubs.count %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" data-toggle="tab" role="tab" aria-controls="opac-user-clubs" aria-selected="false" id="opac-user-clubs-tab-link" href="#opac-user-clubs">
-                                        Clubs ([% borrower_club_enrollments.count || 0 | html %]/[% borrower_enrollable_clubs.count || 0 | html %])
-                                    </a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-clubs" %]
+                                    <span>Clubs ([% borrower_club_enrollments.count || 0 | html %]/[% borrower_enrollable_clubs.count || 0 | html %])</span>
+                                [% END %]
                             [% END %]
 
                             [% IF ( RESERVES.count ) %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-holds-tab" data-toggle="tab" role="tab" aria-controls="opac-user-holds" aria-selected="false" href="#opac-user-holds">Holds ([% RESERVES.count | html %])</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-holds" %]
+                                    <span>Holds ([% RESERVES.count | html %])</span>
+                                [% END %]
                             [% END %]
                             [% IF Koha.Preference('UseRecalls') && RECALLS.count %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-recalls-tab" data-toggle="tab" role="tab" aria-controls="opac-user-recalls" aria-selected="false" href="#opac-user-recalls">Recalls ([% RECALLS.count | html %])</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-recalls" %]
+                                    <span>Recalls ([% RECALLS.count | html %])</span>
+                                [% END %]
                             [% END %]
                             [% IF Koha.Preference('ArticleRequests') %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-article-requests-tab" data-toggle="tab" role="tab" aria-controls="opac-user-article-requests" aria-selected="false" href="#opac-user-article-requests">Article requests ([% current_article_requests.size || 0 | html %])</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-article-requests" %]
+                                    <span>Article requests ([% current_article_requests.size || 0 | html %])</span>
+                                [% END %]
                             [% END %]
                             [% IF ( OverDriveCirculation ) %]
-                                <li class="nav-item" role="presentation">
-                                    <a class="nav-link" id="opac-user-overdrive-tab" data-toggle="tab" role="tab" aria-controls="opac-user-overdrive" aria-selected="false" href="#opac-user-overdrive">OverDrive account</a>
-                                </li>
+                                [% WRAPPER tab_item tabname= "opac-user-overdrive" %]
+                                    <span>OverDrive account</span>
+                                [% END %]
                             [% END %]
-                        </ul>
-                        <div class="tab-content">
+                        [% END # /WRAPPER tabs_nav %]
+
+                        [% WRAPPER tab_panels %]
+                            [% WRAPPER tab_panel tabname="opac-user-overdrive" %]
+                            [% END # /tab_panel#opac-user-overdrive %]
 
-                            <div id="opac-user-overdrive" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-overdrive-tab">
-                            </div>
-                            <div id="opac-user-checkouts" class="tab-pane active" role="tabpanel" aria-labelledby="opac-user-checkouts-tab">
+                            [% WRAPPER tab_panel tabname="opac-user-checkouts" %]
                                 [% IF ( issues_count ) %]
                                     <form id="renewselected" action="/cgi-bin/koha/opac-renew.pl" method="post">
                                         <legend class="sr-only">Renew selected</legend>
@@ -602,19 +601,18 @@
                                         </form>
                                     </div>
                                 </div>
-
-                            </div> <!-- / .opac-user-checkouts -->
+                            [% END # /tab_panel#opac-user-checkouts %]
 
                             [% IF borrower_club_enrollments.count || borrower_enrollable_clubs.count %]
-                                <div id="opac-user-clubs" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-clubs-tab-link">
+                                [% WRAPPER tab_panel tabname="opac-user-clubs" %]
                                     Loading...
-                                </div>
+                                [% END # /tab_panel#opac-user-clubs %]
                             [% END %]
 
                             [% IF ( OPACFinesTab ) %]
                                 <!-- FINES BOX -->
                                 [% IF ( amountoutstanding > 0 ) %]
-                                    <div id="opac-user-fines" class="tab-pane" id="home" role="tabpanel" aria-labelledby="opac-user-fines-tab">
+                                    [% WRAPPER tab_panel tabname="opac-user-fines" %]
                                         <table class="table table-bordered table-striped">
                                             <caption>Charges</caption>
                                             <thead><tr><th colspan="2">Amount</th></tr></thead>
@@ -625,11 +623,11 @@
                                                 </tr>
                                             </tbody>
                                         </table>
-                                    </div>
+                                    [% END # /tab_panel#opac-user-fines %]
                                 [% END %]
 
                                 [% IF ( amountoutstanding < 0 ) %]
-                                    <div id="opac-user-fines" class="tab-pane" id="home" role="tabpanel" aria-labelledby="opac-user-fines-tab">
+                                    [% WRAPPER tab_panel tabname="opac-user-fines" %]
                                         <table class="table table-bordered table-striped">
                                             <caption>Credits</caption>
                                             <thead><tr><th colspan="2">Amount</th></tr></thead>
@@ -639,11 +637,11 @@
                                                 </tr>
                                             </tbody>
                                         </table>
-                                    </div>
+                                    [% END # /tab_panel#opac-user-fines %]
                                 [% END %]
 
                                 [% IF relatives_with_fines %]
-                                    <div id="opac-user-relative-fines" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-relative-fines-tab">
+                                    [% WRAPPER tab_panel tabname="opac-user-relative-fines" %]
                                         <table class="table table-bordered table-striped">
                                             <caption>Fines and charges</caption>
                                             <thead>
@@ -660,12 +658,12 @@
                                                 [% END %]
                                             </tbody>
                                         </table>
-                                    </div>
+                                    [% END # /tab_panel#opac-user-relative-fines %]
                                 [% END %]
                             [% END # / OPACFinesTab %]
 
                             [% IF relatives %]
-                                <div id="opac-user-relative-issues" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-relative-issues-tab">
+                                [% WRAPPER tab_panel tabname="opac-user-relative-issues" %]
                                     <table id="opac-user-relative-issues-table" class="table table-bordered table-striped">
                                         <caption class="sr-only">Relatives' checkouts</caption>
                                         <thead>
@@ -710,11 +708,11 @@
                                             [% END %]
                                         </tbody>
                                     </table>
-                                </div>
+                                [% END # /tab_panel#opac-user-relative-issues %]
                             [% END %]
 
                             [% IF ( overdues_count ) %]
-                                <div id="opac-user-overdues" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-overdues-tab">
+                                [% WRAPPER tab_panel tabname="opac-user-overdues" %]
                                     <table id="overduest" class="table table-bordered table-striped">
                                         <caption>Overdues <span class="count">([% overdues_count | html %] total)</span></caption>
                                         <!-- OVERDUES TABLE ROWS -->
@@ -835,13 +833,17 @@
                                             [% END %]
                                         </tbody>
                                     </table>
-                                </div> <!-- / #opac-user-overdues -->
+                                [% END # /tab_panel#opac-user-overdues %]
                             [% END # /overdues_count %]
 
-                            [% PROCESS 'holds-table.inc' HOLDS = RESERVES, SuspendHoldsOpac = SuspendHoldsOpac, showpriority = showpriority, AutoResumeSuspendedHolds = AutoResumeSuspendedHolds %]
+                            [% IF ( RESERVES.count ) %]
+                                [% WRAPPER tab_panel tabname="opac-user-holds" %]
+                                    [% PROCESS 'holds-table.inc' HOLDS = RESERVES, SuspendHoldsOpac = SuspendHoldsOpac, showpriority = showpriority, AutoResumeSuspendedHolds = AutoResumeSuspendedHolds %]
+                                [% END # /tab_panel#opac-user-holds %]
+                            [% END # / #RESERVES.count %]
 
                             [% IF Koha.Preference('UseRecalls') && RECALLS.count %]
-                                <div id="opac-user-recalls" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-recalls-tab">
+                                [% WRAPPER tab_panel tabname="opac-user-recalls" %]
                                     <table id="recalls-table" class="table table-bordered table-striped">
                                         <caption>Recalls <span class="count">([% RECALLS.count | html %])</span></caption>
                                         <thead>
@@ -912,11 +914,11 @@
                                             </tr>
                                         </tbody>
                                     </table>
-                                </div>
+                                [% END # /tab_panel#opac-user-recalls %]
                             [% END # / # RECALLS.count %]
 
                             [% IF Koha.Preference('ArticleRequests') %]
-                                <div id="opac-user-article-requests" class="tab-pane" role="tabpanel" aria-labelledby="opac-user-article-requests-tab">
+                                [% WRAPPER tab_panel tabname="opac-user-article-requests" %]
                                     [% IF current_article_requests.size %]
                                         <table id="article-requests-table" class="table table-bordered table-striped">
                                             <caption>Article requests <span class="count"></span></caption>
@@ -1025,10 +1027,10 @@
                                             <tr><td>You have no article requests currently.</td></tr>
                                         </table>
                                     [% END # IF current_article_requests.size %]
-                                </div> <!-- / #opac-user-article-requests -->
+                                [% END # /tab_panel#opac-user-article-requests %]
                             [% END %]
-                        </div> <!-- /.tab-content -->
-                    </div> <!-- /#opac-user-views -->
+                        [% END # /WRAPPER tab_panels %]
+                    [% END # /WRAPPER tabs#opac-user-views %]
                 </div> <!-- /#userdetails -->
             </div> <!-- /.col-10 -->
         </div> <!-- /.row -->
@@ -1330,10 +1332,10 @@
                 $("#change-pickup-location" + hold_id ).show();
             });
 
-            if ( $('#opac-user-clubs').length ) {
-                $('#opac-user-clubs-tab-link').on('click', function() {
-                    $('#opac-user-clubs').text(_("Loading..."));
-                    $('#opac-user-clubs').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]');
+            if ( $('#opac-user-clubs_panel').length ) {
+                $('#opac-user-clubs-tab').on('click', function() {
+                    $('#opac-user-clubs_panel').text(_("Loading..."));
+                    $('#opac-user-clubs_panel').load('/cgi-bin/koha/clubs/clubs-tab.pl?borrowernumber=[% borrowernumber | html %]');
                 });
             }
 
@@ -1369,6 +1371,10 @@
             $(".dismiss-message-button").click(function(e){
                 return confirmDelete(_("Are you sure you want to dismiss this message?"));
             });
+
+            if( $("#opac-user-views .tab-pane.active").length < 1 ){
+                $("#opac-user-views a:first").tab("show");
+            }
         });
 
         function submitNote( title, issue_id, note ){
@@ -1451,14 +1457,14 @@
     [%- END -%]
     $(document).ready(function() {
         [% IF ( overdrive_error ) %]
-            KOHA.OverDriveCirculation.display_error("#opac-user-overdrive", "[% overdrive_error.dquote | html %]");
+            KOHA.OverDriveCirculation.display_error("#opac-user-overdrive_panel", "[% overdrive_error.dquote | html %]");
         [% END %]
 
         [% IF ( overdrive_tab ) %]
-            $("#opac-user-views a[href='#opac-user-overdrive']").tab("show");
+            $("#opac-user-views a[href='#opac-user-overdrive_panel']").tab("show");
         [% END %]
 
-        $("#opac-user-overdrive").each( function() {
+        $("#opac-user-overdrive_panel").each( function() {
             KOHA.OverDriveCirculation.display_account_details(this);
         } );
     });
diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/overdrive.js b/koha-tmpl/opac-tmpl/bootstrap/js/overdrive.js
index 7cf4237436..b84f9eca68 100644
--- a/koha-tmpl/opac-tmpl/bootstrap/js/overdrive.js
+++ b/koha-tmpl/opac-tmpl/bootstrap/js/overdrive.js
@@ -225,7 +225,7 @@ KOHA.OverDriveCirculation = new function() {
                 if( $("#overdrive-results-page").length > 0 ){
                     location.reload();
                 } else {
-                    KOHA.OverDriveCirculation.display_account_details( $("#opac-user-overdrive") );
+                    KOHA.OverDriveCirculation.display_account_details( $("#opac-user-overdrive_panel") );
                 }
             }
         });
-- 
2.30.2