Files
repair-cafe-kanban/lib/csv.js
T
travandClaude Opus 5 d1cb472696 Initial commit: repair cafe kanban board
A per-event queue board for a repair cafe. Customers sign items in on a
shared tablet; volunteers drag repairs through Queue, In progress and Done
on a dashboard, then export the day's records as CSV.

Zero npm dependencies: node:http plus JSON files on disk, no build step.
Categories and house rules are set in config.json. Events are deleted
7 days after creation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 15:02:45 -04:00

67 lines
1.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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 };