/* * CSV and attachment export module (F2). Generates a CSV file from the current * report's answers and allows downloading individual attachments. XLSX and ZIP * export can be added by integrating SheetJS and JSZip libraries. */ import { state, getCurrentReport, getTemplateRecord } from './state.js'; import { dbGetAllByIndex } from './db.js'; import { STORE_ATTACHMENTS } from './constants.js'; /* * Exports the active report as a CSV file. Columns are derived from the template * definition so field labels appear as headers and field values as the row. */ export async function exportReportCSV() { const report = getCurrentReport(); if (!report) { throw new Error('No report to export'); } const template = getTemplateRecord(report.templateCode, report.templateVersion); if (!template) { throw new Error('Template definition needed for export'); } const headers = []; const values = []; /* Meta columns. */ headers.push('Report Number', 'Template', 'Version', 'Status', 'Created', 'Updated'); values.push( report.reportNumber, report.templateCode, String(report.templateVersion), report.status, report.createdAt, report.updatedAt ); /* Dynamic field columns derived from the template definition. */ for (const section of template.definition.sections || []) { for (const field of section.fields || []) { if (field.type === 'attachment') { continue; } headers.push(field.label); const raw = report.answers[field.id]; values.push(raw === undefined || raw === null ? '' : String(raw)); } } const csvContent = [ headers.map(csvEscape).join(','), values.map(csvEscape).join(',') ].join('\r\n'); downloadBlob( new Blob([csvContent], { type: 'text/csv;charset=utf-8' }), `${report.reportNumber || 'report'}.csv` ); } /* * Exports all attachments for the active report as individual file downloads. * A future iteration could bundle these into a ZIP archive using JSZip. */ export async function exportReportAttachments() { const report = getCurrentReport(); if (!report) { throw new Error('No report to export'); } const attachments = await dbGetAllByIndex(STORE_ATTACHMENTS, 'byReportId', report.id); for (const attachment of attachments) { downloadBlob(attachment.blob, attachment.generatedFilename); } } /* ── Helpers ────────────────────────────────────────────────────────────── */ function csvEscape(value) { const str = String(value).replace(/"/g, '""'); return /[",\r\n]/.test(str) ? `"${str}"` : str; } function downloadBlob(blob, filename) { const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; document.body.appendChild(anchor); anchor.click(); anchor.remove(); URL.revokeObjectURL(url); }