diff --git a/app/Views/abdm/task_board.php b/app/Views/abdm/task_board.php index 11dae00..d84089b 100644 --- a/app/Views/abdm/task_board.php +++ b/app/Views/abdm/task_board.php @@ -321,9 +321,20 @@ @@ -957,9 +968,170 @@ var fhirModalMeta = document.getElementById('fhirModalMeta'); var fhirModalQuality = document.getElementById('fhirModalQuality'); var fhirModalJson = document.getElementById('fhirModalJson'); + var fhirFormView = document.getElementById('fhirFormView'); + var fhirTabForm = document.getElementById('fhirTabForm'); + var fhirTabJson = document.getElementById('fhirTabJson'); var fhirModalDataBadge = document.getElementById('fhirModalDataBadge'); var fhirModalHttpBadge = document.getElementById('fhirModalHttpBadge'); + // ── Tab switching ────────────────────────────────────────────────── + fhirTabForm.addEventListener('click', function () { + fhirTabForm.classList.add('active'); + fhirTabJson.classList.remove('active'); + fhirFormView.style.display = ''; + fhirModalJson.style.display = 'none'; + }); + fhirTabJson.addEventListener('click', function () { + fhirTabJson.classList.add('active'); + fhirTabForm.classList.remove('active'); + fhirModalJson.style.display = ''; + fhirFormView.style.display = 'none'; + }); + + // ── Render FHIR bundle as human-readable form ────────────────────── + function hesc(s) { + return String(s || '') + .replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); + } + function fmtDate(s) { + if (!s) return ''; + var d = s.toString().substring(0, 10).split('-'); + return d.length === 3 ? d[2]+'/'+d[1]+'/'+d[0] : s.toString().substring(0,16); + } + function renderFhirBundleForm(bundle) { + var resources = (bundle.entry || []).map(function(e) { return e.resource; }).filter(Boolean); + function byType(t) { return resources.filter(function(r){ return r.resourceType === t; }); } + var patient = byType('Patient')[0]; + var encounter = byType('Encounter')[0]; + var practitioner = byType('Practitioner')[0]; + var organization = byType('Organization')[0]; + var allConditions = byType('Condition'); + var observations = byType('Observation'); + var medications = byType('MedicationRequest'); + var serviceReqs = byType('ServiceRequest'); + + var complaints = allConditions.filter(function(c) { + return (c.category || []).some(function(cat) { return (cat.text || '').toLowerCase().includes('complaint'); }); + }); + var diagnoses = allConditions.filter(function(c) { + return !(c.category || []).some(function(cat) { return (cat.text || '').toLowerCase().includes('complaint'); }); + }); + + var html = ''; + + // ── Patient header + if (patient) { + var pname = ((patient.name || [{}])[0].text || '').trim(); + var gender = (patient.gender || '').toUpperCase().charAt(0); + var dob = fmtDate(patient.birthDate); + var abha = (patient.identifier || []).find(function(i){ return (i.system||'').includes('abha'); }); + var docName = practitioner ? ((practitioner.name || [{}])[0].text || '') : ''; + var orgName = organization ? (organization.name || '') : ''; + var encStart = encounter ? fmtDate((encounter.period || {}).start || '') : ''; + html += '
'; + html += '
'; + html += '' + hesc(pname || 'Unknown Patient') + ''; + if (gender) html += '' + hesc(gender) + ''; + if (dob) html += 'DOB: ' + hesc(dob) + ''; + if (abha) html += 'ABHA: ' + hesc(abha.value) + ''; + html += '
'; + html += '
'; + if (docName) html += '' + hesc(docName) + ''; + if (encStart) html += '' + hesc(encStart) + ''; + if (orgName) html += '' + hesc(orgName) + ''; + html += '
'; + } + + // ── Complaints + if (complaints.length) { + html += '
Chief Complaints
'; + html += '
'; + } + + // ── Diagnoses + if (diagnoses.length) { + html += '
Diagnosis
'; + html += '
'; + } + + // ── Vitals + if (observations.length) { + var loincLabel = { '8867-4':'HR','59408-5':'SpO₂','8480-6':'BP Sys','8462-4':'BP Dia','8310-5':'Temp','9279-1':'RR','8302-2':'Height','29463-7':'Weight' }; + html += '
Vitals
'; + observations.forEach(function(o) { + var loinc = (((o.code || {}).coding) || [])[0] || {}; + var label = loincLabel[loinc.code] || (o.code || {}).text || loinc.display || ''; + var val = (o.valueQuantity || {}).value; + var unit = (o.valueQuantity || {}).unit || ''; + if (val === undefined || val === null) return; + html += '
'; + html += '
' + hesc(label) + '
'; + html += '
' + hesc(val) + '
'; + html += '
' + hesc(unit); + if (loinc.code) html += ' '+hesc(loinc.code)+''; + html += '
'; + }); + html += '
'; + } + + // ── Medications + if (medications.length) { + html += '
Medications
'; + html += '
    '; + medications.forEach(function(m) { + var drug = (m.medicationCodeableConcept || {}).text || ''; + var di = (m.dosageInstruction || [{}])[0] || {}; + var dosage = di.text || ''; + var method = (di.method || {}).text || ''; + html += '
  1. ' + hesc(drug) + ''; + if (dosage) html += ' — ' + hesc(dosage) + (method ? ' (' + hesc(method) + ')' : '') + ''; + html += '
  2. '; + }); + html += '
'; + } + + // ── Investigations + if (serviceReqs.length) { + html += '
Investigations
'; + html += '
'; + } + + return html || '

No structured clinical data found in bundle.

'; + } + function fhirCodeQuality(bundle) { var entries = (bundle && bundle.entry) ? bundle.entry : []; var complaints = [], diagnoses = [], services = [], obs = [], meds = []; @@ -1004,10 +1176,14 @@ } function openFhirModal(url, title) { - if (fhirModalTitle) fhirModalTitle.textContent = title || 'FHIR Preview'; - if (fhirModalMeta) { fhirModalMeta.textContent = 'Loading...'; fhirModalMeta.className = 'px-3 py-2 small text-muted'; } - if (fhirModalQuality) { fhirModalQuality.innerHTML = ''; fhirModalQuality.style.display = 'none'; } - if (fhirModalJson) fhirModalJson.textContent = '{\n "loading": true\n}'; + if (fhirModalTitle) fhirModalTitle.textContent = title || 'FHIR Preview'; + if (fhirModalMeta) { fhirModalMeta.textContent = 'Loading...'; fhirModalMeta.className = 'flex-grow-1 small text-muted'; } + if (fhirModalQuality) { fhirModalQuality.innerHTML = ''; fhirModalQuality.style.display = 'none'; } + if (fhirFormView) fhirFormView.innerHTML = '

Loading...

'; + if (fhirModalJson) fhirModalJson.textContent = '{\n "loading": true\n}'; + // Reset to Form View tab + fhirTabForm.classList.add('active'); fhirTabJson.classList.remove('active'); + fhirFormView.style.display = ''; fhirModalJson.style.display = 'none'; if (fhirModalDataBadge) { fhirModalDataBadge.className = 'badge bg-warning text-dark'; fhirModalDataBadge.textContent = 'CHECKING'; } if (fhirModalHttpBadge) { fhirModalHttpBadge.className = 'badge bg-warning text-dark'; fhirModalHttpBadge.textContent = 'HTTP ...'; } fhirPreviewModal.show(); @@ -1019,8 +1195,9 @@ try { parsed = JSON.parse(res.body || '{}'); } catch (e) { parsed = { raw: res.body || '' }; } var bundle = (parsed && parsed.resourceType === 'Bundle') ? parsed : ((parsed && parsed.bundle) ? parsed.bundle : null); var hasFhir = bundle !== null; - if (fhirModalJson) fhirModalJson.textContent = JSON.stringify(parsed, null, 2); - if (fhirModalMeta) { fhirModalMeta.textContent = res.ok ? 'Loaded (' + res.status + ')' : 'Error (' + res.status + ')'; fhirModalMeta.className = 'px-3 py-2 small ' + (res.ok ? 'text-success' : 'text-danger'); } + if (fhirModalJson) fhirModalJson.textContent = JSON.stringify(parsed, null, 2); + if (fhirFormView) fhirFormView.innerHTML = hasFhir ? renderFhirBundleForm(bundle) : '

No FHIR bundle generated yet.

'; + if (fhirModalMeta) { fhirModalMeta.textContent = res.ok ? 'Loaded (' + res.status + ')' : 'Error (' + res.status + ')'; fhirModalMeta.className = 'flex-grow-1 small ' + (res.ok ? 'text-success' : 'text-danger'); } if (fhirModalDataBadge) { fhirModalDataBadge.className = 'badge ' + (hasFhir ? 'bg-success' : 'bg-danger'); fhirModalDataBadge.textContent = hasFhir ? 'HAS FHIR' : 'NOT GENERATED'; } if (fhirModalHttpBadge) { fhirModalHttpBadge.className = 'badge ' + (res.ok ? 'bg-success' : 'bg-danger'); fhirModalHttpBadge.textContent = 'HTTP ' + res.status; } if (fhirModalQuality && hasFhir) { @@ -1029,7 +1206,8 @@ } }) .catch(function (e) { - if (fhirModalMeta) { fhirModalMeta.textContent = 'Request failed: ' + e.message; fhirModalMeta.className = 'px-3 py-2 small text-danger'; } + if (fhirFormView) fhirFormView.innerHTML = '

Request failed: ' + hesc(e.message) + '

'; + if (fhirModalMeta) { fhirModalMeta.textContent = 'Request failed: ' + e.message; fhirModalMeta.className = 'flex-grow-1 small text-danger'; } if (fhirModalDataBadge) { fhirModalDataBadge.className = 'badge bg-danger'; fhirModalDataBadge.textContent = 'ERROR'; } if (fhirModalHttpBadge) { fhirModalHttpBadge.className = 'badge bg-danger'; fhirModalHttpBadge.textContent = 'HTTP ERR'; } });