Skip to content
Merged
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
1 change: 0 additions & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ const CONST = {
CUSTOM_FIELD_KEYS: {customField1: 'employeeUserID', customField2: 'employeePayrollID'},
ANDROID_PACKAGE_NAME,
WORKSPACE_ENABLE_FEATURE_REDIRECT_DELAY: 100,
WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM_ROUTE: 'expenses-from',
ANIMATED_HIGHLIGHT_ENTRY_DELAY: 50,
ANIMATED_HIGHLIGHT_ENTRY_DURATION: 300,
ANIMATED_HIGHLIGHT_START_DELAY: 10,
Expand Down
9 changes: 4 additions & 5 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import type {TupleToUnion, ValueOf} from 'type-fest';
import type {UpperCaseCharacters} from 'type-fest/source/internal';
import type {SearchFilterKey, SearchQueryString, UserFriendlyKey} from './components/Search/types';
import CONST from './CONST';
import type CONST from './CONST';
import type {IOUAction, IOUType} from './CONST';
import type {ReplacementReason} from './libs/actions/Card';
import type {IOURequestType} from './libs/actions/IOU';
Expand Down Expand Up @@ -1727,11 +1727,10 @@ const ROUTES = {
getRoute: (policyID: string, firstApproverEmail: string) => `workspaces/${policyID}/workflows/approvals/${encodeURIComponent(firstApproverEmail)}/edit` as const,
},
WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM: {
route: `workspaces/:policyID/workflows/approvals/${CONST.WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM_ROUTE}`,
route: 'workspaces/:policyID/workflows/approvals/expenses-from',

getRoute: (policyID: string, backTo?: string) =>
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
getUrlWithBackToParam(`workspaces/${policyID}/workflows/approvals/${CONST.WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM_ROUTE}` as const, backTo),
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`workspaces/${policyID}/workflows/approvals/expenses-from` as const, backTo),
},
WORKSPACE_WORKFLOWS_APPROVALS_APPROVER: {
route: 'workspaces/:policyID/workflows/approvals/approver',
Expand Down
20 changes: 4 additions & 16 deletions src/components/ApproverSelectionList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useMemo} from 'react';
import React, {useMemo} from 'react';
import useDebouncedState from '@hooks/useDebouncedState';
import {useMemoizedLazyIllustrations} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -40,7 +40,6 @@ type ApproverSelectionListPageProps = {
onSelectApprover?: (approvers: SelectionListApprover[]) => void;
shouldShowLoadingPlaceholder?: boolean;
shouldEnableHeaderMaxHeight?: boolean;
onSearchChange?: (searchTerm: string) => void;
shouldUpdateFocusedIndex?: boolean;
};

Expand All @@ -67,7 +66,6 @@ function ApproverSelectionList({
onSelectApprover,
shouldShowLoadingPlaceholder,
shouldEnableHeaderMaxHeight,
onSearchChange,
shouldUpdateFocusedIndex = true,
}: ApproverSelectionListPageProps) {
const styles = useThemeStyles();
Expand All @@ -77,16 +75,6 @@ function ApproverSelectionList({
const shouldShowTextInput = shouldShowTextInputProp ?? allApprovers?.length >= CONST.STANDARD_LIST_ITEM_LIMIT;
const lazyIllustrations = useMemoizedLazyIllustrations(['TurtleInShell']);

const handleSearchChange = useCallback(
(term: string) => {
setSearchTerm(term);
if (onSearchChange) {
onSearchChange(term);
}
},
[onSearchChange, setSearchTerm],
);

const selectedMembers = useMemo(() => allApprovers.filter((approver) => approver.isSelected), [allApprovers]);

// eslint-disable-next-line rulesdir/no-negated-variables
Expand Down Expand Up @@ -138,10 +126,10 @@ function ApproverSelectionList({
() => ({
label: shouldShowListEmptyContent ? undefined : translate('selectionList.findMember'),
value: searchTerm,
onChangeText: handleSearchChange,
onChangeText: setSearchTerm,
headerMessage: searchTerm && !data?.length ? translate('common.noResultsFound') : '',
}),
[shouldShowListEmptyContent, translate, searchTerm, handleSearchChange, data?.length],
[shouldShowListEmptyContent, translate, searchTerm, setSearchTerm, data?.length],
);

return (
Expand All @@ -165,9 +153,9 @@ function ApproverSelectionList({
{subtitle}
<SelectionList
data={data}
onSelectRow={toggleApprover}
ListItem={InviteMemberListItem}
textInputOptions={textInputOptions}
onSelectRow={toggleApprover}
canSelectMultiple={allowMultipleSelection}
shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
listEmptyContent={listEmptyContent}
Expand Down
13 changes: 0 additions & 13 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

let allPolicies: OnyxCollection<Policy>;

Onyx.connect({

Check warning on line 63 in src/libs/PolicyUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => (allPolicies = value),
Expand Down Expand Up @@ -504,18 +504,6 @@
return memberEmailsToExclude;
}

/**
* Get excluded users as a Record for use in search selector
*/
function getExcludedUsers(employeeList?: PolicyEmployeeList): Record<string, boolean> {
const ineligibleInvitees = getIneligibleInvitees(employeeList);
const result: Record<string, boolean> = {};
for (const login of ineligibleInvitees) {
result[login] = true;
}
return result;
}

function getSortedTagKeys(policyTagList: OnyxEntry<PolicyTagLists>): Array<keyof PolicyTagLists> {
if (isEmptyObject(policyTagList)) {
return [];
Expand Down Expand Up @@ -1699,7 +1687,6 @@
getValidConnectedIntegration,
getCountOfEnabledTagsOfList,
getIneligibleInvitees,
getExcludedUsers,
getMemberAccountIDsForWorkspace,
getNumericValue,
isMultiLevelTags,
Expand Down
79 changes: 18 additions & 61 deletions src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,30 +66,6 @@ function WorkspaceInviteMessageComponent({
}: WorkspaceInviteMessageComponentProps) {
const styles = useThemeStyles();
const {translate, formatPhoneNumber} = useLocalize();
const policyName = policy?.name;

const isWorkflowApprovalExpensesFromRoute = useMemo(() => {
if (!backTo || typeof backTo !== 'string') {
return false;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return (backTo as string).includes(CONST.WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM_ROUTE);
}, [backTo]);

const headerTitle = useMemo(() => {
if (isWorkflowApprovalExpensesFromRoute) {
return translate('workflowsExpensesFromPage.title');
}
return translate('workspace.inviteMessage.confirmDetails');
}, [isWorkflowApprovalExpensesFromRoute, translate]);

const subtitle = useMemo(() => {
if (isWorkflowApprovalExpensesFromRoute) {
return undefined;
}
return policyName;
}, [isWorkflowApprovalExpensesFromRoute, policyName]);

const [formData, formDataResult] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM_DRAFT, {canBeMissing: true});
const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false});

Expand All @@ -106,25 +82,22 @@ function WorkspaceInviteMessageComponent({
});
const [workspaceInviteRoleDraft = CONST.POLICY.ROLE.USER] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_ROLE_DRAFT}${policyID}`, {canBeMissing: true});
const isOnyxLoading = isLoadingOnyxValue(workspaceInviteMessageDraftResult, invitedEmailsToAccountIDsDraftResult, formDataResult);
const personalDetailsOfInvitedEmails = getPersonalDetailsForAccountIDs(Object.values(invitedEmailsToAccountIDsDraft ?? {}), allPersonalDetails ?? {});
const memberNames = Object.values(personalDetailsOfInvitedEmails)
.map((personalDetail) => {
const displayName = getDisplayNameOrDefault(personalDetail, '', false);
if (displayName) {
return displayName;
}

const memberNames = useMemo(() => {
const personalDetailsOfInvitedEmails = getPersonalDetailsForAccountIDs(Object.values(invitedEmailsToAccountIDsDraft ?? {}), allPersonalDetails ?? {});
return Object.values(personalDetailsOfInvitedEmails)
.map((personalDetail) => {
const displayName = getDisplayNameOrDefault(personalDetail, '', false);
if (displayName) {
return displayName;
}

// We don't have login details for users who are not in the database yet
// So we need to fallback to their login from the invitedEmailsToAccountIDsDraft
const accountID = personalDetail.accountID;
const loginFromInviteMap = Object.entries(invitedEmailsToAccountIDsDraft ?? {}).find(([, id]) => id === accountID)?.[0];
// We don't have login details for users who are not in the database yet
// So we need to fallback to their login from the invitedEmailsToAccountIDsDraft
const accountID = personalDetail.accountID;
const loginFromInviteMap = Object.entries(invitedEmailsToAccountIDsDraft ?? {}).find(([, id]) => id === accountID)?.[0];

return loginFromInviteMap;
})
.join(', ');
}, [invitedEmailsToAccountIDsDraft, allPersonalDetails]);
return loginFromInviteMap;
})
.join(', ');

const welcomeNoteSubject = useMemo(
() => `# ${currentUserPersonalDetails?.displayName ?? ''} invited you to ${policy?.name ?? 'a workspace'}`,
Expand Down Expand Up @@ -174,21 +147,6 @@ function WorkspaceInviteMessageComponent({
return;
}

// If backTo is provided and it's the expenses-from route, navigate to approver screen
if (isWorkflowApprovalExpensesFromRoute) {
// Check if it's initial creation flow (backTo doesn't have a nested backTo param)
const backToStr = typeof backTo === 'string' ? backTo : '';
const isInitialCreationFlow = !backToStr.includes('/expenses-from/');
if (isInitialCreationFlow) {
// Navigate to approver screen for initial creation flow
Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVER.getRoute(policyID, 0));
} else {
// For edit flow, just go back
Navigation.goBack();
}
return;
}

if ((backTo as string)?.endsWith('members')) {
Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.dismissModal());
return;
Expand Down Expand Up @@ -218,6 +176,7 @@ function WorkspaceInviteMessageComponent({
return errorFields;
};

const policyName = policy?.name;
const invitingMemberEmail = Object.keys(invitedEmailsToAccountIDsDraft ?? {}).at(0) ?? '';
const invitingMemberDetails = getPersonalDetailByEmail(invitingMemberEmail);
const invitingMemberName = Str.removeSMSDomain(invitingMemberDetails?.displayName ?? '');
Expand All @@ -242,8 +201,8 @@ function WorkspaceInviteMessageComponent({
>
{shouldShowBackButton && (
<HeaderWithBackButton
title={headerTitle}
subtitle={subtitle}
title={translate('workspace.inviteMessage.confirmDetails')}
subtitle={policyName}
shouldShowBackButton
onCloseButtonPress={() => Navigation.dismissModal()}
onBackButtonPress={() => Navigation.goBack(backTo)}
Expand All @@ -259,9 +218,7 @@ function WorkspaceInviteMessageComponent({
shouldHideFixErrorsAlert
addBottomSafeAreaPadding
>
{(isInviteNewMemberStep || isWorkflowApprovalExpensesFromRoute) && (
<Text style={[styles.textHeadlineLineHeightXXL, styles.mv3]}>{translate('workspace.card.issueNewCard.inviteNewMember')}</Text>
)}
{isInviteNewMemberStep && <Text style={[styles.textHeadlineLineHeightXXL, styles.mv3]}>{translate('workspace.card.issueNewCard.inviteNewMember')}</Text>}
<View style={[styles.mv4, styles.justifyContentCenter, styles.alignItemsCenter]}>
<ReportActionAvatars
size={CONST.AVATAR_SIZE.LARGE}
Expand Down
Loading
Loading