Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/libs/actions/Workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ function createApprovalWorkflow({approvalWorkflow, policy, addExpenseApprovalsTa
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policy.id}`,
value: {
employeeList: Object.fromEntries(Object.keys(updatedEmployees).map((key) => [key, {pendingAction: null, pendingFields: null}])),
employeeList: Object.fromEntries(
Object.keys(updatedEmployees).map((key) => [
key,
previousEmployeeList[key]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? {pendingFields: null} : {pendingAction: null, pendingFields: null},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ CONSISTENCY-3 (docs)

The conditional logic for clearing pendingAction based on DELETE status is duplicated across three functions (createApprovalWorkflow, updateApprovalWorkflow, and removeApprovalWorkflow).

Extract this into a reusable helper function:

function getPendingActionClearValue(previousEmployeeList: Record<string, Employee>, key: string) {
    return previousEmployeeList[key]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE 
        ? {pendingFields: null} 
        : {pendingAction: null, pendingFields: null};
}

Then use it in all three locations:

employeeList: Object.fromEntries(
    Object.keys(updatedEmployees).map((key) => [
        key,
        getPendingActionClearValue(previousEmployeeList, key),
    ]),
)

Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.

]),
),
},
},
];
Expand Down Expand Up @@ -151,7 +156,12 @@ function updateApprovalWorkflow(approvalWorkflow: ApprovalWorkflow, membersToRem
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policy.id}`,
value: {
employeeList: Object.fromEntries(Object.keys(updatedEmployees).map((key) => [key, {pendingAction: null, pendingFields: null}])),
employeeList: Object.fromEntries(
Object.keys(updatedEmployees).map((key) => [
key,
previousEmployeeList[key]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? {pendingFields: null} : {pendingAction: null, pendingFields: null},
]),
),
},
},
];
Expand Down Expand Up @@ -209,7 +219,12 @@ function removeApprovalWorkflow(approvalWorkflow: ApprovalWorkflow, policy: Onyx
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policy.id}`,
value: {
employeeList: Object.fromEntries(Object.keys(updatedEmployees).map((key) => [key, {pendingAction: null}])),
employeeList: Object.fromEntries(
Object.keys(updatedEmployees).map((key) => [
key,
previousEmployeeList[key]?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE ? {pendingFields: null} : {pendingAction: null, pendingFields: null},
]),
),
},
},
];
Expand Down
24 changes: 14 additions & 10 deletions src/pages/workspace/WorkspaceMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,23 @@
* Remove selected users from the workspace
* Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details
*/
const removeUsers = () => {

Check warning on line 229 in src/pages/workspace/WorkspaceMembersPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

The 'removeUsers' function makes the dependencies of useCallback Hook (at line 294) change on every render. Move it inside the useCallback callback. Alternatively, wrap the definition of 'removeUsers' in its own useCallback() Hook

Check warning on line 229 in src/pages/workspace/WorkspaceMembersPage.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

The 'removeUsers' function makes the dependencies of useCallback Hook (at line 294) change on every render. Move it inside the useCallback callback. Alternatively, wrap the definition of 'removeUsers' in its own useCallback() Hook
// Check if any of the members are approvers
const hasApprovers = selectedEmployees.some((email) => isApprover(policy, email));
const selectedEmployeesToRemove = [...selectedEmployees];

// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => {
setSelectedEmployees([]);
removeMembers(policy, selectedEmployeesToRemove, policyMemberEmailsToAccountIDs);

// Check if any of the members are approvers
const hasApprovers = selectedEmployeesToRemove.some((email) => isApprover(policy, email));

if (!hasApprovers) {
return;
}

if (hasApprovers) {
const ownerEmail = ownerDetails.login;
for (const login of selectedEmployees) {
for (const login of selectedEmployeesToRemove) {
if (!isApprover(policy, login)) {
continue;
}
Expand All @@ -256,12 +266,6 @@
}
}
}
}

// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => {
setSelectedEmployees([]);
removeMembers(policy, selectedEmployees, policyMemberEmailsToAccountIDs);
});
};

Expand Down
25 changes: 14 additions & 11 deletions src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Str} from 'expensify-common';
import React, {useContext, useEffect} from 'react';
import {View} from 'react-native';
import {InteractionManager, View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import Avatar from '@components/Avatar';
Expand Down Expand Up @@ -187,25 +187,28 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM
return;
}

// Remove the member and close the modal
removeMemberAndCloseModal();

// Update approval workflows after approver removal
const updatedWorkflows = updateWorkflowDataOnApproverRemoval({
approvalWorkflows,
removedApprover,
ownerDetails,
});

for (const workflow of updatedWorkflows) {
if (workflow?.removeApprovalWorkflow) {
const {removeApprovalWorkflow, ...updatedWorkflow} = workflow;
// eslint-disable-next-line @typescript-eslint/no-deprecated
InteractionManager.runAfterInteractions(() => {
for (const workflow of updatedWorkflows) {
if (workflow?.removeApprovalWorkflow) {
const {removeApprovalWorkflow, ...updatedWorkflow} = workflow;

removeApprovalWorkflowAction(updatedWorkflow, policy);
} else {
updateApprovalWorkflow(workflow, [], [], policy);
removeApprovalWorkflowAction(updatedWorkflow, policy);
} else {
updateApprovalWorkflow(workflow, [], [], policy);
}
}
}

// Remove the member and close the modal
removeMemberAndCloseModal();
});
};

const showRemoveMemberModal = async () => {
Expand Down
Loading