/** Task work sheet (v2.21) — a printable one-pager for a single task. * * Everything needed to actually DO the task, on one sheet of paper: object * + task details, the checklist as real tick boxes, the notes, and a QR * pair (open the task / complete it) so the paper links back to the panel. * When the task has a linked PDF manual with a page hint, the manual * excerpt pages are rendered INLINE (downscaled, two per row) via the * vendored pdf.js legacy build — the whole work sheet prints as one * document. The PDF link stays as the fallback when rendering fails. * * Mirrors helpers/report.ts: pure function building a self-contained HTML * document; the panel opens it in a new tab where the user prints or saves * as PDF. All user strings are escaped; labels arrive translated. */ import type { MaintenanceTask } from "../types"; export interface WorksheetLabels { title: string; // "Work sheet" object: string; type: string; interval: string; nextDue: string; lastDone: string; priority: string; checklist: string; notes: string; parts: string; // "Required parts" scanView: string; // "Scan to open the task" scanComplete: string; // "Scan to complete" manualExcerpt: string; // "Manual excerpt" pages: string; // "pages" printedOn: string; // "Printed" never: string; typeLabel: (t: string) => string; statusLabel: (s: string) => string; } export interface WorksheetExcerpt { title: string; startPage: number; endPage: number; url: string; // signed excerpt-endpoint URL (absolute) /** Absolute base URL of the vendored pdf.js assets; when set, the sheet * renders the excerpt pages inline (downscaled 2-up) via pdf.js. */ vendorBase?: string; } const esc = (v: unknown): string => String(v ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c] as string); export function buildTaskWorksheetHtml( task: MaintenanceTask, objectName: string, L: WorksheetLabels, formatDate: (iso: string) => string, formatRecurrence: (task: MaintenanceTask) => string, qrViewDataUri: string | null, qrCompleteDataUri: string | null, excerpt: WorksheetExcerpt | null, nowIso: string, partsLines: string[] = [], ): string { const meta: Array<[string, string]> = [ [L.object, esc(objectName)], [L.type, esc(L.typeLabel(task.type))], [L.interval, esc(formatRecurrence(task))], [L.nextDue, task.next_due ? esc(formatDate(task.next_due)) : "—"], [L.lastDone, task.last_performed ? esc(formatDate(task.last_performed)) : esc(L.never)], ]; if (task.priority && task.priority !== "normal") { meta.push([L.priority, esc(task.priority)]); } const checklist = (task.checklist || []) .map((item) => `
| ${esc(k)} | ${v} |