Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b7f5709
Fix - No checkmark displayed for the selected recipient
dmkt9 Dec 14, 2025
2e75d3e
Fix - No checkmark displayed for the selected recipient
dmkt9 Dec 15, 2025
8bba565
fix lint
dmkt9 Dec 15, 2025
f522d00
Fix - No checkmark displayed for the selected recipient
dmkt9 Dec 15, 2025
0120ff6
Merge branch 'main' into fix/72129-follow-up
dmkt9 Dec 22, 2025
07bca03
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Dec 22, 2025
56451e2
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Dec 22, 2025
a088c65
Merge branch 'main' into fix/72129b
dmkt9 Dec 23, 2025
663deb9
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Dec 23, 2025
8ef981a
Merge branch 'main' into fix/72129b
dmkt9 Dec 23, 2025
af514f2
fix test
dmkt9 Dec 23, 2025
7d4740d
Merge branch 'main' into fix/72129b
dmkt9 Jan 6, 2026
3a6e9fb
Merge branch 'main' into fix/72129b
dmkt9 Jan 15, 2026
5ce8ae2
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Jan 15, 2026
c2ab915
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Jan 15, 2026
f398d6f
Merge branch 'main' into fix/72129b
dmkt9 Jan 21, 2026
e110ad5
Merge branch 'main' into fix/72129b
dmkt9 Jan 21, 2026
c3de042
Merge branch 'main' into fix/72129b
dmkt9 Jan 22, 2026
669e39b
Fix - No checkmark displayed for the selected recipient
dmkt9 Jan 22, 2026
44da0d9
fix ts
dmkt9 Jan 22, 2026
7f607c4
Merge branch 'main' into fix/72129b
dmkt9 Jan 28, 2026
b062e93
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Jan 28, 2026
ec0029c
fix lint
dmkt9 Jan 28, 2026
65f524d
Merge branch 'main' into fix/72129b
dmkt9 Feb 4, 2026
98d9f5a
Merge branch 'main' into fix/72129b
dmkt9 Feb 9, 2026
dee4d85
Fix - No checkmark displayed for selected recipient in choose recipie…
dmkt9 Feb 9, 2026
43c3e01
Merge branch 'main' into fix/72129b
dmkt9 Feb 10, 2026
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
60 changes: 38 additions & 22 deletions src/libs/OptionsListUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@
*/

let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
Onyx.connect({

Check warning on line 200 in src/libs/OptionsListUtils/index.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

Check warning on line 200 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => (allPersonalDetails = isEmptyObject(value) ? {} : value),
});

const policies: OnyxCollection<Policy> = {};
Onyx.connect({

Check warning on line 206 in src/libs/OptionsListUtils/index.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,
callback: (policy, key) => {
if (!policy || !key || !policy.name) {
Expand All @@ -215,14 +215,14 @@
});

let allPolicies: OnyxCollection<Policy> = {};
Onyx.connect({

Check warning on line 218 in src/libs/OptionsListUtils/index.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: (val) => (allPolicies = val),
});

let allReports: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 225 in src/libs/OptionsListUtils/index.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.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -231,7 +231,7 @@
});

let allReportNameValuePairsOnyxConnect: OnyxCollection<ReportNameValuePairs>;
Onyx.connect({

Check warning on line 234 in src/libs/OptionsListUtils/index.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.REPORT_NAME_VALUE_PAIRS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -243,7 +243,7 @@
const allSortedReportActions: Record<string, ReportAction[]> = {};
let allReportActions: OnyxCollection<ReportActions>;
const lastVisibleReportActions: ReportActions = {};
Onyx.connect({

Check warning on line 246 in src/libs/OptionsListUtils/index.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.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand Down Expand Up @@ -305,7 +305,7 @@
});

let activePolicyID: OnyxEntry<string>;
Onyx.connect({

Check warning on line 308 in src/libs/OptionsListUtils/index.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.NVP_ACTIVE_POLICY_ID,
callback: (value) => (activePolicyID = value),
});
Expand Down Expand Up @@ -2248,12 +2248,17 @@
// This prevents the issue of seeing the selected option twice if you have them as a recent chat and select them
if (!includeSelectedOptions) {
for (const option of selectedOptions) {
if (!option.login) {
if (option.login) {
// Prevent re-inviting already selected users
loginsToExclude[option.login] = true;
loginsToExcludeFromSuggestions[option.login] = true;
continue;
}
// Prevent re-inviting already selected users
loginsToExclude[option.login] = true;
loginsToExcludeFromSuggestions[option.login] = true;

if (option.reportID) {
loginsToExclude[option.reportID] = true;
loginsToExcludeFromSuggestions[option.reportID] = true;
}
Comment on lines +2251 to +2261

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're mixing login and reportID in the same loginsToExclude object. This can be confusing since the name suggests it only contains logins.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe I have only corrected its functionality, since we have also used it together with the name loginsToExclude here:

// If we're excluding threads, check the report to see if it has a single participant and if the participant is already selected
if (!includeThreads && ((!!option.login && loginsToExclude[option.login]) || loginsToExclude[option.reportID])) {
return false;
}

}
}
const {includeP2P = true, shouldBoldTitleByDefault = true, includeDomainEmail = false, shouldShowGBR = false, ...getValidReportsConfig} = config;
Expand Down Expand Up @@ -2757,19 +2762,24 @@
// We show the selected participants at the top of the list when there is no search term or maximum number of participants has already been selected
// However, if there is a search term we remove the selected participants from the top of the list unless they are part of the search results
// This clears up space on mobile views, where if you create a group with 4+ people you can't see the selected participants and the search results at the same time
const selectedOptionsMapper = (participant: Participant) => {
const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false;
const isIOUInvoiceRoom = participant.accountID === CONST.DEFAULT_NUMBER_ID && !!participant.reportID && 'iouType' in participant && participant.iouType === 'invoice';
if (participant.isSelfDM || isIOUInvoiceRoom) {
const privateIsArchived = allReportNameValuePairsOnyxConnect?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${participant.reportID}`]?.private_isArchived;
return getReportOption(participant, privateIsArchived, undefined, currentUserAccountID, personalDetails, reportAttributesDerived);
}
return isReportPolicyExpenseChat
? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived)
: getParticipantsOption(participant, personalDetails);
};

if (searchTerm === '') {
return {
section: {
title: undefined,
sectionIndex: 0,
data: shouldGetOptionDetails
? selectedOptions.map((participant) => {
const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false;
return isReportPolicyExpenseChat
? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived)
: getParticipantsOption(participant, personalDetails);
})
: selectedOptions,
data: shouldGetOptionDetails ? selectedOptions.map(selectedOptionsMapper) : selectedOptions,
},
};
}
Expand All @@ -2779,7 +2789,20 @@
// This will add them to the list of options, deduping them if they already exist in the other lists
const selectedParticipantsWithoutDetails = selectedOptions.filter((participant) => {
const accountID = participant.accountID ?? null;
const isPartOfSearchTerm = getPersonalDetailSearchTerms(participant, currentUserAccountID).join(' ').toLowerCase().includes(cleanSearchTerm);
let currentParticipant = participant;
if (currentParticipant.isSelfDM) {
currentParticipant = {...currentParticipant, accountID: currentUserAccountID};
}
const isPartOfSearchTerm = getPersonalDetailSearchTerms(
{
...currentParticipant,
login: currentParticipant.login ?? personalDetails[currentParticipant.accountID ?? CONST.DEFAULT_NUMBER_ID]?.login,
},
currentUserAccountID,
)
.join(' ')
.toLowerCase()
.includes(cleanSearchTerm);
const isReportInRecentReports = filteredRecentReports.some((report) => report.accountID === accountID) || filteredWorkspaceChats.some((report) => report.accountID === accountID);
const isReportInPersonalDetails = filteredPersonalDetails.some((personalDetail) => personalDetail.accountID === accountID);

Expand All @@ -2790,14 +2813,7 @@
section: {
title: undefined,
sectionIndex: 0,
data: shouldGetOptionDetails
? selectedParticipantsWithoutDetails.map((participant) => {
const isReportPolicyExpenseChat = participant.isPolicyExpenseChat ?? false;
return isReportPolicyExpenseChat
? getPolicyExpenseReportOption(participant, currentUserAccountID, personalDetails, reportAttributesDerived)
: getParticipantsOption(participant, personalDetails);
})
: selectedParticipantsWithoutDetails,
data: shouldGetOptionDetails ? selectedParticipantsWithoutDetails.map(selectedOptionsMapper) : selectedParticipantsWithoutDetails,
},
};
}
Expand All @@ -2819,7 +2835,7 @@
if (item.accountID === currentUserAccountID) {
return getCurrentUserSearchTerms(item);
}
return [item.participantsList?.[0]?.displayName ?? item.displayName ?? '', item.login ?? '', item.login?.replace(CONST.EMAIL_SEARCH_REGEX, '') ?? ''];
return [item.participantsList?.[0]?.displayName ?? item.displayName ?? '', item.login ?? '', item.login?.replace(CONST.EMAIL_SEARCH_REGEX, '') ?? '', item.text ?? ''];
}

function getCurrentUserSearchTerms(item: Partial<SearchOptionData>) {
Expand Down
11 changes: 10 additions & 1 deletion src/libs/actions/IOU/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@
};

let allPersonalDetails: OnyxTypes.PersonalDetailsList = {};
Onyx.connect({

Check warning on line 796 in src/libs/actions/IOU/index.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.PERSONAL_DETAILS_LIST,
callback: (value) => {
allPersonalDetails = value ?? {};
Expand Down Expand Up @@ -887,7 +887,7 @@
};

let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 890 in src/libs/actions/IOU/index.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.TRANSACTION,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -901,7 +901,7 @@
});

let allTransactionDrafts: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
Onyx.connect({

Check warning on line 904 in src/libs/actions/IOU/index.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.TRANSACTION_DRAFT,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -11881,7 +11881,16 @@
let participants: Participant[] = [];

if (isPolicyExpenseChat || shouldAddAsReport) {
participants = [{accountID: 0, reportID: chatReport?.reportID, isPolicyExpenseChat, selected: true, policyID: isPolicyExpenseChat ? chatReport?.policyID : undefined}];
participants = [
{
accountID: 0,
reportID: chatReport?.reportID,
isPolicyExpenseChat,
selected: true,
policyID: isPolicyExpenseChat ? chatReport?.policyID : undefined,
isSelfDM: shouldAddAsReport,
},
];
} else if (isInvoiceRoom(chatReport)) {
participants = [
{reportID: chatReport?.reportID, selected: true},
Expand Down
53 changes: 31 additions & 22 deletions src/pages/iou/request/MoneyRequestParticipantsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,26 +218,27 @@ function MoneyRequestParticipantsSelector({
[isIOUSplit, iouType, onParticipantsAdded],
);

const {searchTerm, debouncedSearchTerm, setSearchTerm, availableOptions, selectedOptions, toggleSelection, areOptionsInitialized, onListEndReached, contactState} = useSearchSelector({
selectionMode: isIOUSplit ? CONST.SEARCH_SELECTOR.SELECTION_MODE_MULTI : CONST.SEARCH_SELECTOR.SELECTION_MODE_SINGLE,
searchContext: CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL,
includeUserToInvite: !isCategorizeOrShareAction && !isPerDiemRequest,
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
includeRecentReports: true,
maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW,
getValidOptionsConfig,
shouldInitialize: didScreenTransitionEnd,
enablePhoneContacts: isNative,
contactOptions: contacts,
initialSelected: participants as OptionData[],
onSelectionChange: handleSelectionChange,
onSingleSelect: (option: OptionData) => {
if (isIOUSplit) {
return;
}
addSingleParticipant(option);
},
});
const {searchTerm, debouncedSearchTerm, setSearchTerm, availableOptions, selectedOptions, setSelectedOptions, toggleSelection, areOptionsInitialized, onListEndReached, contactState} =
useSearchSelector({
selectionMode: isIOUSplit ? CONST.SEARCH_SELECTOR.SELECTION_MODE_MULTI : CONST.SEARCH_SELECTOR.SELECTION_MODE_SINGLE,
searchContext: CONST.SEARCH_SELECTOR.SEARCH_CONTEXT_GENERAL,
includeUserToInvite: !isCategorizeOrShareAction && !isPerDiemRequest,
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
includeRecentReports: true,
maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW,
getValidOptionsConfig,
shouldInitialize: didScreenTransitionEnd,
enablePhoneContacts: isNative,
contactOptions: contacts,
initialSelected: participants as OptionData[],
onSelectionChange: handleSelectionChange,
onSingleSelect: (option: OptionData) => {
if (isIOUSplit) {
return;
}
addSingleParticipant(option);
},
});

const cleanSearchTerm = useMemo(() => debouncedSearchTerm.trim().toLowerCase(), [debouncedSearchTerm]);

Expand Down Expand Up @@ -414,9 +415,15 @@ function MoneyRequestParticipantsSelector({
return;
}

// If the selected option is self DM, we need to recall onParticipantsAdded to handle navigation correctly
if (!option && selectedOptions.length === 1 && selectedOptions.at(0)?.isSelfDM) {
onParticipantsAdded(selectedOptions.map((selectedOption) => sanitizedSelectedParticipant(selectedOption, iouType)));
return;
}

onFinish(CONST.IOU.TYPE.SPLIT);
},
[shouldShowSplitBillErrorMessage, onFinish, addSingleParticipant, selectedOptions.length],
[shouldShowSplitBillErrorMessage, onFinish, addSingleParticipant, onParticipantsAdded, selectedOptions, iouType],
);

const showLoadingPlaceholder = useMemo(() => !areOptionsInitialized || !didScreenTransitionEnd, [areOptionsInitialized, didScreenTransitionEnd]);
Expand Down Expand Up @@ -510,9 +517,11 @@ function MoneyRequestParticipantsSelector({
return;
}

const reportID = option.reportID ?? CONST.REPORT.UNREPORTED_REPORT_ID;
setSelectedOptions([{...option, isSelected: true, reportID, keyForList: reportID}]);
addSingleParticipant(option);
},
[isIOUSplit, addParticipantToSelection, addSingleParticipant],
[isIOUSplit, addParticipantToSelection, addSingleParticipant, setSelectedOptions],
);

const importContactsButtonComponent = useMemo(() => {
Expand Down
21 changes: 14 additions & 7 deletions src/pages/iou/request/step/IOURequestStepAmount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
resetSplitShares,
setDraftSplitTransaction,
setMoneyRequestAmount,
setMoneyRequestParticipants,
setMoneyRequestParticipantsFromReport,
setMoneyRequestTaxAmount,
setMoneyRequestTaxRate,
Expand Down Expand Up @@ -316,12 +317,15 @@ function IOURequestStepAmount({

// Starting from global + menu means no participant context exists yet,
// so we need to handle participant selection based on available workspace settings
const isReturningFromConfirmationPage = !!transaction?.participants?.length;
const firstParticipant = transaction?.participants?.at(0);
const isP2PChat = isParticipantP2P(firstParticipant, currentUserPersonalDetails.accountID);
const isNegativeAmount = convertToBackendAmount(Number.parseFloat(amount)) < 0;
if (shouldUseDefaultExpensePolicy(iouType, defaultExpensePolicy)) {
const shouldAutoReport = !!defaultExpensePolicy?.autoReporting || !!personalPolicy?.autoReporting;
const targetReport = shouldAutoReport ? getPolicyExpenseChat(currentUserAccountIDParam, defaultExpensePolicy?.id) : selfDMReport;
const transactionReportID = isSelfDM(targetReport) ? CONST.REPORT.UNREPORTED_REPORT_ID : targetReport?.reportID;
const iouTypeTrackOrSubmit = transactionReportID === CONST.REPORT.UNREPORTED_REPORT_ID ? CONST.IOU.TYPE.TRACK : CONST.IOU.TYPE.SUBMIT;
const isReturningFromConfirmationPage = !!transaction?.participants?.length;

const resetToDefaultWorkspace = () => {
setTransactionReport(transactionID, {reportID: transactionReportID}, true);
Expand All @@ -331,10 +335,6 @@ function IOURequestStepAmount({
};

if (isReturningFromConfirmationPage) {
const firstParticipant = transaction?.participants?.at(0);
const isP2PChat = isParticipantP2P(firstParticipant);
const isNegativeAmount = convertToBackendAmount(Number.parseFloat(amount)) < 0;

// P2P chats don't support negative amounts, so reset to default workspace when amount is negative.
if (isP2PChat && isNegativeAmount) {
resetToDefaultWorkspace();
Expand All @@ -353,6 +353,13 @@ function IOURequestStepAmount({
} else {
resetToDefaultWorkspace();
}
}
// P2P chats don't support negative amounts, so in cases where there is no default workspace when the amount is negative, we will remove the selected transaction participants.
else if (iouType === CONST.IOU.TYPE.CREATE && isP2PChat && isNegativeAmount && isReturningFromConfirmationPage) {
setTransactionReport(transactionID, {reportID: undefined}, true);
setMoneyRequestParticipants(transactionID, [], true).then(() => {
navigateToParticipantPage(iouType, transactionID, reportID);
});
Comment on lines +357 to +362

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we can remove this logic and instead update the block at lines 344–347 from:

        } else {
            Navigation.setNavigationActionToMicrotaskQueue(() => {
                navigateToParticipantPage(iouType, transactionID, reportID);
            });

to

        else {
            setTransactionReport(transactionID, {reportID: undefined}, true);
            setMoneyRequestParticipants(transactionID, [], true).then(() => {
                navigateToParticipantPage(iouType, transactionID, reportID);
            });
        }

With this change, we ensure the transaction participants are always cleared when navigating from the amount page.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe we should avoid doing this. If we always clear the transaction participants, Test 4 will consistently fail.
This section of code is designed to clear the transaction participants only when the selected participants are no longer valid.

} else {
Navigation.setNavigationActionToMicrotaskQueue(() => {
navigateToParticipantPage(iouType, transactionID, reportID);
Expand Down Expand Up @@ -472,8 +479,8 @@ function IOURequestStepAmount({
/**
* Check if the participant is a P2P chat
*/
function isParticipantP2P(participant: {accountID?: number; isPolicyExpenseChat?: boolean} | undefined): boolean {
return !!(participant?.accountID && !participant.isPolicyExpenseChat);
function isParticipantP2P(participant: {accountID?: number; isPolicyExpenseChat?: boolean} | undefined, currentUserAccountID?: number): boolean {
return !!(participant?.accountID && !participant.isPolicyExpenseChat && (!currentUserAccountID || participant?.accountID !== currentUserAccountID));
}

// eslint-disable-next-line rulesdir/no-negated-variables
Expand Down
14 changes: 9 additions & 5 deletions src/pages/iou/request/step/IOURequestStepParticipants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {Policy} from '@src/types/onyx';
import type {Participant} from '@src/types/onyx/IOU';
import getEmptyArray from '@src/types/utils/getEmptyArray';
import KeyboardUtils from '@src/utils/keyboard';
import StepScreenWrapper from './StepScreenWrapper';
import type {WithFullTransactionOrNotFoundProps} from './withFullTransactionOrNotFound';
Expand Down Expand Up @@ -72,7 +71,11 @@ function IOURequestStepParticipants({
},
transaction: initialTransaction,
}: IOURequestStepParticipantsProps) {
const participants = initialTransaction?.participants;
const isSplitRequest = iouType === CONST.IOU.TYPE.SPLIT;
const participants = useMemo(() => {
const allParticipants = initialTransaction?.participants;
return isSplitRequest ? allParticipants : allParticipants?.filter((participant) => !participant.isSender && participant.selected);
}, [initialTransaction?.participants, isSplitRequest]);
const {translate} = useLocalize();
const styles = useThemeStyles();
const isFocused = useIsFocused();
Expand All @@ -87,10 +90,11 @@ function IOURequestStepParticipants({
const transactionIDs = useMemo(() => transactions?.map((transaction) => transaction.transactionID), [transactions.length]);

// We need to set selectedReportID if user has navigated back from confirmation page and navigates to confirmation page with already selected participant
const selectedReportID = useRef<string>(participants?.length === 1 ? (participants.at(0)?.reportID ?? reportID) : reportID);
// We need to disable the eslint rule here because the reportID from the first participant can be an empty string
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const selectedReportID = useRef<string>(participants?.length === 1 ? participants.at(0)?.reportID || reportID : reportID);
const numberOfParticipants = useRef(participants?.length ?? 0);
const iouRequestType = getRequestType(initialTransaction);
const isSplitRequest = iouType === CONST.IOU.TYPE.SPLIT;
const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseIOUUtils(action);
const headerTitle = useMemo(() => {
if (action === CONST.IOU.ACTION.CATEGORIZE) {
Expand Down Expand Up @@ -454,7 +458,7 @@ function IOURequestStepParticipants({
/>
)}
<MoneyRequestParticipantsSelector
participants={isSplitRequest ? participants : getEmptyArray()}
participants={participants}
onParticipantsAdded={addParticipant}
onFinish={goToNextStep}
iouType={iouType}
Expand Down
27 changes: 27 additions & 0 deletions tests/unit/OptionsListUtilsTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,33 @@ describe('OptionsListUtils', () => {
expect(results.recentReports).not.toEqual(expect.arrayContaining([expect.objectContaining({login: 'receipts@expensify.com'})]));
});

it('should exclude the person and the report from selected options', () => {
const selectedPerson = PERSONAL_DETAILS['3'];
const selectedReport = REPORTS['3'] as unknown as OptionData;

const results = getValidOptions(
{reports: OPTIONS.reports, personalDetails: OPTIONS.personalDetails},
allPolicies,
{},
nvpDismissedProductTraining,
loginList,
CURRENT_USER_ACCOUNT_ID,
CURRENT_USER_EMAIL,
{
excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT,
selectedOptions: [selectedPerson, selectedReport],
},
);

// The person must be excluded
expect(results.recentReports.every((option) => option.login !== selectedPerson.login)).toBe(true);
expect(results.personalDetails.every((option) => option.login !== selectedPerson.login)).toBe(true);

// The report must be excluded
expect(results.recentReports.every((option) => option.reportID !== selectedReport.reportID)).toBe(true);
expect(results.personalDetails.every((option) => option.reportID !== selectedPerson.reportID)).toBe(true);
});

it('should limit recent reports when maxRecentReportElements is specified', () => {
// Given a set of reports and personalDetails with multiple reports
// When we call getValidOptions with maxRecentReportElements set to 2
Expand Down
Loading