diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js
index 76a817acc334..8927088c3f67 100755
--- a/src/pages/NewChatPage.js
+++ b/src/pages/NewChatPage.js
@@ -1,5 +1,5 @@
import _ from 'underscore';
-import React, {Component} from 'react';
+import React, {useState, useEffect, useMemo} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
@@ -44,80 +44,58 @@ const defaultProps = {
reports: {},
};
-class NewChatPage extends Component {
- constructor(props) {
- super(props);
-
- this.toggleOption = this.toggleOption.bind(this);
- this.createChat = this.createChat.bind(this);
- this.createGroup = this.createGroup.bind(this);
- this.updateOptionsWithSearchTerm = this.updateOptionsWithSearchTerm.bind(this);
- this.excludedGroupEmails = _.without(CONST.EXPENSIFY_EMAILS, CONST.EMAIL.CONCIERGE);
-
- const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions(
- props.reports,
- props.personalDetails,
- props.betas,
- '',
- [],
- this.props.isGroupChat ? this.excludedGroupEmails : [],
- );
- this.state = {
- searchTerm: '',
- recentReports,
- personalDetails,
- selectedOptions: [],
- userToInvite,
- };
- }
-
- componentDidUpdate(prevProps) {
- if (_.isEqual(prevProps.reports, this.props.reports) && _.isEqual(prevProps.personalDetails, this.props.personalDetails)) {
- return;
- }
- this.updateOptionsWithSearchTerm(this.state.searchTerm);
- }
-
- /**
- * Returns the sections needed for the OptionsSelector
- *
- * @param {Boolean} maxParticipantsReached
- * @returns {Array}
- */
- getSections(maxParticipantsReached) {
- const sections = [];
+const excludedGroupEmails = _.without(CONST.EXPENSIFY_EMAILS, CONST.EMAIL.CONCIERGE);
+
+function NewChatPage(props) {
+ const [searchTerm, setSearchTerm] = useState('');
+ const [filteredRecentReports, setFilteredRecentReports] = useState([]);
+ const [filteredPersonalDetails, setFilteredPersonalDetails] = useState([]);
+ const [filteredUserToInvite, setFilteredUserToInvite] = useState();
+ const [selectedOptions, setSelectedOptions] = useState([]);
+
+ const maxParticipantsReached = selectedOptions.length === CONST.REPORT.MAXIMUM_PARTICIPANTS;
+ const headerMessage = OptionsListUtils.getHeaderMessage(
+ filteredPersonalDetails.length + filteredRecentReports.length !== 0,
+ Boolean(filteredUserToInvite),
+ searchTerm,
+ maxParticipantsReached,
+ );
+ const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(props.personalDetails);
+
+ const sections = useMemo(() => {
+ const sectionsList = [];
let indexOffset = 0;
- if (this.props.isGroupChat) {
- sections.push({
+ if (props.isGroupChat) {
+ sectionsList.push({
title: undefined,
- data: this.state.selectedOptions,
- shouldShow: !_.isEmpty(this.state.selectedOptions),
+ data: selectedOptions,
+ shouldShow: !_.isEmpty(selectedOptions),
indexOffset,
});
- indexOffset += this.state.selectedOptions.length;
+ indexOffset += selectedOptions.length;
if (maxParticipantsReached) {
- return sections;
+ return sectionsList;
}
}
// Filtering out selected users from the search results
- const filterText = _.reduce(this.state.selectedOptions, (str, {login}) => `${str} ${login}`, '');
- const recentReportsWithoutSelected = _.filter(this.state.recentReports, ({login}) => !filterText.includes(login));
- const personalDetailsWithoutSelected = _.filter(this.state.personalDetails, ({login}) => !filterText.includes(login));
- const hasUnselectedUserToInvite = this.state.userToInvite && !filterText.includes(this.state.userToInvite.login);
+ const filterText = _.reduce(selectedOptions, (str, {login}) => `${str} ${login}`, '');
+ const recentReportsWithoutSelected = _.filter(filteredRecentReports, ({login}) => !filterText.includes(login));
+ const personalDetailsWithoutSelected = _.filter(filteredPersonalDetails, ({login}) => !filterText.includes(login));
+ const hasUnselectedUserToInvite = filteredUserToInvite && !filterText.includes(filteredUserToInvite.login);
- sections.push({
- title: this.props.translate('common.recents'),
+ sectionsList.push({
+ title: props.translate('common.recents'),
data: recentReportsWithoutSelected,
shouldShow: !_.isEmpty(recentReportsWithoutSelected),
indexOffset,
});
indexOffset += recentReportsWithoutSelected.length;
- sections.push({
- title: this.props.translate('common.contacts'),
+ sectionsList.push({
+ title: props.translate('common.contacts'),
data: personalDetailsWithoutSelected,
shouldShow: !_.isEmpty(personalDetailsWithoutSelected),
indexOffset,
@@ -125,67 +103,39 @@ class NewChatPage extends Component {
indexOffset += personalDetailsWithoutSelected.length;
if (hasUnselectedUserToInvite) {
- sections.push({
+ sectionsList.push({
title: undefined,
- data: [this.state.userToInvite],
+ data: [filteredUserToInvite],
shouldShow: true,
indexOffset,
});
}
- return sections;
- }
-
- updateOptionsWithSearchTerm(searchTerm = '') {
- const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions(
- this.props.reports,
- this.props.personalDetails,
- this.props.betas,
- searchTerm,
- [],
- this.props.isGroupChat ? this.excludedGroupEmails : [],
- );
- this.setState({
- searchTerm,
- userToInvite,
- recentReports,
- personalDetails,
- });
- }
+ return sectionsList;
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [filteredPersonalDetails, filteredRecentReports, filteredUserToInvite, maxParticipantsReached, props.isGroupChat, selectedOptions]);
/**
* Removes a selected option from list if already selected. If not already selected add this option to the list.
* @param {Object} option
*/
- toggleOption(option) {
- this.setState((prevState) => {
- const isOptionInList = _.some(prevState.selectedOptions, (selectedOption) => selectedOption.login === option.login);
+ function toggleOption(option) {
+ const isOptionInList = _.some(selectedOptions, (selectedOption) => selectedOption.login === option.login);
- let newSelectedOptions;
+ let newSelectedOptions;
- if (isOptionInList) {
- newSelectedOptions = _.reject(prevState.selectedOptions, (selectedOption) => selectedOption.login === option.login);
- } else {
- newSelectedOptions = [...prevState.selectedOptions, option];
- }
+ if (isOptionInList) {
+ newSelectedOptions = _.reject(selectedOptions, (selectedOption) => selectedOption.login === option.login);
+ } else {
+ newSelectedOptions = [...selectedOptions, option];
+ }
- const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions(
- this.props.reports,
- this.props.personalDetails,
- this.props.betas,
- prevState.searchTerm,
- [],
- this.excludedGroupEmails,
- );
+ const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions(props.reports, props.personalDetails, props.betas, searchTerm, [], excludedGroupEmails);
- return {
- selectedOptions: newSelectedOptions,
- recentReports,
- personalDetails,
- userToInvite,
- searchTerm: prevState.searchTerm,
- };
- });
+ setSelectedOptions(newSelectedOptions);
+ setFilteredRecentReports(recentReports);
+ setFilteredPersonalDetails(personalDetails);
+ setFilteredUserToInvite(userToInvite);
}
/**
@@ -194,7 +144,7 @@ class NewChatPage extends Component {
*
* @param {Object} option
*/
- createChat(option) {
+ function createChat(option) {
Report.navigateToAndOpenReport([option.login]);
}
@@ -202,65 +152,69 @@ class NewChatPage extends Component {
* Creates a new group chat with all the selected options and the current user,
* or navigates to the existing chat if one with those participants already exists.
*/
- createGroup() {
- if (!this.props.isGroupChat) {
+ const createGroup = () => {
+ if (!props.isGroupChat) {
return;
}
- const logins = _.pluck(this.state.selectedOptions, 'login');
+ const logins = _.pluck(selectedOptions, 'login');
if (logins.length < 1) {
return;
}
Report.navigateToAndOpenReport(logins);
- }
+ };
- render() {
- const maxParticipantsReached = this.state.selectedOptions.length === CONST.REPORT.MAXIMUM_PARTICIPANTS;
- const sections = this.getSections(maxParticipantsReached);
- const headerMessage = OptionsListUtils.getHeaderMessage(
- this.state.personalDetails.length + this.state.recentReports.length !== 0,
- Boolean(this.state.userToInvite),
- this.state.searchTerm,
- maxParticipantsReached,
- );
- const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(this.props.personalDetails);
-
- return (
-
- {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
- <>
-
-
- 0 ? safeAreaPaddingBottomStyle : {}]}>
- (this.props.isGroupChat ? this.toggleOption(option) : this.createChat(option))}
- onChangeText={this.updateOptionsWithSearchTerm}
- headerMessage={headerMessage}
- boldStyle
- shouldFocusOnSelectRow={this.props.isGroupChat && !Browser.isMobile()}
- shouldShowConfirmButton={this.props.isGroupChat}
- shouldShowOptions={didScreenTransitionEnd && isOptionsDataReady}
- confirmButtonText={this.props.translate('newChatPage.createGroup')}
- onConfirmSelection={this.createGroup}
- textInputLabel={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')}
- safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
- />
-
- >
- )}
-
+ useEffect(() => {
+ const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions(
+ props.reports,
+ props.personalDetails,
+ props.betas,
+ searchTerm,
+ [],
+ props.isGroupChat ? excludedGroupEmails : [],
);
- }
+ setFilteredRecentReports(recentReports);
+ setFilteredPersonalDetails(personalDetails);
+ setFilteredUserToInvite(userToInvite);
+ // props.betas and props.isGroupChat are not added as dependencies since they don't change during the component lifecycle
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [props.reports, props.personalDetails, searchTerm]);
+
+ return (
+
+ {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
+ <>
+
+ 0 ? safeAreaPaddingBottomStyle : {}]}>
+ (props.isGroupChat ? toggleOption(option) : createChat(option))}
+ onChangeText={setSearchTerm}
+ headerMessage={headerMessage}
+ boldStyle
+ shouldFocusOnSelectRow={props.isGroupChat && !Browser.isMobile()}
+ shouldShowConfirmButton={props.isGroupChat}
+ shouldShowOptions={didScreenTransitionEnd && isOptionsDataReady}
+ confirmButtonText={props.translate('newChatPage.createGroup')}
+ onConfirmSelection={createGroup}
+ textInputLabel={props.translate('optionsSelector.nameEmailOrPhoneNumber')}
+ safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
+ />
+
+ >
+ )}
+
+ );
}
NewChatPage.propTypes = propTypes;
NewChatPage.defaultProps = defaultProps;
+NewChatPage.displayName = 'NewChatPage';
export default compose(
withLocalize,