From f8661e7ebb9cb5afc56440af2bc87ccd5d3fb7dd Mon Sep 17 00:00:00 2001 From: oleh Date: Tue, 6 Jun 2023 16:20:40 +0300 Subject: [PATCH 01/12] Migrate MoneyRequestParticipantsSplitSelector.js to function component --- .../MoneyRequestParticipantsSplitSelector.js | 218 ++++++++---------- 1 file changed, 100 insertions(+), 118 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 28bdc2365622..134f35ff2682 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -59,37 +59,32 @@ const defaultProps = { safeAreaPaddingBottomStyle: {}, }; -class MoneyRequestParticipantsSplitSelector extends Component { - constructor(props) { - super(props); - - this.toggleOption = this.toggleOption.bind(this); - this.finalizeParticipants = this.finalizeParticipants.bind(this); - this.updateOptionsWithSearchTerm = this.updateOptionsWithSearchTerm.bind(this); +function MoneyRequestParticipantsSplitSelector(props) { + const [searchTerm, setSearchTerm] = useState(''); + const [newChatOptions, setNewChatOptions] = useState({ + recentReports: [], + personalDetails: [], + userToInvite: null, + }); + function updateOptionsWithSearchTerm (newSearchTerm = '') { const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( props.reports, props.personalDetails, props.betas, - '', + newSearchTerm, props.participants, CONST.EXPENSIFY_EMAILS, ); - - this.state = { - searchTerm: '', + setSearchTerm(newSearchTerm); + setNewChatOptions({ recentReports, personalDetails, - userToInvite, - }; + userToInvite + }); } - componentDidUpdate(prevProps) { - if (_.isEqual(prevProps.reports, this.props.reports) && _.isEqual(prevProps.personalDetails, this.props.personalDetails)) { - return; - } - this.updateOptionsWithSearchTerm(this.state.searchTerm); - } + const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; /** * Returns the sections needed for the OptionsSelector @@ -97,145 +92,132 @@ class MoneyRequestParticipantsSplitSelector extends Component { * @param {Boolean} maxParticipantsReached * @returns {Array} */ - getSections(maxParticipantsReached) { - const sections = []; + const sections = useMemo(() => { + const newSections = []; let indexOffset = 0; - sections.push({ + newSections.push({ title: undefined, - data: this.props.participants, + data: props.participants, shouldShow: true, indexOffset, }); - indexOffset += this.props.participants.length; + indexOffset += props.participants.length; if (maxParticipantsReached) { - return sections; + return newSections; } - sections.push({ - title: this.props.translate('common.recents'), - data: this.state.recentReports, - shouldShow: !_.isEmpty(this.state.recentReports), + const { + recentReports, + personalDetails, + userToInvite + } = newChatOptions; + + newSections.push({ + title: props.translate('common.recents'), + data: recentReports, + shouldShow: !_.isEmpty(recentReports), indexOffset, }); - indexOffset += this.state.recentReports.length; + indexOffset += recentReports.length; - sections.push({ - title: this.props.translate('common.contacts'), - data: this.state.personalDetails, - shouldShow: !_.isEmpty(this.state.personalDetails), + newSections.push({ + title: props.translate('common.contacts'), + data: personalDetails, + shouldShow: !_.isEmpty(personalDetails), indexOffset, }); - indexOffset += this.state.personalDetails.length; + indexOffset += personalDetails.length; - if (this.state.userToInvite && !OptionsListUtils.isCurrentUser(this.state.userToInvite)) { - sections.push({ + if (userToInvite && !OptionsListUtils.isCurrentUser(userToInvite)) { + newSections.push({ undefined, - data: [this.state.userToInvite], + data: [userToInvite], 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.participants, - CONST.EXPENSIFY_EMAILS, - ); - this.setState({ - searchTerm, - userToInvite, - recentReports, - personalDetails, - }); - } - - /** - * Once a single or more users are selected, navigates to next step - */ - finalizeParticipants() { - this.props.onStepComplete(); - } + return newSections; + }, [props.translate, props.participants, newChatOptions, maxParticipantsReached]) /** * Removes a selected option from list if already selected. If not already selected add this option to the list. * @param {Object} option */ - toggleOption(option) { - const isOptionInList = _.some(this.props.participants, (selectedOption) => selectedOption.login === option.login); + function toggleOption(option) { + const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.login === option.login); let newSelectedOptions; if (isOptionInList) { - newSelectedOptions = _.reject(this.props.participants, (selectedOption) => selectedOption.login === option.login); + newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.login === option.login); } else { - newSelectedOptions = [...this.props.participants, option]; + newSelectedOptions = [...props.participants, option]; } - this.props.onAddParticipants(newSelectedOptions); - - this.setState((prevState) => { - const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( - this.props.reports, - this.props.personalDetails, - this.props.betas, - isOptionInList ? prevState.searchTerm : '', - newSelectedOptions, - CONST.EXPENSIFY_EMAILS, - ); - return { - recentReports, - personalDetails, - userToInvite, - searchTerm: isOptionInList ? prevState.searchTerm : '', - }; + const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( + props.reports, + props.personalDetails, + props.betas, + isOptionInList ? searchTerm : '', + newSelectedOptions, + CONST.EXPENSIFY_EMAILS, + ); + + setNewChatOptions({ + recentReports, + personalDetails, + userToInvite }); + props.onAddParticipants(newSelectedOptions) } - render() { - const maxParticipantsReached = this.props.participants.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 ( - 0 ? this.props.safeAreaPaddingBottomStyle : {}]}> - - - ); + /** + * Once a single or more users are selected, navigates to next step + */ + function finalizeParticipants() { + props.onStepComplete(); } -} + + const headerMessage = OptionsListUtils.getHeaderMessage( + newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0, + Boolean(newChatOptions.userToInvite), + searchTerm, + maxParticipantsReached, + ); + const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(props.personalDetails); + + useEffect(() => { + updateOptionsWithSearchTerm(searchTerm); + }, [props.reports, props.personalDetails, searchTerm]) + + return ( + 0 ? props.safeAreaPaddingBottomStyle : {}]}> + + + ); +}; MoneyRequestParticipantsSplitSelector.propTypes = propTypes; MoneyRequestParticipantsSplitSelector.defaultProps = defaultProps; +MoneyRequestParticipantsSplitSelector.displayName = 'MoneyRequestParticipantsSplitSelector'; export default compose( withLocalize, From 8ecd4fbb6de90d4a67ce775b46e3bb7d27f99f8f Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 7 Jun 2023 00:01:13 +0300 Subject: [PATCH 02/12] Fixed lint issues --- ios/Podfile.lock | 6 +-- .../MoneyRequestParticipantsSplitSelector.js | 48 +++++++++---------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6cb4235c58c8..c6c8ee0b4dce 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1019,7 +1019,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: c70eed50e429f97f5adb285423c7291fb7a032ae AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - boost: a7c83b31436843459a1961bfd74b96033dc77234 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1062,7 +1062,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1135,4 +1135,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.12.0 +COCOAPODS: 1.11.3 diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 134f35ff2682..ad4925e5893d 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo, useState} from 'react'; +import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -67,32 +67,13 @@ function MoneyRequestParticipantsSplitSelector(props) { userToInvite: null, }); - function updateOptionsWithSearchTerm (newSearchTerm = '') { - const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( - props.reports, - props.personalDetails, - props.betas, - newSearchTerm, - props.participants, - CONST.EXPENSIFY_EMAILS, - ); - setSearchTerm(newSearchTerm); - setNewChatOptions({ - recentReports, - personalDetails, - userToInvite - }); - } - - const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; - /** * Returns the sections needed for the OptionsSelector * * @param {Boolean} maxParticipantsReached * @returns {Array} */ - const sections = useMemo(() => { + const getSections = (maxParticipantsReached) => { const newSections = []; let indexOffset = 0; @@ -140,13 +121,13 @@ function MoneyRequestParticipantsSplitSelector(props) { } return newSections; - }, [props.translate, props.participants, newChatOptions, maxParticipantsReached]) + } /** * Removes a selected option from list if already selected. If not already selected add this option to the list. * @param {Object} option */ - function toggleOption(option) { + const toggleOption = (option) => { const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.login === option.login); let newSelectedOptions; @@ -177,10 +158,11 @@ function MoneyRequestParticipantsSplitSelector(props) { /** * Once a single or more users are selected, navigates to next step */ - function finalizeParticipants() { + const finalizeParticipants = () => { props.onStepComplete(); } + const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; const headerMessage = OptionsListUtils.getHeaderMessage( newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0, Boolean(newChatOptions.userToInvite), @@ -189,9 +171,23 @@ function MoneyRequestParticipantsSplitSelector(props) { ); const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(props.personalDetails); + const sections = getSections(maxParticipantsReached); + useEffect(() => { - updateOptionsWithSearchTerm(searchTerm); - }, [props.reports, props.personalDetails, searchTerm]) + const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( + props.reports, + props.personalDetails, + props.betas, + searchTerm, + props.participants, + CONST.EXPENSIFY_EMAILS, + ); + setNewChatOptions({ + recentReports, + personalDetails, + userToInvite + }); + }, [props.betas, props.reports, props.participants, props.personalDetails, searchTerm]) return ( 0 ? props.safeAreaPaddingBottomStyle : {}]}> From 0b66de41bff8c8b06acd1c00e769e2726cbb18a0 Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 7 Jun 2023 00:12:00 +0300 Subject: [PATCH 03/12] Revert podfile.lock --- ios/Podfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c6c8ee0b4dce..0ba0e5d249ee 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1019,7 +1019,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: c70eed50e429f97f5adb285423c7291fb7a032ae AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - boost: 57d2868c099736d80fcd648bf211b4431e51a558 + boost: a7c83b31436843459a1961bfd74b96033dc77234 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1062,7 +1062,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1135,4 +1135,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 \ No newline at end of file From e10cd886530beb97a88b2ee7780d83ca417bdfca Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 7 Jun 2023 00:14:07 +0300 Subject: [PATCH 04/12] Fix --- ios/Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0ba0e5d249ee..6cb4235c58c8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1135,4 +1135,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.12.0 \ No newline at end of file +COCOAPODS: 1.12.0 From 35b3f79d09f34518bee78388e7aad2121fdd0926 Mon Sep 17 00:00:00 2001 From: oleh Date: Fri, 9 Jun 2023 17:42:43 +0300 Subject: [PATCH 05/12] added translate per reviewer request --- .../MoneyRequestParticipantsSplitSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index ad4925e5893d..575b374fa75c 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -187,7 +187,7 @@ function MoneyRequestParticipantsSplitSelector(props) { personalDetails, userToInvite }); - }, [props.betas, props.reports, props.participants, props.personalDetails, searchTerm]) + }, [props.betas, props.reports, props.participants, props.personalDetails, props.translate, searchTerm]) return ( 0 ? props.safeAreaPaddingBottomStyle : {}]}> From 4c375f918095f454fcec1a2486377eb4cb2ad1de Mon Sep 17 00:00:00 2001 From: oleh Date: Mon, 12 Jun 2023 17:57:28 +0300 Subject: [PATCH 06/12] fixed lint issues --- .../MoneyRequestParticipantsSplitSelector.js | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 575b374fa75c..9c77ef68b0e2 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -89,11 +89,7 @@ function MoneyRequestParticipantsSplitSelector(props) { return newSections; } - const { - recentReports, - personalDetails, - userToInvite - } = newChatOptions; + const {recentReports, personalDetails, userToInvite} = newChatOptions; newSections.push({ title: props.translate('common.recents'), @@ -121,7 +117,7 @@ function MoneyRequestParticipantsSplitSelector(props) { } return newSections; - } + }; /** * Removes a selected option from list if already selected. If not already selected add this option to the list. @@ -150,17 +146,17 @@ function MoneyRequestParticipantsSplitSelector(props) { setNewChatOptions({ recentReports, personalDetails, - userToInvite + userToInvite, }); - props.onAddParticipants(newSelectedOptions) - } + props.onAddParticipants(newSelectedOptions); + }; /** * Once a single or more users are selected, navigates to next step */ const finalizeParticipants = () => { props.onStepComplete(); - } + }; const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; const headerMessage = OptionsListUtils.getHeaderMessage( @@ -185,9 +181,9 @@ function MoneyRequestParticipantsSplitSelector(props) { setNewChatOptions({ recentReports, personalDetails, - userToInvite + userToInvite, }); - }, [props.betas, props.reports, props.participants, props.personalDetails, props.translate, searchTerm]) + }, [props.betas, props.reports, props.participants, props.personalDetails, props.translate, searchTerm]); return ( 0 ? props.safeAreaPaddingBottomStyle : {}]}> @@ -209,7 +205,7 @@ function MoneyRequestParticipantsSplitSelector(props) { /> ); -}; +} MoneyRequestParticipantsSplitSelector.propTypes = propTypes; MoneyRequestParticipantsSplitSelector.defaultProps = defaultProps; From 041d78227ec5164f8aeeb8423358857c1b1ff04d Mon Sep 17 00:00:00 2001 From: oleh Date: Thu, 15 Jun 2023 20:04:01 +0300 Subject: [PATCH 07/12] fixed conflicts from main branch --- .../MoneyRequestParticipantsSplitSelector.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 9c77ef68b0e2..6f01444b1f04 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -29,6 +29,7 @@ const propTypes = { participants: PropTypes.arrayOf( PropTypes.shape({ login: PropTypes.string.isRequired, + accountID: PropTypes.number.isRequired, alternateText: PropTypes.string, hasDraftComment: PropTypes.bool, icons: PropTypes.arrayOf(avatarPropTypes), @@ -124,12 +125,12 @@ function MoneyRequestParticipantsSplitSelector(props) { * @param {Object} option */ const toggleOption = (option) => { - const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.login === option.login); + const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); let newSelectedOptions; if (isOptionInList) { - newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.login === option.login); + newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); } else { newSelectedOptions = [...props.participants, option]; } @@ -215,7 +216,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, reports: { key: ONYXKEYS.COLLECTION.REPORT, From 4dd5f0a66e81cbe66d7a5f420f17c45b102bc7e7 Mon Sep 17 00:00:00 2001 From: oleh Date: Tue, 20 Jun 2023 17:58:01 +0300 Subject: [PATCH 08/12] restore function orders per reviewer's request --- .../MoneyRequestParticipantsSplitSelector.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 6f01444b1f04..fd32e2737574 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -134,6 +134,8 @@ function MoneyRequestParticipantsSplitSelector(props) { } else { newSelectedOptions = [...props.participants, option]; } + + props.onAddParticipants(newSelectedOptions); const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( props.reports, @@ -149,14 +151,6 @@ function MoneyRequestParticipantsSplitSelector(props) { personalDetails, userToInvite, }); - props.onAddParticipants(newSelectedOptions); - }; - - /** - * Once a single or more users are selected, navigates to next step - */ - const finalizeParticipants = () => { - props.onStepComplete(); }; const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; @@ -199,7 +193,7 @@ function MoneyRequestParticipantsSplitSelector(props) { boldStyle shouldShowConfirmButton confirmButtonText={props.translate('common.next')} - onConfirmSelection={finalizeParticipants} + onConfirmSelection={props.onStepComplete()} textInputLabel={props.translate('optionsSelector.nameEmailOrPhoneNumber')} safeAreaPaddingBottomStyle={props.safeAreaPaddingBottomStyle} shouldShowOptions={isOptionsDataReady} From ffd6fadc1592092fd8c0db6ee3b2e0d968f291af Mon Sep 17 00:00:00 2001 From: oleh Date: Tue, 20 Jun 2023 18:18:21 +0300 Subject: [PATCH 09/12] fixed prettier issue --- .../MoneyRequestParticipantsSplitSelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index fd32e2737574..cb61d59a903c 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -134,7 +134,7 @@ function MoneyRequestParticipantsSplitSelector(props) { } else { newSelectedOptions = [...props.participants, option]; } - + props.onAddParticipants(newSelectedOptions); const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( From 82be71e43a1bb8a0c83732b74b7f2f3505bad0aa Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 21 Jun 2023 01:29:09 +0300 Subject: [PATCH 10/12] Updated per reviewer's requests --- .../MoneyRequestParticipantsSplitSelector.js | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index cb61d59a903c..14fca3dfdfcd 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -1,4 +1,4 @@ -import React, {useEffect, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -68,13 +68,15 @@ function MoneyRequestParticipantsSplitSelector(props) { userToInvite: null, }); + const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; + /** * Returns the sections needed for the OptionsSelector * * @param {Boolean} maxParticipantsReached * @returns {Array} */ - const getSections = (maxParticipantsReached) => { + const sections = useMemo(() => { const newSections = []; let indexOffset = 0; @@ -118,42 +120,47 @@ function MoneyRequestParticipantsSplitSelector(props) { } return newSections; - }; + }, [maxParticipantsReached, newChatOptions, props.participants, props.translate]); /** * Removes a selected option from list if already selected. If not already selected add this option to the list. * @param {Object} option */ - const toggleOption = (option) => { - const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); - - let newSelectedOptions; - - if (isOptionInList) { - newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); - } else { - newSelectedOptions = [...props.participants, option]; - } - - props.onAddParticipants(newSelectedOptions); - - const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( - props.reports, - props.personalDetails, - props.betas, - isOptionInList ? searchTerm : '', - newSelectedOptions, - CONST.EXPENSIFY_EMAILS, - ); - - setNewChatOptions({ - recentReports, - personalDetails, - userToInvite, - }); - }; + const toggleOption = useCallback( + (option) => { + const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); + + let newSelectedOptions; + + if (isOptionInList) { + newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); + } else { + newSelectedOptions = [...props.participants, option]; + } + + props.onAddParticipants(newSelectedOptions); + + const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( + props.reports, + props.personalDetails, + props.betas, + isOptionInList ? searchTerm : '', + newSelectedOptions, + CONST.EXPENSIFY_EMAILS, + ); + + setNewChatOptions({ + recentReports, + personalDetails, + userToInvite, + }); + if (!isOptionInList) { + setSearchTerm(''); + } + }, + [searchTerm, props.participants, props.onAddParticipants, props.reports, props.personalDetails, props.betas, setNewChatOptions, setSearchTerm], + ); - const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; const headerMessage = OptionsListUtils.getHeaderMessage( newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0, Boolean(newChatOptions.userToInvite), @@ -162,8 +169,6 @@ function MoneyRequestParticipantsSplitSelector(props) { ); const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(props.personalDetails); - const sections = getSections(maxParticipantsReached); - useEffect(() => { const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( props.reports, @@ -193,7 +198,7 @@ function MoneyRequestParticipantsSplitSelector(props) { boldStyle shouldShowConfirmButton confirmButtonText={props.translate('common.next')} - onConfirmSelection={props.onStepComplete()} + onConfirmSelection={props.onStepComplete} textInputLabel={props.translate('optionsSelector.nameEmailOrPhoneNumber')} safeAreaPaddingBottomStyle={props.safeAreaPaddingBottomStyle} shouldShowOptions={isOptionsDataReady} From a1e5ba1bf07c08ac00be7741a6b8c8554cc39cb6 Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 21 Jun 2023 02:13:14 +0300 Subject: [PATCH 11/12] fixed lint issue --- .../MoneyRequestParticipantsSplitSelector.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 14fca3dfdfcd..b1a68cb13c7f 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -120,6 +120,7 @@ function MoneyRequestParticipantsSplitSelector(props) { } return newSections; + // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist }, [maxParticipantsReached, newChatOptions, props.participants, props.translate]); /** @@ -158,6 +159,7 @@ function MoneyRequestParticipantsSplitSelector(props) { setSearchTerm(''); } }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist [searchTerm, props.participants, props.onAddParticipants, props.reports, props.personalDetails, props.betas, setNewChatOptions, setSearchTerm], ); From b70b37ed60f7dbc3479fdbe0121d5c6f5a68c32a Mon Sep 17 00:00:00 2001 From: oleh Date: Sun, 25 Jun 2023 22:26:34 +0300 Subject: [PATCH 12/12] Merge branch 'main' into 16280_refactor_MoneyRequestParticipantsSplitSelector --- .../MoneyRequestParticipantsSplitSelector.js | 90 ++++++++----------- 1 file changed, 36 insertions(+), 54 deletions(-) diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 7469c322f7d4..7aef507ac12d 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -55,7 +55,7 @@ const defaultProps = { safeAreaPaddingBottomStyle: {}, }; -function MoneyRequestParticipantsSplitSelector(props) { +function MoneyRequestParticipantsSplitSelector({betas, participants, personalDetails, reports, translate, onAddParticipants, onStepComplete, safeAreaPaddingBottomStyle}) { const [searchTerm, setSearchTerm] = useState(''); const [newChatOptions, setNewChatOptions] = useState({ recentReports: [], @@ -63,7 +63,7 @@ function MoneyRequestParticipantsSplitSelector(props) { userToInvite: null, }); - const maxParticipantsReached = props.participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; + const maxParticipantsReached = participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS; /** * Returns the sections needed for the OptionsSelector @@ -77,46 +77,43 @@ function MoneyRequestParticipantsSplitSelector(props) { newSections.push({ title: undefined, - data: OptionsListUtils.getParticipantsOptions(props.participants, props.personalDetails), + data: OptionsListUtils.getParticipantsOptions(participants, personalDetails), shouldShow: true, indexOffset, }); - indexOffset += props.participants.length; + indexOffset += participants.length; if (maxParticipantsReached) { return newSections; } - const {recentReports, personalDetails, userToInvite} = newChatOptions; - newSections.push({ - title: props.translate('common.recents'), - data: recentReports, - shouldShow: !_.isEmpty(recentReports), + title: translate('common.recents'), + data: newChatOptions.recentReports, + shouldShow: !_.isEmpty(newChatOptions.recentReports), indexOffset, }); - indexOffset += recentReports.length; + indexOffset += newChatOptions.recentReports.length; newSections.push({ - title: props.translate('common.contacts'), - data: personalDetails, - shouldShow: !_.isEmpty(personalDetails), + title: translate('common.contacts'), + data: newChatOptions.personalDetails, + shouldShow: !_.isEmpty(newChatOptions.personalDetails), indexOffset, }); - indexOffset += personalDetails.length; + indexOffset += newChatOptions.personalDetails.length; - if (userToInvite && !OptionsListUtils.isCurrentUser(userToInvite)) { + if (newChatOptions.userToInvite && !OptionsListUtils.isCurrentUser(newChatOptions.userToInvite)) { newSections.push({ undefined, - data: [userToInvite], + data: [newChatOptions.userToInvite], shouldShow: true, indexOffset, }); } return newSections; - // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist - }, [maxParticipantsReached, newChatOptions, props.participants, props.personalDetails, props.translate]); + }, [maxParticipantsReached, newChatOptions, participants, personalDetails, translate]); /** * Removes a selected option from list if already selected. If not already selected add this option to the list. @@ -124,38 +121,30 @@ function MoneyRequestParticipantsSplitSelector(props) { */ const toggleOption = useCallback( (option) => { - const isOptionInList = _.some(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); + const isOptionInList = _.some(participants, (selectedOption) => selectedOption.accountID === option.accountID); let newSelectedOptions; if (isOptionInList) { - newSelectedOptions = _.reject(props.participants, (selectedOption) => selectedOption.accountID === option.accountID); + newSelectedOptions = _.reject(participants, (selectedOption) => selectedOption.accountID === option.accountID); } else { - newSelectedOptions = [...props.participants, {accountID: option.accountID, login: option.login, selected: true}]; + newSelectedOptions = [...participants, {accountID: option.accountID, login: option.login, selected: true}]; } - props.onAddParticipants(newSelectedOptions); + onAddParticipants(newSelectedOptions); - const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( - props.reports, - props.personalDetails, - props.betas, - isOptionInList ? searchTerm : '', - newSelectedOptions, - CONST.EXPENSIFY_EMAILS, - ); + const chatOptions = OptionsListUtils.getNewChatOptions(reports, personalDetails, betas, isOptionInList ? searchTerm : '', newSelectedOptions, CONST.EXPENSIFY_EMAILS); setNewChatOptions({ - recentReports, - personalDetails, - userToInvite, + recentReports: chatOptions.recentReports, + personalDetails: chatOptions.personalDetails, + userToInvite: chatOptions.userToInvite, }); if (!isOptionInList) { setSearchTerm(''); } }, - // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist - [searchTerm, props.participants, props.onAddParticipants, props.reports, props.personalDetails, props.betas, setNewChatOptions, setSearchTerm], + [searchTerm, participants, onAddParticipants, reports, personalDetails, betas, setNewChatOptions, setSearchTerm], ); const headerMessage = OptionsListUtils.getHeaderMessage( @@ -164,40 +153,33 @@ function MoneyRequestParticipantsSplitSelector(props) { searchTerm, maxParticipantsReached, ); - const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(props.personalDetails); + const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails); useEffect(() => { - const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( - props.reports, - props.personalDetails, - props.betas, - searchTerm, - props.participants, - CONST.EXPENSIFY_EMAILS, - ); + const chatOptions = OptionsListUtils.getNewChatOptions(reports, personalDetails, betas, searchTerm, participants, CONST.EXPENSIFY_EMAILS); setNewChatOptions({ - recentReports, - personalDetails, - userToInvite, + recentReports: chatOptions.recentReports, + personalDetails: chatOptions.personalDetails, + userToInvite: chatOptions.userToInvite, }); - }, [props.betas, props.reports, props.participants, props.personalDetails, props.translate, searchTerm]); + }, [betas, reports, participants, personalDetails, translate, searchTerm, setNewChatOptions]); return ( - 0 ? props.safeAreaPaddingBottomStyle : {}]}> + 0 ? safeAreaPaddingBottomStyle : {}]}>