Files
solution-erp/.claude/agent-memory/frontend-designer/archive/2026-06.md
2026-07-30 09:46:39 +07:00

31 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frontend-designer — archive 2026-06 (L2 verbatim · FROZEN additive)
> Curated from L1 `MEMORY.md` @S96 (2026-07-01) — first-overflow distillation (L1 hit 26129B > autoinject-cap 25600B, H17-loop strike-1). Older Activity-log war-stories moved here VERBATIM (byte-exact, additive-only — NEVER rewrite existing bytes). Recent 3 (S79/S69×2) + all reference sections (design-system · FD2-rig · component-inventory · lessons) stay in L1. Map → `_INDEX.md` · 4-field distill → `2026-06.gist.md`.
## Activity log (archived — moved-set, newest-of-moved on top)
- **S66 (2026-06-16) HRM Hồ sơ Nhân sự fe-user REFINE từ eoffice LIVE (3 việc) — layout 3-cột→2-cột + tô màu detail:** anh góp ý sau khi xem prod. **Việc 1 (layout):** 3-cột-ngang `[tree 244 | list 352 | detail 1fr]`**2-cột** `lg:grid-cols-[22rem_1fr] xl:[24rem_1fr]`: CỘT TRÁI = `<div flex flex-col gap-4>` ôm tree (TRÊN, `lg:max-h-[44%] lg:shrink-0`, overflow-auto) + list+filter (DƯỚI, `flex-1`, overflow-auto) — mỗi panel cuộn độc lập; CỘT PHẢI = detail (flex-1, rộng hơn nhiều, đỡ chật). <lg vẫn 1-col treelistdetail + giữ nguyên `treeOpenMobile` toggle. **Việc 2+3 (màu detail):** thêm `ACCENT` map 5 tone (brand/teal/violet/amberx/greenx) `Card` prop `accent` icon-chip nền nhạt (`--chip-bg/--chip-fg`) + heading `text-{x}-700` + rail trái pseudo-element; `Field` label uppercase `text-{x}-700` semibold (was slate-400 đơn điệu) + value `font-medium text-slate-900`; mỗi card/section gán 1 accent màu nhưng tinh tế, brand #1F7DC1 + Be Vietnam Pro + avatar gradient brand GIỮ. **Strategy chống truncation #53 = ONE atomic `Write` cả file** (1556 LOC) emit change-list + build status SỚM. **2 self-caught bug TRƯỚC build:** (1) `text-{teal,violet,greenx}-800` accent palettes KHÔNG stop -800 (chỉ 50/100/500/600/700) Tailwind v4 silent no-class đổi head sang -700 (all AA on white); (2) rail pseudo thiếu `before:content-['']` ::before không render box thêm. `npm run build` (tsc -b strict + vite v8) **PASS 0 TS err, 495ms** (warning @import-order + chunk-size = pre-existing, không phải mình). **5 satellite CRUD + 15 satellite api endpoint + top-level del + 3 reads + 3 query keys (employees-list/employee-detail/departments-tree-hrm) + cây SOLUTION COMPANY + 5 tab + search/filter preserved VERBATIM** (grep: 15 satellite api.post/put/delete + 3 queryKey + 5 form fns; tsc type-checks mọi payload shape = wiring bất biến). FD2 authed-screenshot SKIPPED per task instruction + gotcha #3 (rig chặn authed ProtectedRoute; anh xem qua deploy) structural verify thay thế. fe-admin + BE NOT touched, no commit (em main commits). Tag [s66, hrm-2col-refine, eoffice-ref, accent-system, atomic-write-antitrunc, crud-preserved, build-pass, tailwind-v4-stop-gotcha].
- **S65 (2026-06-16) HRM Hồ Nhân sự fe-user 3-panel master-detail NamGroup-ref:** RESTRUCTURE `EmployeesListPage.tsx` (1201→~1140 LOC) 6 `<details>` [Org tree | List | Detail 5-tab]. **Strategy chống truncation #53 = ONE atomic `Write` (cả file)** thay piecemeal Edit (atomic Write either fully-lands or errors, KHÔNG half-break) emit change-list TRƯỚC build DID BOTH Part A (avatar header+5 tab+sectiontab redistribution) + Part B (org tree panel) trong 1 pass, không phải defer B. Org tree consume `/departments/tree` verified BE-side (DepartmentFeatures.cs DepartmentTreeNodeDto, controller `[HttpGet("tree")]`, class-Authorize only). Foundation màu mới DÙNG: `.app-gradient-brand` header / `.icon-chip` / accent palette teal/violet/amberx/greenx (avatar tones) brand #1F7DC1 + Be Vietnam Pro KEPT. **5 satellite CRUD + 16 api endpoint + query keys preserved VERBATIM** (grep-verified: 16 api.post/put/delete identical payload shape, 5 form fns intact). `npm run build` (tsc -b strict + vite) **PASS 0 TS err, 6.13s**. 1 self-caught bug: typo garbage token `网络Placeholder` trong lucide import (mojibake autocomplete) removed, all 21 icons valid (node-checked). FD2 authed-screenshot SKIPPED per explicit task instruction + gotcha #3 (rig blocks authed; anh xem qua deploy) did static structural verify instead (grep endpoint/key preservation). fe-admin NOT touched (mirror = separate pass), no commit. Tag [s65, hrm-3panel, namgroup-ref, atomic-write-antitrunc, crud-preserved, build-pass].
- **S58 (2026-06-11) fe-user redesign theo UI/UX guide AI_INFRA canonical KEEP brand [em main proxy truncated #53 giữa FD2 screenshot, 2nd consecutive]:** Mirror design-system fe-admin S55 14 file fe-user (index.css heading-ladder+.label-eyebrow / 6 ui primitives Button gần SHA-identical fe-admin chỉ khác comment / 6 shell DataTable+RowActions-additive·Layout-brand-left-rail·TopBar·PageHeader·PhaseBadge-ring·EmptyState / LoginPage polish). Rubric mới = guide 13 mục `D:\Dropbox\CONG_VIEC\AI_INFRA\docs\reference\ui-ux-design-guide.md` (density 14px/h32-34/radius-8/thead-sticky/action-luôn-hiện/no-font-bold). BRAND KEPT: #1F7DC1 + Be Vietnam Pro + slate (guide cho plug hue riêng). Chết NGAY TRƯỚC with_server.py screenshot /login em main recover: build ×2 PASS 0 TS + diff-review key-stability từng file + ship `e959f72`; authed visual qua deploy prod (rig-gotcha #3 standing). LESSON: 2 lần liên tiếp truncate CÙNG điểm (sau khi sửa xong, lúc bắt đầu FD2 rig) lần sau EMIT file-list verdict TRƯỚC khi vào screenshot loop. Tag [s58, fe-user-redesign, guide-aiinfra, keep-brand, truncated-53-proxy].
- **S55 (2026-06-09) Phase-1 fe-admin redesign density-first NAMGROUP-ref, KEEP brand** [em main proxy truncated #53]: 14 file (index.css density ladder + 6 ui primitive Button h-7/8/10 brand-ring + 6 shell + DashboardPage KPI). Brand #1F7DC1+Be Vietnam Pro KEPT. build 0 TS. Visual loop BLOCKED authed-rig#3 chỉ /login. S58 mirror sang fe-user. (detail archive nếu cần). Tag [s55, density-namgroup, keep-brand].
- **S47 (2026-06-02) FD2 RIG VERIFIED ✅** first real spawn. Ran full FD2 loop end-to-end on fe-user `/login`: read DS (Tailwind v4 CSS-first, corrected stale config-path assumption) started Vite via `with_server.py` Playwright screenshot 375+1440 Read PNGs FD4 critique 1-line contrast fix re-screenshot confirmed `npm run build` 0 TS error. Closes adap-report `2026-06-02-Agent-frontend-designer-floor` FD2 runtime proof. 2 Vite gotchas captured above. Loop is REAL, not theoretical.
## Moved @S160 (2026-07-29) — verbatim from L1 Activity log (moved-not-cut)
- **S69 (2026-06-17) OfficeDashboardPage.tsx fe-user E-Office landing, PURO HomePage, COMPOSES 3 shared widgets:** built `pages/office/OfficeDashboardPage.tsx` (~400 LOC) over EXISTING data hooks of 4 modules. Read-first: 3 ui widgets (exact prop sigs) + 4 source pages (ProposalsListPage/WorkflowAppsListPage/ItTicketsPage/MeetingCalendarPage) to harvest queryKey+endpoint + types + App.tsx routes. **Reused hooks verbatim** shared TanStack cache, ZERO new API/BE: `GET /proposals` (+inboxOnly query for needs-my-action) · `/leave|ot|travel-requests` (merged, countByStatus client-side) · `/it-tickets` · `/meeting-bookings` (today window). Layout = PageHeader(brand) + `lg:grid-cols-3` [LEFT col-span-2 = 4 WidgetCards w/ KpiCard filter-chip bodies | RIGHT col-span-1 = "Công việc của tôi" hero+MetricRows + "Thao tác nhanh" 3 buttons], 1-col <lg. **Routing insight (verified App.tsx):** đơn-từ + ticket have NO standalone `/new` route (creation in-page) quick-actions point at landings `/workflow-apps/leave` + `/it-tickets` (only `/proposals/new` is a real create route) so no link hits the `*` "chưa build" fallback. Per-widget graceful states: WidgetError(retry)/WidgetSkeleton(pulse, motion-reduce)/empty never blocks. a11y full (role=button+Enter/Space+focus-ring on clickables, reduced-motion). `npm run build` (tsc -b strict + vite v8) **PASS 0 TS err, 434ms** (only pre-existing @import-order + chunk-size + INEFFECTIVE_DYNAMIC_IMPORT warnings none from new file). Routing/menu NOT wired (next agent; page not yet in App.tsx). fe-admin NOT mirrored. FD2 authed-screenshot SKIP (ProtectedRoute + rig gotcha #3 verify via deploy). Tag [s69, office-dashboard, compose-3-widgets, reuse-hooks-shared-cache, no-new-be, routing-existing-only, build-pass].
- **S69 (2026-06-17) Văn phòng số / Đơn từ fe-user RE-SKIN (PURO + HRM visual lang) 2 file, CONSUMES shared ui (parallel fan-out, 7 agents same app):** surgical re-skin (KHÔNG rewrite) `pages/office/WorkflowAppsListPage.tsx` + `WorkflowAppDetailPage.tsx` (`:kind`-driven leave/ot/travel/vehicle via KIND_CONFIG). **LIST:** swap `@/components/PageHeader`(constrained)→`@/components/ui/PageHeader`(eyebrow "Văn phòng số · Đơn từ" / title từ KIND_CONFIG / icon per-kind / **accent teal**) + status filter = ROW 4 `ui/KpiCard` (Tất cả teal / Đã gửi duyệt amberx / Trả lại violet / Đã duyệt greenx, `grid-cols-2 sm:grid-cols-4`) + slate table chrome (thead uppercase 11px slate-500, hover teal-50). **Filter là CLIENT-SIDE view** added `useState<StatusFilter>` + 2 `useMemo` (counts + visibleItems) DERIVED over already-fetched `items`; **KHÔNG touch query/endpoint/queryKey/navigation** (page chỉ fetch `page:1` như , không filter-state sẵn nên thêm view-layer = thuần presentation; empty-state phân biệt "chưa data" vs "không đơn trạng thái này"). **DETAIL:** ui/PageHeader teal + 4 section dùng local `Card`(accent-rail pseudo `before:bg-{x}-500` + icon-chip) + `Field`(label uppercase `text-{x}-700`, value `text-brand-800`) copy idiom HRM EmployeesListPage (KHÔNG import HRM, helper local riêng). Accent gán: Thông tin=teal · Số phép=greenx · Quy trình=violet · Ý kiến=brand. Status badge giữ `WORKFLOW_APP_STATUS_BADGE`. Drop raw "⚠" emoji trong over-budget bannertext thuần (anti-slop FD3). **ALL data logic VERBATIM** (grep-verified): 2 query `[endpoint,id]`+`['approval-workflows-v2',applicableType]` (key/endpoint/`enabled` y nguyên) · 3 mutation pinWorkflow(PUT /workflow)/submit(POST /submit)/action(POST /{k}) body+onSuccess+invalidate identical · 3 state + flags isDraft/isInWorkflow/hasWorkflow + mọi onClick/nav target bất biến. **gotcha Tailwind-v4 stop:** dùng CHỈ -50/-500/-700 cho teal/violet/amberx/greenx (no -800) `border-l-greenx-500`/`bg-amberx-50`/`text-amberx-700` đều stop tồn tại (index.css verified). **Self-caught:** `SendHorizonal` (KpiCard "Đã gửi duyệt" icon) export-aggregation-line trong lucide d.ts đổi `Send` (proven-safe export) tránh alias-risk. Self-review: mọi import resolve, 0 unused local (noUnusedLocals strict) `Info`/`Wallet`/`GitBranch`/`MessageSquareText` đều dùng. **KHÔNG run npm build** (em main builds central, 7-agent parallel interference) + KHÔNG modify ui/index.css (other agents edit). FD2 authed-screenshot SKIP (ProtectedRoute + rig gotcha #3 verify via deploy). fe-admin NOT mirrored. Tag [s69, eoffice-donutu-reskin, puro-hrm-visual, consume-ui-pageheader-kpicard, client-side-filter-view, logic-verbatim, no-build-parallel-fanout, lucide-alias-dodge].
## S79 (2026-06-19) PE list fe-user — DECOUPLE chọn/mở-rộng
- **S79 (2026-06-19) PE list fe-user DECOUPLE chọn/mở-rộng (anh chốt, annotated screenshot):** `pages/pe/PurchaseEvaluationsListPage.tsx`. S78 cũ: bấm dòng = mở overlay full-bleed, 2 panel giữa/phải placeholder vĩnh viễn. S79 đổi: **bấm dòng = inline 3-panel detail "như cũ" (8e68ed1)** + thêm nút **"Xem mở rộng"** mỗi dòng overlay. Mechanism = param thứ-2 **`?expand=1`** cạnh `?id`: overlay render CHỈ khi `id && expand`; inline detail (panel giữa `<PeDetailTabs readOnly onBack=closeDetail>` + panel phải `<PeWorkflowPanel readOnly={!pendingMe} onApproved>`) render khi `id && !expand`. Handlers: `selectRow`=set id+clear expand (NHƯNG `<lg`/innerWidth<1024 set expand=1 đi thẳng overlay 3-panel không vừa) · `expandRow`=id+expand=1 · `collapseFocus`(Thu gọn/Esc/backdrop)=`setParam('expand',null)` GIỮ id (về inline, KHÔNG về list) · `closeDetail`(← Đóng/del)=clear id+expand list · `onApproved`=clear cả hai list (phiếu rời inbox). Overlay gate đổi `hasSelection``overlayActive=id&&expand`; Esc gọi collapseFocus (không closeFocus). Nút "Xem mở rộng" = `Maximize2` (lucide, import THÊM) icon-btn 7×7 góc phải-trên mỗi leaf row, `opacity-0 group-hover/row:opacity-100` + `opacity-100` khi selected, `title`+`aria-label`+brand focus-ring; leaf `<button>` bọc trong `<div className="group/row relative">` + `pr-9` chừa chỗ nút. **ALL logic VERBATIM** (grep ✓): 3 queryKey (`approval-workflows-v2-filter`/`pe-list`/`pe-detail`) · 3 endpoint (`/inbox`+paged+detail) · `del` mutation (onSuccess giờ clear id+expand thay `setParam`) · `yearGroups` 4-tầng tree memo · `PeUrgentChips` pill · search/filter/SLA/localStorage-expand. `PurchaseEvaluationDetailPage` route GIỮ. **slide+a11y S78 giữ NGUYÊN** (mount-rAF×2, role=dialog/aria-modal, focus-trap Tab-vòng, body scroll-lock, motion-reduce). `npm run build` (tsc -b strict + vite v8) **PASS 0 TS err, 570ms** (3 warning pre-existing). **FD2: static layout-shell harness** (backend :5443 down authed dev-rig blocked gotcha#3) Playwright 6 shot × 3 state: (a) inline 3-panel desktop1920+laptop1280 = list+PeDetailTabs giữa+PeWorkflowPanel phải, dòng-chọn nút Maximize2; (b) overlay 1920+1280 = full-bleed phiếu+panel cạnh; (c) mobile390 list (1-col, nút mở-rộng) + mobile390 overlay (stack). Read tất 6 PNG đúng hết, no overflow, pill+tree intact. Harness/driver/shots ĐÃ XÓA. Rubric PASS. fe-admin NOT mirrored (implementer-frontend SHA-mirror riêng), no BE, no commit. Tag [s79, pe-decouple-select-expand, expand-param, maximize2-row-btn, inline-restore-8e68ed1, lg-straight-overlay, collapse-keeps-id, logic-verbatim, build-pass, harness-fd2].
## S69 (2026-06-17) 3 shared UI cho Văn phòng số / E-Office
- **3 shared UI cho Văn phòng số / E-Office (S69, 2026-06-17) PURO-style + HRM visual language. ALL build-PASS 0 TS:**
- `fe-user/src/components/ui/PageHeader.tsx` **richer page header** (eyebrow/title/subtitle/icon/accent/actions/breadcrumb). KHÁC `@/components/PageHeader` (constrained {title,description,actions}) module path `@/components/ui/PageHeader` riêng, KHÔNG collision. icon-chip accent-tinted + title `text-xl font-bold` accent-head. Local `ACCENT` map {chipBg,chipFg,head} (brand=text-brand-800, rest -700). Title trên nền SÁNG KHÔNG cần `text-white!`.
- `fe-user/src/components/ui/KpiCard.tsx` **clickable stat card = FILTER chip** (PURO: row KpiCards thay tabs). icon-chip + `.stat-value text-2xl` accent + `.label-eyebrow`. active = `bg-{x}-50` + `border-{x}-300` + `ring-{x}-500`. a11y FULL: `onClick``role=button`+`tabIndex=0`+Enter/Space (`e.key===' '`)+`aria-pressed=active`+focus-visible ring; no-onClick = inert div. hover `-translate-y-0.5` + `motion-reduce:transform-none`.
- `fe-user/src/components/ui/WidgetCard.tsx` **dashboard widget container** (PURO HomePage). Wrap `.card-accent` (rail via inline `--accent`). Header: brand=`.app-gradient-brand text-white` · non-brand=tinted `bg-{x}-50` bar. **gotcha 66 APPLIED:** gradient `<h3>` title = **`text-white!`** (bang) plain text-white thua unlayered h1-h4 rule. Props: title/icon/accent/stats[]/onExpand/onRefresh/children/empty/emptyText. `stats[]` = clickable StatChip row (mỗi chip a11y button khi onClick). empty muted icon-chip + emptyText. Header IconButton (RefreshCw/Maximize2) contrast-adapt gradienttinted, aria-label.
- **3 đều:** NAMED export · `import type` (verbatimModuleSyntax) · `cn` from `@/lib/cn` · lucide-react · accent palettes stop 50/100/500/600/700 ONLY (no -800) head/value -700 (brand -800 OK) · icon-chip recolor `['--chip-bg' as string]`/`['--chip-fg' as string]` inline (pattern từ HRM Card). NO new npm dep. Build `tsc -b && vite` PASS 0 TS, 24.87s (warning @import-order + chunk-size = pre-existing). fe-admin NOT mirrored (separate pass nếu cần). FD2 authed-screenshot SKIP (components chưa wired vào page nào pure library; visual verify khi page tiêu thụ chúng).
## S69 (2026-06-17) OfficeDashboardPage.tsx — E-Office landing
- `fe-user/src/pages/office/OfficeDashboardPage.tsx` **E-Office landing dashboard (S69, 2026-06-17) — PURO HomePage, COMPOSES the 3 shared ui widgets. build-PASS 0 TS, 434ms.** Layout: `ui/PageHeader` (eyebrow "Văn phòng số" / title "Bảng điều khiển" / icon LayoutDashboard / accent brand) on top `grid grid-cols-1 lg:grid-cols-3 gap-5`: LEFT `lg:col-span-2` = stack of 4 `WidgetCard` (Đề xuất brand / Đơn từ teal / Ticket CNTT violet / Phòng họp hôm nay amberx each body = row of 3 `KpiCard` filter-chips except Phòng họp = 1 KpiCard + next-4 booking peek list) · RIGHT `lg:col-span-1` = "Công việc của tôi" WidgetCard (brand-50 hero count `myTodo` + 3 clickable `MetricRow`) + "Thao tác nhanh" `.card-accent` panel (3 Button primary/secondary/outline). Stacks 1-col <lg. **Hooks REUSED (verbatim queryKey+endpoint = shared TanStack cache, NO new API, NO new BE):** proposals `['proposals',{…}]``GET /proposals` (+ separate `inboxOnly:true` query for "Cần duyệt" = needs-my-action signal) · đơn-từ `['/leave-requests'|'/ot-requests'|'/travel-requests',{page:1}]`those 3 endpoints, merged+`countByStatus` client-side · tickets `['it-tickets']``GET /it-tickets` · meetings `['meeting-bookings',{…}]``GET /meeting-bookings` windowed to today (local-midnight→+1d ISO). **Counts ALL client-side** (`countByStatus` reducer; status enums from `@/types/proposal` + `@/types/workflowApps`). **States graceful per-widget:** isError`WidgetError` (retry btn, accent-500 chip) · isLoading`WidgetSkeleton` (3 pulse bars, `motion-reduce:animate-none`) · emptyWidgetCard `empty` prop. NEVER blocks page. **Routing question:** only `/proposals/new` exists as real create route quick-actions "Tạo đề xuất"→`/proposals/new`, "Tạo đơn"→`/workflow-apps/leave` (đơn-từ landing, NO standalone /new), "Tạo ticket"→`/it-tickets` (ticket landing) every link hits an EXISTING route (no `*` fallback dead-link). onExpand per widget its real route. a11y: KpiCard/MetricRow clickable = role=button+Enter/Space+focus-ring; reduced-motion honored. Routing/menu wiring NOT done (next agent's job page NOT imported in App.tsx yet). fe-admin NOT mirrored. FD2 authed-screenshot SKIP (ProtectedRoute + gotcha #3 rig blocks authed; visual verify via deploy).