[CLAUDE] PE-Duyệt: ẩn dropdown trạng thái + filter cứng "Đã gửi duyệt"
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m12s

Leaf "Duyệt" (pendingMe=1) chỉ load phiếu trạng thái "Đã gửi duyệt".
Nháp / Trả lại / Đã duyệt / Từ chối lọc bỏ client-side.

- Replace <Select> trạng thái bằng hint amber "Lọc cố định: Đã gửi duyệt"
- allRows.filter qua getPeDisplayStatus === DaGuiDuyet
- Header count dùng rows.length khi pendingMe (inbox không paged)
- Mirror fe-admin + fe-user

Workaround BE /inbox loose UAT (trả phiếu Nháp). Phân quyền strict V2
pending Session 18+.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-08 17:07:23 +07:00
parent 8680f4c849
commit aaa1c6cba6
2 changed files with 66 additions and 38 deletions

View File

@ -107,7 +107,13 @@ export function PurchaseEvaluationsListPage() {
} }
} }
const rows = list.data?.items ?? [] const allRows = list.data?.items ?? []
// Duyệt (pendingMe) → filter cứng client-side chỉ "Đã gửi duyệt" (Nháp/Trả lại/
// Đã duyệt/Từ chối loại bỏ). BE /inbox hiện loose UAT có thể trả phiếu Nháp →
// FE filter để UX đúng kỳ vọng. Phân quyền strict V2 BE pending Session 18+.
const rows = pendingMe
? allRows.filter(p => getPeDisplayStatus(p.phase) === PeDisplayStatus.DaGuiDuyet)
: allRows
const headerTitle = typeFilter const headerTitle = typeFilter
? (pendingMe ? `${PurchaseEvaluationTypeLabel[typeFilter]} — Chờ duyệt` : PurchaseEvaluationTypeLabel[typeFilter]) ? (pendingMe ? `${PurchaseEvaluationTypeLabel[typeFilter]} — Chờ duyệt` : PurchaseEvaluationTypeLabel[typeFilter])
@ -120,7 +126,7 @@ export function PurchaseEvaluationsListPage() {
<ClipboardCheck className="h-5 w-5 text-slate-500" /> <ClipboardCheck className="h-5 w-5 text-slate-500" />
<h1 className="text-base font-semibold tracking-tight text-slate-900">{headerTitle}</h1> <h1 className="text-base font-semibold tracking-tight text-slate-900">{headerTitle}</h1>
<span className="ml-2 rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-medium text-slate-600"> <span className="ml-2 rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-medium text-slate-600">
{list.data?.total ?? 0} {pendingMe ? rows.length : (list.data?.total ?? 0)}
</span> </span>
</div> </div>
</header> </header>
@ -151,6 +157,13 @@ export function PurchaseEvaluationsListPage() {
))} ))}
</Select> </Select>
)} )}
{/* Duyệt (pendingMe) → filter cứng "Đã gửi duyệt", ẩn dropdown trạng thái.
Danh sách (pendingMe=false) → giữ dropdown cho user filter mọi trạng thái. */}
{pendingMe ? (
<div className="rounded border border-amber-200 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-700">
Lọc cố đnh: <strong>Đã gửi duyệt</strong> (phiếu đang chờ duyệt)
</div>
) : (
<Select value={phase} onChange={e => setParam('phase', e.target.value)}> <Select value={phase} onChange={e => setParam('phase', e.target.value)}>
<option value="">Tất cả trạng thái</option> <option value="">Tất cả trạng thái</option>
{Object.values(PeDisplayStatus).map(s => { {Object.values(PeDisplayStatus).map(s => {
@ -168,6 +181,7 @@ export function PurchaseEvaluationsListPage() {
) : null ) : null
})} })}
</Select> </Select>
)}
</div> </div>
<div className="flex-1 overflow-y-auto"> <div className="flex-1 overflow-y-auto">

View File

@ -107,7 +107,13 @@ export function PurchaseEvaluationsListPage() {
} }
} }
const rows = list.data?.items ?? [] const allRows = list.data?.items ?? []
// Duyệt (pendingMe) → filter cứng client-side chỉ "Đã gửi duyệt" (Nháp/Trả lại/
// Đã duyệt/Từ chối loại bỏ). BE /inbox hiện loose UAT có thể trả phiếu Nháp →
// FE filter để UX đúng kỳ vọng. Phân quyền strict V2 BE pending Session 18+.
const rows = pendingMe
? allRows.filter(p => getPeDisplayStatus(p.phase) === PeDisplayStatus.DaGuiDuyet)
: allRows
const headerTitle = typeFilter const headerTitle = typeFilter
? (pendingMe ? `${PurchaseEvaluationTypeLabel[typeFilter]} — Chờ duyệt` : PurchaseEvaluationTypeLabel[typeFilter]) ? (pendingMe ? `${PurchaseEvaluationTypeLabel[typeFilter]} — Chờ duyệt` : PurchaseEvaluationTypeLabel[typeFilter])
@ -120,7 +126,7 @@ export function PurchaseEvaluationsListPage() {
<ClipboardCheck className="h-5 w-5 text-slate-500" /> <ClipboardCheck className="h-5 w-5 text-slate-500" />
<h1 className="text-base font-semibold tracking-tight text-slate-900">{headerTitle}</h1> <h1 className="text-base font-semibold tracking-tight text-slate-900">{headerTitle}</h1>
<span className="ml-2 rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-medium text-slate-600"> <span className="ml-2 rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-medium text-slate-600">
{list.data?.total ?? 0} {pendingMe ? rows.length : (list.data?.total ?? 0)}
</span> </span>
</div> </div>
</header> </header>
@ -151,6 +157,13 @@ export function PurchaseEvaluationsListPage() {
))} ))}
</Select> </Select>
)} )}
{/* Duyệt (pendingMe) → filter cứng "Đã gửi duyệt", ẩn dropdown trạng thái.
Danh sách (pendingMe=false) → giữ dropdown cho user filter mọi trạng thái. */}
{pendingMe ? (
<div className="rounded border border-amber-200 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-700">
Lọc cố đnh: <strong>Đã gửi duyệt</strong> (phiếu đang chờ duyệt)
</div>
) : (
<Select value={phase} onChange={e => setParam('phase', e.target.value)}> <Select value={phase} onChange={e => setParam('phase', e.target.value)}>
<option value="">Tất cả trạng thái</option> <option value="">Tất cả trạng thái</option>
{Object.values(PeDisplayStatus).map(s => { {Object.values(PeDisplayStatus).map(s => {
@ -168,6 +181,7 @@ export function PurchaseEvaluationsListPage() {
) : null ) : null
})} })}
</Select> </Select>
)}
</div> </div>
<div className="flex-1 overflow-y-auto"> <div className="flex-1 overflow-y-auto">