Add worker checkboxes and help text to shift timetable for improved usability

This commit is contained in:
Ross
2025-08-12 11:43:53 +01:00
parent 0599586f47
commit d55b1d38ea
+99 -30
View File
@@ -382,17 +382,6 @@ oshifts.forEach((shift, i) => {
$("#shift-timetable-options").append(
`<button id="toggle-grid-view" style="margin-left:10px;">Toggle Linear/Grid View</button><br/>`
);
// Add help text to the shift timetable section
$("#shift-timetable-options").prepend(`
<details id="shift-timetable-help" style="margin-bottom:8px; font-size: 0.95em; color: #444;">
<summary><b>Shift Timetables Help:</b></summary>
<ul style="margin: 4px 0 0 18px; padding: 0;">
<li>Select one or more shifts below to view which workers are assigned on each day.</li>
<li>Use the colour pickers to customise shift colours in the timetable and main table.</li>
<li>Toggle between linear and grid view using the "Toggle Linear/Grid View" button.</li>
</ul>
</details>
`);
let gridViewEnabled = false;
@@ -494,32 +483,83 @@ function rgb2hex(rgb) {
return "#ffe066";
}
// Add a worker filter input to the shift timetable section
$("#shift-timetable-options").prepend(`
<div id="shift-timetable-worker-filter" style="margin-bottom:8px;">
<label for="worker-filter-input"><b>Filter workers:</b></label>
<input type="text" id="worker-filter-input" placeholder="Type to filter by name..." style="margin-left:4px; padding:2px 6px;"/>
</div>
`);
// --- Add worker checkboxes to the shift timetable section ---
function renderWorkerCheckboxes() {
// Get all unique worker names and IDs from the main table
let workerList = [];
$("table#main-table td.worker").each(function () {
let workerId = $(this).attr("data-worker-id");
let workerName = $(this).find("span.name").text().trim();
if (workerId && !workerList.some(w => w.id === workerId)) {
workerList.push({ id: workerId, name: workerName });
}
});
// Store the current filter value
let workerFilterValue = "";
// Build checkboxes
let html = `<details id="shift-timetable-worker-filter" style="margin-bottom:8px;">
<summary><b>Show workers:</b></summary>`;
// Add a "Toggle All" button
html += `<button type="button" id="toggle-all-workers" style="margin-right:10px;">Toggle All</button>`;
// Update the filter value on input
$("#worker-filter-input").on("input", function() {
workerFilterValue = $(this).val().toLowerCase();
workerList.forEach(w => {
html += `<label style="margin-right:8px;">
<input type="checkbox" name="worker-filter-checkbox" value="${w.id}" checked> ${w.name}
</label>`;
});
// Attach toggle logic after DOM insertion
setTimeout(() => {
$("#toggle-all-workers").off("click").on("click", function() {
const $checkboxes = $("input[name='worker-filter-checkbox']");
const allChecked = $checkboxes.length === $checkboxes.filter(":checked").length;
$checkboxes.prop("checked", !allChecked);
// Update the filter set and re-render once, instead of triggering "change" for each
workerFilterSet = new Set(
Array.from(document.querySelectorAll("input[name='worker-filter-checkbox']:checked"))
.map(cb => cb.value)
);
// Call your function here after the map has finished
renderShiftTimetable();
});
}, 0);
html += `</details>`;
// Prepend to the shift timetable options
$("#shift-timetable-options").prepend(html);
}
// Store the current filter value (set of workerIds)
let workerFilterSet = new Set();
// Call this after the DOM is ready and after timetable is rendered
renderWorkerCheckboxes();
// On first render, select all workers by default
$("input[name='worker-filter-checkbox']").each(function() {
workerFilterSet.add($(this).val());
});
renderShiftTimetable();
// Update the filter set on checkbox change
$(document).on("change", "input[name='worker-filter-checkbox']", function() {
workerFilterSet = new Set(
$("input[name='worker-filter-checkbox']:checked").map(function() { return $(this).val(); }).get()
);
renderShiftTimetable();
});
// Patch renderShiftTimetable to filter workers in both linear and grid views
function renderShiftTimetable() {
console.log("Render shift timetable");
console.log(workerFilterSet)
$("#shift-timetable-div").empty();
if (selectedShifts.size === 0) return;
if (workerFilterSet.size === 0) return;
// Helper: returns true if worker name matches filter
function workerMatchesFilter(workerName) {
if (!workerFilterValue) return true;
return workerName.toLowerCase().includes(workerFilterValue);
// Helper: returns true if worker id matches filter set or set is empty (all)
function workerMatchesFilter(workerId) {
if (workerFilterSet.size === 0) return true;
return workerFilterSet.has(workerId);
}
if (!gridViewEnabled) {
@@ -553,7 +593,8 @@ function renderShiftTimetable() {
}).each((n, td) => {
let workerTd = $(td).closest("tr").children("td:first");
let workerName = workerTd.find("span.name").text().trim();
if (!workerMatchesFilter(workerName)) return;
let workerId = workerTd.attr("data-worker-id");
if (!workerMatchesFilter(workerId)) return;
let cell_shifts = $(td).attr("data-shift").split(",").map(s => s.trim());
let matchedShifts = Array.from(selectedShifts).filter(s => cell_shifts.includes(s));
let color = "#fff";
@@ -590,9 +631,9 @@ function renderShiftTimetable() {
let workerIdToName = {};
$("table#main-table td.worker").each(function () {
let workerId = $(this).attr("data-worker-id");
let workerName = $(this).find("span.name").text().trim();
if (workerId && !workerIds.includes(workerId)) {
let workerName = $(this).find("span.name").text().trim();
if (workerMatchesFilter(workerName)) {
if (workerMatchesFilter(workerId)) {
workerIds.push(workerId);
workerIdToName[workerId] = workerName;
}
@@ -650,6 +691,21 @@ function renderShiftTimetable() {
$("#shift-timetable-div").append(gridTable);
}
// Re-render worker checkboxes after timetable is updated (in case workers change)
function rerenderWorkerCheckboxesIfNeeded() {
$("#shift-timetable-worker-filter").remove();
renderWorkerCheckboxes();
// Restore checked state
$("input[name='worker-filter-checkbox']").each(function() {
if (workerFilterSet.has($(this).val())) {
$(this).prop("checked", true);
}
});
}
// Call this after timetable is (re)rendered if needed
rerenderWorkerCheckboxesIfNeeded();
// Patch the timetable button logic to use renderShiftTimetable
oshifts.forEach((shift) => {
let button = $(`<button data-shift='${shift}'>${shift}</button>`);
@@ -676,6 +732,19 @@ oshifts.forEach((shift) => {
$("#shift-timetable-options").append(button);
});
// Add help text to the shift timetable section
$("#shift-timetable-options").prepend(`
<details id="shift-timetable-help" style="margin-bottom:8px; font-size: 0.95em; color: #444;">
<summary><b>Shift Timetables Help:</b></summary>
<ul style="margin: 4px 0 0 18px; padding: 0;">
<li>Select one or more shifts below to view which workers are assigned on each day.</li>
<li>Use the colour pickers to customise shift colours in the timetable and main table.</li>
<li>Toggle between linear and grid view using the "Toggle Linear/Grid View" button.</li>
</ul>
</details>
`);
//$("table.summary")
// $("body").prepend("<div id='global-settings'>Settings:<br />Customise training days lost per shift (you need to press recalculate for changes to take effect)<form></form></div>")