From e320027074a544d3d36a8dfd8b2d931a6297b481 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Thu, 7 May 2026 16:41:33 +0700 Subject: [PATCH] [CLAUDE] FE-Admin+FE-User: PE InfoTab auto re-edit on pencil click + active state visual feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User feedback 2026-05-07: bấm pencil cho phiếu khác KHÔNG sáng + KHÔNG vào edit mode (do useState init mount-time only, ev.id thay đổi không re-trigger). Cũng cần visual feedback "sáng lên" để user biết đang edit phiếu nào. Implementation: ~ PeDetailTabs.tsx (× 2 app) + import useEffect ~ InfoTab: thêm useEffect watch [autoEdit, canEdit, ev.id, ev.tenGoiThau, ev.diaDiem, ev.moTa, ev.paymentTerms]. Khi autoEdit && canEdit → setEditing(true) + sync values từ ev mới (tránh stale state khi switch giữa 2 phiếu khác id). Note: Dự án disabled đã có sẵn (line 458 ``) — verify hỏi user, KHÔNG thay đổi. ~ PeListPanel.tsx (× 2 app) + Prop `editingRowId?: string | null` — row đang edit (URL editHeader=1) ~ Pencil icon: thêm `isEditingThis = editable && editingRowId === p.id` state → bg-brand-100 + text-brand-700 + ring-brand-300 + shadow-sm khi active → tooltip đổi "✎ Đang sửa phiếu này — click để toggle / xem khác" ~ PurchaseEvaluationWorkspacePage.tsx (× 2 app) + Pass `editingRowId={autoEditHeader ? selectedId : null}` xuống PeListPanel Verify: npm run build fe-admin + fe-user pass · 0 TS error · áp rule strict verify khi add new prop chain + useEffect. UAT mode: skip dotnet test (FE-only), push ngay. Co-Authored-By: Claude Opus 4.7 (1M context) --- fe-admin/src/components/pe/PeDetailTabs.tsx | 16 +++++++++++++++- fe-admin/src/components/pe/PeListPanel.tsx | 17 ++++++++++++++--- .../pe/PurchaseEvaluationWorkspacePage.tsx | 1 + fe-user/src/components/pe/PeDetailTabs.tsx | 16 +++++++++++++++- fe-user/src/components/pe/PeListPanel.tsx | 17 ++++++++++++++--- .../pe/PurchaseEvaluationWorkspacePage.tsx | 1 + 6 files changed, 60 insertions(+), 8 deletions(-) diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index 1ccdd26..668df84 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -2,7 +2,7 @@ // NCC + Hạng mục + Báo giá stack vertically trong 1 màn hình. // Duyệt history + Lịch sử thay đổi → moved to Panel 3 (xem PeWorkflowPanel // → PeApprovalsSection + PeHistorySection). -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useNavigate } from 'react-router-dom' import { toast } from 'sonner' @@ -399,6 +399,20 @@ function InfoTab({ ev, readOnly, autoEdit }: { ev: PeDetailBundle; readOnly: boo const [moTa, setMoTa] = useState(ev.moTa ?? '') const [paymentTerms, setPaymentTerms] = useState(ev.paymentTerms ?? '') + // User 2026-05-07: re-trigger editing mode khi click pencil ở Panel 1 cho + // PHIẾU KHÁC (ev.id thay đổi) hoặc autoEdit prop change. useState init chỉ + // chạy mount-time → cần useEffect sync khi parent re-render với props mới. + useEffect(() => { + if (autoEdit && canEdit) { + setEditing(true) + // Sync values từ ev mới (tránh stale state khi switch giữa 2 phiếu) + setTenGoiThau(ev.tenGoiThau) + setDiaDiem(ev.diaDiem ?? '') + setMoTa(ev.moTa ?? '') + setPaymentTerms(ev.paymentTerms ?? '') + } + }, [autoEdit, canEdit, ev.id, ev.tenGoiThau, ev.diaDiem, ev.moTa, ev.paymentTerms]) + const dirty = tenGoiThau !== ev.tenGoiThau || diaDiem !== (ev.diaDiem ?? '') || moTa !== (ev.moTa ?? '') diff --git a/fe-admin/src/components/pe/PeListPanel.tsx b/fe-admin/src/components/pe/PeListPanel.tsx index f7bea17..14c3c9d 100644 --- a/fe-admin/src/components/pe/PeListPanel.tsx +++ b/fe-admin/src/components/pe/PeListPanel.tsx @@ -39,6 +39,7 @@ export function PeListPanel({ onCreate, onEditClick, editableOnly = false, + editingRowId = null, }: { typeFilter: number | null pendingMe?: boolean @@ -55,6 +56,9 @@ export function PeListPanel({ /** Workspace mode: chỉ list phiếu editable (DangSoanThao + TraLai). Filter * client-side sau khi fetch — BE chưa hỗ trợ multi-phase param. */ editableOnly?: boolean + /** Row đang được edit (URL editHeader=1) — pencil icon "sáng lên" active state. + * User 2026-05-07: visual feedback khi click pencil. */ + editingRowId?: string | null }) { const list = useQuery({ queryKey: ['pe-list', { typeFilter, pendingMe, search, phase }], @@ -185,20 +189,27 @@ export function PeListPanel({ {/* Edit pencil — LUÔN visible (user 2026-05-07). Bright/active khi phase editable (DangSoanThao + TraLai). Dim/disabled khi phase không edit được (Đã gửi duyệt / Đã duyệt - / Từ chối) — click không có tác dụng. */} + / Từ chối) — click không có tác dụng. + "Sáng lên" active state khi row.id === editingRowId (user + vừa click pencil + đang edit) — bg-brand-100 + ring. */} {onEditClick && (() => { const editable = isEditablePhase(p.phase) + const isEditingThis = editable && editingRowId === p.id return (