Unify Consultant navigation and align full-width header

This commit is contained in:
A R R R Associates
2026-07-11 10:57:08 +05:30
parent a31c39155a
commit b62644c6bf
3 changed files with 65 additions and 40 deletions
@@ -18,21 +18,7 @@
</div>
</section>
<section class="rounded-3xl border border-slate-200 bg-white p-3 shadow-soft">
{% set tabs = [
('overview','Overview'),
('work-centre','Work Centre'),
('clients-requests','Clients & Requests'),
('documents-clarifications','Documents & Clarifications'),
('reports','Reports')
] %}
<div class="flex gap-2 overflow-x-auto" id="consultant-portal-tabs">
{% for code, label in tabs %}
<button type="button" data-tab="{{ code }}" class="consultant-portal-tab whitespace-nowrap rounded-2xl px-4 py-2 text-sm font-semibold transition {% if active_tab == code %}bg-brand-600 text-white{% else %}text-slate-600 hover:bg-slate-100{% endif %}">{{ label }}</button>
{% endfor %}
</div>
</section>
{# Dashboard sections are now available from the global Consultant Dashboard menu. #}
<section id="consultant-portal-panel">
{% if active_tab == 'work-centre' %}
{% include "modules/consultants/templates/consultants/portal_partials/work_centre.html" %}
@@ -50,24 +36,10 @@
<script>
(function(){
const buttons = Array.from(document.querySelectorAll('.consultant-portal-tab'));
const panel = document.getElementById('consultant-portal-panel');
if (!buttons.length || !panel) return;
function activate(tab) {
buttons.forEach(btn => {
if (btn.dataset.tab === tab) {
btn.classList.add('bg-brand-600','text-white');
btn.classList.remove('text-slate-600','hover:bg-slate-100');
} else {
btn.classList.remove('bg-brand-600','text-white');
btn.classList.add('text-slate-600','hover:bg-slate-100');
}
});
}
if (!panel) return;
async function loadTab(tab) {
activate(tab);
panel.innerHTML = '<div class="rounded-3xl border border-slate-200 bg-white p-8 text-center text-sm text-slate-500 shadow-soft">Loading...</div>';
try {
const res = await fetch('/consultant/dashboard/tab/' + encodeURIComponent(tab), {headers: {'X-Requested-With':'fetch'}});
@@ -79,7 +51,7 @@
}
}
buttons.forEach(btn => btn.addEventListener('click', () => loadTab(btn.dataset.tab)));
window.loadConsultantDashboardTab = loadTab;
})();
</script>
{% endblock %}
@@ -1,19 +1,23 @@
{% if navigation_render_location_v2|default('page') == 'global-host' or not global_role_navigation_host_v2|default(false) %}
{#
UI/UX V2 Phase 1C — Consultant pilot navigation
This component preserves the existing consultant portal URLs and visibility.
It changes presentation only and does not grant access, change routes, or
replace the consultant dashboard's existing AJAX content tabs.
UI/UX V2 Phase 1C.3 Unified Consultant navigation.
Presentation only. Existing routes and route-level permissions remain authoritative.
#}
{% set _consultant_path = request.url.path %}
{% set _consultant_tab = request.query_params.get('tab', 'overview') %}
{% set navigation_aria_label_v2 = 'Consultant workspace navigation' %}
{% set navigation_items_v2 = [
{
'label': 'Dashboard',
'url': '/consultant/dashboard',
'visible': true,
'active': _consultant_path == '/consultant/dashboard'
'active': _consultant_path.startswith('/consultant/dashboard'),
'children': [
{'label': 'Overview', 'url': '/consultant/dashboard?tab=overview', 'active': _consultant_path.startswith('/consultant/dashboard') and _consultant_tab == 'overview'},
{'label': 'Work Centre', 'url': '/consultant/dashboard?tab=work-centre', 'active': _consultant_path.startswith('/consultant/dashboard') and _consultant_tab == 'work-centre'},
{'label': 'Clients & Requests', 'url': '/consultant/dashboard?tab=clients-requests', 'active': _consultant_path.startswith('/consultant/dashboard') and _consultant_tab == 'clients-requests'},
{'label': 'Documents & Clarifications', 'url': '/consultant/dashboard?tab=documents-clarifications', 'active': _consultant_path.startswith('/consultant/dashboard') and _consultant_tab == 'documents-clarifications'},
{'label': 'Reports', 'url': '/consultant/dashboard?tab=reports', 'active': _consultant_path.startswith('/consultant/dashboard') and _consultant_tab == 'reports'}
]
},
{
'label': 'Work',
@@ -66,8 +70,57 @@
}
] %}
<div class="mb-6 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-soft" data-uiux-v2-pilot="consultant">
<div class="border-b border-slate-200 bg-white shadow-sm" data-uiux-v2-pilot="consultant">
{% include "ui/templates/components/navigation_v2.html" %}
{% include "ui/templates/components/mobile_navigation_v2.html" %}
</div>
<script>
(function () {
"use strict";
function initialiseConsultantDropdowns() {
var root = document.querySelector('[data-uiux-v2-pilot="consultant"]');
if (!root || root.dataset.dropdownAutoCloseInitialised === 'true') return;
var desktopNav = root.querySelector('nav[data-uiux-v2="desktop-navigation"]');
if (!desktopNav) return;
root.dataset.dropdownAutoCloseInitialised = 'true';
var dropdowns = Array.from(desktopNav.querySelectorAll('details'));
function closeAllExcept(exception) {
dropdowns.forEach(function (details) {
if (details !== exception) details.removeAttribute('open');
});
}
dropdowns.forEach(function (details) {
details.addEventListener('toggle', function () {
if (details.open) closeAllExcept(details);
});
details.querySelectorAll('a[href]').forEach(function (link) {
link.addEventListener('click', function () {
details.removeAttribute('open');
});
});
});
document.addEventListener('click', function (event) {
if (!root.contains(event.target)) closeAllExcept(null);
});
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape') closeAllExcept(null);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialiseConsultantDropdowns, { once: true });
} else {
initialiseConsultantDropdowns();
}
})();
</script>
{% endif %}
@@ -1,4 +1,4 @@
{% set _uiux_full_width_header = ('System Admin' in (ui_roles|default([], true))) or ('Firm Admin' in (ui_roles|default([], true))) or ('Partner' in (ui_roles|default([], true))) or ('Manager' in (ui_roles|default([], true))) or ('Branch Manager' in (ui_roles|default([], true))) or ('Staff' in (ui_roles|default([], true))) or ('Employee' in (ui_roles|default([], true))) or ('Client' in (ui_roles|default([], true))) %}
{% set _uiux_full_width_header = ('System Admin' in (ui_roles|default([], true))) or ('Firm Admin' in (ui_roles|default([], true))) or ('Partner' in (ui_roles|default([], true))) or ('Manager' in (ui_roles|default([], true))) or ('Branch Manager' in (ui_roles|default([], true))) or ('Staff' in (ui_roles|default([], true))) or ('Employee' in (ui_roles|default([], true))) or ('Client' in (ui_roles|default([], true))) or ('Consultant' in (ui_roles|default([], true))) %}
<header class="sticky top-0 z-40 border-b border-slate-200/70 {{ 'bg-white/95' if _uiux_full_width_header else 'bg-slate-100/85' }} backdrop-blur-xl">
<div class="{{ 'w-full px-4 py-3 sm:px-6 lg:px-8' if _uiux_full_width_header else 'mx-auto max-w-[1500px] px-3 py-3 sm:px-6 lg:px-8' }}">
<div class="{{ 'border-0 bg-transparent px-0 py-0 shadow-none' if _uiux_full_width_header else 'rounded-3xl border border-slate-200 bg-white/95 px-3 py-3 shadow-soft sm:px-4' }}">