fix(absences): team filter reads worker ID from <input> value, not data-attr
Konrad reported that selecting a team on /absences/log/ hid ALL workers, not just non-team. Root cause: the JS read row.dataset.workerId to filter, which depends on how Django renders choice_value for ModelMultipleChoiceField iteration — not reliable. Switched to read the actual <input name='workers'> value attribute, matching the attendance_log's proven pattern. Same UX intent (hide non-team workers); more robust implementation. Also uses an O(1) object lookup instead of array.indexOf, and adds defensive fallback for both string and numeric team-id keys.
This commit is contained in:
parent
7d4d7b1f8b
commit
4368e53d95
@ -156,6 +156,17 @@ them from the WorkLog).
|
||||
// re-runs the combined visibility pass via applyWorkerFilters().
|
||||
//
|
||||
// Empty selection in either filter = "no restriction" for that filter.
|
||||
//
|
||||
// IMPLEMENTATION NOTE: we read the worker's id from the inner
|
||||
// <input name="workers"> value attribute, NOT from data-worker-id on
|
||||
// the row div. This matches the attendance form's proven pattern and
|
||||
// avoids brittleness around how Django renders choice_value for
|
||||
// ModelMultipleChoiceField iteration.
|
||||
//
|
||||
// REGRESSION: this used to read data-worker-id, which silently hid
|
||||
// all workers in some renders. Reading from input[name="workers"]
|
||||
// value is the same pattern attendance_log.html uses and is proven.
|
||||
// See 7d4d7b1+ Konrad's bug report on production.
|
||||
(function() {
|
||||
var searchInput = document.getElementById('workerSearch');
|
||||
var teamSelect = document.querySelector('[name="team"]');
|
||||
@ -166,18 +177,33 @@ them from the WorkLog).
|
||||
function applyWorkerFilters() {
|
||||
var q = searchInput ? searchInput.value.toLowerCase() : '';
|
||||
var teamId = teamSelect ? teamSelect.value : '';
|
||||
// Workers allowed by the team filter — null means "no team filter".
|
||||
var allowedWorkerIds = null;
|
||||
if (teamId && teamWorkersMap[teamId]) {
|
||||
// Stringify so we can compare against data-worker-id (which is a string).
|
||||
allowedWorkerIds = teamWorkersMap[teamId].map(function(id) { return String(id); });
|
||||
|
||||
// Build allowed set as STRINGS (matching DOM input.value strings).
|
||||
// null means "no team filter applied" (show everyone).
|
||||
var allowedSet = null;
|
||||
if (teamId) {
|
||||
// Defensive fallback: object keys are always strings in JS, but
|
||||
// be explicit about handling both raw and stringified keys just
|
||||
// in case the JSON payload ever changes shape.
|
||||
var teamWorkers = teamWorkersMap[teamId] || teamWorkersMap[String(teamId)];
|
||||
if (teamWorkers) {
|
||||
allowedSet = {};
|
||||
teamWorkers.forEach(function(id) { allowedSet[String(id)] = true; });
|
||||
} else {
|
||||
// Team key not in map — show no one (defensive)
|
||||
allowedSet = {};
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.worker-row').forEach(function(row) {
|
||||
var name = row.dataset.name || '';
|
||||
var wid = row.dataset.workerId || '';
|
||||
// Visible only if BOTH conditions pass.
|
||||
var matchesSearch = name.indexOf(q) > -1;
|
||||
var matchesTeam = (allowedWorkerIds === null) || (allowedWorkerIds.indexOf(wid) > -1);
|
||||
// Read worker id from the actual checkbox input — proven reliable.
|
||||
var input = row.querySelector('input[name="workers"]');
|
||||
var wid = input ? String(input.value) : '';
|
||||
|
||||
var matchesSearch = q === '' || name.indexOf(q) > -1;
|
||||
var matchesTeam = (allowedSet === null) || (allowedSet[wid] === true);
|
||||
|
||||
row.style.display = (matchesSearch && matchesTeam) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user