| 'use client'; |
|
|
| import { useCallback } from 'react'; |
|
|
| export type NoteExportFormat = 'pdf' | 'docx' | 'txt'; |
|
|
| export function useNoteExport() { |
| |
| const exportToText = useCallback((noteText: string): void => { |
| downloadFile( |
| noteText, |
| `clinical-note-${new Date().toISOString().split('T')[0]}.txt`, |
| 'text/plain' |
| ); |
| }, []); |
|
|
| |
| 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(); |
| }; |
| }, []); |
|
|
| |
| const exportToDocx = useCallback(async (noteText: string): Promise<void> => { |
| const { Document, Packer, Paragraph, TextRun, AlignmentType } = await import('docx'); |
|
|
| |
| const paragraphs = noteText.split('\n').map(line => |
| new Paragraph({ |
| children: [ |
| new TextRun({ |
| text: line || ' ', |
| font: 'Arial', |
| size: 22, |
| }), |
| ], |
| spacing: { |
| after: 200, |
| }, |
| }) |
| ); |
|
|
| |
| const doc = new Document({ |
| sections: [{ |
| properties: {}, |
| children: [ |
| new Paragraph({ |
| children: [ |
| new TextRun({ |
| text: 'Clinical Note', |
| bold: true, |
| font: 'Arial', |
| size: 28, |
| }), |
| ], |
| alignment: AlignmentType.CENTER, |
| spacing: { |
| after: 400, |
| }, |
| }), |
| ...paragraphs, |
| ], |
| }], |
| }); |
|
|
| |
| 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); |
| }, []); |
|
|
| |
| 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 }; |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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; |
| } |
|
|