From ab7f3e8319b1188e5abf2159c36acbf78c10e5bd Mon Sep 17 00:00:00 2001 From: Maruf Sharifi Date: Thu, 12 Mar 2026 13:01:40 +0430 Subject: [PATCH 1/4] fix: approver page shows empty state when prevent self-approvals is enabled --- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 8d0582c0a926b..bdf6f7870db02 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -62,7 +62,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa return null; } - if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email)) { + if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email) && selectedApproverEmail !== email ) { return null; } @@ -140,6 +140,10 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa if (isRemovingApprover) { clearApprovalWorkflowApprover({approverIndex, currentApprovalWorkflow: approvalWorkflow}); + if (isChangeApproverRoute && approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.EDIT) { + Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover)); + return; + } goBack(); return; } @@ -171,7 +175,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVAL_LIMIT.getRoute(route.params.policyID, approverIndex)); } }, - [approverIndex, approvalWorkflow, employeeList, personalDetails, policy, route.params.policyID, goBack, personalDetailsByEmail, isChangeApproverRoute], + [approverIndex, approvalWorkflow, employeeList, personalDetails, policy, route.params.policyID, goBack, personalDetailsByEmail, isChangeApproverRoute, firstApprover], ); const subtitle = useMemo( From a06e9fafffde38243031a039c284cce43fd79bce Mon Sep 17 00:00:00 2001 From: marufsharifi Date: Thu, 12 Mar 2026 14:13:24 +0430 Subject: [PATCH 2/4] fixed prettier --- .../WorkspaceWorkflowsApprovalsApproverPage.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index bdf6f7870db02..aa373bfa0b0ce 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -62,7 +62,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa return null; } - if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email) && selectedApproverEmail !== email ) { + if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email) && selectedApproverEmail !== email) { return null; } @@ -140,10 +140,10 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa if (isRemovingApprover) { clearApprovalWorkflowApprover({approverIndex, currentApprovalWorkflow: approvalWorkflow}); - if (isChangeApproverRoute && approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.EDIT) { - Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover)); - return; - } + if (isChangeApproverRoute && approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.EDIT) { + Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover)); + return; + } goBack(); return; } From 13d5e26bbad7136f54b9599721fd1e328258d361 Mon Sep 17 00:00:00 2001 From: marufsharifi Date: Sun, 15 Mar 2026 12:09:27 +0430 Subject: [PATCH 3/4] Fix approver workflow back navigation and deselect transition --- ...orkspaceWorkflowsApprovalsApproverPage.tsx | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index aa373bfa0b0ce..913e7f751e321 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -1,5 +1,5 @@ import {useNavigationState} from '@react-navigation/native'; -import React, {useCallback, useMemo} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import type {SelectionListApprover} from '@components/ApproverSelectionList'; import ApproverSelectionList from '@components/ApproverSelectionList'; import Text from '@components/Text'; @@ -36,12 +36,14 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa const approverIndex = Number(route.params.approverIndex) ?? 0; const rhpRoutes = useNavigationState((state) => state.routes); const defaultApprover = getDefaultApprover(policy); - const firstApprover = approvalWorkflow?.approvers?.[0]?.email ?? ''; + const firstApprover = approvalWorkflow?.originalApprovers?.[0]?.email ?? ''; + const [removingApproverEmail, setRemovingApproverEmail] = useState(); const isChangeApproverRoute = route.name === SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER_CHANGE; const isInitialCreationFlow = approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && approvalWorkflow?.isInitialFlow; const currentApprover = approvalWorkflow?.approvers[approverIndex]; const selectedApproverEmail = currentApprover?.email; + const visibleSelectedApproverEmail = removingApproverEmail ?? selectedApproverEmail; const employeeList = policy?.employeeList; const approversFromWorkflow = approvalWorkflow?.approvers; @@ -62,13 +64,13 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa return null; } - if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email) && selectedApproverEmail !== email) { + if (!isDefault && policy?.preventSelfApproval && membersEmail?.includes(email) && visibleSelectedApproverEmail !== email) { return null; } // Do not allow the same email to be added twice const isEmailAlreadyInApprovers = approversFromWorkflow?.some((approver, index) => approver?.email === email && index !== approverIndex); - if (isEmailAlreadyInApprovers && selectedApproverEmail !== email) { + if (isEmailAlreadyInApprovers && visibleSelectedApproverEmail !== email) { return null; } @@ -90,7 +92,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa text: displayName, alternateText: email, keyForList: email, - isSelected: selectedApproverEmail === email, + isSelected: visibleSelectedApproverEmail === email, login: email, icons: [{source: avatar ?? icons.FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: displayName, id: accountID}], rightElement: ( @@ -111,14 +113,14 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa policy?.owner, approvalWorkflow?.members, approversFromWorkflow, - selectedApproverEmail, + visibleSelectedApproverEmail, approverIndex, defaultApprover, personalDetails, icons.FallbackAvatar, ]); - const shouldShowListEmptyContent = !!approvalWorkflow && !isApprovalWorkflowLoading; + const shouldShowListEmptyContent = !!approvalWorkflow && !isApprovalWorkflowLoading && !removingApproverEmail; const goBack = useCallback(() => { let backToRoute; @@ -139,6 +141,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa const isRemovingApprover = approvers.length === 0; if (isRemovingApprover) { + setRemovingApproverEmail(visibleSelectedApproverEmail); clearApprovalWorkflowApprover({approverIndex, currentApprovalWorkflow: approvalWorkflow}); if (isChangeApproverRoute && approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.EDIT) { Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover)); @@ -175,7 +178,19 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVAL_LIMIT.getRoute(route.params.policyID, approverIndex)); } }, - [approverIndex, approvalWorkflow, employeeList, personalDetails, policy, route.params.policyID, goBack, personalDetailsByEmail, isChangeApproverRoute, firstApprover], + [ + approverIndex, + approvalWorkflow, + employeeList, + personalDetails, + policy, + route.params.policyID, + goBack, + personalDetailsByEmail, + isChangeApproverRoute, + firstApprover, + visibleSelectedApproverEmail, + ], ); const subtitle = useMemo( @@ -199,7 +214,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa subtitle={subtitle} isLoadingReportData={isLoadingReportData} policy={policy} - initiallyFocusedOptionKey={selectedApproverEmail} + initiallyFocusedOptionKey={visibleSelectedApproverEmail} shouldShowNotFoundViewLink allApprovers={allApprovers} onBackButtonPress={goBack} From 099d67bb0967e6447a011e4d1dc23e9df42154f7 Mon Sep 17 00:00:00 2001 From: marufsharifi Date: Wed, 18 Mar 2026 12:09:17 +0430 Subject: [PATCH 4/4] docs: clarify temporary approver state comment --- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 913e7f751e321..f8392a034d755 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -37,6 +37,9 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa const rhpRoutes = useNavigationState((state) => state.routes); const defaultApprover = getDefaultApprover(policy); const firstApprover = approvalWorkflow?.originalApprovers?.[0]?.email ?? ''; + // Keep the removed approver visible until navigation finishes. + // Without this temporary state, clearing the approver immediately causes the empty state to flash + // while this screen is still mounted during the dismiss animation. const [removingApproverEmail, setRemovingApproverEmail] = useState(); const isChangeApproverRoute = route.name === SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER_CHANGE;