Files
Meeting-Mixer/js/excel.js
T
ferdi2goandClaude Opus 4.8 fd9870871b refactor: centralize shared date/name helpers in utils.js (#12)
New js/utils.js exports toISO, monthPrefix, getWeekday, formatDateDE and
buildNameMap. algorithm.js, calendar.js, excel.js and history.js now import
these instead of re-implementing ISO construction, weekday math, DD.MM.YYYY
formatting and the id→name map inline. Adds tests/utils.test.mjs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 13:01:28 +00:00

58 lines
2.2 KiB
JavaScript

import { formatDateDE, buildNameMap } from './utils.js';
// Reads employee names from first column of xlsx (skips header row 0)
export function readEmployeeNames(arrayBuffer) {
const wb = XLSX.read(arrayBuffer, { type: 'array' });
const sheet = wb.Sheets[wb.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 });
return rows.slice(1)
.map(row => String(row[0] ?? '').trim())
.filter(name => name.length > 0);
}
// Neutralize spreadsheet formula injection: Excel/Sheets treat a cell starting
// with = + - @ (or certain control chars) as a formula. Prefix such values with
// an apostrophe so they render as literal text.
export function sanitizeCell(value) {
const s = String(value ?? '');
return /^[=+\-@\t\r]/.test(s) ? "'" + s : s;
}
// Pure helper: returns { names: [...], dates: [...] } columns for a schedule.
// Multiple employees per date are joined alphabetically with " & ".
export function buildScheduleColumns(assignments, employees) {
const nameById = buildNameMap(employees);
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 =>
sanitizeCell(byDate.get(d).slice().sort((x, y) => x.localeCompare(y, 'de')).join(' & '))
);
const dates = sortedDates.map(formatDateDE);
return { names, dates };
}
// Exports schedule as xlsx blob
// assignments: [{ date: "2026-04-01", employeeId }] — multiple entries per date allowed
// employees: [{ id, name }]
export function exportSchedule(assignments, employees) {
const { names, dates } = buildScheduleColumns(assignments, employees);
const ws = XLSX.utils.aoa_to_sheet([names, dates]);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Moderationsplan');
const buf = XLSX.write(wb, { type: 'array', bookType: 'xlsx' });
return new Blob([buf], { type: 'application/octet-stream' });
}
export function downloadBlob(blob, filename) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}