Feat: left sidebar nav, tab persistence, admin models fix, hospital/chart save

- Replace horizontal tab-nav with collapsible left sidebar (sticky desktop, slide-in mobile with hamburger toggle)
- Fix tab persistence: use localStorage instead of URL hash; restore last tab after login in enterApp()
- Fix admin CMS models loading: move autoDeleteDays read inside .then() callback (was ReferenceError), switch admin loading from click-only to tabChanged event
- Add Save/Load bars to Hospital Course and Chart Review tabs with popover support
- Add wv (well visit) save handler in encounters.js
- Register load handlers for hospital and chart tabs
- Expand popover prefix list to include hosp and chart
This commit is contained in:
Daniel Onyejesi 2026-03-22 17:17:45 -04:00
parent 97f8009d38
commit bc47be371a
8 changed files with 241 additions and 98 deletions

View file

@ -50,15 +50,25 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
.btn-header{background:rgba(255,255,255,0.15);border:none;color:white;width:36px;height:36px;border-radius:8px;cursor:pointer;font-size:14px;transition:background 0.2s;} .btn-header{background:rgba(255,255,255,0.15);border:none;color:white;width:36px;height:36px;border-radius:8px;cursor:pointer;font-size:14px;transition:background 0.2s;}
.btn-header:hover{background:rgba(255,255,255,0.3);} .btn-header:hover{background:rgba(255,255,255,0.3);}
/* TABS */ /* APP BODY LAYOUT */
.tab-nav{display:flex;background:white;border-bottom:2px solid var(--g200);max-width:1200px;margin:0 auto;overflow-x:auto;} .app-body{display:flex;min-height:calc(100vh - 66px);}
.tab-btn{display:flex;align-items:center;gap:6px;padding:12px 18px;border:none;border-bottom:3px solid transparent;background:none;color:var(--g500);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap;font-family:inherit;transition:all 0.2s;}
.tab-btn:hover{color:var(--g700);background:var(--g50);} /* SIDEBAR */
.tab-btn.active{color:var(--blue);border-bottom-color:var(--blue);} .sidebar{width:210px;flex-shrink:0;background:white;border-right:1.5px solid var(--g200);display:flex;flex-direction:column;position:sticky;top:0;height:calc(100vh - 66px);overflow-y:auto;z-index:100;}
.tab-btn i{font-size:15px;} .sidebar-header{display:none;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--g200);}
.sidebar-title{font-size:13px;font-weight:700;color:var(--g700);}
.sidebar-nav{display:flex;flex-direction:column;padding:8px 0;flex:1;}
.sidebar-section-label{font-size:10px;font-weight:700;color:var(--g400);text-transform:uppercase;letter-spacing:0.7px;padding:10px 16px 4px;}
.tab-btn{display:flex;align-items:center;gap:10px;padding:10px 16px;border:none;border-left:3px solid transparent;background:none;color:var(--g600);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap;font-family:inherit;transition:all 0.15s;width:100%;text-align:left;}
.tab-btn:hover{background:var(--g50);color:var(--g900);}
.tab-btn.active{background:var(--blue-light);color:var(--blue);border-left-color:var(--blue);font-weight:600;}
.tab-btn i{width:16px;text-align:center;flex-shrink:0;font-size:14px;}
.tab-btn span{overflow:hidden;text-overflow:ellipsis;}
.sidebar-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:199;}
.btn-menu-toggle{display:none;}
/* MAIN */ /* MAIN */
.main-content{max-width:1200px;margin:0 auto;padding:20px 16px;} .main-content{flex:1;min-width:0;padding:20px 20px;}
.tab-content{display:none;} .tab-content{display:none;}
.tab-content.active{display:block;animation:fadeIn 0.25s ease;} .tab-content.active{display:block;animation:fadeIn 0.25s ease;}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}} @keyframes fadeIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:translateY(0);}}
@ -223,13 +233,18 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
/* RESPONSIVE */ /* RESPONSIVE */
@media(max-width:768px){ @media(max-width:768px){
.header-top{flex-direction:column;align-items:flex-start;} .header-top{flex-direction:row;align-items:center;}
.header-right{width:100%;flex-wrap:wrap;} .header-right{flex-wrap:wrap;}
.model-selector{flex:1;} .model-selector{flex:1;}
.model-selector select{max-width:100%;flex:1;} .model-selector select{max-width:160px;flex:1;}
.tab-btn span{display:none;} .btn-menu-toggle{display:flex;align-items:center;justify-content:center;}
.tab-btn{flex:1;justify-content:center;padding:10px;} /* Sidebar: hidden off-screen on mobile, slides in */
.tab-btn i{font-size:16px;} .app-body{display:block;}
.sidebar{position:fixed;left:-220px;top:0;width:220px;height:100vh;z-index:200;transition:left 0.28s ease;box-shadow:none;}
.sidebar.open{left:0;box-shadow:4px 0 20px rgba(0,0,0,0.18);}
.sidebar.open~.sidebar-overlay{display:block;}
.sidebar-header{display:flex;}
.main-content{padding:12px;}
.demographics-bar{flex-direction:column;} .demographics-bar{flex-direction:column;}
.demo-field input,.demo-field select{min-width:100%;} .demo-field input,.demo-field select{min-width:100%;}
.note-meta{flex-direction:column;} .note-meta{flex-direction:column;}

View file

@ -102,11 +102,16 @@
<header class="app-header"> <header class="app-header">
<div class="header-content"> <div class="header-content">
<div class="header-top"> <div class="header-top">
<div class="logo"> <div style="display:flex;align-items:center;gap:10px;">
<i class="fas fa-stethoscope"></i> <button id="btn-menu-toggle" class="btn-header btn-menu-toggle" title="Menu" aria-label="Toggle menu">
<div> <i class="fas fa-bars"></i>
<h1>Pediatric AI Scribe</h1> </button>
<p class="tagline">Welcome, <span id="user-name">Doctor</span></p> <div class="logo">
<i class="fas fa-stethoscope"></i>
<div>
<h1>Pediatric AI Scribe</h1>
<p class="tagline">Welcome, <span id="user-name">Doctor</span></p>
</div>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
@ -135,50 +140,66 @@
<button class="announcement-close" onclick="this.parentElement.classList.add('hidden')" aria-label="Dismiss"><i class="fas fa-times"></i></button> <button class="announcement-close" onclick="this.parentElement.classList.add('hidden')" aria-label="Dismiss"><i class="fas fa-times"></i></button>
</div> </div>
<!-- TAB NAVIGATION --> <div class="app-body">
<nav class="tab-nav">
<button class="tab-btn active" data-tab="encounter"> <!-- SIDEBAR NAVIGATION -->
<i class="fas fa-comments"></i> <nav class="sidebar" id="sidebar">
<span>Encounter HPI</span> <div class="sidebar-header">
</button> <span class="sidebar-title"><i class="fas fa-stethoscope"></i> Menu</span>
<button class="tab-btn" data-tab="dictation"> <button id="btn-sidebar-close" class="btn-sm btn-ghost" title="Close menu" style="padding:4px 8px;">
<i class="fas fa-microphone"></i> <i class="fas fa-times"></i>
<span>Dictation HPI</span> </button>
</button> </div>
<button class="tab-btn" data-tab="hospital"> <div class="sidebar-nav">
<i class="fas fa-hospital"></i> <span class="sidebar-section-label">Encounters</span>
<span>Hospital Course</span> <button class="tab-btn active" data-tab="encounter">
</button> <i class="fas fa-comments"></i>
<button class="tab-btn" data-tab="chart"> <span>Encounter HPI</span>
<i class="fas fa-clipboard-list"></i> </button>
<span>Chart Review</span> <button class="tab-btn" data-tab="dictation">
</button> <i class="fas fa-microphone"></i>
<button class="tab-btn" data-tab="soap"> <span>Dictation HPI</span>
<i class="fas fa-file-waveform"></i> </button>
<span>SOAP Note</span> <span class="sidebar-section-label">Notes</span>
</button> <button class="tab-btn" data-tab="hospital">
<button class="tab-btn" data-tab="milestones"> <i class="fas fa-hospital"></i>
<i class="fas fa-baby"></i> <span>Hospital Course</span>
<span>Milestones</span> </button>
</button> <button class="tab-btn" data-tab="chart">
<button class="tab-btn" data-tab="wellvisit"> <i class="fas fa-clipboard-list"></i>
<i class="fas fa-calendar-check"></i> <span>Chart Review</span>
<span>Well Visit</span> </button>
</button> <button class="tab-btn" data-tab="soap">
<button class="tab-btn" data-tab="sickvisit"> <i class="fas fa-file-waveform"></i>
<i class="fas fa-thermometer-half"></i> <span>SOAP Note</span>
<span>Sick Visit</span> </button>
</button> <span class="sidebar-section-label">Pediatric</span>
<button class="tab-btn" data-tab="settings"> <button class="tab-btn" data-tab="milestones">
<i class="fas fa-cog"></i> <i class="fas fa-baby"></i>
<span>Settings</span> <span>Milestones</span>
</button> </button>
<button class="tab-btn hidden" data-tab="admin" id="admin-tab-btn"> <button class="tab-btn" data-tab="wellvisit">
<i class="fas fa-user-shield"></i> <i class="fas fa-calendar-check"></i>
<span>Admin</span> <span>Well Visit</span>
</button> </button>
<button class="tab-btn" data-tab="sickvisit">
<i class="fas fa-thermometer-half"></i>
<span>Sick Visit</span>
</button>
<span class="sidebar-section-label">Account</span>
<button class="tab-btn" data-tab="settings">
<i class="fas fa-cog"></i>
<span>Settings</span>
</button>
<button class="tab-btn hidden" data-tab="admin" id="admin-tab-btn">
<i class="fas fa-user-shield"></i>
<span>Admin</span>
</button>
</div>
</nav> </nav>
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<main class="main-content"> <main class="main-content">
<!-- ===== TAB: ENCOUNTER HPI ===== --> <!-- ===== TAB: ENCOUNTER HPI ===== -->
@ -386,6 +407,25 @@
</div> </div>
</div> </div>
<!-- Save/Load bar -->
<div class="save-bar-wrap">
<div class="save-bar" id="hosp-save-bar">
<div style="display:flex;align-items:center;gap:8px;flex:1;">
<i class="fas fa-tag" style="color:var(--g400);font-size:13px;"></i>
<input type="text" id="hosp-label" class="save-label-input" placeholder="Patient label (e.g. John D, Visit #42)">
</div>
<button id="btn-hosp-save" class="btn-sm btn-ghost"><i class="fas fa-floppy-disk"></i> Save</button>
<button id="btn-hosp-load" class="btn-sm btn-ghost"><i class="fas fa-folder-open"></i> Load</button>
</div>
<div id="hosp-load-popover" class="enc-load-popover hidden">
<div class="enc-load-popover-inner">
<input type="text" id="hosp-load-search" class="enc-load-search" placeholder="Search saved encounters...">
<button class="enc-pop-close btn-sm btn-ghost"><i class="fas fa-times"></i></button>
</div>
<div id="hosp-pop-list" class="enc-pop-list"></div>
</div>
</div>
<!-- ED Note --> <!-- ED Note -->
<div class="card"> <div class="card">
<div class="card-header"><h3><i class="fas fa-truck-medical"></i> ED Note (before admission)</h3></div> <div class="card-header"><h3><i class="fas fa-truck-medical"></i> ED Note (before admission)</h3></div>
@ -513,6 +553,25 @@
</div> </div>
</div> </div>
<!-- Save/Load bar -->
<div class="save-bar-wrap">
<div class="save-bar" id="chart-save-bar">
<div style="display:flex;align-items:center;gap:8px;flex:1;">
<i class="fas fa-tag" style="color:var(--g400);font-size:13px;"></i>
<input type="text" id="chart-label" class="save-label-input" placeholder="Patient label (e.g. John D, Visit #42)">
</div>
<button id="btn-chart-save" class="btn-sm btn-ghost"><i class="fas fa-floppy-disk"></i> Save</button>
<button id="btn-chart-load" class="btn-sm btn-ghost"><i class="fas fa-folder-open"></i> Load</button>
</div>
<div id="chart-load-popover" class="enc-load-popover hidden">
<div class="enc-load-popover-inner">
<input type="text" id="chart-load-search" class="enc-load-search" placeholder="Search saved encounters...">
<button class="enc-pop-close btn-sm btn-ghost"><i class="fas fa-times"></i></button>
</div>
<div id="chart-pop-list" class="enc-pop-list"></div>
</div>
</div>
<!-- Visits --> <!-- Visits -->
<div id="cr-visits-container"> <div id="cr-visits-container">
<div class="card visit-card"> <div class="card visit-card">
@ -1285,7 +1344,7 @@
</section> </section>
<!-- ===== TAB: SETTINGS ===== --> <!-- ===== TAB: SETTINGS ===== -->
<section id="settings-tab" class="tab-content hidden"> <section id="settings-tab" class="tab-content">
<div class="module-header"> <div class="module-header">
<h2><i class="fas fa-cog"></i> Settings</h2> <h2><i class="fas fa-cog"></i> Settings</h2>
<p>Account security, integrations, and personal templates</p> <p>Account security, integrations, and personal templates</p>
@ -1388,6 +1447,8 @@
</main> </main>
</div><!-- /.app-body -->
<!-- dummy settings-modal kept for any stale JS references --> <!-- dummy settings-modal kept for any stale JS references -->
<div id="settings-modal" class="hidden" style="display:none !important;"></div> <div id="settings-modal" class="hidden" style="display:none !important;"></div>

View file

@ -6,12 +6,14 @@
var loaded = false; var loaded = false;
// Load admin panel when tab is clicked // Load admin panel when admin tab is activated
document.addEventListener('click', function(e) { document.addEventListener('tabChanged', function(e) {
var btn = e.target.closest('.tab-btn'); if (e.detail && e.detail.tab === 'admin') {
if (btn && btn.getAttribute('data-tab') === 'admin') {
if (!loaded) { loadAdmin(); loaded = true; } if (!loaded) { loadAdmin(); loaded = true; }
} }
});
document.addEventListener('click', function(e) {
// Refresh button // Refresh button
if (e.target.closest('#btn-refresh-users')) { if (e.target.closest('#btn-refresh-users')) {
loadUsers(); loadUsers();
@ -237,12 +239,14 @@
var cmsLoaded = false; var cmsLoaded = false;
// Load CMS when admin tab is opened // Load CMS when admin tab is opened (via tabChanged event or click)
document.addEventListener('click', function(e) { document.addEventListener('tabChanged', function(e) {
var btn = e.target.closest('.tab-btn'); if (e.detail && e.detail.tab === 'admin') {
if (btn && btn.getAttribute('data-tab') === 'admin') {
if (!cmsLoaded) { loadCms(); cmsLoaded = true; } if (!cmsLoaded) { loadCms(); cmsLoaded = true; }
} }
});
document.addEventListener('click', function(e) {
// Save buttons // Save buttons
if (e.target.closest('#btn-save-announcement')) saveAnnouncement(); if (e.target.closest('#btn-save-announcement')) saveAnnouncement();
@ -288,6 +292,13 @@
if (flagReadAloud) flagReadAloud.value = cfg['feature.read_aloud'] !== undefined ? cfg['feature.read_aloud'] : 'true'; if (flagReadAloud) flagReadAloud.value = cfg['feature.read_aloud'] !== undefined ? cfg['feature.read_aloud'] : 'true';
if (flagNextcloud) flagNextcloud.value = cfg['feature.nextcloud'] !== undefined ? cfg['feature.nextcloud'] : 'true'; if (flagNextcloud) flagNextcloud.value = cfg['feature.nextcloud'] !== undefined ? cfg['feature.nextcloud'] : 'true';
// Auto-delete setting
var autoDeleteDays = cfg['site.auto_delete_days'] || '7';
var el = document.getElementById('cms-auto-delete-days');
if (el) el.value = autoDeleteDays;
el = document.getElementById('admin-auto-delete-days');
if (el) el.textContent = autoDeleteDays;
// Email — load verify template by default // Email — load verify template by default
window._adminEmailConfig = cfg; window._adminEmailConfig = cfg;
loadEmailFields('verify'); loadEmailFields('verify');
@ -297,13 +308,6 @@
loadPromptList(); loadPromptList();
loadSmtp(); loadSmtp();
loadModels(); loadModels();
// Auto-delete setting
var autoDeleteDays = cfg['site.auto_delete_days'] || '7';
var el = document.getElementById('cms-auto-delete-days');
if (el) el.value = autoDeleteDays;
el = document.getElementById('admin-auto-delete-days');
if (el) el.textContent = autoDeleteDays;
} }
// ---- ANNOUNCEMENT ---- // ---- ANNOUNCEMENT ----

View file

@ -35,21 +35,41 @@ document.addEventListener('DOMContentLoaded', function() {
btn.classList.add('active'); btn.classList.add('active');
var tabEl = document.getElementById(tabName + '-tab'); var tabEl = document.getElementById(tabName + '-tab');
if (tabEl) tabEl.classList.add('active'); if (tabEl) tabEl.classList.add('active');
window.location.hash = tabName; // Persist last tab in localStorage (restored after login in auth.js)
try { localStorage.setItem('ped_last_tab', tabName); } catch(e) {}
document.dispatchEvent(new CustomEvent('tabChanged', { detail: { tab: tabName } })); document.dispatchEvent(new CustomEvent('tabChanged', { detail: { tab: tabName } }));
// Close sidebar on mobile after tab click
var sidebar = document.getElementById('sidebar');
if (sidebar && window.innerWidth <= 768) {
sidebar.classList.remove('open');
}
return true; return true;
} }
// Expose activateTab globally so auth.js can call it after login
window.activateTab = activateTab;
document.querySelectorAll('.tab-btn').forEach(function(btn) { document.querySelectorAll('.tab-btn').forEach(function(btn) {
btn.addEventListener('click', function() { btn.addEventListener('click', function() {
activateTab(btn.getAttribute('data-tab')); activateTab(btn.getAttribute('data-tab'));
}); });
}); });
// Restore tab from URL hash on load // --- SIDEBAR TOGGLE ---
var hash = window.location.hash.replace('#', ''); var sidebar = document.getElementById('sidebar');
if (!hash || !activateTab(hash)) { var sidebarOverlay = document.getElementById('sidebar-overlay');
activateTab('encounter'); // default document.addEventListener('click', function(e) {
if (e.target.closest('#btn-menu-toggle')) {
if (sidebar) sidebar.classList.toggle('open');
}
if (e.target.closest('#btn-sidebar-close') || e.target.closest('#sidebar-overlay')) {
if (sidebar) sidebar.classList.remove('open');
}
});
if (sidebarOverlay) {
sidebarOverlay.addEventListener('click', function() {
if (sidebar) sidebar.classList.remove('open');
});
} }
// Load settings data when settings tab is activated // Load settings data when settings tab is activated

View file

@ -94,6 +94,15 @@ document.addEventListener('DOMContentLoaded', function() {
console.log('[Auth] ✅ Entered app as:', user.email, 'Role:', user.role); console.log('[Auth] ✅ Entered app as:', user.email, 'Role:', user.role);
// Restore last visited tab (saved by activateTab)
var lastTab = null;
try { lastTab = localStorage.getItem('ped_last_tab'); } catch(e) {}
if (typeof window.activateTab === 'function') {
if (!lastTab || !window.activateTab(lastTab)) {
window.activateTab('encounter');
}
}
// Load announcement banner if function is available // Load announcement banner if function is available
if (typeof loadAnnouncement === 'function') loadAnnouncement(); if (typeof loadAnnouncement === 'function') loadAnnouncement();
} }

View file

@ -113,5 +113,15 @@
document.getElementById('cr-refine-btn').addEventListener('click', function() { refineDocument('cr-review-text', 'cr-refine-input'); }); document.getElementById('cr-refine-btn').addEventListener('click', function() { refineDocument('cr-review-text', 'cr-refine-input'); });
document.getElementById('cr-shorten-btn').addEventListener('click', function() { shortenDocument('cr-review-text'); }); document.getElementById('cr-shorten-btn').addEventListener('click', function() { shortenDocument('cr-review-text'); });
// Register load handler for saved encounters
window.registerEncounterLoadHandler('chart', function(enc) {
if (enc.generated_note) {
var reviewText = document.getElementById('cr-review-text');
var outputCard = document.getElementById('cr-output');
if (reviewText) reviewText.textContent = enc.generated_note;
if (outputCard) outputCard.classList.remove('hidden');
}
});
console.log('✅ Chart Review module loaded'); console.log('✅ Chart Review module loaded');
})(); })();

View file

@ -100,7 +100,7 @@
_savedEncounters = data.encounters || []; _savedEncounters = data.encounters || [];
renderSavedList(); renderSavedList();
// Refresh any open popovers // Refresh any open popovers
['enc', 'dict', 'wv', 'sick'].forEach(function(pfx) { ['enc', 'dict', 'wv', 'sick', 'hosp', 'chart'].forEach(function(pfx) {
var pop = document.getElementById(pfx + '-load-popover'); var pop = document.getElementById(pfx + '-load-popover');
if (pop && !pop.classList.contains('hidden')) { if (pop && !pop.classList.contains('hidden')) {
var search = pop.querySelector('.enc-load-search'); var search = pop.querySelector('.enc-load-search');
@ -190,7 +190,7 @@
if (!popover) return; if (!popover) return;
var isHidden = popover.classList.contains('hidden'); var isHidden = popover.classList.contains('hidden');
// Close all popovers first // Close all popovers first
['enc', 'dict', 'wv', 'sick'].forEach(function(p) { ['enc', 'dict', 'wv', 'sick', 'hosp', 'chart'].forEach(function(p) {
var pop = document.getElementById(p + '-load-popover'); var pop = document.getElementById(p + '-load-popover');
if (pop) pop.classList.add('hidden'); if (pop) pop.classList.add('hidden');
}); });
@ -228,15 +228,16 @@
if (!data.success) { showToast(data.error || 'Failed', 'error'); return; } if (!data.success) { showToast(data.error || 'Failed', 'error'); return; }
var enc = data.encounter; var enc = data.encounter;
// Close all popovers // Close all popovers
['enc', 'dict', 'wv', 'sick'].forEach(function(p) { ['enc', 'dict', 'wv', 'sick', 'hosp', 'chart'].forEach(function(p) {
var pop = document.getElementById(p + '-load-popover'); var pop = document.getElementById(p + '-load-popover');
if (pop) pop.classList.add('hidden'); if (pop) pop.classList.add('hidden');
}); });
// Navigate to correct tab // Navigate to correct tab
var tabMap = { var tabMap = {
encounter: 'encounter', dictation: 'dictation', hospital: 'hospital', encounter: 'encounter', dictation: 'dictation',
chart: 'chart', soap: 'soap', milestones: 'milestones', hospital: 'hospital', chart: 'chart',
soap: 'soap', milestones: 'milestones',
wellvisit: 'wellvisit', sickvisit: 'sickvisit' wellvisit: 'wellvisit', sickvisit: 'sickvisit'
}; };
var tabName = tabMap[enc.enc_type] || 'encounter'; var tabName = tabMap[enc.enc_type] || 'encounter';
@ -294,17 +295,23 @@
loadSavedEncountersList(); loadSavedEncountersList();
} }
// Save buttons per tab // Save buttons per tab
if (e.target.closest('#btn-enc-save')) saveFromTab('encounter', 'enc'); if (e.target.closest('#btn-enc-save')) saveFromTab('encounter', 'enc');
if (e.target.closest('#btn-dict-save')) saveFromTab('dictation', 'dict'); if (e.target.closest('#btn-dict-save')) saveFromTab('dictation', 'dict');
if (e.target.closest('#btn-hosp-save')) saveFromTab('hospital', 'hosp');
if (e.target.closest('#btn-chart-save')) saveFromTab('chart', 'chart');
if (e.target.closest('#btn-wv-save')) saveFromTab('wellvisit', 'wv');
// Load buttons — open inline popovers // Load buttons — open inline popovers
if (e.target.closest('#btn-enc-load')) openLoadPopover('enc'); if (e.target.closest('#btn-enc-load')) openLoadPopover('enc');
if (e.target.closest('#btn-dict-load')) openLoadPopover('dict'); if (e.target.closest('#btn-dict-load')) openLoadPopover('dict');
if (e.target.closest('#btn-wv-load')) openLoadPopover('wv'); if (e.target.closest('#btn-wv-load')) openLoadPopover('wv');
if (e.target.closest('#btn-sick-load')) openLoadPopover('sick'); if (e.target.closest('#btn-sick-load')) openLoadPopover('sick');
// Close popovers when clicking outside (popover stops its own propagation so this only fires for outside clicks) if (e.target.closest('#btn-hosp-load')) openLoadPopover('hosp');
if (!e.target.closest('#btn-enc-load') && !e.target.closest('#btn-dict-load') && if (e.target.closest('#btn-chart-load')) openLoadPopover('chart');
!e.target.closest('#btn-wv-load') && !e.target.closest('#btn-sick-load')) { // Close popovers when clicking outside
['enc', 'dict', 'wv', 'sick'].forEach(function(p) { var loadBtnIds = ['#btn-enc-load','#btn-dict-load','#btn-wv-load','#btn-sick-load','#btn-hosp-load','#btn-chart-load'];
var clickedLoadBtn = loadBtnIds.some(function(id) { return e.target.closest(id); });
if (!clickedLoadBtn) {
['enc', 'dict', 'wv', 'sick', 'hosp', 'chart'].forEach(function(p) {
var pop = document.getElementById(p + '-load-popover'); var pop = document.getElementById(p + '-load-popover');
if (pop) pop.classList.add('hidden'); if (pop) pop.classList.add('hidden');
}); });
@ -313,13 +320,20 @@
function saveFromTab(type, prefix) { function saveFromTab(type, prefix) {
var labelEl = document.getElementById(prefix + '-label'); var labelEl = document.getElementById(prefix + '-label');
var transcriptEl = document.getElementById(prefix + '-transcript');
var noteEl = document.getElementById(prefix + '-hpi-text');
var label = labelEl ? labelEl.value.trim() : ''; var label = labelEl ? labelEl.value.trim() : '';
if (!label) { showToast('Enter a patient label before saving', 'error'); return; } if (!label) { showToast('Enter a patient label before saving', 'error'); return; }
var savedId = window['_savedEncId_' + type] || null; var savedId = window['_savedEncId_' + type] || null;
var transcriptEl = document.getElementById(prefix + '-transcript');
// Each tab stores its generated note in a different element
var noteIdMap = {
encounter: 'enc-hpi-text', dictation: 'dict-hpi-text',
hospital: 'hc-course-text', chart: 'cr-review-text',
wellvisit: 'wv-note-text'
};
var noteEl = document.getElementById(noteIdMap[type] || (prefix + '-hpi-text'));
window.saveEncounter({ window.saveEncounter({
id: savedId, id: savedId,
label: label, label: label,

View file

@ -191,5 +191,15 @@
.catch(function(err) { hideLoading(); showToast(err.message, 'error'); }); .catch(function(err) { hideLoading(); showToast(err.message, 'error'); });
}); });
// Register load handler for saved encounters
window.registerEncounterLoadHandler('hospital', function(enc) {
if (enc.generated_note) {
var courseText = document.getElementById('hc-course-text');
var outputCard = document.getElementById('hc-output');
if (courseText) courseText.textContent = enc.generated_note;
if (outputCard) outputCard.classList.remove('hidden');
}
});
console.log('✅ Hospital Course module loaded'); console.log('✅ Hospital Course module loaded');
})(); })();