File size: 4,926 Bytes
9bc2f29 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | 'use client';
import { useCallback } from 'react';
export type NoteExportFormat = 'pdf' | 'docx' | 'txt';
export function useNoteExport() {
// Export to plain text
const exportToText = useCallback((noteText: string): void => {
downloadFile(
noteText,
`clinical-note-${new Date().toISOString().split('T')[0]}.txt`,
'text/plain'
);
}, []);
// Export to PDF (using print dialog)
const exportToPDF = useCallback((noteText: string): void => {
const printWindow = window.open('', '', 'width=800,height=600');
if (!printWindow) {
alert('Please allow popups to export to PDF');
return;
}
const html = generatePrintHTML(noteText);
printWindow.document.write(html);
printWindow.document.close();
printWindow.onload = () => {
printWindow.focus();
printWindow.print();
};
}, []);
// Export to DOCX (using docx library)
const exportToDocx = useCallback(async (noteText: string): Promise<void> => {
const { Document, Packer, Paragraph, TextRun, AlignmentType } = await import('docx');
// Split text into paragraphs
const paragraphs = noteText.split('\n').map(line =>
new Paragraph({
children: [
new TextRun({
text: line || ' ', // Add space for empty lines to preserve spacing
font: 'Arial',
size: 22, // 11pt in half-points
}),
],
spacing: {
after: 200, // spacing after paragraph
},
})
);
// Create document with header
const doc = new Document({
sections: [{
properties: {},
children: [
new Paragraph({
children: [
new TextRun({
text: 'Clinical Note',
bold: true,
font: 'Arial',
size: 28, // 14pt in half-points
}),
],
alignment: AlignmentType.CENTER,
spacing: {
after: 400,
},
}),
...paragraphs,
],
}],
});
// Generate and download
const blob = await Packer.toBlob(doc);
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `clinical-note-${new Date().toISOString().split('T')[0]}.docx`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, []);
// Main export function
const exportNote = useCallback(
async (format: NoteExportFormat, noteText: string) => {
if (!noteText.trim()) {
return;
}
switch (format) {
case 'txt':
exportToText(noteText);
break;
case 'pdf':
exportToPDF(noteText);
break;
case 'docx':
await exportToDocx(noteText);
break;
}
},
[exportToText, exportToPDF, exportToDocx]
);
return { exportNote };
}
// Utility function to download file
function downloadFile(content: string, filename: string, mimeType: string) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
// Generate print-friendly HTML for PDF export
function generatePrintHTML(noteText: string): string {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Clinical Note</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
@page {
size: letter;
margin: 1in;
}
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.6;
color: #000;
padding: 2rem;
max-width: 8.5in;
margin: 0 auto;
}
.header {
text-align: center;
font-size: 14pt;
font-weight: bold;
color: #000;
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 2px solid #ccc;
}
.note-content {
white-space: pre-wrap;
word-wrap: break-word;
font-family: Arial, Helvetica, sans-serif;
font-size: 11pt;
line-height: 1.6;
}
.footer {
margin-top: 3rem;
padding-top: 1rem;
border-top: 1px solid #e5e7eb;
text-align: center;
color: #9ca3af;
font-size: 0.875rem;
}
@media print {
body { padding: 0; }
}
</style>
</head>
<body>
<div class="header">Clinical Note</div>
<div class="note-content">${escapeHtml(noteText)}</div>
<div class="footer">
Generated on ${new Date().toLocaleDateString()} • Clinical Error Detector
</div>
</body>
</html>
`;
}
function escapeHtml(text: string): string {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
|