diff --git a/js/calendar.js b/js/calendar.js index 57d1502..6329128 100644 --- a/js/calendar.js +++ b/js/calendar.js @@ -140,8 +140,18 @@ function renderGrid(wrapper, exportBtn) { wrapper.replaceChildren(); const daysInMonth = new Date(currentYear, currentMonth, 0).getDate(); - const nameById = Object.fromEntries(state.employees.map(e => [e.id, e.name])); - const planByDate = Object.fromEntries(currentPlan.map(a => [a.date, a.employeeId])); + const empNameById = Object.fromEntries(state.employees.map(e => [e.id, e.name])); + const entriesByDate = {}; + for (const a of currentPlan) { + if (!entriesByDate[a.date]) entriesByDate[a.date] = []; + entriesByDate[a.date].push(a); + } + // Sort each date's entries alphabetically by employee name (stable slot order) + for (const date of Object.keys(entriesByDate)) { + entriesByDate[date].sort((x, y) => + (empNameById[x.employeeId] ?? '').localeCompare(empNameById[y.employeeId] ?? '', 'de') + ); + } // Day-of-week header row const headerGrid = document.createElement('div'); @@ -174,7 +184,6 @@ function renderGrid(wrapper, exportBtn) { const isWeekend = wdNum >= 6; const isHoliday = state.calendar.holidays.includes(iso); const isClosure = state.calendar.companyClosures.includes(iso); - const assigneeId = planByDate[iso]; const cell = document.createElement('div'); cell.className = 'cal-day'; @@ -210,38 +219,52 @@ function renderGrid(wrapper, exportBtn) { tag.appendChild(removeBtn); cell.appendChild(tag); } else { - // Assignee dropdown - const sel = document.createElement('select'); - - const emptyOpt = document.createElement('option'); - emptyOpt.value = ''; - emptyOpt.textContent = '— Leer —'; - sel.appendChild(emptyOpt); - - for (const emp of state.employees) { - const opt = document.createElement('option'); - opt.value = emp.id; - opt.textContent = emp.name; // textContent: safe - if (emp.id === assigneeId) opt.selected = true; - sel.appendChild(opt); + // N slots per day + const slotCount = state.settings.moderatorsPerDay; + const dayEntries = entriesByDate[iso] ?? []; // already alphabetically sorted + const slotValues = []; // employeeId per slot index, '' if empty + for (let s = 0; s < slotCount; s++) { + slotValues.push(dayEntries[s]?.employeeId ?? ''); } - sel.addEventListener('change', () => { - const empId = sel.value; - if (empId) { - const entry = { date: iso, employeeId: empId, manual: true }; - addHistoryEntries(state, [entry]); - const idx = currentPlan.findIndex(a => a.date === iso); - if (idx >= 0) currentPlan[idx] = entry; else currentPlan.push(entry); - } else { - removeHistoryEntry(state, iso); - currentPlan = currentPlan.filter(a => a.date !== iso); - } - saveState(); - exportBtn.style.display = currentPlan.length > 0 ? 'inline-block' : 'none'; - }); + for (let slotIdx = 0; slotIdx < slotCount; slotIdx++) { + const sel = document.createElement('select'); + sel.dataset.slot = String(slotIdx); - cell.appendChild(sel); + const emptyOpt = document.createElement('option'); + emptyOpt.value = ''; + emptyOpt.textContent = '— Leer —'; + sel.appendChild(emptyOpt); + + for (const emp of state.employees) { + const opt = document.createElement('option'); + opt.value = emp.id; + opt.textContent = emp.name; // textContent: safe + // Disable if already picked in a different slot for this day + const pickedElsewhere = slotValues.some((id, i) => i !== slotIdx && id === emp.id); + if (pickedElsewhere) opt.disabled = true; + if (emp.id === slotValues[slotIdx]) opt.selected = true; + sel.appendChild(opt); + } + + sel.addEventListener('change', () => { + const newId = sel.value; + const oldId = slotValues[slotIdx]; + if (oldId) { + removeHistoryEntry(state, iso, oldId); + currentPlan = currentPlan.filter(a => !(a.date === iso && a.employeeId === oldId)); + } + if (newId) { + const entry = { date: iso, employeeId: newId, manual: true }; + addHistoryEntries(state, [entry]); + currentPlan.push(entry); + } + saveState(); + renderGrid(wrapper, exportBtn); + }); + + cell.appendChild(sel); + } // FT / BU mark buttons const btnRow = document.createElement('div');