diff --git a/src/components/OptionsSelector.js b/src/components/OptionsSelector.js old mode 100755 new mode 100644 index d03519c43de1..651992c16032 --- a/src/components/OptionsSelector.js +++ b/src/components/OptionsSelector.js @@ -13,6 +13,12 @@ const propTypes = { /** Callback to fire when a row is tapped */ onSelectRow: PropTypes.func, + /** Function to get a filtered result as list */ + searchSections: PropTypes.func, + + /** Function to get header message from parent component */ + getCustomHeaderMessage: PropTypes.func, + /** Sections for the section list */ sections: PropTypes.arrayOf(PropTypes.shape({ /** Title of the section */ @@ -28,21 +34,12 @@ const propTypes = { shouldShow: PropTypes.bool, })).isRequired, - /** Value in the search input field */ - value: PropTypes.string.isRequired, - - /** Callback fired when text changes */ - onChangeText: PropTypes.func.isRequired, - /** Optional placeholder text for the selector */ placeholderText: PropTypes.string, /** Options that have already been selected */ selectedOptions: PropTypes.arrayOf(optionPropTypes), - /** Optional header message */ - headerMessage: PropTypes.string, - /** Whether we can select multiple options */ canSelectMultipleOptions: PropTypes.bool, @@ -69,9 +66,10 @@ const propTypes = { const defaultProps = { onSelectRow: () => {}, + searchSections: () => {}, + getCustomHeaderMessage: () => {}, placeholderText: '', selectedOptions: [], - headerMessage: '', canSelectMultipleOptions: false, hideSectionHeaders: false, disableArrowKeysActions: false, @@ -86,11 +84,14 @@ class OptionsSelector extends Component { super(props); this.handleKeyPress = this.handleKeyPress.bind(this); + this.onChangeText = this.onChangeText.bind(this); this.selectRow = this.selectRow.bind(this); this.viewableItems = []; + this.searchValue = ''; this.state = { focusedIndex: 0, + sections: props.sections, }; } @@ -98,6 +99,17 @@ class OptionsSelector extends Component { this.textInput.focus(); } + /** + * Updates sections filtered by searchValue + * + * @param {String} searchValue + */ + onChangeText(searchValue) { + const sections = this.props.searchSections(searchValue); + this.searchValue = searchValue; + this.setState({sections}); + } + /** * Scrolls to the focused index within the SectionList * @@ -195,9 +207,8 @@ class OptionsSelector extends Component { styleFocusIn={[styles.textInputReversedFocus]} ref={el => this.textInput = el} style={[styles.textInput]} - value={this.props.value} - onChangeText={this.props.onChangeText} onKeyPress={this.handleKeyPress} + onChangeText={this.onChangeText} placeholder={this.props.placeholderText || this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} placeholderTextColor={themeColors.placeholderText} @@ -207,12 +218,12 @@ class OptionsSelector extends Component { ref={el => this.list = el} optionHoveredStyle={styles.hoveredComponentBG} onSelectRow={this.selectRow} - sections={this.props.sections} + sections={this.state.sections} focusedIndex={this.state.focusedIndex} selectedOptions={this.props.selectedOptions} canSelectMultipleOptions={this.props.canSelectMultipleOptions} hideSectionHeaders={this.props.hideSectionHeaders} - headerMessage={this.props.headerMessage} + headerMessage={this.props.getCustomHeaderMessage(this.searchValue)} disableFocusOptions={this.props.disableArrowKeysActions} hideAdditionalOptionStates={this.props.hideAdditionalOptionStates} forceTextUnreadStyle={this.props.forceTextUnreadStyle} diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js old mode 100755 new mode 100644 index 564e0181679c..6b224722de81 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -1,4 +1,3 @@ -import _ from 'underscore'; import React, {Component} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; @@ -65,34 +64,35 @@ class SearchPage extends Component { Timing.start(CONST.TIMING.SEARCH_RENDER); this.selectReport = this.selectReport.bind(this); - this.onChangeText = this.onChangeText.bind(this); - this.debouncedUpdateOptions = _.debounce(this.updateOptions.bind(this), 300); + this.searchSections = this.searchSections.bind(this); + this.getCustomHeaderMessage = this.getCustomHeaderMessage.bind(this); + } + componentDidMount() { + Timing.end(CONST.TIMING.SEARCH_RENDER); + } + + /** + * Returns header message given searchValue + * @param {String} searchValue + * @returns {String} header messae + */ + getCustomHeaderMessage(searchValue = '') { const { recentReports, personalDetails, userToInvite, } = getSearchOptions( - props.reports, - props.personalDetails, + this.props.reports, + this.props.personalDetails, '', - props.betas, + this.props.betas, + ); + return getHeaderMessage( + (recentReports.length + personalDetails.length) !== 0, + Boolean(userToInvite), + searchValue, ); - - this.state = { - searchValue: '', - recentReports, - personalDetails, - userToInvite, - }; - } - - componentDidMount() { - Timing.end(CONST.TIMING.SEARCH_RENDER); - } - - onChangeText(searchValue = '') { - this.setState({searchValue}, this.debouncedUpdateOptions); } /** @@ -101,17 +101,37 @@ class SearchPage extends Component { * @returns {Array} */ getSections() { + // getSections is same to searchSections given empty searchValue + return this.searchSections(); + } + + /** + * Returns the sections needed for the OptionsSelector + * @param {String} searchValue + * @returns {Array} + */ + searchSections(searchValue = '') { + const { + recentReports, + personalDetails, + userToInvite, + } = getSearchOptions( + this.props.reports, + this.props.personalDetails, + searchValue, + this.props.betas, + ); const sections = [{ title: this.props.translate('common.recents'), - data: this.state.recentReports.concat(this.state.personalDetails), + data: recentReports.concat(personalDetails), shouldShow: true, indexOffset: 0, }]; - if (this.state.userToInvite) { + if (userToInvite) { sections.push(({ undefined, - data: [this.state.userToInvite], + data: [userToInvite], shouldShow: true, indexOffset: 0, })); @@ -120,24 +140,6 @@ class SearchPage extends Component { return sections; } - updateOptions() { - const { - recentReports, - personalDetails, - userToInvite, - } = getSearchOptions( - this.props.reports, - this.props.personalDetails, - this.state.searchValue, - this.props.betas, - ); - this.setState({ - userToInvite, - recentReports, - personalDetails, - }); - } - /** * Reset the search value and redirect to the selected report * @@ -149,11 +151,7 @@ class SearchPage extends Component { } if (option.reportID) { - this.setState({ - searchValue: '', - }, () => { - Navigation.navigate(ROUTES.getReportRoute(option.reportID)); - }); + Navigation.navigate(ROUTES.getReportRoute(option.reportID)); } else { fetchOrCreateChatReport([ this.props.session.email, @@ -164,36 +162,32 @@ class SearchPage extends Component { render() { const sections = this.getSections(); - const headerMessage = getHeaderMessage( - (this.state.recentReports.length + this.state.personalDetails.length) !== 0, - Boolean(this.state.userToInvite), - this.state.searchValue, - ); return ( {({didScreenTransitionEnd}) => ( - <> - Navigation.dismissModal(true)} - /> - - - {didScreenTransitionEnd && ( - + Navigation.dismissModal(true)} /> - )} - - - + + + {didScreenTransitionEnd && ( + + )} + + + + ) )} );