Split the Bedside clinical reference section out of calculators.js (~1220 lines) into 20 focused ES modules under public/js/bedside/. Each module owns one clinical topic (cardiac, seizure, sepsis, burns, etc.) and exports an init() wired up by bedside/index.js. Shared helpers live in shared.js and also set window._EM for back-compat with the 4 remaining call sites in calculators.js. Load order: classic defer calculators.js first, then module script bedside/index.js. Handlers bind at DOM-ready; runtime _EM lookups resolve after both are evaluated. Makes bedside content editable per-section, shrinks calculators.js from 4111 to 2891 lines, and keeps the existing Playwright smoke suite (e2e/tests/bedside-smoke.spec.js) as the behavioral contract.
82 lines
6.8 KiB
JavaScript
82 lines
6.8 KiB
JavaScript
// ============================================================
|
|
// bedside/anaphylaxis.js
|
|
// ANAPHYLAXIS MANAGEMENT.
|
|
// ============================================================
|
|
|
|
import { S } from './shared.js';
|
|
|
|
function d(wt, mgPerKg, max) { var v = Math.round(wt * mgPerKg * 100) / 100; return max ? Math.min(v, max) : v; }
|
|
|
|
// Lookup a drug entry (by name) from window._DRUGS.sections.anaphylaxis,
|
|
// falling back to a hardcoded record so rendering stays identical if the
|
|
// JSON fetch hasn't resolved (or failed). Returns an object exposing the
|
|
// per-kg + max fields needed by S.dStr.
|
|
var ANAPH_FALLBACK = {
|
|
'Epinephrine IM': { dose_mg_per_kg: 0.01, max_mg: 0.5, unit: 'mg' },
|
|
'Normal saline bolus': { dose_mg_per_kg: 20, max_mg: null, unit: 'mL' },
|
|
'Diphenhydramine': { dose_mg_per_kg: 1.25, max_mg: 50, unit: 'mg' },
|
|
'Ranitidine': { dose_mg_per_kg: 1, max_mg: 50, unit: 'mg' },
|
|
'Dexamethasone': { dose_mg_per_kg: 0.6, max_mg: 16, unit: 'mg' },
|
|
'Methylprednisolone': { dose_mg_per_kg: 2, max_mg: 125, unit: 'mg' },
|
|
'Glucagon': { dose_mg_per_kg: 0.02, max_mg: 1, unit: 'mg' }
|
|
};
|
|
|
|
function anaphDrug(name) {
|
|
var s = window._DRUGS && window._DRUGS.sections && window._DRUGS.sections.anaphylaxis;
|
|
if (s && s.drugs) {
|
|
var hit = s.drugs.filter(function(x) { return x.name === name; })[0];
|
|
if (hit) return hit;
|
|
}
|
|
return ANAPH_FALLBACK[name] || {};
|
|
}
|
|
|
|
function calcAnaphylaxis() {
|
|
var wt = parseFloat(document.getElementById('anaph-weight').value);
|
|
var age = document.getElementById('anaph-age') ? document.getElementById('anaph-age').value : null; // kept for parity; not currently branched on
|
|
void age;
|
|
var resultDiv = document.getElementById('anaph-result');
|
|
if (!wt) { resultDiv.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
|
|
|
|
var epi = anaphDrug('Epinephrine IM');
|
|
var fluids = anaphDrug('Normal saline bolus');
|
|
var dph = anaphDrug('Diphenhydramine');
|
|
var rnt = anaphDrug('Ranitidine');
|
|
var dex = anaphDrug('Dexamethasone');
|
|
var mpn = anaphDrug('Methylprednisolone');
|
|
var glc = anaphDrug('Glucagon');
|
|
|
|
var epiDose = d(wt, epi.dose_mg_per_kg, epi.max_mg);
|
|
var epiVol = Math.round(epiDose * 10) / 10; // 1:1000 = 1 mg/mL
|
|
var autoInjector = wt < 10 ? 'Draw up manually' : wt <= 25 ? 'EpiPen Jr / Auvi-Q 0.15 mg' : 'EpiPen / Auvi-Q 0.3 mg';
|
|
|
|
var html = '<div style="padding:14px;border-radius:10px;background:#fee2e2;border:2px solid #ef4444;margin-bottom:16px;">';
|
|
html += '<div style="font-size:18px;font-weight:700;color:#dc2626;margin-bottom:6px;"><i class="fas fa-triangle-exclamation"></i> STEP 1: Epinephrine IM — GIVE IMMEDIATELY</div>';
|
|
html += '<div style="font-size:15px;font-weight:600;color:var(--g800);margin-bottom:4px;">Epinephrine 1:1000 (1 mg/mL): <span style="color:#dc2626;">' + epiDose + ' mg (' + epiVol + ' mL)</span> IM to lateral thigh</div>';
|
|
html += '<div style="font-size:13px;color:var(--g600);">' + epi.dose_mg_per_kg + ' mg/kg (max ' + epi.max_mg + ' mg) | Auto-injector: ' + autoInjector + '</div>';
|
|
html += '<div style="font-size:12px;color:#991b1b;margin-top:6px;">May repeat every 5-15 minutes if symptoms persist. No contraindications in anaphylaxis.</div>';
|
|
html += '</div>';
|
|
|
|
html += '<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:12px;"><table style="width:100%;min-width:560px;border-collapse:collapse;font-size:13px;"><thead><tr style="background:var(--g100);"><th style="text-align:left;padding:6px 8px;">Step</th><th style="padding:6px 8px;">Drug</th><th style="padding:6px 8px;">Dose</th><th style="padding:6px 8px;">Route</th><th style="padding:6px 8px;">Notes</th></tr></thead><tbody>';
|
|
|
|
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 2</td><td style="font-weight:600;">Position</td><td>Supine + legs elevated</td><td>—</td><td style="font-size:12px;color:var(--g500);">If dyspneic: sitting position. If vomiting: recovery position</td></tr>';
|
|
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 3</td><td style="font-weight:600;">O2</td><td>High flow 10-15 L/min</td><td>Face mask</td><td style="font-size:12px;color:var(--g500);">100% O2. Prepare for airway management</td></tr>';
|
|
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 4</td><td style="font-weight:600;">IV fluids</td><td>NS ' + S.dStr(wt, fluids.dose_mg_per_kg, fluids.max_mg, ' mL') + ' bolus</td><td>IV/IO</td><td style="font-size:12px;color:var(--g500);">Repeat up to 60 mL/kg for hypotension</td></tr>';
|
|
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 5</td><td style="font-weight:600;">Diphenhydramine</td><td>' + S.dStr(wt, dph.dose_mg_per_kg, dph.max_mg) + '</td><td>IV/IM/PO</td><td style="font-size:12px;color:var(--g500);">H1 blocker. NOT first-line — adjunct only</td></tr>';
|
|
html += '<tr><td></td><td style="font-weight:600;">Ranitidine</td><td>' + S.dStr(wt, rnt.dose_mg_per_kg, rnt.max_mg) + '</td><td>IV over 5 min</td><td style="font-size:12px;color:var(--g500);">H2 blocker. Optional adjunct</td></tr>';
|
|
html += '<tr><td style="font-weight:600;color:var(--blue);">STEP 6</td><td style="font-weight:600;">Dexamethasone</td><td>' + S.dStr(wt, dex.dose_mg_per_kg, dex.max_mg) + '</td><td>IV/IM/PO</td><td style="font-size:12px;color:var(--g500);">Prevents biphasic reaction (4-6 hrs later)</td></tr>';
|
|
html += '<tr><td></td><td style="font-weight:600;">Methylprednisolone</td><td>' + S.dStr(wt, mpn.dose_mg_per_kg, mpn.max_mg) + '</td><td>IV</td><td style="font-size:12px;color:var(--g500);">Alternative steroid</td></tr>';
|
|
|
|
html += '<tr style="background:#fef3c7;"><td style="font-weight:600;color:#dc2626;">IF REFRACTORY</td><td style="font-weight:600;">Epinephrine gtt</td><td>0.1-1 mcg/kg/min</td><td>IV infusion</td><td style="font-size:12px;color:var(--g500);">For persistent hypotension despite fluids + IM epi</td></tr>';
|
|
html += '<tr style="background:#fef3c7;"><td></td><td style="font-weight:600;">Glucagon</td><td>' + S.dStr(wt, glc.dose_mg_per_kg, glc.max_mg) + '</td><td>IV/IM</td><td style="font-size:12px;color:var(--g500);">For patients on beta-blockers not responding to epi</td></tr>';
|
|
|
|
html += '</tbody></table></div>';
|
|
html += '<div style="padding:10px 12px;background:var(--amber-light);border-radius:6px;font-size:12px;color:#92400e;"><strong>Observe minimum 4-6 hours</strong> after last dose of epinephrine (biphasic reactions occur in 5-20% of cases). Discharge with EpiPen prescription and anaphylaxis action plan. Refer to allergist.</div>';
|
|
html += '<p style="font-size:11px;color:var(--g400);margin:8px 0 0;">ASCIA Anaphylaxis Guidelines 2021. WAO Anaphylaxis Guidance 2020. AAP/ACAAI Practice Parameters.</p>';
|
|
resultDiv.innerHTML = html;
|
|
}
|
|
|
|
export function init() {
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.id === 'btn-anaph-calc' || e.target.closest('#btn-anaph-calc')) calcAnaphylaxis();
|
|
});
|
|
}
|