DotNet_Capstone_Project/.Net Capstone Project/sidebarv8.js

127 lines
5.7 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Single source of truth for the left navigation on EVERY page.
//
// Two problems this file solves:
//
// 1. Pages that never call renderSidebar() — it self-initialises on
// DOMContentLoaded, so just including the script is enough.
//
// 2. Pages with their own custom script that renders a DIFFERENT (shorter)
// menu — a MutationObserver watches the container and re-asserts the full
// list whenever something replaces it. This is why CDS Alerts and
// Observations were showing only 10 items while the Dashboard showed all
// of them: those pages build their own nav after this script has run.
//
// Adding a nav item? Add it to SIDEBAR_ITEMS and it appears everywhere.
const SIDEBAR_ITEMS = [
{ key: 'dashboard', href: 'dashboard.html', icon: '🏠', label: 'Dashboard' },
{ key: 'patients', href: 'patients.html', icon: '🧑\u200d⚕', label: 'Patients' },
{ key: 'conditions', href: 'conditions.html', icon: '🩺', label: 'Conditions' },
{ key: 'observations', href: 'observations.html', icon: '📈', label: 'Observations' },
{ key: 'allergies', href: 'allergies.html', icon: '⚠️', label: 'Allergies' },
{ key: 'medications', href: 'medications.html', icon: '💊', label: 'Medications' },
{ key: 'encounters', href: 'encounters.html', icon: '📅', label: 'Encounters' },
{ key: 'organizations', href: 'organizations.html', icon: '🏥', label: 'Organizations' },
{ key: 'locations', href: 'locations.html', icon: '📍', label: 'Locations' },
{ key: 'practitioners', href: 'practitioners.html', icon: '👨‍⚕️', label: 'Practitioners' },
{ key: 'practitionerroles', href: 'practitionerroles.html', icon: '🩹', label: 'Practitioner Roles' },
{ key: 'servicerequests', href: 'servicerequests.html', icon: '📄', label: 'Service Requests' },
{ key: 'riskassessments', href: 'riskassessments.html', icon: '📊', label: 'Risk Assessment' },
{ key: 'cdsalerts', href: 'cdsalerts.html', icon: '🔔', label: 'CDS Alerts' },
{ key: 'careplans', href: 'careplans.html', icon: '📋', label: 'Care Plans' },
{ key: 'cdsrules', href: 'cdsrules.html', icon: '⚙️', label: 'CDS Rules' },
{ key: 'users', href: 'users.html', icon: '👤', label: 'Users' }
];
// Pages that deliberately have no sidebar (public / auth screens).
const SIDEBAR_EXCLUDED_PAGES = ['index.html', 'login.html', 'register.html', 'callback.html'];
// Set while this script is writing to the container, so the observer below
// doesn't react to its own changes and loop forever.
let sidebarWriting = false;
function sidebarContainer() {
return document.getElementById('appSidebar') || document.querySelector('.app-sidebar');
}
// Works out which item to highlight from the URL, so a page doesn't have to
// pass its key in. An explicit key still wins when one is supplied.
function sidebarKeyFromUrl() {
const file = (window.location.pathname.split('/').pop() || 'dashboard.html').toLowerCase();
const match = SIDEBAR_ITEMS.find(i => i.href.toLowerCase() === file);
return match ? match.key : '';
}
function renderSidebar(activeKey) {
const container = sidebarContainer();
if (!container) return;
const key = activeKey || sidebarKeyFromUrl();
const collapsed = localStorage.getItem('cip_sidebar_collapsed') === '1';
sidebarWriting = true;
container.innerHTML = `
<button class="sidebar-toggle" id="sidebarToggle" type="button"
title="Collapse / expand menu" aria-label="Toggle navigation">☰</button>
<nav class="sidebar-nav">
${SIDEBAR_ITEMS.map(i => `
<a href="${i.href}" class="sidebar-link ${i.key === key ? 'active' : ''}" title="${i.label}">
<span class="sidebar-icon">${i.icon}</span><span class="sidebar-text">${i.label}</span>
</a>`).join('')}
</nav>
`;
applySidebarState(collapsed);
document.getElementById('sidebarToggle').addEventListener('click', () => {
const nowCollapsed = !document.body.classList.contains('sidebar-collapsed');
applySidebarState(nowCollapsed);
localStorage.setItem('cip_sidebar_collapsed', nowCollapsed ? '1' : '0');
});
// Release on the next tick so the observer ignores this whole write.
setTimeout(() => { sidebarWriting = false; }, 0);
}
function applySidebarState(collapsed) {
document.body.classList.toggle('sidebar-collapsed', collapsed);
}
// Re-render if the menu ever ends up with the wrong number of links — which
// is what happens when a page's own script overwrites the container after
// this one has run.
function guardSidebar() {
const container = sidebarContainer();
if (!container) return;
new MutationObserver(() => {
if (sidebarWriting) return;
const links = container.querySelectorAll('.sidebar-link').length;
if (links !== SIDEBAR_ITEMS.length) renderSidebar();
}).observe(container, { childList: true, subtree: true });
}
function initSidebar() {
const file = (window.location.pathname.split('/').pop() || '').toLowerCase();
if (SIDEBAR_EXCLUDED_PAGES.includes(file)) return;
renderSidebar();
guardSidebar();
// Belt and braces for pages whose own script runs late (after images and
// stylesheets finish loading).
window.addEventListener('load', () => {
const container = sidebarContainer();
if (container && container.querySelectorAll('.sidebar-link').length !== SIDEBAR_ITEMS.length) {
renderSidebar();
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSidebar);
} else {
initSidebar();
}