[CLAUDE] Fix sidebar highlight: strip transient keys (id/q/awId/...) khỏi queryMatches
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m17s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m17s
Bug UAT 2026-05-08: ở leaf "Danh sách" /purchase-evaluations?type=1, click
chọn 1 phiếu → URL thành ?type=1&id=abc → leaf bị mất highlight box.
Root cause: queryMatches exact-set equality — `{type}` (target) vs
`{type, id}` (current) length mismatch → no match → leaf unhighlight.
Fix: TRANSIENT_QUERY_KEYS = {id, q, editHeader, page, phase, awId} —
strip trước khi compare. Match dựa trên "navigation identity" only.
Edge case verify (cả 2 case quan trọng đều OK):
- /pe?type=1 click phiếu → ?type=1&id=abc → strip id → match Danh sách ✓
- /pe?type=1&pendingMe=1 → strip nothing → distinct với Danh sách ?type=1 ✓
- /pe?type=1&phase=10 (filter) → strip phase → match Danh sách ✓
- /pe?type=1&pendingMe=1&awId=xyz → strip awId → match Duyệt ✓
Mirror fe-admin + fe-user.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -192,14 +192,19 @@ function MenuGroup({ node, depth }: { node: MenuNode; depth: number }) {
|
||||
)
|
||||
}
|
||||
|
||||
// So sánh 2 query string dạng key-value set (thứ tự param không quan trọng).
|
||||
// Dùng để distinguish /path?type=2 vs /path?type=2&pendingMe=1 — NavLink isActive
|
||||
// built-in chỉ match pathname, không check query string.
|
||||
// Transient query keys — không phải "navigation identity", strip trước khi
|
||||
// compare để menu giữ highlight khi user select row / search / filter.
|
||||
// Ví dụ leaf "Danh sách" `?type=1` vẫn highlight khi user click phiếu →
|
||||
// `?type=1&id=abc`. Trước đó exact-set match → mất highlight (bug UAT 2026-05-08).
|
||||
const TRANSIENT_QUERY_KEYS = new Set(['id', 'q', 'editHeader', 'page', 'phase', 'awId'])
|
||||
|
||||
// So sánh 2 query string dạng key-value set (thứ tự param không quan trọng,
|
||||
// transient keys ignored). Dùng để distinguish /path?type=2 vs /path?type=2&pendingMe=1.
|
||||
function queryMatches(current: string, target: string): boolean {
|
||||
const a = new URLSearchParams(current)
|
||||
const b = new URLSearchParams(target)
|
||||
const aKeys = [...a.keys()].sort()
|
||||
const bKeys = [...b.keys()].sort()
|
||||
const aKeys = [...a.keys()].filter(k => !TRANSIENT_QUERY_KEYS.has(k)).sort()
|
||||
const bKeys = [...b.keys()].filter(k => !TRANSIENT_QUERY_KEYS.has(k)).sort()
|
||||
if (aKeys.length !== bKeys.length) return false
|
||||
return aKeys.every((k, i) => bKeys[i] === k && a.get(k) === b.get(k))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user