/** Self-contained printable maintenance report for one object. * * Produces a full HTML document (inline print CSS) that the panel opens in a new * tab via a Blob URL — the user then prints or "Save as PDF" from the browser. * No PDF dependency, works offline. All user content is HTML-escaped. */ import type { MaintenanceObject, MaintenanceTask } from "../types"; export interface ReportLabels { title: string; generated: string; manufacturer: string; model: string; serial: string; installed: string; warranty: string; area: string; notes: string; tasksHeading: string; colTask: string; colType: string; colStatus: string; colSchedule: string; colLastDone: string; colNextDue: string; colCost: string; colTimes: string; totalCost: string; /** Human schedule label for a task — pass formatRecurrence so calendar * kinds (weekdays/nth_weekday/…) render properly, not just intervals. */ scheduleLabel: (t: MaintenanceTask) => string; statusLabel: (s: string) => string; typeLabel: (t: string) => string; none: string; } function esc(v: unknown): string { return String(v ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c] as string)); } export function buildObjectReportHtml( obj: MaintenanceObject, tasks: MaintenanceTask[], labels: ReportLabels, fmtDate: (iso: string | null | undefined) => string, currencySymbol: string, nowIso: string, ): string { const meta = ([ [labels.manufacturer, obj.manufacturer], [labels.model, obj.model], [labels.serial, obj.serial_number], [labels.installed, obj.installation_date ? fmtDate(obj.installation_date) : null], [labels.warranty, obj.warranty_expiry ? fmtDate(obj.warranty_expiry) : null], ] as Array<[string, string | null | undefined]>).filter(([, v]) => !!v); const rows = tasks.map((t) => { const schedule = labels.scheduleLabel(t); return `
${esc(labels.title)} · ${esc(labels.generated)}: ${esc(fmtDate(nowIso))}
${meta.length ? `` : ""}| ${esc(labels.colTask)} | ${esc(labels.colType)} | ${esc(labels.colStatus)} | ${esc(labels.colSchedule)} | ${esc(labels.colLastDone)} | ${esc(labels.colNextDue)} | ${esc(labels.colTimes)} | ${esc(labels.colCost)} |
|---|---|---|---|---|---|---|---|
| ${esc(labels.none)} | |||||||
| ${esc(labels.totalCost)} | ${totalCost.toFixed(2)} ${esc(currencySymbol)} | ||||||