Add worker checkboxes and help text to shift timetable for improved usability
This commit is contained in:
+99
-30
@@ -382,17 +382,6 @@ oshifts.forEach((shift, i) => {
|
|||||||
$("#shift-timetable-options").append(
|
$("#shift-timetable-options").append(
|
||||||
`<button id="toggle-grid-view" style="margin-left:10px;">Toggle Linear/Grid View</button><br/>`
|
`<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;
|
let gridViewEnabled = false;
|
||||||
|
|
||||||
@@ -494,32 +483,83 @@ function rgb2hex(rgb) {
|
|||||||
return "#ffe066";
|
return "#ffe066";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a worker filter input to the shift timetable section
|
// --- Add worker checkboxes to the shift timetable section ---
|
||||||
$("#shift-timetable-options").prepend(`
|
function renderWorkerCheckboxes() {
|
||||||
<div id="shift-timetable-worker-filter" style="margin-bottom:8px;">
|
// Get all unique worker names and IDs from the main table
|
||||||
<label for="worker-filter-input"><b>Filter workers:</b></label>
|
let workerList = [];
|
||||||
<input type="text" id="worker-filter-input" placeholder="Type to filter by name..." style="margin-left:4px; padding:2px 6px;"/>
|
$("table#main-table td.worker").each(function () {
|
||||||
</div>
|
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
|
// Build checkboxes
|
||||||
let workerFilterValue = "";
|
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
|
workerList.forEach(w => {
|
||||||
$("#worker-filter-input").on("input", function() {
|
html += `<label style="margin-right:8px;">
|
||||||
workerFilterValue = $(this).val().toLowerCase();
|
<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();
|
renderShiftTimetable();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Patch renderShiftTimetable to filter workers in both linear and grid views
|
// Patch renderShiftTimetable to filter workers in both linear and grid views
|
||||||
function renderShiftTimetable() {
|
function renderShiftTimetable() {
|
||||||
|
console.log("Render shift timetable");
|
||||||
|
console.log(workerFilterSet)
|
||||||
$("#shift-timetable-div").empty();
|
$("#shift-timetable-div").empty();
|
||||||
if (selectedShifts.size === 0) return;
|
if (selectedShifts.size === 0) return;
|
||||||
|
if (workerFilterSet.size === 0) return;
|
||||||
|
|
||||||
// Helper: returns true if worker name matches filter
|
// Helper: returns true if worker id matches filter set or set is empty (all)
|
||||||
function workerMatchesFilter(workerName) {
|
function workerMatchesFilter(workerId) {
|
||||||
if (!workerFilterValue) return true;
|
if (workerFilterSet.size === 0) return true;
|
||||||
return workerName.toLowerCase().includes(workerFilterValue);
|
return workerFilterSet.has(workerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gridViewEnabled) {
|
if (!gridViewEnabled) {
|
||||||
@@ -553,7 +593,8 @@ function renderShiftTimetable() {
|
|||||||
}).each((n, td) => {
|
}).each((n, td) => {
|
||||||
let workerTd = $(td).closest("tr").children("td:first");
|
let workerTd = $(td).closest("tr").children("td:first");
|
||||||
let workerName = workerTd.find("span.name").text().trim();
|
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 cell_shifts = $(td).attr("data-shift").split(",").map(s => s.trim());
|
||||||
let matchedShifts = Array.from(selectedShifts).filter(s => cell_shifts.includes(s));
|
let matchedShifts = Array.from(selectedShifts).filter(s => cell_shifts.includes(s));
|
||||||
let color = "#fff";
|
let color = "#fff";
|
||||||
@@ -590,9 +631,9 @@ function renderShiftTimetable() {
|
|||||||
let workerIdToName = {};
|
let workerIdToName = {};
|
||||||
$("table#main-table td.worker").each(function () {
|
$("table#main-table td.worker").each(function () {
|
||||||
let workerId = $(this).attr("data-worker-id");
|
let workerId = $(this).attr("data-worker-id");
|
||||||
if (workerId && !workerIds.includes(workerId)) {
|
|
||||||
let workerName = $(this).find("span.name").text().trim();
|
let workerName = $(this).find("span.name").text().trim();
|
||||||
if (workerMatchesFilter(workerName)) {
|
if (workerId && !workerIds.includes(workerId)) {
|
||||||
|
if (workerMatchesFilter(workerId)) {
|
||||||
workerIds.push(workerId);
|
workerIds.push(workerId);
|
||||||
workerIdToName[workerId] = workerName;
|
workerIdToName[workerId] = workerName;
|
||||||
}
|
}
|
||||||
@@ -650,6 +691,21 @@ function renderShiftTimetable() {
|
|||||||
$("#shift-timetable-div").append(gridTable);
|
$("#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
|
// Patch the timetable button logic to use renderShiftTimetable
|
||||||
oshifts.forEach((shift) => {
|
oshifts.forEach((shift) => {
|
||||||
let button = $(`<button data-shift='${shift}'>${shift}</button>`);
|
let button = $(`<button data-shift='${shift}'>${shift}</button>`);
|
||||||
@@ -676,6 +732,19 @@ oshifts.forEach((shift) => {
|
|||||||
|
|
||||||
$("#shift-timetable-options").append(button);
|
$("#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")
|
//$("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>")
|
// $("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>")
|
||||||
|
|||||||
Reference in New Issue
Block a user