[CLAUDE] FE-Admin+FE-User: PE diagnose "Lưu & Gửi Duyệt" — tooltip + confirm rõ phase
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m17s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m17s
User báo button "Lưu & Gửi Duyệt" KHÔNG hoạt động + suy đoán "trùng ID".
Phân tích: button disabled khi `evaluation.workflow.nextPhases` không có
forward phase (chỉ TuChoi/TraLai). Hiện FE silent — không cách nào biết.
Improvement (cả 2 app, mirror):
- Compute `forwardPhase` once thay vì 2 lần (.find / .some).
- Add `submitDisabledReason` string giải thích reason:
* canEditPhase=false → "Phiếu đã ở phase X — chỉ Bản nháp / Trả lại
mới sửa + gửi được"
* readOnly → "Chế độ chỉ đọc"
* !forwardPhase → "Workflow không có phase tiếp theo từ X. Liên hệ
admin kiểm tra cấu hình quy trình"
- Button title attribute show reason (hover tooltip) hoặc forward phase
label khi enabled: "Gửi phiếu sang 'Chờ Purchasing'"
- Confirm dialog show forward phase explicit: 'Gửi phiếu vào quy trình
duyệt? Sẽ chuyển sang "Chờ Purchasing". Sau khi gửi sẽ KHÔNG sửa
được nữa (trừ khi approver Trả lại).'
Note "trùng ID" KHÔNG phải bug FE: PurchaseEvaluationWorkspacePage
URL state đúng (`+ Thêm mới` clear `id`, save set new). Mỗi PE row
unique GUID + MaPhieu. User feedback có thể due to button silent
disabled — tooltip giờ rõ reason.
Verify: npm build fe-admin + fe-user pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -98,10 +98,22 @@ export function PeDetailTabs({
|
||||
onError: e => toast.error(getErrorMessage(e)),
|
||||
})
|
||||
|
||||
const forwardPhase = evaluation.workflow.nextPhases.find(p =>
|
||||
p !== PurchaseEvaluationPhase.TuChoi && p !== PurchaseEvaluationPhase.TraLai)
|
||||
const canSubmitForApproval = mode === 'workspace'
|
||||
&& canEditPhase
|
||||
&& !readOnly
|
||||
&& evaluation.workflow.nextPhases.some(p => p !== PurchaseEvaluationPhase.TuChoi && p !== PurchaseEvaluationPhase.TraLai)
|
||||
&& forwardPhase != null
|
||||
|
||||
// Tooltip reason cho button disabled (giúp diagnose tại sao "Lưu & Gửi Duyệt"
|
||||
// không bấm được — user feedback 2026-05-07).
|
||||
const submitDisabledReason = !canEditPhase
|
||||
? `Phiếu đã ở phase ${PurchaseEvaluationPhaseLabel[evaluation.phase]} — chỉ Bản nháp / Trả lại mới sửa + gửi được.`
|
||||
: readOnly
|
||||
? 'Chế độ chỉ đọc.'
|
||||
: !forwardPhase
|
||||
? `Workflow không có phase tiếp theo từ ${PurchaseEvaluationPhaseLabel[evaluation.phase]}. Liên hệ admin kiểm tra cấu hình quy trình.`
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-slate-200 bg-white shadow-sm">
|
||||
@ -213,11 +225,13 @@ export function PeDetailTabs({
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (confirm('Gửi phiếu vào quy trình duyệt? Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).')) {
|
||||
if (!forwardPhase) return
|
||||
if (confirm(`Gửi phiếu vào quy trình duyệt? Sẽ chuyển sang "${PurchaseEvaluationPhaseLabel[forwardPhase]}". Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).`)) {
|
||||
submitForApproval.mutate()
|
||||
}
|
||||
}}
|
||||
disabled={!canSubmitForApproval || submitForApproval.isPending}
|
||||
title={submitDisabledReason ?? `Gửi phiếu sang "${forwardPhase ? PurchaseEvaluationPhaseLabel[forwardPhase] : '?'}"`}
|
||||
className="text-xs"
|
||||
>
|
||||
{submitForApproval.isPending ? 'Đang gửi…' : 'Lưu & Gửi Duyệt →'}
|
||||
|
||||
@ -98,10 +98,22 @@ export function PeDetailTabs({
|
||||
onError: e => toast.error(getErrorMessage(e)),
|
||||
})
|
||||
|
||||
const forwardPhase = evaluation.workflow.nextPhases.find(p =>
|
||||
p !== PurchaseEvaluationPhase.TuChoi && p !== PurchaseEvaluationPhase.TraLai)
|
||||
const canSubmitForApproval = mode === 'workspace'
|
||||
&& canEditPhase
|
||||
&& !readOnly
|
||||
&& evaluation.workflow.nextPhases.some(p => p !== PurchaseEvaluationPhase.TuChoi && p !== PurchaseEvaluationPhase.TraLai)
|
||||
&& forwardPhase != null
|
||||
|
||||
// Tooltip reason cho button disabled (giúp diagnose tại sao "Lưu & Gửi Duyệt"
|
||||
// không bấm được — user feedback 2026-05-07).
|
||||
const submitDisabledReason = !canEditPhase
|
||||
? `Phiếu đã ở phase ${PurchaseEvaluationPhaseLabel[evaluation.phase]} — chỉ Bản nháp / Trả lại mới sửa + gửi được.`
|
||||
: readOnly
|
||||
? 'Chế độ chỉ đọc.'
|
||||
: !forwardPhase
|
||||
? `Workflow không có phase tiếp theo từ ${PurchaseEvaluationPhaseLabel[evaluation.phase]}. Liên hệ admin kiểm tra cấu hình quy trình.`
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-slate-200 bg-white shadow-sm">
|
||||
@ -213,11 +225,13 @@ export function PeDetailTabs({
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (confirm('Gửi phiếu vào quy trình duyệt? Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).')) {
|
||||
if (!forwardPhase) return
|
||||
if (confirm(`Gửi phiếu vào quy trình duyệt? Sẽ chuyển sang "${PurchaseEvaluationPhaseLabel[forwardPhase]}". Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).`)) {
|
||||
submitForApproval.mutate()
|
||||
}
|
||||
}}
|
||||
disabled={!canSubmitForApproval || submitForApproval.isPending}
|
||||
title={submitDisabledReason ?? `Gửi phiếu sang "${forwardPhase ? PurchaseEvaluationPhaseLabel[forwardPhase] : '?'}"`}
|
||||
className="text-xs"
|
||||
>
|
||||
{submitForApproval.isPending ? 'Đang gửi…' : 'Lưu & Gửi Duyệt →'}
|
||||
|
||||
Reference in New Issue
Block a user