[CLAUDE] FE-Admin FE-User: Chunk E — K6 Workspace DROP Drafter checkbox + ADD Approver toggle (Mig 31 F2 refactor)
Plan K Chunk E mirror 2 app rule §3.9. Refactor F2 UX flow:
DROP fe-admin + fe-user Workspace Drafter checkbox:
- PeDetailTabs.tsx Workspace action bar: REMOVE "Gửi thẳng Cấp cuối (skip trung gian)"
violet label + state skipToFinal + allowSkipToFinal lookup + skipToFinal payload
- submitForApproval mutation signature simplify: opts: { skipToFinal: boolean } → void
- Confirm dialog text + button label drop skipToFinal conditional
ADD fe-admin + fe-user Approver toggle trong PeWorkflowPanel dialog:
- State skipToFinalApprover default false
- Visible khi Approve forward (NOT Cancel + NOT SendBack) + currentLevelOptions?.allowApproverSkipToFinal
- Checkbox violet panel với description "Phiếu sẽ tiến thẳng tới Đã duyệt (terminal)"
- Amber warning khi checked: "Hành động KHÔNG quay lại được"
- Mutation payload +skipToFinal: !isReject && skipToFinalApprover
- onSuccess reset state
Type ApprovalWorkflowOptions × 2 app: +allowApproverSkipToFinal: boolean (7th)
Type PeDetailBundle × 2 app: REMOVE drafterAllowSkipToFinal field + comment Mig 29+30+31
UX design Dialog approach (consistent với Trả lại Mode picker pattern):
- Skip thẳng Cấp cuối = destructive action → confirm dialog amber warning
- Mirror Mig 28 Trả lại 4 mode picker UX consistency
- Em main solo K6 per UX flow decision criteria
Per bro decision Plan K S23 t1: "Chỗ cấu hình cho phép skip → duyệt thẳng cho phép
trong trạng thái đang duyệt" + "Tất cả đều cấu hình ngay trong chỗ setup quy trình duyệt".
Verify:
- npm run build × 2 app pass clean (0 TS err)
- Pre-existing warnings unchanged (chunk size + INEFFECTIVE_DYNAMIC_IMPORT)
- Bundle hash rotated × 2 app
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -37,6 +37,9 @@ export function PeWorkflowPanel({
|
||||
// Mig 28 (S21 t4) — F1 mode Trả lại. Default Drafter (backward compat S17).
|
||||
const [returnMode, setReturnMode] = useState<WorkflowReturnMode>(WorkflowReturnMode.Drafter)
|
||||
const [returnTargetUserId, setReturnTargetUserId] = useState<string | null>(null)
|
||||
// Mig 31 (S23 t1) — F2 Approver duyệt thẳng Cấp cuối. Default false (admin opt-in
|
||||
// per slot tick → checkbox visible trong dialog Approve, default unchecked).
|
||||
const [skipToFinalApprover, setSkipToFinalApprover] = useState(false)
|
||||
const qc = useQueryClient()
|
||||
const { user: currentUser } = useAuth()
|
||||
const isAdmin = currentUser?.roles?.includes('Admin') ?? false
|
||||
@ -96,6 +99,9 @@ export function PeWorkflowPanel({
|
||||
returnMode: isTraLaiAction ? returnMode : null,
|
||||
returnTargetUserId: isTraLaiAction && returnMode === WorkflowReturnMode.Assignee
|
||||
? returnTargetUserId : null,
|
||||
// Mig 31 (S23 t1) — F2 Approver scope ChoDuyet duyệt thẳng Cấp cuối.
|
||||
// BE check matchingLevel.AllowApproverSkipToFinal (admin opt-in per slot).
|
||||
skipToFinal: !isReject && skipToFinalApprover,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
@ -107,6 +113,7 @@ export function PeWorkflowPanel({
|
||||
setComment('')
|
||||
setReturnMode(WorkflowReturnMode.Drafter)
|
||||
setReturnTargetUserId(null)
|
||||
setSkipToFinalApprover(false)
|
||||
},
|
||||
onError: e => toast.error(getErrorMessage(e)),
|
||||
})
|
||||
@ -394,6 +401,32 @@ export function PeWorkflowPanel({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{/* Mig 31 (S23 t1) — F2 Approver toggle: chỉ visible khi Approve forward
|
||||
+ admin tick AllowApproverSkipToFinal cho slot Cấp hiện tại. */}
|
||||
{!isCancel && !isSendBack && levelOptions?.allowApproverSkipToFinal && (
|
||||
<div className="mb-3">
|
||||
<label className="flex cursor-pointer items-start gap-2 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[12px] text-violet-800 hover:bg-violet-100/60">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5"
|
||||
checked={skipToFinalApprover}
|
||||
onChange={e => setSkipToFinalApprover(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Duyệt thẳng Cấp cuối (skip Bước/Cấp trung gian)</span>
|
||||
<span className="mt-0.5 block text-[11px] text-violet-700/80">
|
||||
Phiếu sẽ tiến thẳng tới "Đã duyệt" (terminal) — bỏ qua mọi Cấp/Bước còn lại.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{!isCancel && !isSendBack && skipToFinalApprover && (
|
||||
<div className="mb-3 rounded border border-amber-300 bg-amber-50 px-3 py-2 text-[11px] text-amber-800">
|
||||
⚠ Hành động KHÔNG quay lại được (trừ khi Drafter reset toàn bộ). Phiếu sẽ
|
||||
skip qua tất cả Cấp/Bước còn lại và chuyển thẳng "Đã duyệt".
|
||||
</div>
|
||||
)}
|
||||
<Label>Ghi chú (tùy chọn)</Label>
|
||||
<Textarea value={comment} onChange={e => setComment(e.target.value)} rows={3} />
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user