feat(excel): group entries by date, join names with ' & '
This commit is contained in:
1 parent
ad680ae1f6
commit
69e424519d
3 files changed
+90
-8
No files matched your search
+22
-7
@@ -8,16 +8,31 @@ export function readEmployeeNames(arrayBuffer) {
|
|||||||
.filter(name => name.length > 0);
|
.filter(name => name.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pure helper: returns { names: [...], dates: [...] } columns for a schedule.
|
||||||
|
// Multiple employees per date are joined alphabetically with " & ".
|
||||||
|
export function buildScheduleColumns(assignments, employees) {
|
||||||
|
const nameById = Object.fromEntries(employees.map(e => [e.id, e.name]));
|
||||||
|
const byDate = new Map();
|
||||||
|
for (const a of assignments) {
|
||||||
|
if (!byDate.has(a.date)) byDate.set(a.date, []);
|
||||||
|
byDate.get(a.date).push(nameById[a.employeeId] ?? '');
|
||||||
|
}
|
||||||
|
const sortedDates = [...byDate.keys()].sort();
|
||||||
|
const names = sortedDates.map(d =>
|
||||||
|
byDate.get(d).slice().sort((x, y) => x.localeCompare(y, 'de')).join(' & ')
|
||||||
|
);
|
||||||
|
const dates = sortedDates.map(d => {
|
||||||
|
const [y, m, day] = d.split('-');
|
||||||
|
return day + '.' + m + '.' + y;
|
||||||
|
});
|
||||||
|
return { names, dates };
|
||||||
|
}
|
||||||
|
|
||||||
// Exports schedule as xlsx blob
|
// Exports schedule as xlsx blob
|
||||||
// assignments: [{ date: "2026-04-01", employeeId }]
|
// assignments: [{ date: "2026-04-01", employeeId }] — multiple entries per date allowed
|
||||||
// employees: [{ id, name }]
|
// employees: [{ id, name }]
|
||||||
export function exportSchedule(assignments, employees) {
|
export function exportSchedule(assignments, employees) {
|
||||||
const nameById = Object.fromEntries(employees.map(e => [e.id, e.name]));
|
const { names, dates } = buildScheduleColumns(assignments, employees);
|
||||||
const names = assignments.map(a => nameById[a.employeeId] ?? '');
|
|
||||||
const dates = assignments.map(a => {
|
|
||||||
const [y, m, d] = a.date.split('-');
|
|
||||||
return d + '.' + m + '.' + y;
|
|
||||||
});
|
|
||||||
const ws = XLSX.utils.aoa_to_sheet([names, dates]);
|
const ws = XLSX.utils.aoa_to_sheet([names, dates]);
|
||||||
const wb = XLSX.utils.book_new();
|
const wb = XLSX.utils.book_new();
|
||||||
XLSX.utils.book_append_sheet(wb, ws, 'Moderationsplan');
|
XLSX.utils.book_append_sheet(wb, ws, 'Moderationsplan');
|
||||||
|
|||||||
+1
-1
@@ -5,6 +5,6 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx serve . -p 3001",
|
"start": "npx serve . -p 3001",
|
||||||
"test": "node tests/algorithm.test.mjs && node tests/data.test.mjs"
|
"test": "node tests/algorithm.test.mjs && node tests/data.test.mjs && node tests/excel.test.mjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { buildScheduleColumns } from '../js/excel.js';
|
||||||
|
|
||||||
|
const employees = [
|
||||||
|
{ id: 'a1', name: 'Anna Müller' },
|
||||||
|
{ id: 'b1', name: 'Bernd Schulz' },
|
||||||
|
{ id: 'c1', name: 'Carla Weber' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Single employee per day
|
||||||
|
{
|
||||||
|
const assignments = [
|
||||||
|
{ date: '2026-04-01', employeeId: 'a1' },
|
||||||
|
{ date: '2026-04-02', employeeId: 'b1' }
|
||||||
|
];
|
||||||
|
const cols = buildScheduleColumns(assignments, employees);
|
||||||
|
assert.deepEqual(cols.names, ['Anna Müller', 'Bernd Schulz'], 'names per single-entry day');
|
||||||
|
assert.deepEqual(cols.dates, ['01.04.2026', '02.04.2026'], 'dates formatted DD.MM.YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two employees per day → joined with " & ", alphabetical
|
||||||
|
{
|
||||||
|
const assignments = [
|
||||||
|
{ date: '2026-04-01', employeeId: 'b1' }, // Bernd inserted first
|
||||||
|
{ date: '2026-04-01', employeeId: 'a1' } // Anna inserted second
|
||||||
|
];
|
||||||
|
const cols = buildScheduleColumns(assignments, employees);
|
||||||
|
assert.equal(cols.names.length, 1, 'one column per date');
|
||||||
|
assert.equal(cols.names[0], 'Anna Müller & Bernd Schulz', 'names alphabetical, joined with " & "');
|
||||||
|
assert.equal(cols.dates[0], '01.04.2026', 'one date entry');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Three employees per day
|
||||||
|
{
|
||||||
|
const assignments = [
|
||||||
|
{ date: '2026-04-01', employeeId: 'c1' },
|
||||||
|
{ date: '2026-04-01', employeeId: 'a1' },
|
||||||
|
{ date: '2026-04-01', employeeId: 'b1' }
|
||||||
|
];
|
||||||
|
const cols = buildScheduleColumns(assignments, employees);
|
||||||
|
assert.equal(cols.names[0], 'Anna Müller & Bernd Schulz & Carla Weber', 'three names joined alphabetical');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiple dates with multiple employees, dates ascending
|
||||||
|
{
|
||||||
|
const assignments = [
|
||||||
|
{ date: '2026-04-02', employeeId: 'a1' },
|
||||||
|
{ date: '2026-04-01', employeeId: 'b1' },
|
||||||
|
{ date: '2026-04-01', employeeId: 'a1' }
|
||||||
|
];
|
||||||
|
const cols = buildScheduleColumns(assignments, employees);
|
||||||
|
assert.deepEqual(cols.dates, ['01.04.2026', '02.04.2026'], 'dates sorted ascending');
|
||||||
|
assert.deepEqual(cols.names, ['Anna Müller & Bernd Schulz', 'Anna Müller'], 'names per column in date order');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown employeeId: empty string slot, sorted with other names
|
||||||
|
{
|
||||||
|
const assignments = [
|
||||||
|
{ date: '2026-04-01', employeeId: 'a1' },
|
||||||
|
{ date: '2026-04-01', employeeId: 'unknown' }
|
||||||
|
];
|
||||||
|
const cols = buildScheduleColumns(assignments, employees);
|
||||||
|
// Empty-string sorts before 'Anna Müller'
|
||||||
|
assert.equal(cols.names[0], ' & Anna Müller', 'unknown employee → empty string in join');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('All excel tests passed.');
|
||||||
Reference in new issue
Block a user