[CLAUDE] FE-Admin FE-User: Chunk U — Sidebar truncate long label + tooltip (Mig 27 DisplayLabel dài wrap fix)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s

Bro UAT screenshot 2026-05-15: Submenu "1. Duyệt Nhà Cung Cấp - Thầu phụ
(NCC -TP)" trong sidebar fe-user wrap 2 dòng (label dài ~50 chars vs
sidebar w-60 = 240px chỉ fit ~25 chars).

Root: Admin đã set DisplayLabel custom qua Mig 27 (S20 t7 Menu eOffice
admin page) — `MenuItems.Pe_DuyetNcc` DisplayLabel = "1. Duyệt Nhà Cung
Cấp - Thầu phụ (NCC -TP)" (Label gốc = "Duyệt NCC" ngắn). FE render
{effectiveLabel(node)} thẳng vào span flex KHÔNG có truncate.

Fix Plan U mirror 2 app (rule §3.9):

3 nơi render label trong fe-user/Layout.tsx + 2 nơi mirror fe-admin:
1. MenuNodeRenderer button (accordion toggle):
   ```diff
   - <span className="flex items-center gap-2">
   + <span className="flex min-w-0 flex-1 items-center gap-2">
   -   <Icon className="h-4 w-4" />
   -   {effectiveLabel(node)}
   +   <Icon className="h-4 w-4 shrink-0" />
   +   <span className="truncate" title={effectiveLabel(node)}>{effectiveLabel(node)}</span>
     </span>
   - <ChevronDown ... transition />
   + <ChevronDown ... shrink-0 ... transition />
   ```

2. MenuLeaf NavLink:
   ```diff
   - <NavLink to={path} className={cn('flex items-center gap-2.5...')}>
   + <NavLink to={path} title={effectiveLabel(node)} className={cn('flex min-w-0 items-center gap-2.5...')}>
   -   <Icon className={cn(isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
   -   {effectiveLabel(node)}
   +   <Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
   +   <span className="truncate">{effectiveLabel(node)}</span>
     </NavLink>
   ```

3. StaticLeaf NavLink (fe-user only — Hộp thư static entry):
   Pattern tương tự MenuLeaf

fe-admin dùng `node.label` thay vì `effectiveLabel(node)` (admin sidebar
luôn show Label gốc, KHÔNG đụng DisplayLabel per S20 t7 Q2=b).

Pattern key:
- `min-w-0 flex-1` trên flex parent — cần thiết để truncate child shrink
- `shrink-0` trên Icon + ChevronDown — giữ size không co
- `truncate` (Tailwind = overflow-hidden text-ellipsis whitespace-nowrap) trên span text
- `title={label}` tooltip hover show full label nếu user cần đọc đầy đủ

Verify:
- npm run build fe-user PASS 16.79s clean
- npm run build fe-admin PASS 8.16s clean
- 0 TS error

KHÔNG đụng BE. Admin tự control DisplayLabel qua Mig 27 Menu eOffice page
— Plan U chỉ ensure FE render gracefully với label dài (truncate +
tooltip hover) thay vì wrap broken visual.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-15 15:33:17 +07:00
parent 7b7b28f2cd
commit 86d8806afc
2 changed files with 25 additions and 17 deletions

View File

@ -141,11 +141,13 @@ function MenuGroup({ node, depth }: { node: MenuNode; depth: number }) {
: 'px-3 py-1.5 text-[13px] font-medium text-slate-600 hover:bg-slate-100 hover:text-slate-900',
)}
>
<span className="flex items-center gap-2">
<Icon className="h-4 w-4" />
{node.label}
{/* Plan U S23 t11 — truncate label dài + tooltip hover (mirror fe-user
rule §3.9). min-w-0 cần thiết cho truncate flex child. */}
<span className="flex min-w-0 flex-1 items-center gap-2">
<Icon className="h-4 w-4 shrink-0" />
<span className="truncate" title={node.label}>{node.label}</span>
</span>
<ChevronDown className={cn('h-3.5 w-3.5 text-slate-400 transition', !open && '-rotate-90')} />
<ChevronDown className={cn('h-3.5 w-3.5 shrink-0 text-slate-400 transition', !open && '-rotate-90')} />
</button>
{open && (
<div className={cn(
@ -193,16 +195,17 @@ function MenuLeaf({ node, depth }: { node: MenuNode; depth: number }) {
return (
<NavLink
to={path}
title={node.label}
className={cn(
'flex items-center gap-2.5 rounded-md transition',
'flex min-w-0 items-center gap-2.5 rounded-md transition',
isDeep ? 'px-3 py-1 text-[12px]' : 'px-3 py-2 text-sm font-medium',
isActive
? 'bg-brand-50 text-brand-700'
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
)}
>
<Icon className={cn(isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
{node.label}
<Icon className={cn('shrink-0', isDeep ? 'h-3.5 w-3.5' : 'h-4 w-4')} />
<span className="truncate">{node.label}</span>
</NavLink>
)
}