diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 67d4ebb57876..2ee29380ff80 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {useCallback, useEffect, useState, useMemo} from 'react'; +import React, {Component} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; @@ -9,15 +9,17 @@ import * as ReportUtils from '../libs/ReportUtils'; import ONYXKEYS from '../ONYXKEYS'; import styles from '../styles/styles'; import Navigation from '../libs/Navigation/Navigation'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions'; import * as Report from '../libs/actions/Report'; import HeaderWithBackButton from '../components/HeaderWithBackButton'; import ScreenWrapper from '../components/ScreenWrapper'; import Timing from '../libs/actions/Timing'; import CONST from '../CONST'; +import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; +import compose from '../libs/compose'; import personalDetailsPropType from './personalDetailsPropType'; import reportPropTypes from './reportPropTypes'; import Performance from '../libs/Performance'; -import useLocalize from '../hooks/useLocalize'; const propTypes = { /* Onyx Props */ @@ -30,6 +32,11 @@ const propTypes = { /** All reports shared with the user */ reports: PropTypes.objectOf(reportPropTypes), + + /** Window Dimensions Props */ + ...windowDimensionsPropTypes, + + ...withLocalizePropTypes, }; const defaultProps = { @@ -38,158 +45,172 @@ const defaultProps = { reports: {}, }; -function SearchPage({betas, personalDetails, reports}) { - // Data for initialization (runs only on the first render) - const { - recentReports: initialRecentReports, - personalDetails: initialPersonalDetails, - userToInvite: initialUserToInvite, - // Ignoring the rule because in this case we need the data only initially - // eslint-disable-next-line react-hooks/exhaustive-deps - } = useMemo(() => OptionsListUtils.getSearchOptions(reports, personalDetails, '', betas), []); - - const [searchValue, setSearchValue] = useState(''); - const [searchOptions, setSearchOptions] = useState({ - recentReports: initialRecentReports, - personalDetails: initialPersonalDetails, - userToInvite: initialUserToInvite, - }); - - const {translate} = useLocalize(); - - const updateOptions = useCallback(() => { - const { - recentReports: localRecentReports, - personalDetails: localPersonalDetails, - userToInvite: localUserToInvite, - } = OptionsListUtils.getSearchOptions(reports, personalDetails, searchValue.trim(), betas); - - setSearchOptions({ - recentReports: localRecentReports, - personalDetails: localPersonalDetails, - userToInvite: localUserToInvite, - }); - }, [reports, personalDetails, searchValue, betas]); - - const debouncedUpdateOptions = useMemo(() => _.debounce(updateOptions, 75), [updateOptions]); +class SearchPage extends Component { + constructor(props) { + super(props); - useEffect(() => { Timing.start(CONST.TIMING.SEARCH_RENDER); Performance.markStart(CONST.TIMING.SEARCH_RENDER); - }, []); - useEffect(() => { - debouncedUpdateOptions(); - }, [searchValue, debouncedUpdateOptions]); + this.searchRendered = this.searchRendered.bind(this); + this.selectReport = this.selectReport.bind(this); + this.onChangeText = this.onChangeText.bind(this); + this.debouncedUpdateOptions = _.debounce(this.updateOptions.bind(this), 75); + + const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getSearchOptions(props.reports, props.personalDetails, '', props.betas); + + this.state = { + searchValue: '', + recentReports, + personalDetails, + userToInvite, + }; + } + + componentDidUpdate(prevProps) { + if (_.isEqual(prevProps.reports, this.props.reports) && _.isEqual(prevProps.personalDetails, this.props.personalDetails)) { + return; + } + this.updateOptions(); + } + + onChangeText(searchValue = '') { + this.setState({searchValue}, this.debouncedUpdateOptions); + } /** * Returns the sections needed for the OptionsSelector * * @returns {Array} */ - const getSections = () => { + getSections() { const sections = []; let indexOffset = 0; - if (searchOptions.recentReports.length > 0) { + if (this.state.recentReports.length > 0) { sections.push({ - data: searchOptions.recentReports, + data: this.state.recentReports, shouldShow: true, indexOffset, }); - indexOffset += searchOptions.recentReports.length; + indexOffset += this.state.recentReports.length; } - if (searchOptions.personalDetails.length > 0) { + if (this.state.personalDetails.length > 0) { sections.push({ - data: searchOptions.personalDetails, + data: this.state.personalDetails, shouldShow: true, indexOffset, }); - indexOffset += searchOptions.recentReports.length; + indexOffset += this.state.recentReports.length; } - if (searchOptions.userToInvite) { + if (this.state.userToInvite) { sections.push({ - data: [searchOptions.userToInvite], + data: [this.state.userToInvite], shouldShow: true, indexOffset, }); } return sections; - }; + } - const searchRendered = () => { + searchRendered() { Timing.end(CONST.TIMING.SEARCH_RENDER); Performance.markEnd(CONST.TIMING.SEARCH_RENDER); - }; - - const onChangeText = (value = '') => { - setSearchValue(value); - }; + } + + updateOptions() { + const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getSearchOptions( + this.props.reports, + this.props.personalDetails, + this.state.searchValue.trim(), + this.props.betas, + ); + this.setState({ + userToInvite, + recentReports, + personalDetails, + }); + } /** * Reset the search value and redirect to the selected report * * @param {Object} option */ - const selectReport = (option) => { + selectReport(option) { if (!option) { return; } + if (option.reportID) { - setSearchValue(''); - Navigation.dismissModal(option.reportID); + this.setState( + { + searchValue: '', + }, + () => { + Navigation.dismissModal(option.reportID); + }, + ); } else { Report.navigateToAndOpenReport([option.login]); } - }; - - const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails); - const headerMessage = OptionsListUtils.getHeaderMessage( - searchOptions.recentReports.length + searchOptions.personalDetails.length !== 0, - Boolean(searchOptions.userToInvite), - searchValue, - ); - return ( - - {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( - <> - - - - - - )} - - ); + } + + render() { + const sections = this.getSections(); + const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(this.props.personalDetails); + const headerMessage = OptionsListUtils.getHeaderMessage( + this.state.recentReports.length + this.state.personalDetails.length !== 0, + Boolean(this.state.userToInvite), + this.state.searchValue, + ); + + return ( + + {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( + <> + + + + + + )} + + ); + } } SearchPage.propTypes = propTypes; SearchPage.defaultProps = defaultProps; -SearchPage.displayName = 'SearchPage'; -export default withOnyx({ - reports: { - key: ONYXKEYS.COLLECTION.REPORT, - }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - betas: { - key: ONYXKEYS.BETAS, - }, -})(SearchPage); + +export default compose( + withLocalize, + withWindowDimensions, + withOnyx({ + reports: { + key: ONYXKEYS.COLLECTION.REPORT, + }, + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(SearchPage);