diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js
index 95fa64723737..327ff39ef248 100644
--- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js
+++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js
@@ -1,25 +1,30 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import React, {useCallback, useEffect, useMemo, useState} from 'react';
+import React, {useCallback, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import Button from '@components/Button';
import FormHelpMessage from '@components/FormHelpMessage';
-import OptionsSelector from '@components/OptionsSelector';
-import refPropTypes from '@components/refPropTypes';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import Icon from '@components/Icon';
+import {Info} from '@components/Icon/Expensicons';
+import {PressableWithFeedback, PressableWithoutFeedback} from '@components/Pressable';
+import SelectCircle from '@components/SelectCircle';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import * as Report from '@libs/actions/Report';
import * as Browser from '@libs/Browser';
-import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
-import * as ReportUtils from '@libs/ReportUtils';
import personalDetailsPropType from '@pages/personalDetailsPropType';
import reportPropTypes from '@pages/reportPropTypes';
+import useTheme from '@styles/themes/useTheme';
import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Beta features list */
@@ -28,9 +33,6 @@ const propTypes = {
/** Callback to request parent modal to go to next step, which should be split */
onFinish: PropTypes.func.isRequired,
- /** A ref to forward to options selector's text input */
- forwardedRef: refPropTypes,
-
/** Callback to add participants in MoneyRequestModal */
onParticipantsAdded: PropTypes.func.isRequired,
@@ -62,13 +64,10 @@ const propTypes = {
/** Whether we are searching for reports in the server */
isSearchingForReports: PropTypes.bool,
-
- ...withLocalizePropTypes,
};
const defaultProps = {
participants: [],
- forwardedRef: undefined,
safeAreaPaddingBottomStyle: {},
personalDetails: {},
reports: {},
@@ -77,12 +76,10 @@ const defaultProps = {
};
function MoneyTemporaryForRefactorRequestParticipantsSelector({
- forwardedRef,
betas,
participants,
personalDetails,
reports,
- translate,
onFinish,
onParticipantsAdded,
safeAreaPaddingBottomStyle,
@@ -90,15 +87,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
iouRequestType,
isSearchingForReports,
}) {
+ const {translate} = useLocalize();
const styles = useThemeStyles();
+ const theme = useTheme();
const [searchTerm, setSearchTerm] = useState('');
- const [newChatOptions, setNewChatOptions] = useState({
- recentReports: [],
- personalDetails: [],
- userToInvite: null,
- });
const {isOffline} = useNetwork();
+ const offlineMessage = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : '';
+
const maxParticipantsReached = participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS;
/**
@@ -106,15 +102,42 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
*
* @returns {Array}
*/
- const sections = useMemo(() => {
+ const [sections, newChatOptions] = useMemo(() => {
const newSections = [];
let indexOffset = 0;
+ const chatOptions = OptionsListUtils.getFilteredOptions(
+ reports,
+ personalDetails,
+ betas,
+ searchTerm,
+ participants,
+ CONST.EXPENSIFY_EMAILS,
+
+ // If we are using this component in the "Request money" flow then we pass the includeOwnedWorkspaceChats argument so that the current user
+ // sees the option to request money from their admin on their own Workspace Chat.
+ iouType === CONST.IOU.TYPE.REQUEST,
+
+ // We don't want to include any P2P options like personal details or reports that are not workspace chats for certain features.
+ iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE,
+ false,
+ {},
+ [],
+ false,
+ {},
+ [],
+
+ // We don't want the user to be able to invite individuals when they are in the "Distance request" flow for now.
+ // This functionality is being built here: https://github.com/Expensify/App/issues/23291
+ iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE,
+ true,
+ );
+
const formatResults = OptionsListUtils.formatSectionsFromSearchTerm(
searchTerm,
participants,
- newChatOptions.recentReports,
- newChatOptions.personalDetails,
+ chatOptions.recentReports,
+ chatOptions.personalDetails,
personalDetails,
true,
indexOffset,
@@ -128,24 +151,24 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
newSections.push({
title: translate('common.recents'),
- data: newChatOptions.recentReports,
- shouldShow: !_.isEmpty(newChatOptions.recentReports),
+ data: chatOptions.recentReports,
+ shouldShow: !_.isEmpty(chatOptions.recentReports),
indexOffset,
});
- indexOffset += newChatOptions.recentReports.length;
+ indexOffset += chatOptions.recentReports.length;
newSections.push({
title: translate('common.contacts'),
- data: newChatOptions.personalDetails,
- shouldShow: !_.isEmpty(newChatOptions.personalDetails),
+ data: chatOptions.personalDetails,
+ shouldShow: !_.isEmpty(chatOptions.personalDetails),
indexOffset,
});
- indexOffset += newChatOptions.personalDetails.length;
+ indexOffset += chatOptions.personalDetails.length;
- if (newChatOptions.userToInvite && !OptionsListUtils.isCurrentUser(newChatOptions.userToInvite)) {
+ if (chatOptions.userToInvite && !OptionsListUtils.isCurrentUser(chatOptions.userToInvite)) {
newSections.push({
title: undefined,
- data: _.map([newChatOptions.userToInvite], (participant) => {
+ data: _.map([chatOptions.userToInvite], (participant) => {
const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false);
return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails);
}),
@@ -154,8 +177,8 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
});
}
- return newSections;
- }, [maxParticipantsReached, newChatOptions, participants, personalDetails, translate, searchTerm]);
+ return [newSections, chatOptions];
+ }, [reports, personalDetails, betas, searchTerm, participants, iouType, iouRequestType, maxParticipantsReached, translate]);
/**
* Adds a single participant to the request
@@ -213,48 +236,17 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
[participants, onParticipantsAdded],
);
- const headerMessage = OptionsListUtils.getHeaderMessage(
- newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0,
- Boolean(newChatOptions.userToInvite),
- searchTerm.trim(),
- maxParticipantsReached,
- _.some(participants, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())),
+ const headerMessage = useMemo(
+ () =>
+ OptionsListUtils.getHeaderMessage(
+ newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0,
+ Boolean(newChatOptions.userToInvite),
+ searchTerm.trim(),
+ maxParticipantsReached,
+ _.some(participants, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())),
+ ),
+ [maxParticipantsReached, newChatOptions.personalDetails.length, newChatOptions.recentReports.length, newChatOptions.userToInvite, participants, searchTerm],
);
- const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails);
-
- useEffect(() => {
- const chatOptions = OptionsListUtils.getFilteredOptions(
- reports,
- personalDetails,
- betas,
- searchTerm,
- participants,
- CONST.EXPENSIFY_EMAILS,
-
- // If we are using this component in the "Request money" flow then we pass the includeOwnedWorkspaceChats argument so that the current user
- // sees the option to request money from their admin on their own Workspace Chat.
- iouType === CONST.IOU.TYPE.REQUEST,
-
- // We don't want to include any P2P options like personal details or reports that are not workspace chats for certain features.
- iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE,
- false,
- {},
- [],
- false,
- {},
- [],
-
- // We don't want the user to be able to invite individuals when they are in the "Distance request" flow for now.
- // This functionality is being built here: https://github.com/Expensify/App/issues/23291
- iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE,
- true,
- );
- setNewChatOptions({
- recentReports: chatOptions.recentReports,
- personalDetails: chatOptions.personalDetails,
- userToInvite: chatOptions.userToInvite,
- });
- }, [betas, reports, participants, personalDetails, translate, searchTerm, setNewChatOptions, iouType, iouRequestType]);
// When search term updates we will fetch any reports
const setSearchTermAndSearchInServer = useCallback((text = '') => {
@@ -270,6 +262,7 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
const hasPolicyExpenseChatParticipant = _.some(participants, (participant) => participant.isPolicyExpenseChat);
const shouldShowSplitBillErrorMessage = participants.length > 1 && hasPolicyExpenseChatParticipant;
const isAllowedToSplit = iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE;
+ const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST;
const handleConfirmSelection = useCallback(() => {
if (shouldShowSplitBillErrorMessage) {
@@ -281,6 +274,32 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({
const footerContent = (
+
+ {
+ Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(referralContentType));
+ }}
+ style={[styles.p5, styles.w100, styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10}]}
+ accessibilityLabel="referral"
+ role={CONST.ACCESSIBILITY_ROLE.BUTTON}
+ >
+
+ {translate(`referralProgram.${referralContentType}.buttonText1`)}
+
+ {translate(`referralProgram.${referralContentType}.buttonText2`)}
+
+
+
+
+
+
{shouldShowSplitBillErrorMessage && (
)}
-
+
+ {!!participants.length && (
+
+ )}
);
+ const itemRightSideComponent = useCallback(
+ (item) => {
+ if (!isAllowedToSplit) {
+ return null;
+ }
+ if (item.isSelected) {
+ return (
+ addParticipantToSelection(item)}
+ disabled={item.isDisabled}
+ role={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
+ accessibilityLabel={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
+ style={[styles.flexRow, styles.alignItemsCenter, styles.ml3]}
+ >
+
+
+ );
+ }
+
+ return (
+