diff --git a/app/modules/clients/templates/clients/_client_tabs.html b/app/modules/clients/templates/clients/_client_tabs.html index 357add7..bd12389 100644 --- a/app/modules/clients/templates/clients/_client_tabs.html +++ b/app/modules/clients/templates/clients/_client_tabs.html @@ -1 +1,12 @@ -{# Replaced by the permanent permission-aware navigation in base/layout.html. #} +
+
+ {% set path = request.url.path %} + Overview + My Compliance + My Documents + My Messages + My Bills + My Profile + My Alert +
+
diff --git a/app/modules/consultants/templates/consultants/_consultant_tabs.html b/app/modules/consultants/templates/consultants/_consultant_tabs.html index 357add7..b3abbaa 100644 --- a/app/modules/consultants/templates/consultants/_consultant_tabs.html +++ b/app/modules/consultants/templates/consultants/_consultant_tabs.html @@ -1 +1,14 @@ -{# Replaced by the permanent permission-aware navigation in base/layout.html. #} +{% set path = request.url.path %} +
+ +
diff --git a/app/modules/employees/templates/employees/_my_workspace_tabs.html b/app/modules/employees/templates/employees/_my_workspace_tabs.html index 357add7..bbdc683 100644 --- a/app/modules/employees/templates/employees/_my_workspace_tabs.html +++ b/app/modules/employees/templates/employees/_my_workspace_tabs.html @@ -1 +1,38 @@ -{# Replaced by the permanent permission-aware navigation in base/layout.html. #} +{% set current_path = request.url.path %} +{% set _tab_base = "inline-flex shrink-0 items-center rounded-xl px-3 py-2 text-sm font-semibold whitespace-nowrap transition" %} +{% set _tab_active = "bg-brand-600 text-white shadow-soft" %} +{% set _tab_idle = "border border-slate-300 bg-white text-slate-700 hover:bg-slate-50" %} +
+
My Workspace
+
+
+ {% if can_view_employee_portal(current_user, current_user_permissions, current_user_roles) %} + Overview + {% endif %} + {% if can_view_own_employee_work(current_user, current_user_permissions, current_user_roles) %} + My Work Board + {% endif %} + {% if can_view_own_employee_attendance(current_user, current_user_permissions, current_user_roles) %} + My Attendance + {% endif %} + {% if can_view_employee_portal(current_user, current_user_permissions, current_user_roles) %} + My Profile + {% endif %} + {% if can_view_own_employee_leave(current_user, current_user_permissions, current_user_roles) %} + My Leave + {% endif %} + {% if can_view_own_employee_documents(current_user, current_user_permissions, current_user_roles) %} + My Documents + {% endif %} + {% if can_view_own_employee_payslips(current_user, current_user_permissions, current_user_roles) %} + My Payslips + {% endif %} + {% if can_request_own_employee_offboarding(current_user, current_user_permissions, current_user_roles) %} + My Offboarding + {% endif %} + + My Alert{% if unread_alert_count is defined and unread_alert_count > 0 %}{{ unread_alert_count }}{% endif %} + +
+
+
diff --git a/app/modules/managers/templates/managers/_manager_tabs.html b/app/modules/managers/templates/managers/_manager_tabs.html index 357add7..21fc760 100644 --- a/app/modules/managers/templates/managers/_manager_tabs.html +++ b/app/modules/managers/templates/managers/_manager_tabs.html @@ -1 +1,12 @@ -{# Replaced by the permanent permission-aware navigation in base/layout.html. #} +{% set manager_path = request.url.path %} +
+
+ Overview + Team Work Board + Detailed Allocation + Engagement Progress + Team Attendance + Team Leave + My Alert +
+
diff --git a/app/modules/partners/templates/partners/_partner_tabs.html b/app/modules/partners/templates/partners/_partner_tabs.html index 357add7..5d9a71c 100644 --- a/app/modules/partners/templates/partners/_partner_tabs.html +++ b/app/modules/partners/templates/partners/_partner_tabs.html @@ -1 +1,12 @@ -{# Replaced by the permanent permission-aware navigation in base/layout.html. #} +{% set path = request.url.path %} +
+
+ Overview + Review Board + My Clients + Engagements + Documents + Billing + My Alert +
+
diff --git a/app/static/js/navigation_shell.js b/app/static/js/navigation_shell.js deleted file mode 100644 index 6a9c10c..0000000 --- a/app/static/js/navigation_shell.js +++ /dev/null @@ -1,98 +0,0 @@ -(function () { - 'use strict'; - - function textOf(el) { - return (el.textContent || '').replace(/\s+/g, ' ').trim(); - } - - function prepareMobileNavigation() { - var desktop = document.querySelector('nav[aria-label="Primary navigation"]'); - var drawer = document.getElementById('af-mobile-nav'); - var target = drawer && drawer.querySelector('[data-af-mobile-links]'); - var open = document.querySelector('[data-af-mobile-open]'); - if (!desktop || !drawer || !target || !open) return; - - var clone = desktop.cloneNode(true); - clone.className = 'block'; - clone.removeAttribute('aria-label'); - clone.querySelectorAll('.af-nav-menu').forEach(function (menu) { - menu.classList.remove('af-nav-menu'); - menu.classList.add('ml-3', 'mt-1', 'space-y-1', 'border-l', 'border-slate-200', 'pl-3'); - }); - clone.querySelectorAll('.af-nav-dropdown').forEach(function (item) { - item.classList.add('rounded-xl', 'border', 'border-slate-200', 'p-1'); - }); - clone.querySelectorAll('.af-nav-link, .af-nav-summary').forEach(function (item) { - item.classList.add('block', 'w-full'); - }); - target.appendChild(clone); - - function show() { - drawer.classList.remove('hidden'); - drawer.setAttribute('aria-hidden', 'false'); - document.documentElement.classList.add('overflow-hidden'); - } - function hide() { - drawer.classList.add('hidden'); - drawer.setAttribute('aria-hidden', 'true'); - document.documentElement.classList.remove('overflow-hidden'); - } - open.addEventListener('click', show); - drawer.querySelectorAll('[data-af-mobile-close]').forEach(function (button) { button.addEventListener('click', hide); }); - drawer.querySelectorAll('a').forEach(function (link) { link.addEventListener('click', hide); }); - document.addEventListener('keydown', function (event) { if (event.key === 'Escape') hide(); }); - } - - function normalizeBackAction() { - var slot = document.getElementById('af-shared-back-slot'); - var main = document.querySelector('main'); - if (!slot || !main) return; - - var candidates = Array.prototype.slice.call(main.querySelectorAll('a, button')); - var existing = candidates.find(function (el) { - if (el.closest('#af-page-context')) return false; - var text = textOf(el).toLowerCase(); - return text === 'back' || text.indexOf('back to ') === 0 || text.indexOf('← back') === 0; - }); - - if (existing) { - existing.className = 'inline-flex items-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-semibold text-slate-700 shadow-sm transition hover:border-brand-300 hover:text-brand-700'; - if (textOf(existing).indexOf('←') !== 0) existing.textContent = '← ' + textOf(existing); - slot.appendChild(existing); - return; - } - - var path = window.location.pathname.replace(/\/$/, ''); - var segments = path.split('/').filter(Boolean); - var isRoot = segments.length <= 1 || /\/(dashboard|workspaces)$/.test(path); - if (isRoot) return; - - var referrerIsLocal = false; - try { referrerIsLocal = !!document.referrer && new URL(document.referrer).origin === window.location.origin; } catch (e) {} - if (!referrerIsLocal && window.history.length <= 1) return; - - var button = document.createElement('button'); - button.type = 'button'; - button.className = 'inline-flex items-center rounded-xl border border-slate-300 bg-white px-3 py-2 text-xs font-semibold text-slate-700 shadow-sm transition hover:border-brand-300 hover:text-brand-700'; - button.textContent = '← Back'; - button.addEventListener('click', function () { - if (referrerIsLocal || window.history.length > 1) window.history.back(); - else window.location.href = '/workspaces'; - }); - slot.appendChild(button); - } - - function closeDesktopDropdowns() { - document.addEventListener('click', function (event) { - document.querySelectorAll('[data-af-nav-dropdown][open]').forEach(function (item) { - if (!item.contains(event.target)) item.removeAttribute('open'); - }); - }); - } - - document.addEventListener('DOMContentLoaded', function () { - prepareMobileNavigation(); - normalizeBackAction(); - closeDesktopDropdowns(); - }); -})(); diff --git a/app/ui/static/pwa/sw.js b/app/ui/static/pwa/sw.js index e0758cd..922d6b9 100644 --- a/app/ui/static/pwa/sw.js +++ b/app/ui/static/pwa/sw.js @@ -1,4 +1,4 @@ -const CACHE_VERSION = 'arrr-erp-pwa-v2-navigation-fix'; +const CACHE_VERSION = 'arrr-erp-pwa-v1'; const CORE_ASSETS = [ '/manifest.webmanifest', '/static/css/theme_tokens.css', @@ -8,20 +8,14 @@ const CORE_ASSETS = [ self.addEventListener('install', (event) => { event.waitUntil( - caches.open(CACHE_VERSION) - .then((cache) => cache.addAll(CORE_ASSETS)) - .catch(() => undefined) + caches.open(CACHE_VERSION).then((cache) => cache.addAll(CORE_ASSETS)).catch(() => undefined) ); self.skipWaiting(); }); self.addEventListener('activate', (event) => { event.waitUntil( - caches.keys().then((keys) => Promise.all( - keys - .filter((key) => key !== CACHE_VERSION) - .map((key) => caches.delete(key)) - )) + caches.keys().then((keys) => Promise.all(keys.filter((key) => key !== CACHE_VERSION).map((key) => caches.delete(key)))) ); self.clients.claim(); }); @@ -33,47 +27,16 @@ self.addEventListener('fetch', (event) => { const url = new URL(request.url); if (url.origin !== self.location.origin) return; - // Cache static assets only. Never substitute a CSS response for an HTML page. if (url.pathname.startsWith('/static/')) { event.respondWith( - caches.match(request).then((cached) => { - if (cached) return cached; - - return fetch(request).then((response) => { - if (response && response.ok) { - const copy = response.clone(); - caches.open(CACHE_VERSION) - .then((cache) => cache.put(request, copy)) - .catch(() => undefined); - } - return response; - }); - }) + caches.match(request).then((cached) => cached || fetch(request).then((response) => { + const copy = response.clone(); + caches.open(CACHE_VERSION).then((cache) => cache.put(request, copy)).catch(() => undefined); + return response; + })) ); return; } - // Application pages, login, API calls and downloads remain network-first. - // If the network is unavailable, return a valid HTML response instead of CSS. - event.respondWith( - fetch(request).catch(() => { - if (request.mode === 'navigate') { - return new Response( - 'Offline | Audit Firm ERP

You are offline

The ERP could not reach the server. Check your internet connection and refresh this page.

', - { - status: 503, - headers: { - 'Content-Type': 'text/html; charset=utf-8', - 'Cache-Control': 'no-store' - } - } - ); - } - - return new Response('', { - status: 503, - headers: { 'Cache-Control': 'no-store' } - }); - }) - ); + event.respondWith(fetch(request).catch(() => caches.match('/static/css/theme_tokens.css'))); }); diff --git a/app/ui/templates/base/layout.html b/app/ui/templates/base/layout.html index b301bfd..8f2acb1 100644 --- a/app/ui/templates/base/layout.html +++ b/app/ui/templates/base/layout.html @@ -4,22 +4,22 @@ {% set __title_user = current_user if current_user is defined else None %} - {% set __firm_branding = get_current_firm_branding(request, __title_user)|default(none, true) %} - + {% set __firm_branding = get_current_firm_branding(request, __title_user) %} + - {% if __firm_branding and (__firm_branding.favicon_url|default("", true)) %}{% endif %} + {% if __firm_branding.favicon_url %}{% endif %} {% set __title_auth = __title_user and request.session.get("otp_verified", False) %} {% if __title_auth %} {% set __title_firm = get_current_tenant_name(request, __title_user) %} {% set __title_branch = get_current_branch_name(request, __title_user) %} {{ title or "Workspace" }} | {{ __title_firm }}{% if __title_branch and __title_branch != "-" %} - {{ __title_branch }}{% endif %} {% else %} - {{ title or "Welcome" }} | {{ (__firm_branding.firm_name|default("", true)) if __firm_branding else "Audit Firm ERP" }} + {{ title or "Welcome" }} | {{ __firm_branding.firm_name or "Audit Firm ERP" }} {% endif %} - diff --git a/app/ui/templates/components/breadcrumbs.html b/app/ui/templates/components/breadcrumbs.html deleted file mode 100644 index d1d099b..0000000 --- a/app/ui/templates/components/breadcrumbs.html +++ /dev/null @@ -1,21 +0,0 @@ -{% set crumb_path = request.url.path %} -{% set crumb_parts = crumb_path.strip('/').split('/') if crumb_path != '/' else [] %} -{% set crumb_labels = { - 'system-admin':'System Administration','firm-admin':'Firm Administration','partner':'Partner','manager':'Manager','employee':'Employee','employees':'Team','consultant':'Consultant','consultants':'Consultants','client':'Client','clients':'Clients','services':'Services','engagements':'Engagements','documents':'Documents','billing':'Billing','system-settings':'Firm Setup','users':'Users','rbac':'Roles & Permissions','roles':'Roles','branches':'Branches','financial-years':'Financial Years','audit-logs':'Audit Logs','alerts':'Alerts','work':'Work','attendance':'Attendance','leave':'Leave','profile':'Profile','dashboard':'Dashboard','reviews':'Reviews','compliance':'Compliance','messages':'Messages','imports':'Imports','import':'Import','export':'Export','new':'New','edit':'Edit','settings':'Settings','domains':'Domains','email':'Email','aqmm':'AQMM','peer-review':'Peer Review','evidence':'Evidence' -} %} -
-
- -
-
-
diff --git a/app/ui/templates/components/role_navigation.html b/app/ui/templates/components/role_navigation.html deleted file mode 100644 index b3a3cb4..0000000 --- a/app/ui/templates/components/role_navigation.html +++ /dev/null @@ -1,182 +0,0 @@ -{% set nav_path = request.url.path %} -{% set nav_roles = ui_roles if ui_roles is defined else [] %} -{% set nav_perms = ui_perms if ui_perms is defined else [] %} -{% set nav_workspace = 'employee' %} -{% if nav_path.startswith('/system-admin') %}{% set nav_workspace = 'system' %} -{% elif nav_path.startswith('/firm-admin') %}{% set nav_workspace = 'firm' %} -{% elif nav_path.startswith('/partner') %}{% set nav_workspace = 'partner' %} -{% elif nav_path.startswith('/manager') or nav_path.startswith('/employees/work') or nav_path.startswith('/employees/progress') or nav_path.startswith('/employees/attendance') or nav_path.startswith('/employees/leave') %}{% set nav_workspace = 'manager' %} -{% elif nav_path.startswith('/consultant') %}{% set nav_workspace = 'consultant' %} -{% elif nav_path.startswith('/client') %}{% set nav_workspace = 'client' %} -{% elif nav_path.startswith('/employee') %}{% set nav_workspace = 'employee' %} -{% elif 'System Admin' in nav_roles %}{% set nav_workspace = 'system' %} -{% elif 'Firm Admin' in nav_roles %}{% set nav_workspace = 'firm' %} -{% elif 'Partner' in nav_roles %}{% set nav_workspace = 'partner' %} -{% elif 'Manager' in nav_roles or 'Branch Manager' in nav_roles %}{% set nav_workspace = 'manager' %} -{% elif 'Consultant' in nav_roles %}{% set nav_workspace = 'consultant' %} -{% elif 'Client' in nav_roles %}{% set nav_workspace = 'client' %} -{% endif %} - -{% macro nav_link(url, label, prefixes=None) -%} - {% set checks = prefixes if prefixes else [url] %} - {% set ns = namespace(active=false) %} - {% for prefix in checks %}{% if nav_path == prefix or nav_path.startswith(prefix ~ '/') %}{% set ns.active = true %}{% endif %}{% endfor %} - {{ label }} -{%- endmacro %} - -{% macro dropdown(label, prefixes) -%} - {% set ns = namespace(active=false) %} - {% for prefix in prefixes %}{% if nav_path == prefix or nav_path.startswith(prefix ~ '/') %}{% set ns.active = true %}{% endif %}{% endfor %} -
- {{ label }} -
{{ caller() }}
-
-{%- endmacro %} - - - - diff --git a/app/ui/templates/components/top_workspace_bar.html b/app/ui/templates/components/top_workspace_bar.html index 769386a..a4aa317 100644 --- a/app/ui/templates/components/top_workspace_bar.html +++ b/app/ui/templates/components/top_workspace_bar.html @@ -1,72 +1,85 @@ -
-
-
-
- - {% if current_firm_logo_url|default("", true) %} - {{ current_firm_name }} logo +
+
+
+
+ + {% if firm_branding.logo_url %} + {{ current_firm_name }} logo {% else %} -
{{ (current_firm_name[:2] if current_firm_name else 'AF')|upper }}
+
{{ (current_firm_name[:2] if current_firm_name else 'AF')|upper }}
{% endif %} -
diff --git a/app/ui/templates/components/workspace_switcher.html b/app/ui/templates/components/workspace_switcher.html index ea440e4..d172dc1 100644 --- a/app/ui/templates/components/workspace_switcher.html +++ b/app/ui/templates/components/workspace_switcher.html @@ -3,15 +3,18 @@ {% set perms = ui_perms if ui_perms is defined else [] %} {% set current = current_path if current_path is defined else request.url.path %} {% set can_employee = ('Staff' in roles) or ('Employee' in roles) or ('employees.ess.view' in perms) or ('employees.work.view_self' in perms) or ('employees.attendance.view_self' in perms) or ('employees.leave.view_self' in perms) or ('employees.documents.view_self' in perms) or ('employees.payroll.view_self' in perms) %} - - +
+ + + All workspaces +
{% endif %}