[CLAUDE] FE-Admin: PE InfoTab inline edit Section 1 + PeListPanel pencil edit hover
User feedback 2026-05-07: muốn thêm nút edit kế bên row trong Panel 1, click →
Panel 2 sáng nội dung Section 1 lên cho user sửa header inline (KHÔNG cần đi
"Sửa header" page). Cũng muốn create new interface gần giống detail view
sectioned (defer cho chunk sau, hoặc keep PeHeaderForm nếu user OK).
Implementation:
~ PeDetailTabs.tsx
- InfoTab thêm prop `readOnly` + `autoEdit` (trigger edit mode tự động khi
mount nếu URL ?editHeader=1)
- canEdit = !readOnly && isDraft (DangSoanThao):
→ display mode: hiển thị FormRow + button "✎ Sửa" góc trên phải Section 1
→ editing mode (click Sửa hoặc autoEdit): card border brand-200 + 4 input
(Tên * / Dự án disabled / Địa điểm / Mô tả / Payment) + nút Lưu/Hủy
- Save: PUT /pe/:id full payload (current ev values + new editable fields).
onSuccess: invalidate ['pe-detail', 'pe-list'] + setEditing(false)
- PeDetailTabs prop `autoEditHeader` mới — pass-through xuống InfoTab
~ PeListPanel.tsx
- Thêm prop `onEditClick?: (id) => void`
- Pencil icon (lucide) absolute right-2 top-2 trong mỗi <li>, opacity-0
group-hover:opacity-100 — chỉ hiện khi user hover row + onEditClick set
- Click → trigger onEditClick(id) callback (different from row click)
~ PurchaseEvaluationWorkspacePage.tsx
- Đọc URL ?editHeader=1 → pass autoEditHeader xuống PeDetailTabs
- PeListPanel onEditClick → setParams({ id, mode: null, editHeader: '1' })
- onSelect (click row thường) → editHeader: null (clear flag)
- onBack → clear editHeader
Verify: npm run build fe-admin pass · 0 TS error.
Pending: workspace "new" mode wrap PeHeaderForm trong sectioned layout giống
detail view (defer — user có thể chấp nhận PeHeaderForm hiện tại nếu OK).
Next: Chunk 2 fe-user mirror.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -34,6 +34,7 @@ export function PurchaseEvaluationWorkspacePage() {
|
||||
const phase = sp.get('phase') ?? ''
|
||||
const selectedId = sp.get('id')
|
||||
const mode = sp.get('mode') // 'new' | null
|
||||
const autoEditHeader = sp.get('editHeader') === '1'
|
||||
|
||||
const detail = useQuery({
|
||||
queryKey: ['pe-detail', selectedId],
|
||||
@ -77,17 +78,18 @@ export function PurchaseEvaluationWorkspacePage() {
|
||||
</header>
|
||||
|
||||
<div className="grid flex-1 grid-cols-1 overflow-hidden lg:grid-cols-[320px_1fr]">
|
||||
{/* Panel 1: List pure picker + sticky create */}
|
||||
{/* Panel 1: List pure picker + sticky create + pencil edit hover */}
|
||||
<PeListPanel
|
||||
typeFilter={typeFilter}
|
||||
selectedId={selectedId}
|
||||
search={search}
|
||||
phase={phase}
|
||||
onSelect={id => setParams({ id, mode: null })}
|
||||
onSelect={id => setParams({ id, mode: null, editHeader: null })}
|
||||
onSearchChange={q => setParams({ q })}
|
||||
onPhaseChange={p => setParams({ phase: p })}
|
||||
showCreateButton
|
||||
onCreate={() => setParams({ mode: 'new', id: null })}
|
||||
onCreate={() => setParams({ mode: 'new', id: null, editHeader: null })}
|
||||
onEditClick={id => setParams({ id, mode: null, editHeader: '1' })}
|
||||
/>
|
||||
|
||||
{/* Panel 2: Empty | Header form | Detail tabs (workspace mode) */}
|
||||
@ -117,9 +119,10 @@ export function PurchaseEvaluationWorkspacePage() {
|
||||
{selectedId && detail.data && (
|
||||
<PeDetailTabs
|
||||
evaluation={detail.data}
|
||||
onBack={() => setParams({ id: null })}
|
||||
onBack={() => setParams({ id: null, editHeader: null })}
|
||||
onDelete={() => del.mutate(detail.data!.id)}
|
||||
mode="workspace"
|
||||
autoEditHeader={autoEditHeader}
|
||||
/>
|
||||
)}
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user