Bug 15792: Throttle patron renewal links to prevent double-clicks
- Replace plain <a> renewal links in patron_messages.inc with the
reusable throttled-button component introduced in Bug 40896
- Covers all four renewal links: warndeparture and expired states,
in both circulation and patron detail contexts
- Include throttledButton.js in circulation.tt and moremember.tt
- Add persist mode and done icon state to throttled-button component
so the button stays disabled on bfcache restore with a check icon
instead of a misleading spinner
Test plan:
1) Create or update a patron category with an enrollment fee and an
enrollment period in months (e.g. 24 months)
2) Create a patron of that type and write off any initial enrollment
fee
3) Set the patron's dateexpiry to the past so the account is expired
4) Go to /cgi-bin/koha/circ/circulation.pl and scan the patron
5) Observe the "Renew" link in the expiration warning now shows as a
small button with a rotate icon
6) Click "Renew" and confirm the button becomes disabled with a
spinner, preventing a second click
7) Verify the patron is renewed correctly with only one enrollment
fee charged and the correct expiry date
8) Press the browser back button to return via bfcache
9) Verify the button remains disabled and shows a check icon instead
of the spinner, indicating the action was already completed
10) Repeat from the patron detail page (moremember.pl) to verify the
same throttle and done-state behavior there
11) Test the warndeparture case by setting dateexpiry to a near-future
date and confirming the same behavior
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit is contained in:
parent
96d2287a6a
commit
3a6a79a607
|
|
@ -24,10 +24,12 @@
|
|||
<span class="circ-hlt">Expiration:</span>
|
||||
<span>Patron's card expires on [% patron.dateexpiry | $KohaDates %].</span>
|
||||
[% IF ( moremember ) %]
|
||||
<a href="/cgi-bin/koha/members/setstatus.pl?borrowernumber=[% patron.borrowernumber | uri %]&destination=member&reregistration=y">Renew</a> or
|
||||
[% INCLUDE 'throttled-button.inc' element_type='link' href='/cgi-bin/koha/members/setstatus.pl?borrowernumber=' _ patron.borrowernumber _ '&destination=member&reregistration=y' classes='btn btn-default btn-xs' ready_icon='fa-solid fa-rotate' label=t('Renew') persist=1 done_icon='fa-solid fa-check' %]
|
||||
or
|
||||
<a href="/cgi-bin/koha/members/memberentry.pl?op=edit_form&destination=member&borrowernumber=[% patron.borrowernumber | uri %]">Edit details</a>
|
||||
[% ELSE %]
|
||||
<a href="/cgi-bin/koha/members/setstatus.pl?borrowernumber=[% patron.borrowernumber | uri %]&destination=circ&reregistration=y">Renew</a> or
|
||||
[% INCLUDE 'throttled-button.inc' element_type='link' href='/cgi-bin/koha/members/setstatus.pl?borrowernumber=' _ patron.borrowernumber _ '&destination=circ&reregistration=y' classes='btn btn-default btn-xs' ready_icon='fa-solid fa-rotate' label=t('Renew') persist=1 done_icon='fa-solid fa-check' %]
|
||||
or
|
||||
<a href="/cgi-bin/koha/members/memberentry.pl?op=edit_form&destination=circ&borrowernumber=[% patron.borrowernumber | uri %]">Edit details</a>
|
||||
[% END %]
|
||||
</li>
|
||||
|
|
@ -47,10 +49,12 @@
|
|||
<span>Patron's card expired on [% expiry | $KohaDates %]</span>
|
||||
[% END %]
|
||||
[% IF ( moremember ) %]
|
||||
<a href="/cgi-bin/koha/members/setstatus.pl?borrowernumber=[% patron.borrowernumber | uri %]&destination=member&reregistration=y">Renew</a> or
|
||||
[% INCLUDE 'throttled-button.inc' element_type='link' href='/cgi-bin/koha/members/setstatus.pl?borrowernumber=' _ patron.borrowernumber _ '&destination=member&reregistration=y' classes='btn btn-default btn-xs' ready_icon='fa-solid fa-rotate' label=t('Renew') persist=1 done_icon='fa-solid fa-check' %]
|
||||
or
|
||||
<a href="/cgi-bin/koha/members/memberentry.pl?op=edit_form&destination=member&borrowernumber=[% patron.borrowernumber | uri %]">Edit details</a>
|
||||
[% ELSE %]
|
||||
<a href="/cgi-bin/koha/members/setstatus.pl?borrowernumber=[% patron.borrowernumber | uri %]&destination=circ&reregistration=y">Renew</a> or
|
||||
[% INCLUDE 'throttled-button.inc' element_type='link' href='/cgi-bin/koha/members/setstatus.pl?borrowernumber=' _ patron.borrowernumber _ '&destination=circ&reregistration=y' classes='btn btn-default btn-xs' ready_icon='fa-solid fa-rotate' label=t('Renew') persist=1 done_icon='fa-solid fa-check' %]
|
||||
or
|
||||
<a href="/cgi-bin/koha/members/memberentry.pl?op=edit_form&destination=circ&borrowernumber=[% patron.borrowernumber | uri %]">Edit details</a>
|
||||
[% END %]
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -7,12 +7,16 @@
|
|||
[% DEFAULT href = '#' %]
|
||||
|
||||
[%# Common attributes shared by both button and link %]
|
||||
[% BLOCK common_attrs %]class="[% classes | html %]"[% IF id %]id="[% id | html %]"[% END %] data-state="ready" data-throttled-button [% IF attrs %][% FOREACH key IN attrs.keys %][% key | html %]="[% attrs.$key | html %]"[% END %][% END %][% END %]
|
||||
[% BLOCK common_attrs %]
|
||||
class="[% classes | html %]"[% IF id %]id="[% id | html %]"[% END %] data-state="ready" data-throttled-button [% IF persist %]data-throttle-persist[% END %]
|
||||
[% IF attrs %][% FOREACH key IN attrs.keys %][% key | html %]="[% attrs.$key | html %]"[% END %][% END %]
|
||||
[% END %]
|
||||
|
||||
[%# Inner content shared by both button and link %]
|
||||
[% BLOCK inner_content %]
|
||||
<span class="button-icon-ready"><i class="[% ready_icon | html %]"></i></span>
|
||||
<span class="button-icon-running" style="display: none;"><i class="[% active_icon | html %]"></i></span>
|
||||
[% IF done_icon %]<span class="button-icon-done" style="display: none;"><i class="[% done_icon | html %]"></i></span>[% END %]
|
||||
[% UNLESS icon_only %][% label | html %][% END %]
|
||||
[% END %]
|
||||
|
||||
|
|
|
|||
|
|
@ -1260,6 +1260,7 @@
|
|||
[% Asset.js("js/checkouts.js") | $raw %]
|
||||
[% Asset.js("js/tables/bookings.js") | $raw %]
|
||||
[% Asset.js("js/recalls.js") | $raw %]
|
||||
[% Asset.js("js/throttledButton.js") | $raw %]
|
||||
[% END %]
|
||||
|
||||
[% INCLUDE 'intranet-bottom.inc' %]
|
||||
|
|
|
|||
|
|
@ -849,6 +849,7 @@
|
|||
[% INCLUDE 'str/members-menu.inc' %]
|
||||
[% Asset.js("js/members-menu.js") | $raw %]
|
||||
[% Asset.js("js/recalls.js") | $raw %]
|
||||
[% Asset.js("js/throttledButton.js") | $raw %]
|
||||
[% Asset.js("js/hold-group.js") | $raw %]
|
||||
<script nonce="[% Koha.CSPNonce | $raw %]">
|
||||
const LoadCheckoutsTableDelay = 0;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,22 @@
|
|||
clearTimeout(timeoutId);
|
||||
pendingTimeouts.delete(button);
|
||||
}
|
||||
toggleButton(button);
|
||||
if (!button.hasAttribute("data-throttle-persist")) {
|
||||
toggleButton(button);
|
||||
} else {
|
||||
const runningIcon = button.querySelector(
|
||||
".button-icon-running"
|
||||
);
|
||||
const doneIcon =
|
||||
button.querySelector(".button-icon-done");
|
||||
if (runningIcon) {
|
||||
runningIcon.style.display = "none";
|
||||
}
|
||||
if (doneIcon) {
|
||||
doneIcon.style.display = "";
|
||||
}
|
||||
button.dataset.state = "done";
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue