Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CRITICAL] Implement <WorkspaceWorkflowsApprovalsCreatePage /> for Workflow Creation #46798

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
88e2519
Test navigation
blazejkustra Aug 5, 2024
b0878c5
Fix navigating between screens for create flow
blazejkustra Aug 5, 2024
66c99d3
Attach API action
blazejkustra Aug 5, 2024
a0c289b
Merge branch 'Guccio163/45951_implementApprovalWorkflowSection' into …
blazejkustra Aug 5, 2024
11372db
Fix small mistakes and old comments
blazejkustra Aug 5, 2024
d243bd5
Add translations
blazejkustra Aug 6, 2024
d1f0dce
Add one more translation
blazejkustra Aug 6, 2024
5108e12
Add an option to parse text in formHelpMessage component
blazejkustra Aug 6, 2024
062e45a
Adjust MenuItem component to allow parsing text in formHelpMessage co…
blazejkustra Aug 6, 2024
c0734c8
Fix minor errors
blazejkustra Aug 6, 2024
89f6ee0
Create a new type for ApprovalWorkflow that is kept in onyx
blazejkustra Aug 6, 2024
8405648
Take care of all edge cases and error handling
blazejkustra Aug 6, 2024
3a39deb
Allow to deselect an approver
blazejkustra Aug 6, 2024
c4da7e3
Clean the expenses from page logic
blazejkustra Aug 6, 2024
dbb4311
Create an ApprovalWorkflowEditor and adjust CreatePage logic
blazejkustra Aug 6, 2024
e92b654
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 6, 2024
d4ae460
Bring back Permissions.ts
blazejkustra Aug 6, 2024
77555f3
Remove backTo from WORKSPACE_WORKFLOWS_APPROVALS_NEW screen
blazejkustra Aug 7, 2024
1c6ae4b
Fix tests
blazejkustra Aug 7, 2024
31d8863
Do final corrections
blazejkustra Aug 7, 2024
faee4e3
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 7, 2024
ebd1e05
Fix displaying errors and sorting default workflow
blazejkustra Aug 7, 2024
9fa7889
Fix lint
blazejkustra Aug 7, 2024
69c31e2
Change util name to calculateApprovers, fix that circular approver wa…
blazejkustra Aug 7, 2024
b67e8b8
Address comments after initial review
blazejkustra Aug 7, 2024
ba8a3d3
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 7, 2024
755954c
Fix copilot mistake 🙄
blazejkustra Aug 7, 2024
603b6ff
Adjust a comment
blazejkustra Aug 7, 2024
230080e
Remove role from CreateWorkspaceApprovalParams
blazejkustra Aug 7, 2024
54453fb
Filter out the default approver when selecting the first approver for…
blazejkustra Aug 8, 2024
b9b7937
Fix how form errors are displayed
blazejkustra Aug 8, 2024
68d5caf
Fix lint
blazejkustra Aug 8, 2024
64e7f0b
Improve error handling
blazejkustra Aug 8, 2024
cd36817
Implement the logic similar to other function
blazejkustra Aug 8, 2024
436457b
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 9, 2024
4c0078a
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 12, 2024
17cab91
Use const for flow and mode options
blazejkustra Aug 12, 2024
f554da6
Clean the logic for displaying hints
blazejkustra Aug 12, 2024
6707500
Fix that additionalApprover error is cleared
blazejkustra Aug 12, 2024
c38d5d7
Revert "Clean the logic for displaying hints"
blazejkustra Aug 12, 2024
d74ed36
Improve isInMultipleWorkflows logic
blazejkustra Aug 12, 2024
f9ea365
Rename consts
blazejkustra Aug 13, 2024
9bde486
Enable submit button when offline
blazejkustra Aug 13, 2024
e732c6c
Implement offline pattern B
blazejkustra Aug 13, 2024
05c552f
Remove redundant code
blazejkustra Aug 13, 2024
914bb1f
Fix code formatting
blazejkustra Aug 13, 2024
30d8a6a
Remove unnecessary test case
blazejkustra Aug 13, 2024
14f6eb2
Move key further up
blazejkustra Aug 13, 2024
69ab537
Merge branch 'main' into approval-workflows/create-edit-screen
blazejkustra Aug 13, 2024
5f3f64f
Rename variables
blazejkustra Aug 13, 2024
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
12 changes: 12 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5471,6 +5471,18 @@ const CONST = {
NAVIGATION_ACTIONS: {
RESET: 'RESET',
},

APPROVAL_WORKFLOW: {
ACTION: {
CREATE: 'create',
EDIT: 'edit',
},
TYPE: {
CREATE: 'create',
UPDATE: 'update',
REMOVE: 'remove',
},
},
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand Down
2 changes: 1 addition & 1 deletion src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END]: number;
[ONYXKEYS.NVP_WORKSPACE_TOOLTIP]: OnyxTypes.WorkspaceTooltip;
[ONYXKEYS.NVP_PRIVATE_CANCELLATION_DETAILS]: OnyxTypes.CancellationDetails[];
[ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflow;
[ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflowOnyx;
};

type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping;
Expand Down
6 changes: 3 additions & 3 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,12 +633,12 @@ const ROUTES = {
},
WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM: {
route: 'settings/workspaces/:policyID/workflows/approvals/expenses-from',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/workflows/approvals/expenses-from` as const,
getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/workflows/approvals/expenses-from` as const, backTo),
},
WORKSPACE_WORKFLOWS_APPROVALS_APPROVER: {
route: 'settings/workspaces/:policyID/workflows/approvals/approver',
getRoute: (policyID: string, approverIndex?: number) =>
`settings/workspaces/${policyID}/workflows/approvals/approver${approverIndex !== undefined ? `?approverIndex=${approverIndex}` : ''}` as const,
getRoute: (policyID: string, approverIndex?: number, backTo?: string) =>
getUrlWithBackToParam(`settings/workspaces/${policyID}/workflows/approvals/approver${approverIndex !== undefined ? `?approverIndex=${approverIndex}` : ''}` as const, backTo),
},
WORKSPACE_WORKFLOWS_PAYER: {
route: 'settings/workspaces/:policyID/workflows/payer',
Expand Down
8 changes: 4 additions & 4 deletions src/components/ApprovalWorkflowSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ type ApprovalWorkflowSectionProps = {
approvalWorkflow: ApprovalWorkflow;

/** ID of the policy */
policyId?: string;
policyID: string;
};

function ApprovalWorkflowSection({approvalWorkflow, policyId}: ApprovalWorkflowSectionProps) {
function ApprovalWorkflowSection({approvalWorkflow, policyID}: ApprovalWorkflowSectionProps) {
const styles = useThemeStyles();
const theme = useTheme();
const {translate, toLocaleOrdinal} = useLocalize();
const {isSmallScreenWidth} = useWindowDimensions();
const openApprovalsEdit = useCallback(
() => Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(policyId ?? '', approvalWorkflow.approvers[0].email)),
[approvalWorkflow.approvers, policyId],
() => Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(policyID, approvalWorkflow.approvers[0].email)),
[approvalWorkflow.approvers, policyID],
);
const approverTitle = useCallback(
(index: number) =>
Expand Down
26 changes: 23 additions & 3 deletions src/components/FormHelpMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import isEmpty from 'lodash/isEmpty';
import React from 'react';
import React, {useMemo} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import Parser from '@libs/Parser';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import RenderHTML from './RenderHTML';
import Text from './Text';

type FormHelpMessageProps = {
Expand All @@ -23,11 +25,29 @@ type FormHelpMessageProps = {

/** Whether to show dot indicator */
shouldShowRedDotIndicator?: boolean;

/** Whether should render error text as HTML or as Text */
shouldRenderMessageAsHTML?: boolean;
};

function FormHelpMessage({message = '', children, isError = true, style, shouldShowRedDotIndicator = true}: FormHelpMessageProps) {
function FormHelpMessage({message = '', children, isError = true, style, shouldShowRedDotIndicator = true, shouldRenderMessageAsHTML = false}: FormHelpMessageProps) {
const theme = useTheme();
const styles = useThemeStyles();

const HTMLMessage = useMemo(() => {
if (typeof message !== 'string' || !shouldRenderMessageAsHTML) {
return '';
}

const replacedText = Parser.replace(message, {shouldEscapeText: false});

if (isError) {
return `<alert-text>${replacedText}</alert-text>`;
}

return `<muted-text-label>${replacedText}</muted-text-label>`;
}, [isError, message, shouldRenderMessageAsHTML]);

if (isEmpty(message) && isEmpty(children)) {
return null;
}
Expand All @@ -41,7 +61,7 @@ function FormHelpMessage({message = '', children, isError = true, style, shouldS
/>
)}
<View style={[styles.flex1, isError && shouldShowRedDotIndicator ? styles.ml2 : {}]}>
{children ?? <Text style={[isError ? styles.formError : styles.formHelp, styles.mb0]}>{message}</Text>}
{children ?? (shouldRenderMessageAsHTML ? <RenderHTML html={HTMLMessage} /> : <Text style={[isError ? styles.formError : styles.formHelp, styles.mb0]}>{message}</Text>)}
</View>
</View>
);
Expand Down
10 changes: 10 additions & 0 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,12 @@ type MenuItemBaseProps = {
/** Whether should render helper text as HTML or as Text */
shouldParseHelperText?: boolean;

/** Whether should render hint text as HTML or as Text */
shouldRenderHintAsHTML?: boolean;

/** Whether should render error text as HTML or as Text */
shouldRenderErrorAsHTML?: boolean;

/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress?: boolean;

Expand Down Expand Up @@ -394,6 +400,8 @@ function MenuItem(
shouldBlockSelection = false,
shouldParseTitle = false,
shouldParseHelperText = false,
shouldRenderHintAsHTML = false,
shouldRenderErrorAsHTML = false,
shouldCheckActionAllowedOnPress = true,
onSecondaryInteraction,
titleWithTooltips,
Expand Down Expand Up @@ -802,6 +810,7 @@ function MenuItem(
shouldShowRedDotIndicator={!!shouldShowRedDotIndicator}
message={errorText}
style={[styles.menuItemError, errorTextStyle]}
shouldRenderMessageAsHTML={shouldRenderErrorAsHTML}
/>
)}
{!!hintText && (
Expand All @@ -810,6 +819,7 @@ function MenuItem(
shouldShowRedDotIndicator={false}
message={hintText}
style={styles.menuItemError}
shouldRenderMessageAsHTML={shouldRenderHintAsHTML}
/>
)}
</View>
Expand Down
10 changes: 9 additions & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
AddressLineParams,
AdminCanceledRequestParams,
AlreadySignedInParams,
ApprovalWorkflowErrorParams,
ApprovedAmountParams,
BeginningOfChatHistoryAdminRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartOneParams,
Expand Down Expand Up @@ -1310,14 +1311,21 @@ export default {
/* eslint-enable @typescript-eslint/naming-convention */
},
},
approverInMultipleWorkflows: ({name1, name2}: ApprovalWorkflowErrorParams) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

@blazejkustra Do you confirm this translation with the internal team before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

`<strong>${name1}</strong> already approves reports to <strong>${name2}</strong> in a separate workflow. If you change this approval relationship, all other workflows will be updated.`,
approverCircularReference: ({name1, name2}: ApprovalWorkflowErrorParams) =>
`<strong>${name1}</strong> already approves reports to <strong>${name2}</strong>. Please choose a different approver to avoid a circular workflow.`,
},
workflowsDelayedSubmissionPage: {
autoReportingErrorMessage: "Delayed submission couldn't be changed. Please try again or contact support.",
autoReportingFrequencyErrorMessage: "Submission frequency couldn't be changed. Please try again or contact support.",
monthlyOffsetErrorMessage: "Monthly frequency couldn't be changed. Please try again or contact support.",
},
workflowsCreateApprovalsPage: {
title: 'Add approval workflow',
title: 'Confirm',
header: 'Add more approvers and confirm.',
additionalApprover: 'Additional approver',
submitButton: 'Add workflow',
},
workflowsEditApprovalsPage: {
title: 'Edit approval workflow',
Expand Down
10 changes: 9 additions & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
AddressLineParams,
AdminCanceledRequestParams,
AlreadySignedInParams,
ApprovalWorkflowErrorParams,
ApprovedAmountParams,
BeginningOfChatHistoryAdminRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartOneParams,
Expand Down Expand Up @@ -1319,14 +1320,21 @@ export default {
/* eslint-enable @typescript-eslint/naming-convention */
},
},
approverInMultipleWorkflows: ({name1, name2}: ApprovalWorkflowErrorParams) =>
`<strong>${name1}</strong> ya aprueba informes a <strong>${name2}</strong> en otro flujo de trabajo Si modificas esta relación de aprobación, se actualizarán todos los demás flujos de trabajo.`,
approverCircularReference: ({name1, name2}: ApprovalWorkflowErrorParams) =>
`<strong>${name1}</strong> ya aprueba informes a <strong>${name2}</strong>. Por favor, elige un aprobador diferente para evitar un flujo de trabajo circular.`,
},
workflowsDelayedSubmissionPage: {
autoReportingErrorMessage: 'El parámetro de envío retrasado no pudo ser cambiado. Por favor, inténtelo de nuevo o contacte al soporte.',
autoReportingFrequencyErrorMessage: 'La frecuencia de envío no pudo ser cambiada. Por favor, inténtelo de nuevo o contacte al soporte.',
monthlyOffsetErrorMessage: 'La frecuencia mensual no pudo ser cambiada. Por favor, inténtelo de nuevo o contacte al soporte.',
},
workflowsCreateApprovalsPage: {
title: 'Añadir flujo de aprobación',
title: 'Confirmar',
header: 'Agrega más aprobadores y confirma.',
additionalApprover: 'Añadir aprobador',
submitButton: 'Añadir flujo de trabajo',
},
workflowsEditApprovalsPage: {
title: 'Edicion flujo de aprobación',
Expand Down
6 changes: 6 additions & 0 deletions src/languages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ type IssueVirtualCardParams = {
link: string;
};

type ApprovalWorkflowErrorParams = {
name1: string;
name2: string;
};

export type {
AddressLineParams,
AdminCanceledRequestParams,
Expand Down Expand Up @@ -475,4 +480,5 @@ export type {
UnapprovedParams,
RemoveMembersWarningPrompt,
DeleteExpenseTranslationParams,
ApprovalWorkflowErrorParams,
};
12 changes: 9 additions & 3 deletions src/libs/API/parameters/WorkspaceApprovalParams.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import type {PolicyEmployee} from '@src/types/onyx';

type CreateWorkspaceApprovalParams = {
authToken: string;
policyID: string;
employees: PolicyEmployee[];
/**
* Stringified JSON object with type of following structure:
* Array<{
* email: string;
* forwardsTo?: string;
* submitsTo?: string;
* }>
*/
employees: string;
};
blazejkustra marked this conversation as resolved.
Show resolved Hide resolved

type UpdateWorkspaceApprovalParams = CreateWorkspaceApprovalParams;
Expand Down
3 changes: 3 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1123,17 +1123,20 @@ type FullScreenNavigatorParamList = {
};
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT]: {
policyID: string;
firstApproverEmail: string;
};
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER]: {
policyID: string;
approverIndex?: number;
backTo?: Routes;
};
[SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY]: {
policyID: string;
Expand Down
46 changes: 29 additions & 17 deletions src/libs/WorkflowUtils.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import lodashMapKeys from 'lodash/mapKeys';
import type {Approver, Member} from '@src/types/onyx/ApprovalWorkflow';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import type {ApprovalWorkflowOnyx, Approver, Member} from '@src/types/onyx/ApprovalWorkflow';
import type ApprovalWorkflow from '@src/types/onyx/ApprovalWorkflow';
import type {PersonalDetailsList} from '@src/types/onyx/PersonalDetails';
import type {PolicyEmployeeList} from '@src/types/onyx/PolicyEmployee';

const EMPTY_APPROVAL_WORKFLOW: ApprovalWorkflow = {
const INITIAL_APPROVAL_WORKFLOW: ApprovalWorkflowOnyx = {
members: [],
approvers: [],
availableMembers: [],
isDefault: false,
isBeingEdited: false,
action: CONST.APPROVAL_WORKFLOW.ACTION.CREATE,
isLoading: false,
};

Expand All @@ -29,8 +32,8 @@ type GetApproversParams = {
firstEmail: string;
};

/** Get the list of approvers for a given workflow */
function getApprovalWorkflowApprovers({employees, firstEmail, personalDetailsByEmail}: GetApproversParams): Approver[] {
/** Get the list of approvers for a given email */
function calculateApprovers({employees, firstEmail, personalDetailsByEmail}: GetApproversParams): Approver[] {
const approvers: Approver[] = [];
// Keep track of approver emails to detect circular references
const currentApproverEmails = new Set<string>();
Expand Down Expand Up @@ -98,14 +101,13 @@ function convertPolicyEmployeesToApprovalWorkflows({employees, defaultApprover,

const member: Member = {email, avatar: personalDetailsByEmail[email]?.avatar, displayName: personalDetailsByEmail[email]?.displayName ?? email};
if (!approvalWorkflows[submitsTo]) {
const approvers = getApprovalWorkflowApprovers({employees, firstEmail: submitsTo, personalDetailsByEmail});
const approvers = calculateApprovers({employees, firstEmail: submitsTo, personalDetailsByEmail});
approvers.forEach((approver) => (approverCountsByEmail[approver.email] = (approverCountsByEmail[approver.email] ?? 0) + 1));

approvalWorkflows[submitsTo] = {
members: [],
approvers,
isDefault: defaultApprover === submitsTo,
isBeingEdited: false,
};
}
approvalWorkflows[submitsTo].members.push(member);
Expand All @@ -117,9 +119,23 @@ function convertPolicyEmployeesToApprovalWorkflows({employees, defaultApprover,
return -1;
}

if (b.isDefault) {
return 1;
}

return (a.approvers[0]?.displayName ?? '-1').localeCompare(b.approvers[0]?.displayName ?? '-1');
});

// Add a default workflow if one doesn't exist (no employees submit to the default approver)
blazejkustra marked this conversation as resolved.
Show resolved Hide resolved
const firstWorkflow = sortedApprovalWorkflows.at(0);
blazejkustra marked this conversation as resolved.
Show resolved Hide resolved
if (firstWorkflow && !firstWorkflow.isDefault) {
sortedApprovalWorkflows.unshift({
members: [],
approvers: calculateApprovers({employees, firstEmail: defaultApprover, personalDetailsByEmail}),
isDefault: true,
});
}

// Add a flag to each approver to indicate if they are in multiple workflows
return sortedApprovalWorkflows.map((workflow) => ({
...workflow,
Expand All @@ -142,13 +158,13 @@ type ConvertApprovalWorkflowToPolicyEmployeesParams = {
employeeList: PolicyEmployeeList;

/**
* Should the workflow be removed from the employees
* Mode to use when converting the approval workflow
*/
removeWorkflow?: boolean;
type: ValueOf<typeof CONST.APPROVAL_WORKFLOW.TYPE>;
};

/** Convert an approval workflow to a list of policy employees */
function convertApprovalWorkflowToPolicyEmployees({approvalWorkflow, employeeList, removeWorkflow = false}: ConvertApprovalWorkflowToPolicyEmployeesParams): PolicyEmployeeList {
function convertApprovalWorkflowToPolicyEmployees({approvalWorkflow, employeeList, type}: ConvertApprovalWorkflowToPolicyEmployeesParams): PolicyEmployeeList {
const updatedEmployeeList: PolicyEmployeeList = {};
const firstApprover = approvalWorkflow.approvers.at(0);

Expand All @@ -157,25 +173,21 @@ function convertApprovalWorkflowToPolicyEmployees({approvalWorkflow, employeeLis
}

approvalWorkflow.approvers.forEach((approver, index) => {
if (updatedEmployeeList[approver.email]) {
return;
}

const nextApprover = approvalWorkflow.approvers.at(index + 1);
updatedEmployeeList[approver.email] = {
...employeeList[approver.email],
forwardsTo: removeWorkflow ? undefined : nextApprover?.email,
forwardsTo: type === CONST.APPROVAL_WORKFLOW.TYPE.REMOVE ? '' : nextApprover?.email ?? '',
};
});

approvalWorkflow.members.forEach(({email}) => {
updatedEmployeeList[email] = {
...(updatedEmployeeList[email] ? updatedEmployeeList[email] : employeeList[email]),
submitsTo: removeWorkflow ? undefined : firstApprover.email,
submitsTo: type === CONST.APPROVAL_WORKFLOW.TYPE.REMOVE ? '' : firstApprover.email ?? '',
};
});

return updatedEmployeeList;
}

export {getApprovalWorkflowApprovers, convertPolicyEmployeesToApprovalWorkflows, convertApprovalWorkflowToPolicyEmployees, EMPTY_APPROVAL_WORKFLOW};
export {calculateApprovers, convertPolicyEmployeesToApprovalWorkflows, convertApprovalWorkflowToPolicyEmployees, INITIAL_APPROVAL_WORKFLOW};
Loading
Loading