fix financial and certificates

This commit is contained in:
root
2026-06-05 01:51:12 -04:00
parent 647b96cafc
commit c4d7a06a17
16 changed files with 1689 additions and 374 deletions
+37 -6
View File
@@ -1,5 +1,6 @@
import { useEffect, useMemo, useState, type ReactNode } from 'react'
import { Link, NavLink, Outlet, useLocation, useNavigate } from 'react-router-dom'
import { ApiHttpError } from '../api/http'
import { fetchNavMenu } from '../api/session'
import type { NavItem } from '../api/types'
import { useAuth } from '../auth/AuthProvider'
@@ -8,6 +9,25 @@ import {
spaPathFromCiUrl,
} from '../lib/ciSpaPaths'
const navLabelCollator = new Intl.Collator(undefined, {
sensitivity: 'base',
numeric: true,
})
function compareNavItemsByLabel(a: NavItem, b: NavItem): number {
const labelResult = navLabelCollator.compare(a.label?.trim() || '', b.label?.trim() || '')
return labelResult || a.id - b.id
}
function sortNavTree(items: NavItem[]): NavItem[] {
return [...items]
.map((item) => ({
...item,
children: sortNavTree(item.children ?? []),
}))
.sort(compareNavItemsByLabel)
}
function normalizeNavItems(payload: unknown): NavItem[] {
const rawItems = Array.isArray(payload)
? (payload as NavItem[])
@@ -20,7 +40,7 @@ function normalizeNavItems(payload: unknown): NavItem[] {
if (rawItems.length === 0) return []
if (rawItems.some((item) => Array.isArray(item.children) && item.children.length > 0)) {
return rawItems
return sortNavTree(rawItems)
}
const byId = new Map<number, NavItem>()
@@ -38,7 +58,7 @@ function normalizeNavItems(payload: unknown): NavItem[] {
}
}
return tree
return sortNavTree(tree)
}
function branchContainsPath(item: NavItem, pathname: string): boolean {
@@ -59,8 +79,6 @@ function NavTree({ items, pathname }: { items: NavItem[]; pathname: string }) {
function NavBranch({ item, depth, pathname }: { item: NavItem; depth: number; pathname: string }) {
const enabled = item.is_enabled !== 0
if (!enabled) return null
const label = item.label?.trim() || 'Menu'
const url = item.url?.trim() || ''
const external = isExternalNavUrl(url)
@@ -71,7 +89,7 @@ function NavBranch({ item, depth, pathname }: { item: NavItem; depth: number; pa
<i className={`${item.icon_class} me-2`} aria-hidden />
) : null
const children = (item.children ?? []).filter((c) => c.is_enabled !== 0)
const children = sortNavTree((item.children ?? []).filter((c) => c.is_enabled !== 0))
const hasChildren = children.length > 0
const [open, setOpen] = useState(() => hasChildren && branchContainsPath(item, pathname))
@@ -81,6 +99,8 @@ function NavBranch({ item, depth, pathname }: { item: NavItem; depth: number; pa
}
}, [hasChildren, item, pathname])
if (!enabled) return null
const linkInner = (
<>
{icon}
@@ -187,6 +207,17 @@ export function ManagementLayout() {
}
} catch (e) {
if (!cancelled) {
if (e instanceof ApiHttpError && e.status === 401) {
logout()
navigate('/login', {
replace: true,
state: {
from: `${location.pathname}${location.search}${location.hash}`,
message: 'Your session expired. Please sign in again.',
},
})
return
}
setItems([])
setMenuError(e instanceof Error ? e.message : 'Unable to load menu.')
}
@@ -195,7 +226,7 @@ export function ManagementLayout() {
return () => {
cancelled = true
}
}, [])
}, [location.hash, location.pathname, location.search, logout, navigate])
const navTree = useMemo(() => normalizeNavItems(items), [items])