// admin-sidebar-loader.js - Shared sidebar for all admin pages // Replaces sidebar innerHTML. Preserves all element IDs and CSS classes // that existing page JS uses for role-visibility and user info updates. (function() { var s = document.querySelector('.sidebar'); if (!s) return; s.innerHTML = '' + '' + '' + '' + ''; // Highlight active page var page = window.location.pathname.split('/').pop().replace('.html',''); var items = s.querySelectorAll('.nav-item[data-page]'); for (var i = 0; i < items.length; i++) { if (items[i].getAttribute('data-page') === page) items[i].classList.add('active'); } // Fix sidebar overflow for many nav items var nav = s.querySelector('.sidebar-nav'); if (nav) nav.style.overflowY = 'auto'; // Apply role-based visibility after a tick (so page JS can set currentUser first) // Pages can call applySidebarRoles(role) manually, or it auto-runs on DOMContentLoaded window.applySidebarRoles = function(role, additionalRoles) { if (!role) return; additionalRoles = additionalRoles || []; var show = function(id) { var el = document.getElementById(id); if (el) el.style.display = el.tagName === 'A' ? 'flex' : 'block'; }; var hide = function(id) { var el = document.getElementById(id); if (el) el.style.display = 'none'; }; // Clinical roles: Psychologist / Psychiatrist // Show ONLY My Cases and My Profile — hide everything else if (role === 'psychologist' || role === 'psychiatrist') { // Hide main nav items var mainItems = s.querySelectorAll('.nav-item:not(#myCasesNavItem)'); for (var k = 0; k < mainItems.length; k++) { mainItems[k].style.display = 'none'; } // Hide section labels var labels = s.querySelectorAll('.nav-section-label'); for (var l = 0; l < labels.length; l++) { labels[l].style.display = 'none'; } // Show only My Cases and My Profile show('myCasesNavItem'); // My Profile is always visible via Account section - re-show it var profileItem = s.querySelector('.nav-item[data-page="my-profile"]'); if (profileItem) profileItem.style.display = 'flex'; return; // Skip all other role checks } // GC / Admin / Counselor if (['superadmin','admin','counselor'].includes(role)) { show('managementLabel'); show('usersNavItem'); } // Buy Tokens: admin, counselor if (role === 'admin' || role === 'counselor') { show('buyTokensNavItem'); } // ORL-35: a counselor who ALSO holds an additional Psychologist/Psychiatrist // role keeps their full GC nav (unlike a single-role clinical account above) // but additionally gets the My Cases item, since they can be assigned cases. if (role === 'counselor' && (additionalRoles.includes('psychologist') || additionalRoles.includes('psychiatrist'))) { show('myCasesNavItem'); } // Superadmin-only items if (role === 'superadmin') { show('managementLabel'); show('usersNavItem'); show('orgsNavItem'); show('contactsNavItem'); show('pricingNavItem'); show('tokensNavItem'); show('auditLogNavItem'); } }; // Auto-apply roles - poll until currentUser is available var attempts = 0; var rolePoller = setInterval(function() { attempts++; if (window.currentUser && window.currentUser.role) { window.applySidebarRoles(window.currentUser.role, window.currentUser.additionalRoles); clearInterval(rolePoller); } else if (attempts > 50) { clearInterval(rolePoller); } }, 100); // ── HAMBURGER MENU FOR MOBILE ────────────────── // Add overlay var overlay = document.createElement('div'); overlay.className = 'sidebar-overlay'; overlay.onclick = function() { closeSidebar(); }; document.body.appendChild(overlay); // Add hamburger button to topbar (inject immediately — script runs after DOM) var topbar = document.querySelector('.topbar'); if (topbar) { var hamburger = document.createElement('button'); hamburger.className = 'hamburger-btn'; hamburger.innerHTML = '☰'; hamburger.onclick = function() { window.toggleSidebar(); }; topbar.insertBefore(hamburger, topbar.firstChild); } window.toggleSidebar = function() { s.classList.toggle('open'); overlay.classList.toggle('show'); document.body.style.overflow = s.classList.contains('open') ? 'hidden' : ''; }; window.closeSidebar = function() { s.classList.remove('open'); overlay.classList.remove('show'); document.body.style.overflow = ''; }; // Close sidebar when nav item is clicked (mobile) var navItems = s.querySelectorAll('.nav-item'); for (var j = 0; j < navItems.length; j++) { navItems[j].addEventListener('click', function() { closeSidebar(); }); } // ── SESSION TIMEOUT ──────────────────────────────────── var SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes var WARNING_BEFORE = 5 * 60 * 1000; // warn at 25 minutes var sessionTimer, warningTimer, warningShown = false; function resetSessionTimer() { clearTimeout(sessionTimer); clearTimeout(warningTimer); // Remove warning banner if showing if (warningShown) { var banner = document.getElementById('session-warning-banner'); if (banner) banner.remove(); warningShown = false; } // Set warning timer (25 min) warningTimer = setTimeout(function() { showSessionWarning(); }, SESSION_TIMEOUT - WARNING_BEFORE); // Set logout timer (30 min) sessionTimer = setTimeout(function() { doSessionLogout(); }, SESSION_TIMEOUT); } function showSessionWarning() { warningShown = true; var banner = document.createElement('div'); banner.id = 'session-warning-banner'; banner.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:99999;background:#f59e0b;color:#1a1a1a;padding:12px 24px;text-align:center;font-family:Arial,sans-serif;font-size:14px;font-weight:600;display:flex;align-items:center;justify-content:center;gap:16px;'; banner.innerHTML = '⚠️ Your session will expire in 5 minutes due to inactivity. '; document.body.insertBefore(banner, document.body.firstChild); } function doSessionLogout() { sessionStorage.removeItem('hopeAndCopeUser'); alert('Your session has expired due to inactivity. Please log in again.'); window.location.href = '../login.html'; } // Listen for user activity ['mousemove','keydown','click','scroll','touchstart'].forEach(function(evt) { document.addEventListener(evt, resetSessionTimer, { passive: true }); }); // Start the timer resetSessionTimer(); window.resetSessionTimer = resetSessionTimer; })();