// EMR Page JavaScript // static/js/emr.js class EMRPage { constructor() { this.currentPatientId = null; this.currentPatient = null; this.emrEntries = []; this.filteredEntries = []; this.currentPage = 1; this.entriesPerPage = 20; this.init(); } async init() { this.setupEventListeners(); await this.loadPatientFromURL(); if (this.currentPatientId) { await this.loadEMRData(); await this.loadPatientStats(); } else { this.showEmptyState(); } } setupEventListeners() { // Refresh button document.getElementById('refreshBtn').addEventListener('click', () => { this.loadEMRData(); }); // Search button document.getElementById('searchBtn').addEventListener('click', () => { this.openSearchModal(); }); // Search input document.getElementById('searchInput').addEventListener('input', (e) => { this.filterEntries(e.target.value); }); // Filter selects document.getElementById('dateFilter').addEventListener('change', () => { this.applyFilters(); }); document.getElementById('typeFilter').addEventListener('change', () => { this.applyFilters(); }); // Tab buttons document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', (e) => { this.switchTab(e.target.dataset.tab); }); }); // Modal handlers this.setupModalHandlers(); // File upload handlers this.setupFileUploadHandlers(); } setupModalHandlers() { // EMR Detail Modal const emrDetailModal = document.getElementById('emrDetailModal'); const emrDetailModalClose = document.getElementById('emrDetailModalClose'); const emrDetailModalCancel = document.getElementById('emrDetailModalCancel'); if (emrDetailModalClose) { emrDetailModalClose.addEventListener('click', () => { emrDetailModal.classList.remove('show'); }); } if (emrDetailModalCancel) { emrDetailModalCancel.addEventListener('click', () => { emrDetailModal.classList.remove('show'); }); } // Search Modal const searchModal = document.getElementById('searchModal'); const searchModalClose = document.getElementById('searchModalClose'); const searchModalCancel = document.getElementById('searchModalCancel'); const performSearchBtn = document.getElementById('performSearchBtn'); if (searchModalClose) { searchModalClose.addEventListener('click', () => { searchModal.classList.remove('show'); }); } if (searchModalCancel) { searchModalCancel.addEventListener('click', () => { searchModal.classList.remove('show'); }); } if (performSearchBtn) { performSearchBtn.addEventListener('click', () => { this.performAdvancedSearch(); searchModal.classList.remove('show'); }); } // Document Preview Modal const documentPreviewModal = document.getElementById('documentPreviewModal'); const documentPreviewModalClose = document.getElementById('documentPreviewModalClose'); const documentPreviewCancel = document.getElementById('documentPreviewCancel'); const saveDocumentAnalysis = document.getElementById('saveDocumentAnalysis'); if (documentPreviewModalClose) { documentPreviewModalClose.addEventListener('click', () => { documentPreviewModal.classList.remove('show'); }); } if (documentPreviewCancel) { documentPreviewCancel.addEventListener('click', () => { documentPreviewModal.classList.remove('show'); }); } if (saveDocumentAnalysis) { saveDocumentAnalysis.addEventListener('click', () => { this.saveDocumentAnalysis(); }); } } setupFileUploadHandlers() { const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); const uploadBtn = document.getElementById('uploadBtn'); const uploadProgress = document.getElementById('uploadProgress'); // Click to upload if (uploadBtn) { uploadBtn.addEventListener('click', () => { fileInput.click(); }); } if (uploadArea) { uploadArea.addEventListener('click', () => { fileInput.click(); }); } // File input change if (fileInput) { fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { this.handleFileUpload(e.target.files); } }); } // Drag and drop if (uploadArea) { uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); if (e.dataTransfer.files.length > 0) { this.handleFileUpload(e.dataTransfer.files); } }); } } async loadPatientFromURL() { const urlParams = new URLSearchParams(window.location.search); const patientId = urlParams.get('patient_id'); // Check if patientId is valid (not undefined, null, or empty) if (patientId && patientId !== 'undefined' && patientId !== 'null' && patientId.trim() !== '') { this.currentPatientId = patientId; await this.loadPatientInfo(); } else { // Try to get from localStorage const savedPatientId = localStorage.getItem('medicalChatbotPatientId'); if (savedPatientId && savedPatientId !== 'undefined' && savedPatientId !== 'null' && savedPatientId.trim() !== '') { this.currentPatientId = savedPatientId; await this.loadPatientInfo(); } else { console.warn('No valid patient ID found in URL or localStorage'); this.showEmptyState(); } } } async loadPatientInfo() { try { const response = await fetch(`/patient/${this.currentPatientId}`); if (response.ok) { this.currentPatient = await response.json(); this.updatePatientInfoBar(); } else { console.error('Failed to load patient info'); this.showEmptyState(); } } catch (error) { console.error('Error loading patient info:', error); this.showEmptyState(); } } updatePatientInfoBar() { if (!this.currentPatient) return; const patientInfoBar = document.getElementById('patientInfoBar'); const patientName = document.getElementById('patientName'); const patientDetails = document.getElementById('patientDetails'); patientName.textContent = this.currentPatient.name; patientDetails.textContent = `Age: ${this.currentPatient.age} | Sex: ${this.currentPatient.sex} | ID: ${this.currentPatient._id}`; patientInfoBar.style.display = 'block'; } async loadPatientStats() { try { const response = await fetch(`/emr/statistics/${this.currentPatientId}`); if (response.ok) { const stats = await response.json(); this.updatePatientStats(stats); } } catch (error) { console.error('Error loading patient stats:', error); } } updatePatientStats(stats) { const patientStats = document.getElementById('patientStats'); patientStats.innerHTML = `
${stats.total_entries || 0}
Total Entries
${Math.round((stats.avg_confidence || 0) * 100)}%
Avg Confidence
${stats.diagnosis_count || 0}
Diagnoses
${stats.medication_count || 0}
Medications
`; } async loadEMRData() { if (!this.currentPatientId) return; this.showLoading(true); try { const response = await fetch(`/emr/patient/${this.currentPatientId}?limit=100`); if (response.ok) { this.emrEntries = await response.json(); this.filteredEntries = [...this.emrEntries]; this.renderEMRTable(); } else { console.error('Failed to load EMR data'); this.showEmptyState(); } } catch (error) { console.error('Error loading EMR data:', error); this.showErrorState('Failed to load EMR data. Please try again.'); } finally { this.showLoading(false); } } renderEMRTable() { const tableBody = document.getElementById('emrTableBody'); if (this.filteredEntries.length === 0) { this.showEmptyState(); return; } tableBody.innerHTML = this.filteredEntries.map(entry => { const date = new Date(entry.created_at).toLocaleString(); const type = this.getEMRType(entry.extracted_data); const diagnosis = entry.extracted_data.diagnosis?.slice(0, 2).join(', ') || '-'; const medications = entry.extracted_data.medications?.slice(0, 2).map(m => m.name).join(', ') || '-'; const vitals = this.formatVitalSigns(entry.extracted_data.vital_signs); const confidence = this.formatConfidence(entry.confidence_score); return ` ${date} ${type} ${diagnosis} ${medications} ${vitals} ${confidence}
`; }).join(''); } getEMRType(extractedData) { if (extractedData.diagnosis?.length > 0) return 'diagnosis'; if (extractedData.medications?.length > 0) return 'medication'; if (extractedData.vital_signs && Object.values(extractedData.vital_signs).some(v => v)) return 'vitals'; if (extractedData.lab_results?.length > 0) return 'lab'; return 'general'; } formatVitalSigns(vitalSigns) { if (!vitalSigns) return '-'; const vitals = []; if (vitalSigns.blood_pressure) vitals.push(`BP: ${vitalSigns.blood_pressure}`); if (vitalSigns.heart_rate) vitals.push(`HR: ${vitalSigns.heart_rate}`); if (vitalSigns.temperature) vitals.push(`Temp: ${vitalSigns.temperature}`); return vitals.length > 0 ? vitals.join(', ') : '-'; } formatConfidence(score) { const percentage = Math.round(score * 100); const level = score >= 0.8 ? 'high' : score >= 0.6 ? 'medium' : 'low'; return `
${percentage}%
`; } async viewEMRDetail(emrId) { try { const response = await fetch(`/emr/${emrId}`); if (response.ok) { const entry = await response.json(); this.showEMRDetailModal(entry); } else { alert('Failed to load EMR details'); } } catch (error) { console.error('Error loading EMR detail:', error); alert('Error loading EMR details'); } } showEMRDetailModal(entry) { const modal = document.getElementById('emrDetailModal'); const content = document.getElementById('emrDetailContent'); const date = new Date(entry.created_at).toLocaleString(); content.innerHTML = `

Basic Information

Date: ${date}

Confidence: ${Math.round(entry.confidence_score * 100)}%

Original Message:

${entry.original_message}
${entry.extracted_data.diagnosis?.length > 0 ? `

Diagnoses

` : ''} ${entry.extracted_data.symptoms?.length > 0 ? `

Symptoms

` : ''} ${entry.extracted_data.medications?.length > 0 ? `

Medications

${entry.extracted_data.medications.map(med => `
${med.name}
${med.dosage ? `Dosage: ${med.dosage}` : ''} ${med.frequency ? ` | Frequency: ${med.frequency}` : ''} ${med.duration ? ` | Duration: ${med.duration}` : ''}
`).join('')}
` : ''} ${entry.extracted_data.vital_signs && Object.values(entry.extracted_data.vital_signs).some(v => v) ? `

Vital Signs

${Object.entries(entry.extracted_data.vital_signs).map(([key, value]) => value ? `
${key.replace('_', ' ').toUpperCase()}
${value}
` : '' ).join('')}
` : ''} ${entry.extracted_data.lab_results?.length > 0 ? `

Lab Results

` : ''} ${entry.extracted_data.procedures?.length > 0 ? `

Procedures

` : ''} ${entry.extracted_data.notes ? `

Notes

${entry.extracted_data.notes}

` : ''} `; modal.classList.add('show'); } async deleteEMREntry(emrId) { if (!confirm('Are you sure you want to delete this EMR entry?')) { return; } try { const response = await fetch(`/emr/${emrId}`, { method: 'DELETE' }); if (response.ok) { this.loadEMRData(); // Refresh the data this.loadPatientStats(); // Refresh stats } else { alert('Failed to delete EMR entry'); } } catch (error) { console.error('Error deleting EMR entry:', error); alert('Error deleting EMR entry'); } } filterEntries(query) { if (!query.trim()) { this.filteredEntries = [...this.emrEntries]; } else { this.filteredEntries = this.emrEntries.filter(entry => { const searchText = query.toLowerCase(); return ( entry.original_message.toLowerCase().includes(searchText) || entry.extracted_data.diagnosis?.some(d => d.toLowerCase().includes(searchText)) || entry.extracted_data.symptoms?.some(s => s.toLowerCase().includes(searchText)) || entry.extracted_data.medications?.some(m => m.name.toLowerCase().includes(searchText)) || entry.extracted_data.notes?.toLowerCase().includes(searchText) ); }); } this.renderEMRTable(); } applyFilters() { const dateFilter = document.getElementById('dateFilter').value; const typeFilter = document.getElementById('typeFilter').value; this.filteredEntries = this.emrEntries.filter(entry => { // Date filter if (dateFilter !== 'all') { const entryDate = new Date(entry.created_at); const now = new Date(); switch (dateFilter) { case 'today': if (entryDate.toDateString() !== now.toDateString()) return false; break; case 'week': const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); if (entryDate < weekAgo) return false; break; case 'month': const monthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); if (entryDate < monthAgo) return false; break; } } // Type filter if (typeFilter !== 'all') { const entryType = this.getEMRType(entry.extracted_data); if (entryType !== typeFilter) return false; } return true; }); this.renderEMRTable(); } openSearchModal() { document.getElementById('searchModal').classList.add('show'); } async performAdvancedSearch() { const semanticQuery = document.getElementById('semanticSearchInput').value.trim(); const exactQuery = document.getElementById('exactSearchInput').value.trim(); if (!semanticQuery && !exactQuery) { alert('Please enter a search query'); return; } this.showLoading(true); try { let searchResults = []; if (semanticQuery) { const response = await fetch(`/emr/search/${this.currentPatientId}?query=${encodeURIComponent(semanticQuery)}&limit=50`); if (response.ok) { searchResults = await response.json(); } } if (exactQuery) { const exactResults = this.emrEntries.filter(entry => { const searchText = exactQuery.toLowerCase(); return ( entry.original_message.toLowerCase().includes(searchText) || entry.extracted_data.diagnosis?.some(d => d.toLowerCase().includes(searchText)) || entry.extracted_data.symptoms?.some(s => s.toLowerCase().includes(searchText)) || entry.extracted_data.medications?.some(m => m.name.toLowerCase().includes(searchText)) || entry.extracted_data.notes?.toLowerCase().includes(searchText) ); }); // Merge results if both searches were performed if (semanticQuery) { const exactIds = new Set(exactResults.map(r => r.emr_id)); searchResults = searchResults.concat(exactResults.filter(r => !exactIds.has(r.emr_id))); } else { searchResults = exactResults; } } this.filteredEntries = searchResults; this.renderEMRTable(); } catch (error) { console.error('Error performing search:', error); alert('Error performing search'); } finally { this.showLoading(false); } } showLoading(show) { const loadingState = document.getElementById('loadingState'); const tableContainer = document.querySelector('.emr-table-container'); if (show) { loadingState.style.display = 'block'; tableContainer.style.display = 'none'; } else { loadingState.style.display = 'none'; tableContainer.style.display = 'block'; } } showEmptyState() { const emptyState = document.getElementById('emptyState'); const tableContainer = document.querySelector('.emr-table-container'); emptyState.style.display = 'block'; tableContainer.style.display = 'none'; } showErrorState(message) { const emptyState = document.getElementById('emptyState'); const tableContainer = document.querySelector('.emr-table-container'); // Update the empty state to show error message emptyState.querySelector('h3').textContent = 'Error Loading EMR Data'; emptyState.querySelector('p').textContent = message; emptyState.querySelector('.btn').style.display = 'none'; emptyState.style.display = 'block'; tableContainer.style.display = 'none'; } switchTab(tabName) { // Update tab buttons document.querySelectorAll('.tab-btn').forEach(btn => { btn.classList.remove('active'); }); document.querySelector(`[data-tab="${tabName}"]`).classList.add('active'); // Update tab content document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); document.getElementById(`${tabName}-tab`).classList.add('active'); // Load specific tab data switch (tabName) { case 'diagnosis': this.renderDiagnosisTab(); break; case 'medications': this.renderMedicationsTab(); break; case 'vitals': this.renderVitalsTab(); break; case 'lab': this.renderLabTab(); break; case 'procedures': this.renderProceduresTab(); break; } } renderDiagnosisTab() { const timeline = document.getElementById('diagnosisTimeline'); const diagnoses = []; this.emrEntries.forEach(entry => { if (entry.extracted_data.diagnosis && entry.extracted_data.diagnosis.length > 0) { entry.extracted_data.diagnosis.forEach(diagnosis => { diagnoses.push({ name: diagnosis, date: new Date(entry.created_at).toLocaleDateString(), confidence: Math.round(entry.confidence_score * 100) }); }); } }); if (diagnoses.length === 0) { timeline.innerHTML = '

No diagnoses found in EMR entries.

'; return; } timeline.innerHTML = diagnoses.map(diagnosis => `
${diagnosis.date}
${diagnosis.name}
${diagnosis.confidence}%
`).join(''); } renderMedicationsTab() { const grid = document.getElementById('medicationsGrid'); const medications = []; this.emrEntries.forEach(entry => { if (entry.extracted_data.medications && entry.extracted_data.medications.length > 0) { entry.extracted_data.medications.forEach(med => { medications.push({ name: med.name, dosage: med.dosage || 'Not specified', frequency: med.frequency || 'Not specified', duration: med.duration || 'Not specified', date: new Date(entry.created_at).toLocaleDateString() }); }); } }); if (medications.length === 0) { grid.innerHTML = '

No medications found in EMR entries.

'; return; } grid.innerHTML = medications.map(med => `
${med.name}
Dosage: ${med.dosage}
Frequency: ${med.frequency}
Duration: ${med.duration}
Date: ${med.date}
`).join(''); } renderVitalsTab() { const tableBody = document.getElementById('vitalsTableBody'); const vitalsData = []; this.emrEntries.forEach(entry => { if (entry.extracted_data.vital_signs) { const vitals = entry.extracted_data.vital_signs; if (Object.values(vitals).some(v => v)) { vitalsData.push({ date: new Date(entry.created_at).toLocaleDateString(), blood_pressure: vitals.blood_pressure || '-', heart_rate: vitals.heart_rate || '-', temperature: vitals.temperature || '-', respiratory_rate: vitals.respiratory_rate || '-', oxygen_saturation: vitals.oxygen_saturation || '-' }); } } }); if (vitalsData.length === 0) { tableBody.innerHTML = 'No vital signs found in EMR entries.'; return; } tableBody.innerHTML = vitalsData.map(vitals => ` ${vitals.date} ${vitals.blood_pressure} ${vitals.heart_rate} ${vitals.temperature} ${vitals.respiratory_rate} ${vitals.oxygen_saturation} `).join(''); } renderLabTab() { const container = document.getElementById('labResultsContainer'); const labResults = []; this.emrEntries.forEach(entry => { if (entry.extracted_data.lab_results && entry.extracted_data.lab_results.length > 0) { entry.extracted_data.lab_results.forEach(lab => { labResults.push({ test_name: lab.test_name, value: lab.value, unit: lab.unit || '', reference_range: lab.reference_range || 'Not specified', date: new Date(entry.created_at).toLocaleDateString() }); }); } }); if (labResults.length === 0) { container.innerHTML = '

No lab results found in EMR entries.

'; return; } container.innerHTML = labResults.map(lab => `
${lab.test_name}
${lab.value} ${lab.unit}
Date: ${lab.date} Reference Range: ${lab.reference_range}
`).join(''); } renderProceduresTab() { const timeline = document.getElementById('proceduresTimeline'); const procedures = []; this.emrEntries.forEach(entry => { if (entry.extracted_data.procedures && entry.extracted_data.procedures.length > 0) { entry.extracted_data.procedures.forEach(procedure => { procedures.push({ name: procedure, date: new Date(entry.created_at).toLocaleDateString(), confidence: Math.round(entry.confidence_score * 100) }); }); } }); if (procedures.length === 0) { timeline.innerHTML = '

No procedures found in EMR entries.

'; return; } timeline.innerHTML = procedures.map(procedure => `
${procedure.date}
${procedure.name}
${procedure.confidence}%
`).join(''); } async handleFileUpload(files) { if (!this.currentPatientId) { alert('Please select a patient first'); return; } const file = files[0]; // Handle only the first file for now // Validate file type const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'image/jpeg', 'image/jpg', 'image/png', 'image/tiff']; if (!allowedTypes.includes(file.type)) { alert('Unsupported file type. Please upload PDF, DOC, DOCX, JPG, PNG, or TIFF files.'); return; } // Validate file size (10MB limit) if (file.size > 10 * 1024 * 1024) { alert('File size exceeds 10MB limit.'); return; } this.showUploadProgress(true); try { // Create FormData const formData = new FormData(); formData.append('patient_id', this.currentPatientId); formData.append('file', file); // Upload and analyze document const response = await fetch('/emr/preview-document', { method: 'POST', body: formData }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to analyze document'); } const result = await response.json(); this.showDocumentPreview(result); } catch (error) { console.error('Error uploading file:', error); alert(`Error analyzing document: ${error.message}`); } finally { this.showUploadProgress(false); } } showUploadProgress(show) { const uploadProgress = document.getElementById('uploadProgress'); const uploadArea = document.getElementById('uploadArea'); if (show) { uploadProgress.style.display = 'block'; uploadArea.style.display = 'none'; } else { uploadProgress.style.display = 'none'; uploadArea.style.display = 'block'; } } showDocumentPreview(analysisResult) { const modal = document.getElementById('documentPreviewModal'); const content = document.getElementById('documentPreviewContent'); // Store the analysis result for saving this.currentDocumentAnalysis = analysisResult; content.innerHTML = this.renderDocumentPreview(analysisResult); modal.classList.add('show'); } renderDocumentPreview(data) { const { filename, confidence_score, extracted_data } = data; return `

Document Information

Filename: ${filename}

Confidence Score: ${Math.round(confidence_score * 100)}%

${extracted_data.overview ? `

Overview

` : ''}

Diagnoses

Symptoms

Medications

${(extracted_data.medications || []).map((med, index) => `
Medication ${index + 1}
`).join('')}
${extracted_data.vital_signs ? `

Vital Signs

` : ''}

Lab Results

${(extracted_data.lab_results || []).map((lab, index) => `
Lab Test ${index + 1}
`).join('')}

Procedures

Notes

`; } addDiagnosis() { const list = document.getElementById('diagnosisList'); const li = document.createElement('li'); li.innerHTML = ` `; list.appendChild(li); } addSymptom() { const list = document.getElementById('symptomsList'); const li = document.createElement('li'); li.innerHTML = ` `; list.appendChild(li); } addMedication() { const list = document.getElementById('medicationsList'); const index = list.children.length; const div = document.createElement('div'); div.className = 'medication-preview-item'; div.innerHTML = `
Medication ${index + 1}
`; list.appendChild(div); } addLabResult() { const list = document.getElementById('labResultsList'); const index = list.children.length; const div = document.createElement('div'); div.className = 'lab-result-preview-item'; div.innerHTML = `
Lab Test ${index + 1}
`; list.appendChild(div); } addProcedure() { const list = document.getElementById('proceduresList'); const li = document.createElement('li'); li.innerHTML = ` `; list.appendChild(li); } removeListItem(button) { button.parentElement.remove(); } removeMedication(button) { button.parentElement.remove(); } removeLabResult(button) { button.parentElement.remove(); } async saveDocumentAnalysis() { if (!this.currentDocumentAnalysis) { alert('No document analysis to save'); return; } try { // Collect all the edited data const extractedData = this.collectEditedData(); const formData = new FormData(); formData.append('patient_id', this.currentPatientId); formData.append('filename', this.currentDocumentAnalysis.filename); formData.append('extracted_data', JSON.stringify(extractedData)); formData.append('confidence_score', this.currentDocumentAnalysis.confidence_score); const response = await fetch('/emr/save-document-analysis', { method: 'POST', body: formData }); if (!response.ok) { const error = await response.json(); throw new Error(error.detail || 'Failed to save document analysis'); } const result = await response.json(); // Close modal and refresh EMR data document.getElementById('documentPreviewModal').classList.remove('show'); this.loadEMRData(); this.loadPatientStats(); alert('Document analysis saved successfully!'); } catch (error) { console.error('Error saving document analysis:', error); alert(`Error saving document analysis: ${error.message}`); } } collectEditedData() { const data = { overview: document.getElementById('overviewField')?.value || '', diagnosis: Array.from(document.querySelectorAll('.diagnosis-input')).map(input => input.value).filter(val => val.trim()), symptoms: Array.from(document.querySelectorAll('.symptom-input')).map(input => input.value).filter(val => val.trim()), medications: Array.from(document.querySelectorAll('.medication-preview-item')).map(item => ({ name: item.querySelector('.med-name-input')?.value || '', dosage: item.querySelector('.med-dosage-input')?.value || '', frequency: item.querySelector('.med-frequency-input')?.value || '', duration: item.querySelector('.med-duration-input')?.value || '' })).filter(med => med.name.trim()), vital_signs: { blood_pressure: document.getElementById('bpInput')?.value || null, heart_rate: document.getElementById('hrInput')?.value || null, temperature: document.getElementById('tempInput')?.value || null, respiratory_rate: document.getElementById('rrInput')?.value || null, oxygen_saturation: document.getElementById('o2Input')?.value || null }, lab_results: Array.from(document.querySelectorAll('.lab-result-preview-item')).map(item => ({ test_name: item.querySelector('.lab-name-input')?.value || '', value: item.querySelector('.lab-value-input')?.value || '', unit: item.querySelector('.lab-unit-input')?.value || '', reference_range: item.querySelector('.lab-range-input')?.value || '' })).filter(lab => lab.test_name.trim()), procedures: Array.from(document.querySelectorAll('.procedure-input')).map(input => input.value).filter(val => val.trim()), notes: document.getElementById('notesField')?.value || '' }; // Clean up empty vital signs if (Object.values(data.vital_signs).every(val => !val)) { data.vital_signs = null; } return data; } } // Initialize the EMR page when DOM is loaded document.addEventListener('DOMContentLoaded', () => { window.emrPage = new EMRPage(); });