diff --git a/.Net Capstone Project/sidebarv8.js b/.Net Capstone Project/sidebarv8.js new file mode 100644 index 0000000..ca265d7 --- /dev/null +++ b/.Net Capstone Project/sidebarv8.js @@ -0,0 +1,126 @@ +// 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 = ` + + + `; + + 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(); +}