[CLAUDE] FE-Admin+FE-User: PE InfoTab auto re-edit on pencil click + active state visual feedback
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m7s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m7s
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 `<Input value={ev.projectName}
disabled className="bg-slate-100" />`) — 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) <noreply@anthropic.com>
This commit is contained in:
@ -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 ?? '')
|
||||
|
||||
@ -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 (
|
||||
<button
|
||||
onClick={() => editable && onEditClick(p.id)}
|
||||
disabled={!editable}
|
||||
className={cn(
|
||||
'absolute right-2 top-2 rounded p-1.5 transition',
|
||||
editable
|
||||
isEditingThis
|
||||
? 'bg-brand-100 text-brand-700 shadow-sm ring-1 ring-brand-300 cursor-pointer'
|
||||
: editable
|
||||
? 'text-brand-600 hover:bg-brand-50 hover:shadow-sm cursor-pointer'
|
||||
: 'text-slate-300 cursor-not-allowed',
|
||||
)}
|
||||
title={editable
|
||||
title={isEditingThis
|
||||
? '✎ Đang sửa phiếu này — click để toggle / xem khác'
|
||||
: editable
|
||||
? 'Sửa phiếu (header + chi tiết)'
|
||||
: 'Phiếu đã gửi duyệt / đã duyệt / từ chối — không sửa được'}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user