Skip to content

Commit 16a58b5

Browse files
authored
Merge pull request #63060 from nkdengineer/fix/61304
2 parents ac8e0f3 + df37e10 commit 16a58b5

5 files changed

Lines changed: 81 additions & 29 deletions

File tree

src/components/WorkspaceMembersSelectionList.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import {canUseTouchScreen} from '@libs/DeviceCapabilities';
88
import {getSearchValueForPhoneOrEmail, sortAlphabetically} from '@libs/OptionsListUtils';
99
import {getMemberAccountIDsForWorkspace} from '@libs/PolicyUtils';
1010
import tokenizedSearch from '@libs/tokenizedSearch';
11+
import MemberRightIcon from '@pages/workspace/MemberRightIcon';
1112
import CONST from '@src/CONST';
1213
import type {Icon} from '@src/types/onyx/OnyxCommon';
13-
import Badge from './Badge';
1414
import {FallbackAvatar} from './Icon/Expensicons';
1515
import {usePersonalDetails} from './OnyxProvider';
1616
import SelectionList from './SelectionList';
@@ -47,7 +47,6 @@ function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}
4747
if (policy?.employeeList) {
4848
const availableApprovers = Object.values(policy.employeeList)
4949
.map((employee): SelectionListApprover | null => {
50-
const isAdmin = employee?.role === CONST.REPORT.ROLE.ADMIN;
5150
const email = employee.email;
5251

5352
if (!email) {
@@ -56,7 +55,7 @@ function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}
5655

5756
const policyMemberEmailsToAccountIDs = getMemberAccountIDsForWorkspace(policy?.employeeList);
5857
const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? '');
59-
const {avatar, displayName = email} = personalDetails?.[accountID] ?? {};
58+
const {avatar, displayName = email, login} = personalDetails?.[accountID] ?? {};
6059

6160
return {
6261
text: displayName,
@@ -65,7 +64,13 @@ function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}
6564
isSelected: selectedApprover === email,
6665
login: email,
6766
icons: [{source: avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: displayName, id: accountID}],
68-
rightElement: isAdmin ? <Badge text={translate('common.admin')} /> : undefined,
67+
rightElement: (
68+
<MemberRightIcon
69+
role={employee.role}
70+
owner={policy?.owner}
71+
login={login}
72+
/>
73+
),
6974
};
7075
})
7176
.filter((approver): approver is SelectionListApprover => !!approver);
@@ -82,7 +87,7 @@ function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}
8287
shouldShow: true,
8388
},
8489
];
85-
}, [debouncedSearchTerm, personalDetails, policy?.employeeList, selectedApprover, translate]);
90+
}, [debouncedSearchTerm, personalDetails, policy?.employeeList, policy?.owner, selectedApprover]);
8691

8792
const handleOnSelectRow = (approver: SelectionListApprover) => {
8893
setApprover(approver.login);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import Badge from '@components/Badge';
3+
import useLocalize from '@hooks/useLocalize';
4+
import CONST from '@src/CONST';
5+
import type {TranslationPaths} from '@src/languages/types';
6+
7+
type MemberRightIconProps = {
8+
owner?: string;
9+
role?: string;
10+
login?: string;
11+
};
12+
13+
export default function MemberRightIcon({role, owner, login}: MemberRightIconProps) {
14+
const {translate} = useLocalize();
15+
16+
let badgeText: TranslationPaths | undefined;
17+
if (owner && owner === login) {
18+
badgeText = 'common.owner';
19+
} else if (role === CONST.POLICY.ROLE.ADMIN) {
20+
badgeText = 'common.admin';
21+
} else if (role === CONST.POLICY.ROLE.AUDITOR) {
22+
badgeText = 'common.auditor';
23+
}
24+
if (badgeText) {
25+
return <Badge text={translate(badgeText)} />;
26+
}
27+
return null;
28+
}

src/pages/workspace/WorkspaceMembersPage.tsx

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {InteractionManager, View} from 'react-native';
66
import type {OnyxEntry} from 'react-native-onyx';
77
import {useOnyx} from 'react-native-onyx';
88
import type {ValueOf} from 'type-fest';
9-
import Badge from '@components/Badge';
109
import Button from '@components/Button';
1110
import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
1211
import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types';
@@ -66,6 +65,7 @@ import type SCREENS from '@src/SCREENS';
6665
import type {PersonalDetails, PersonalDetailsList, PolicyEmployee, PolicyEmployeeList} from '@src/types/onyx';
6766
import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon';
6867
import {isEmptyObject} from '@src/types/utils/EmptyObject';
68+
import MemberRightIcon from './MemberRightIcon';
6969
import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading';
7070
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
7171
import WorkspacePageWithSections from './WorkspacePageWithSections';
@@ -428,15 +428,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
428428
return;
429429
}
430430
}
431-
const isOwner = policy?.owner === details.login;
432-
const isAdmin = policyEmployee.role === CONST.POLICY.ROLE.ADMIN;
433-
const isAuditor = policyEmployee.role === CONST.POLICY.ROLE.AUDITOR;
434-
let roleBadge = null;
435-
if (isOwner || isAdmin) {
436-
roleBadge = <Badge text={isOwner ? translate('common.owner') : translate('common.admin')} />;
437-
} else if (isAuditor) {
438-
roleBadge = <Badge text={translate('common.auditor')} />;
439-
}
431+
440432
const isPendingDeleteOrError = isPolicyAdmin && (policyEmployee.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !isEmptyObject(policyEmployee.errors));
441433

442434
result.push({
@@ -448,7 +440,13 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
448440
cursorStyle: details.isOptimisticPersonalDetail ? styles.cursorDefault : {},
449441
text: formatPhoneNumber(getDisplayNameOrDefault(details)),
450442
alternateText: formatPhoneNumber(details?.login ?? ''),
451-
rightElement: roleBadge,
443+
rightElement: (
444+
<MemberRightIcon
445+
role={policyEmployee.role}
446+
owner={policy?.owner}
447+
login={details.login}
448+
/>
449+
),
452450
icons: [
453451
{
454452
source: details.avatar ?? FallbackAvatar,
@@ -476,7 +474,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers
476474
policyMemberEmailsToAccountIDs,
477475
policyOwner,
478476
session?.accountID,
479-
translate,
480477
styles.cursorDefault,
481478
isPolicyAdmin,
482479
]);

src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import debounce from 'lodash/debounce';
33
import React, {useCallback, useEffect, useMemo, useState} from 'react';
44
import type {SectionListData} from 'react-native';
55
import {useOnyx} from 'react-native-onyx';
6-
import Badge from '@components/Badge';
76
import BlockingView from '@components/BlockingViews/BlockingView';
87
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
98
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
@@ -27,6 +26,7 @@ import {getSearchValueForPhoneOrEmail, sortAlphabetically} from '@libs/OptionsLi
2726
import {getMemberAccountIDsForWorkspace, goBackFromInvalidPolicy, isPendingDeletePolicy, isPolicyAdmin} from '@libs/PolicyUtils';
2827
import tokenizedSearch from '@libs/tokenizedSearch';
2928
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
29+
import MemberRightIcon from '@pages/workspace/MemberRightIcon';
3030
import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading';
3131
import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
3232
import variables from '@styles/variables';
@@ -93,7 +93,6 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa
9393
if (employeeList) {
9494
const availableApprovers = Object.values(employeeList)
9595
.map((employee): SelectionListApprover | null => {
96-
const isAdmin = employee?.role === CONST.REPORT.ROLE.ADMIN;
9796
const email = employee.email;
9897

9998
if (!email) {
@@ -117,7 +116,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa
117116

118117
const policyMemberEmailsToAccountIDs = getMemberAccountIDsForWorkspace(employeeList);
119118
const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? '');
120-
const {avatar, displayName = email} = personalDetails?.[accountID] ?? {};
119+
const {avatar, displayName = email, login} = personalDetails?.[accountID] ?? {};
121120

122121
return {
123122
text: displayName,
@@ -126,7 +125,13 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa
126125
isSelected: selectedApproverEmail === email,
127126
login: email,
128127
icons: [{source: avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: displayName, id: accountID}],
129-
rightElement: isAdmin ? <Badge text={translate('common.admin')} /> : undefined,
128+
rightElement: (
129+
<MemberRightIcon
130+
role={employee.role}
131+
owner={policy?.owner}
132+
login={login}
133+
/>
134+
),
130135
};
131136
})
132137
.filter((approver): approver is SelectionListApprover => !!approver);
@@ -159,7 +164,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa
159164
selectedApproverEmail,
160165
membersEmail,
161166
policy?.preventSelfApproval,
162-
translate,
167+
policy?.owner,
163168
]);
164169

165170
const shouldShowListEmptyContent = !debouncedSearchTerm && !!approvalWorkflow && !sections.at(0)?.data.length && !isApprovalWorkflowLoading;

src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, {useCallback, useEffect, useMemo, useState} from 'react';
22
import type {SectionListData} from 'react-native';
33
import {useOnyx} from 'react-native-onyx';
4-
import Badge from '@components/Badge';
54
import BlockingView from '@components/BlockingViews/BlockingView';
65
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
76
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
@@ -14,6 +13,7 @@ import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem
1413
import type {Section} from '@components/SelectionList/types';
1514
import Text from '@components/Text';
1615
import useDebouncedState from '@hooks/useDebouncedState';
16+
import useDeepCompareRef from '@hooks/useDeepCompareRef';
1717
import useLocalize from '@hooks/useLocalize';
1818
import useThemeStyles from '@hooks/useThemeStyles';
1919
import {setApprovalWorkflowMembers} from '@libs/actions/Workflow';
@@ -25,6 +25,7 @@ import {getSearchValueForPhoneOrEmail, sortAlphabetically} from '@libs/OptionsLi
2525
import {getMemberAccountIDsForWorkspace, goBackFromInvalidPolicy, isPendingDeletePolicy, isPolicyAdmin} from '@libs/PolicyUtils';
2626
import tokenizedSearch from '@libs/tokenizedSearch';
2727
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
28+
import MemberRightIcon from '@pages/workspace/MemberRightIcon';
2829
import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading';
2930
import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
3031
import variables from '@styles/variables';
@@ -57,6 +58,8 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
5758
const {translate} = useLocalize();
5859
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');
5960
const [approvalWorkflow, approvalWorkflowResults] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW, {canBeMissing: true});
61+
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false});
62+
6063
const isLoadingApprovalWorkflow = isLoadingOnyxValue(approvalWorkflowResults);
6164
const [selectedMembers, setSelectedMembers] = useState<SelectionListMember[]>([]);
6265

@@ -66,6 +69,8 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
6669
const shouldShowListEmptyContent = !isLoadingApprovalWorkflow && approvalWorkflow && approvalWorkflow.availableMembers.length === 0;
6770
const firstApprover = approvalWorkflow?.approvers?.[0]?.email ?? '';
6871

72+
const personalDetailLogins = useDeepCompareRef(Object.fromEntries(Object.entries(personalDetails ?? {}).map(([id, details]) => [id, details?.login])));
73+
6974
useEffect(() => {
7075
if (!approvalWorkflow?.members) {
7176
return;
@@ -75,7 +80,7 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
7580
approvalWorkflow.members.map((member) => {
7681
const policyMemberEmailsToAccountIDs = getMemberAccountIDsForWorkspace(policy?.employeeList);
7782
const accountID = Number(policyMemberEmailsToAccountIDs[member.email] ?? '');
78-
const isAdmin = policy?.employeeList?.[member.email]?.role === CONST.REPORT.ROLE.ADMIN;
83+
const login = personalDetailLogins?.[accountID];
7984

8085
return {
8186
text: member.displayName,
@@ -84,11 +89,17 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
8489
isSelected: true,
8590
login: member.email,
8691
icons: [{source: member.avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: member.displayName, id: accountID}],
87-
rightElement: isAdmin ? <Badge text={translate('common.admin')} /> : undefined,
92+
rightElement: (
93+
<MemberRightIcon
94+
role={policy?.employeeList?.[member.email]?.role}
95+
owner={policy?.owner}
96+
login={login}
97+
/>
98+
),
8899
};
89100
}),
90101
);
91-
}, [approvalWorkflow?.members, policy?.employeeList, translate]);
102+
}, [approvalWorkflow?.members, policy?.employeeList, policy?.owner, personalDetailLogins, translate]);
92103

93104
const approversEmail = useMemo(() => approvalWorkflow?.approvers.map((member) => member?.email), [approvalWorkflow?.approvers]);
94105
const sections: MembersSection[] = useMemo(() => {
@@ -97,9 +108,9 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
97108
if (approvalWorkflow?.availableMembers) {
98109
const availableMembers = approvalWorkflow.availableMembers
99110
.map((member) => {
100-
const isAdmin = policy?.employeeList?.[member.email]?.role === CONST.REPORT.ROLE.ADMIN;
101111
const policyMemberEmailsToAccountIDs = getMemberAccountIDsForWorkspace(policy?.employeeList);
102112
const accountID = Number(policyMemberEmailsToAccountIDs[member.email] ?? '');
113+
const login = personalDetailLogins?.[accountID];
103114

104115
return {
105116
text: member.displayName,
@@ -108,7 +119,13 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
108119
isSelected: false,
109120
login: member.email,
110121
icons: [{source: member.avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: member.displayName, id: accountID}],
111-
rightElement: isAdmin ? <Badge text={translate('common.admin')} /> : undefined,
122+
rightElement: (
123+
<MemberRightIcon
124+
role={policy?.employeeList?.[member.email]?.role}
125+
owner={policy?.owner}
126+
login={login}
127+
/>
128+
),
112129
};
113130
})
114131
.filter(
@@ -128,7 +145,7 @@ function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportDat
128145
shouldShow: true,
129146
},
130147
];
131-
}, [approvalWorkflow?.availableMembers, debouncedSearchTerm, policy?.preventSelfApproval, policy?.employeeList, selectedMembers, translate, approversEmail]);
148+
}, [approvalWorkflow?.availableMembers, debouncedSearchTerm, policy?.preventSelfApproval, policy?.employeeList, policy?.owner, selectedMembers, approversEmail, personalDetailLogins]);
132149

133150
const goBack = useCallback(() => {
134151
let backTo;

0 commit comments

Comments
 (0)