Bug 42169: Unify patron category change popups

To test:
1. APPLY PATCH, restart_all
2. Go to  Administration > Patron categories
3. Edit or create some categories with different Enrollment periods and messaaging preferences
4. Find or create some patrons in different categories than the ones setup in step 3.
5. Edit the patron and change the category to one setup in step 3.
6. Notice a popup asking about both patron expiratoin date and messaging preferences, both should be checked by default.
7. Confirm and check that both the patron expiration date and messaging preferences updated to the category defaults.
8. Try again, checking only one of the 2 checkboxes. Make sure things updated correctly. Try this with both checkboxes.

Signed-off-by: John Vinke <jvinke@austinseminary.edu>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 0809d09222)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
This commit is contained in:
Lucas Gass 2026-03-25 15:18:18 +00:00 committed by Jacob O'Mara
parent 8d676a4d65
commit fd1c8ce9c9
No known key found for this signature in database
3 changed files with 98 additions and 80 deletions

View File

@ -1674,24 +1674,31 @@
<!-- /.main.container-fluid -->
<!-- Expiration date modal-->
<div id="expirationDateModal" class="modal" tabindex="-1" role="dialog" aria-labelledby="expirationDateModalLabel" aria-hidden="true">
<div id="categoryChangeModal" class="modal" tabindex="-1" role="dialog" aria-labelledby="categoryChangeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title" id="expirationDateModalLabel">Confirm expiration date</h1>
<h1 class="modal-title" id="categoryChangeModalLabel">Patron category changed</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Change expiration date to default for this category?</p>
<p>Would you like to apply the defaults for the new category?</p>
<div class="form-check">
<input type="checkbox" id="categoryChangeUpdateMessaging" />
<label class="form-check-label" for="categoryChangeUpdateMessaging"> Reset messaging preferences to category defaults </label>
</div>
<div class="form-check">
<input type="checkbox" id="categoryChangeUpdateExpiry" />
<label class="form-check-label" for="categoryChangeUpdateExpiry"> Reset expiration date to category default </label>
</div>
</div>
<div class="modal-footer">
<button id="expirationDateConfirmBtn" class="btn btn-primary"><i class="fa fa-check" aria-hidden="true"></i> Yes</button>
<button id="expirationDateCancelBtn" data-bs-dismiss="modal" class="btn btn-secondary"><i class="fa fa-times" aria-hidden="true"></i> No</button>
<button id="categoryChangeConfirmBtn" class="btn btn-primary"><i class="fa fa-check" aria-hidden="true"></i> Confirm</button>
<button id="categoryChangeCancelBtn" data-bs-dismiss="modal" class="btn btn-secondary"><i class="fa fa-times" aria-hidden="true"></i> Cancel</button>
</div>
</div>
</div>
</div>
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'calendar.inc' %]
[% INCLUDE 'str/members-menu.inc' %]
@ -1989,8 +1996,8 @@
var TalkingTechItivaPhoneNotification = [% Koha.Preference('TalkingTechItivaPhoneNotification') || 0 | html %];
var PhoneNotification = [% Koha.Preference('PhoneNotification') || 0 | html %];
</script>
[% Asset.js("js/members.js") | $raw %]
[% Asset.js("js/messaging-preference-form.js") | $raw %]
[% Asset.js("js/members.js") | $raw %]
[% PROCESS 'password_check.inc' new_password => 'password', category_selector => '#categorycode_entry', minPasswordLength => patron.category.effective_min_password_length, RequireStrongPassword => patron.category.effective_require_strong_password %]
[% INCLUDE 'select2.inc' %]

View File

@ -88,24 +88,6 @@ function update_category_code(category_code) {
);
var hint_string = __("Minimum password length: %s").format(min_length);
hint.html(hint_string);
// Change patron's expiration date
$("#categorycode_entry").change(function () {
$("#expirationDateModal").modal("show");
// Handle confirmation Yes button click
$("#expirationDateConfirmBtn").on("click", function () {
var fp = $("#to").flatpickr();
var expiryDate = $(
"select" + category_selector + " option:selected"
).data("expiryDate");
// Check if expiryDate is available and format it to YYYY-MM-DD
if (expiryDate) {
var formattedDate = expiryDate.split("T")[0];
fp.setDate(formattedDate);
}
$("#expirationDateModal").modal("hide");
});
});
}
function select_user(borrowernumber, borrower, relationship) {

View File

@ -5,68 +5,98 @@ $(document).ready(function () {
});
if (window.location.href.indexOf("op=add") === -1) {
message_prefs_dirty = true; // unless op=add consider the message prefs dirty
message_prefs_dirty = true;
}
if ($("#messaging_prefs_loading").length) {
// This element only appears in the template if op=add
$("#categorycode_entry").change(function () {
var messaging_prefs_loading = $("#messaging_prefs_loading");
// Upon selecting a new patron category, show "Loading" message for messaging defaults
messaging_prefs_loading.show();
var categorycode = $(this).val();
if (message_prefs_dirty) {
if (
!confirm(
__(
"Change messaging preferences to default for this category?"
)
)
) {
// Not loading messaging defaults. Hide loading indicator
messaging_prefs_loading.hide();
return;
}
}
var jqxhr = $.getJSON(
"/cgi-bin/koha/members/default_messageprefs.pl?categorycode=" +
categorycode,
function (data) {
$.each(data.messaging_preferences, function (i, item) {
var attrid = item.message_attribute_id;
var transports = ["email", "rss", "sms"];
$.each(transports, function (j, transport) {
if (item["transports_" + transport] == 1) {
$("#" + transport + attrid).prop(
"checked",
true
// Show the combined modal and reset checkboxes to checked
$("#categoryChangeUpdateMessaging").prop("checked", true);
$("#categoryChangeUpdateExpiry").prop("checked", true);
$("#categoryChangeModal").modal("show");
// Remove any previously bound confirm handler to avoid stacking
$("#categoryChangeConfirmBtn")
.off("click")
.on("click", function () {
$("#categoryChangeModal").modal("hide");
// --- Update messaging preferences ---
if (
$("#categoryChangeUpdateMessaging").prop("checked") &&
message_prefs_dirty
) {
var messaging_prefs_loading = $(
"#messaging_prefs_loading"
);
messaging_prefs_loading.show();
$.getJSON(
"/cgi-bin/koha/members/default_messageprefs.pl?categorycode=" +
categorycode,
function (data) {
$.each(
data.messaging_preferences,
function (i, item) {
var attrid = item.message_attribute_id;
var transports = [
"email",
"rss",
"sms",
];
$.each(
transports,
function (j, transport) {
var checked =
item[
"transports_" +
transport
] == 1;
$(
"#" + transport + attrid
).prop("checked", checked);
toggle_digest(attrid);
}
);
if (item.digest && item.digest != " ") {
$("#digest" + attrid).prop(
"checked",
true
);
} else {
$("#digest" + attrid).prop(
"checked",
false
);
}
if (item.takes_days == "1") {
$("[name=" + attrid + "-DAYS]").val(
"" + item.days_in_advance
);
}
}
);
toggle_digest(attrid);
} else {
$("#" + transport + attrid).prop(
"checked",
false
);
toggle_digest(attrid);
message_prefs_dirty = false;
}
).always(function () {
messaging_prefs_loading.hide();
});
if (item.digest && item.digest != " ") {
$("#digest" + attrid).prop("checked", true);
} else {
$("#digest" + attrid).prop("checked", false);
}
// --- Update expiry date ---
if ($("#categoryChangeUpdateExpiry").prop("checked")) {
var fp = $("#to").flatpickr();
var expiryDate = $(
"select" + category_selector + " option:selected"
).data("expiryDate");
if (expiryDate) {
var formattedDate = expiryDate.split("T")[0];
fp.setDate(formattedDate);
}
if (item.takes_days == "1") {
$("[name=" + attrid + "-DAYS]").val(
"" + item.days_in_advance
);
}
});
message_prefs_dirty = false;
}
).always(function () {
// Loaded messaging defaults. Hide loading indicator
messaging_prefs_loading.hide();
});
}
});
});
}
@ -91,12 +121,11 @@ $(document).ready(function () {
.tooltip("enable");
}
}
// At load time, we want digest disabled if no digest using transport is enabled
$(".pmp_email").each(function () {
toggle_digest(Number($(this).attr("id").replace("email", "")));
});
// If user clears all digest using transports for a notice, disable digest checkbox
$(".pmp_email").click(function () {
toggle_digest(Number($(this).attr("id").replace("email", "")));
});