'use strict'; const COLUMNS = [ 'event', 'date/time added', 'customer', 'item', 'category', 'problem', 'status', 'repairer', 'outcome', 'tools/consumables', 'notes', ]; // Quote a field if it contains anything that would break the row, doubling any // quotes inside it. Everything else goes out bare. function escapeField(value) { const text = value === null || value === undefined ? '' : String(value); if (/[",\r\n]/.test(text)) return '"' + text.replace(/"/g, '""') + '"'; return text; } function row(fields) { return fields.map(escapeField).join(','); } // "2026-08-15 17:14" in the server's timezone — spreadsheets read that as a // date, which a raw UTC ISO string does not. function localDateTime(iso) { const d = new Date(iso); if (Number.isNaN(d.getTime())) return iso; const pad = (n) => String(n).padStart(2, '0'); return ( `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ` + `${pad(d.getHours())}:${pad(d.getMinutes())}` ); } function repairRows(event) { return event.repairs.map((r) => row([ event.name, localDateTime(r.createdAt), r.customer, r.item, r.category, r.problem, r.status, r.repairer, r.outcome, r.toolsUsed, (r.notes || []).map((n) => n.text).join(' | '), ]) ); } // A leading BOM so Excel reads it as UTF-8 rather than mangling accents. function toCsv(events) { const lines = [row(COLUMNS)]; for (const event of events) lines.push(...repairRows(event)); return '' + lines.join('\r\n') + '\r\n'; } module.exports = { toCsv, escapeField, COLUMNS };