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.
90 lines
6.4 KiB
JavaScript
90 lines
6.4 KiB
JavaScript
// ============================================================
|
|
// bedside/airway.js
|
|
// AIRWAY / RSI.
|
|
// ============================================================
|
|
|
|
import { S } from './shared.js';
|
|
|
|
function calcAirway() {
|
|
var wt = parseFloat(document.getElementById('airway-weight').value);
|
|
var age = parseFloat(document.getElementById('airway-age').value);
|
|
var el = document.getElementById('airway-result');
|
|
if (!wt) { el.innerHTML = '<p style="color:var(--red);font-size:13px;">Enter weight (kg).</p>'; return; }
|
|
|
|
// Equipment sizing
|
|
var ettUncuff = age ? Math.round(((age/4) + 4) * 2) / 2 : null;
|
|
var ettCuff = age ? Math.round(((age/4) + 3.5) * 2) / 2 : null;
|
|
var ettDepth = ettUncuff ? Math.round(ettUncuff * 3 * 10) / 10 : null;
|
|
var bladeSize = age != null ? (age < 1 ? 'Miller 0-1' : age < 2 ? 'Miller 1 / Mac 1' : age < 8 ? 'Miller 2 / Mac 2' : 'Miller/Mac 3') : '—';
|
|
var lmaSize = wt < 5 ? '1' : wt < 10 ? '1.5' : wt < 20 ? '2' : wt < 30 ? '2.5' : wt < 50 ? '3' : wt < 70 ? '4' : '5';
|
|
|
|
var html = '<div style="padding:10px 14px;border-radius:8px;background:var(--blue-light);border:1.5px solid var(--blue);margin-bottom:10px;"><strong style="color:var(--blue-dark);">RSI doses & equipment — ' + wt + ' kg' + (age ? ', ~' + age + ' yr' : '') + '</strong></div>';
|
|
|
|
// Pre-medication
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:10px 0 4px;">Pre-medication (optional)</h5>';
|
|
html += S.drugTable(
|
|
S.drugRow('Atropine', S.dStr(wt, 0.02, 1, ' mg') + ' (min 0.1 mg)', 'IV', 'Consider <1 yr or if using succinylcholine, or bradycardia risk') +
|
|
S.drugRow('Lidocaine 2%', S.dStr(wt, 1.5, 100, ' mg'), 'IV over 1 min', 'For ↑ICP, asthma; give 2-3 min pre-induction') +
|
|
S.drugRow('Fentanyl', S.dStr(wt, 2, 150, ' mcg') + ' (2-3 mcg/kg)', 'IV over 1 min', 'Blunts sympathetic response; avoid if hypotensive')
|
|
);
|
|
|
|
// Induction
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Induction</h5>';
|
|
html += S.drugTable(
|
|
S.drugRow('Ketamine', S.dStr(wt, 1.5, 150, ' mg') + ' (1-2 mg/kg)', 'IV', 'Preserves BP. First-line for shock, asthma, sepsis') +
|
|
S.drugRow('Etomidate', S.dStr(wt, 0.3, 30, ' mg'), 'IV', 'Hemodynamically neutral. Avoid in septic shock (adrenal suppression)') +
|
|
S.drugRow('Propofol', S.dStr(wt, 2, 200, ' mg') + ' (1-2 mg/kg)', 'IV', 'Causes hypotension. Avoid in shock') +
|
|
S.drugRow('Midazolam', S.dStr(wt, 0.2, 10, ' mg'), 'IV', 'Less optimal induction — slower onset')
|
|
);
|
|
|
|
// Paralytics
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Paralytics</h5>';
|
|
html += S.drugTable(
|
|
S.drugRow('Rocuronium', S.dStr(wt, 1.2, 100, ' mg') + ' (1-1.2 mg/kg)', 'IV', '30-60 sec onset; 30-45 min duration. First-line non-depolarizing.') +
|
|
S.drugRow('Succinylcholine', S.dStr(wt, (wt < 10 ? 2 : 1.5), 150, ' mg'), 'IV', '<10kg: 2 mg/kg; ≥10kg: 1.5 mg/kg. Avoid in burns/crush/hyperK/MH/NM dz. IM option: 4 mg/kg.') +
|
|
S.drugRow('Vecuronium', S.dStr(wt, 0.1, 10, ' mg'), 'IV', '2-3 min onset; longer duration than roc')
|
|
);
|
|
|
|
// Post-intubation sedation
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Maintenance sedation / analgesia</h5>';
|
|
html += S.drugTable(
|
|
S.drugRow('Midazolam gtt', S.dStr(wt, 0.05, 2, ' mg') + '-' + S.dStr(wt, 0.2, 10, ' mg') + '/hr', 'IV infusion', '0.05-0.2 mg/kg/hr') +
|
|
S.drugRow('Fentanyl gtt', S.dStr(wt, 1, 100, ' mcg') + '-' + S.dStr(wt, 4, 200, ' mcg') + '/hr', 'IV infusion', '1-4 mcg/kg/hr') +
|
|
S.drugRow('Ketamine gtt', S.dStr(wt, 0.5, 30, ' mg') + '-' + S.dStr(wt, 2, 100, ' mg') + '/hr', 'IV infusion', '0.5-2 mg/kg/hr. Good for asthma') +
|
|
S.drugRow('Dexmedetomidine gtt', '0.2-1.4 mcg/kg/hr', 'IV infusion', 'No resp depression; causes bradycardia + hypotension') +
|
|
S.drugRow('Rocuronium gtt', '10-12 mcg/kg/min', 'IV infusion', 'If continued paralysis needed — only with adequate sedation')
|
|
);
|
|
|
|
// Equipment
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Equipment sizing</h5>';
|
|
html += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px;font-size:12px;">';
|
|
if (age != null) {
|
|
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>ETT (uncuffed):</strong> ' + ettUncuff + ' mm<br><strong>ETT (cuffed):</strong> ' + ettCuff + ' mm<br><strong>Depth at lip:</strong> ~' + ettDepth + ' cm</div>';
|
|
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>Laryngoscope blade:</strong><br>' + bladeSize + '</div>';
|
|
} else {
|
|
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><em>Enter age for ETT/blade sizing.</em><br>ETT (uncuffed) = (age/4) + 4<br>ETT (cuffed) = (age/4) + 3.5<br>Depth = ETT size × 3</div>';
|
|
}
|
|
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>LMA size:</strong> ' + lmaSize + '<br>OPA = corner mouth → angle mandible<br>NPA = tip nose → tragus</div>';
|
|
html += '<div style="padding:10px;background:var(--g50);border-radius:6px;"><strong>Suction catheter (Fr):</strong> ETT size × 2<br><strong>NG tube:</strong> ETT × 2<br><strong>Chest tube:</strong> 4 × ETT</div>';
|
|
html += '</div>';
|
|
|
|
// Ventilator starting settings
|
|
html += '<h5 style="font-size:13px;font-weight:700;color:var(--g700);margin:14px 0 4px;">Ventilator — starting settings</h5>';
|
|
html += '<div style="padding:10px;background:var(--blue-light);border-radius:6px;font-size:12px;color:var(--g700);">';
|
|
html += '<strong>Mode:</strong> Volume or pressure control<br>';
|
|
html += '<strong>Tidal volume:</strong> 6-8 mL/kg (= ' + S.d(wt, 6) + '-' + S.d(wt, 8) + ' mL). Use lower (4-6 mL/kg) for ARDS.<br>';
|
|
html += '<strong>Rate:</strong> Infant 25-30, Child 15-25, Adolescent 12-16<br>';
|
|
html += '<strong>PEEP:</strong> 5 cmH2O (↑ for oxygenation problems)<br>';
|
|
html += '<strong>FiO2:</strong> Start 100%, wean to SpO2 92-97%<br>';
|
|
html += '<strong>I:E ratio:</strong> 1:2 (1:3-4 for obstructive disease)';
|
|
html += '</div>';
|
|
|
|
html += S.ref('Harriet Lane Handbook 23rd ed / PALS 2020. Always confirm doses against institutional protocols.');
|
|
el.innerHTML = html;
|
|
}
|
|
|
|
export function init() {
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.id === 'btn-airway-calc' || e.target.closest('#btn-airway-calc')) calcAirway();
|
|
});
|
|
}
|