diff --git a/src/App.js b/src/App.js index af27b3a6f854..987795c6fa22 100644 --- a/src/App.js +++ b/src/App.js @@ -17,7 +17,7 @@ import SafeArea from './components/SafeArea'; import * as Environment from './libs/Environment/Environment'; import {WindowDimensionsProvider} from './components/withWindowDimensions'; import {KeyboardStateProvider} from './components/withKeyboardState'; -import {CurrentReportIdContextProvider} from './components/withCurrentReportId'; +import {CurrentReportIDContextProvider} from './components/withCurrentReportID'; // For easier debugging and development, when we are in web we expose Onyx to the window, so you can more easily set data into Onyx if (window && Environment.isDevelopment()) { @@ -46,7 +46,7 @@ function App() { HTMLEngineProvider, WindowDimensionsProvider, KeyboardStateProvider, - CurrentReportIdContextProvider, + CurrentReportIDContextProvider, PickerStateProvider, ]} > diff --git a/src/components/withCurrentReportID.js b/src/components/withCurrentReportID.js new file mode 100644 index 000000000000..48924e8ea609 --- /dev/null +++ b/src/components/withCurrentReportID.js @@ -0,0 +1,76 @@ +import React, {createContext, forwardRef, useCallback, useState, useMemo} from 'react'; +import PropTypes from 'prop-types'; + +import getComponentDisplayName from '../libs/getComponentDisplayName'; +import Navigation from '../libs/Navigation/Navigation'; + +const CurrentReportIDContext = createContext(null); + +const withCurrentReportIDPropTypes = { + /** Function to update the state */ + updateCurrentReportID: PropTypes.func.isRequired, + + /** The top most report id */ + currentReportID: PropTypes.string, +}; + +const withCurrentReportIDDefaultProps = { + currentReportID: '', +}; + +function CurrentReportIDContextProvider(props) { + const [currentReportID, setCurrentReportID] = useState(''); + + /** + * This function is used to update the currentReportID + * @param {Object} state root navigation state + */ + const updateCurrentReportID = useCallback( + (state) => { + setCurrentReportID(Navigation.getTopmostReportId(state)); + }, + [setCurrentReportID], + ); + + /** + * The context this component exposes to child components + * @returns {Object} currentReportID to share between central pane and LHN + */ + const contextValue = useMemo( + () => ({ + updateCurrentReportID, + currentReportID, + }), + [updateCurrentReportID, currentReportID], + ); + + return {props.children}; +} + +CurrentReportIDContextProvider.displayName = 'CurrentReportIDContextProvider'; +CurrentReportIDContextProvider.propTypes = { + /** Actual content wrapped by this component */ + children: PropTypes.node.isRequired, +}; + +export default function withCurrentReportID(WrappedComponent) { + const WithCurrentReportID = forwardRef((props, ref) => ( + + {(currentReportIDUtils) => ( + + )} + + )); + + WithCurrentReportID.displayName = `withCurrentReportID(${getComponentDisplayName(WrappedComponent)})`; + + return WithCurrentReportID; +} + +export {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps, CurrentReportIDContextProvider}; diff --git a/src/components/withCurrentReportId.js b/src/components/withCurrentReportId.js deleted file mode 100644 index 4611187ed404..000000000000 --- a/src/components/withCurrentReportId.js +++ /dev/null @@ -1,72 +0,0 @@ -import React, {createContext, forwardRef, useCallback, useState, useMemo} from 'react'; -import PropTypes from 'prop-types'; - -import getComponentDisplayName from '../libs/getComponentDisplayName'; -import Navigation from '../libs/Navigation/Navigation'; - -const CurrentReportIdContext = createContext(null); - -const withCurrentReportIdPropTypes = { - /** Function to update the state */ - updateCurrentReportId: PropTypes.func.isRequired, - - /** The top most report id */ - currentReportId: PropTypes.string, -}; - -function CurrentReportIdContextProvider(props) { - const [currentReportId, setCurrentReportId] = useState(''); - - /** - * This function is used to update the currentReportId - * @param {Object} state root navigation state - */ - const updateCurrentReportId = useCallback( - (state) => { - setCurrentReportId(Navigation.getTopmostReportId(state)); - }, - [setCurrentReportId], - ); - - /** - * The context this component exposes to child components - * @returns {Object} currentReportId to share between central pane and LHN - */ - const contextValue = useMemo( - () => ({ - updateCurrentReportId, - currentReportId, - }), - [updateCurrentReportId, currentReportId], - ); - - return {props.children}; -} - -CurrentReportIdContextProvider.displayName = 'CurrentReportIdContextProvider'; -CurrentReportIdContextProvider.propTypes = { - /** Actual content wrapped by this component */ - children: PropTypes.node.isRequired, -}; - -export default function withCurrentReportId(WrappedComponent) { - const WithCurrentReportId = forwardRef((props, ref) => ( - - {(currentReportIdUtils) => ( - - )} - - )); - - WithCurrentReportId.displayName = `withCurrentReportId(${getComponentDisplayName(WrappedComponent)})`; - - return WithCurrentReportId; -} - -export {withCurrentReportIdPropTypes, CurrentReportIdContextProvider}; diff --git a/src/libs/Navigation/NavigationRoot.js b/src/libs/Navigation/NavigationRoot.js index ee389e530d0f..cd2c74ad1863 100644 --- a/src/libs/Navigation/NavigationRoot.js +++ b/src/libs/Navigation/NavigationRoot.js @@ -8,7 +8,7 @@ import AppNavigator from './AppNavigator'; import themeColors from '../../styles/themes/default'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions'; import Log from '../Log'; -import withCurrentReportId, {withCurrentReportIdPropTypes} from '../../components/withCurrentReportId'; +import withCurrentReportID, {withCurrentReportIDPropTypes} from '../../components/withCurrentReportID'; import compose from '../compose'; // https://reactnavigation.org/docs/themes @@ -28,7 +28,7 @@ const propTypes = { /** Fired when react-navigation is ready */ onReady: PropTypes.func.isRequired, - ...withCurrentReportIdPropTypes, + ...withCurrentReportIDPropTypes, }; /** @@ -61,7 +61,7 @@ function NavigationRoot(props) { return; } navigationStateRef.current = state; - props.updateCurrentReportId(state); + props.updateCurrentReportID(state); parseAndLogRoute(state); }; @@ -85,4 +85,4 @@ function NavigationRoot(props) { NavigationRoot.displayName = 'NavigationRoot'; NavigationRoot.propTypes = propTypes; -export default compose(withWindowDimensions, withCurrentReportId)(NavigationRoot); +export default compose(withWindowDimensions, withCurrentReportID)(NavigationRoot); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3a03903b0cf8..84ad9585446a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1950,6 +1950,11 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, iouRep return false; } + // Hide thread reports that haven't been commented on + if (isThread(report) && !report.lastMessageText) { + return false; + } + return true; } diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index 77070f272bb6..59088e9aa8ad 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -28,7 +28,7 @@ import SidebarUtils from '../../../libs/SidebarUtils'; import reportPropTypes from '../../reportPropTypes'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import withNavigationFocus from '../../../components/withNavigationFocus'; -import withCurrentReportId, {withCurrentReportIdPropTypes} from '../../../components/withCurrentReportId'; +import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../../../components/withCurrentReportID'; import withNavigation, {withNavigationPropTypes} from '../../../components/withNavigation'; import Header from '../../../components/Header'; import defaultTheme from '../../../styles/themes/default'; @@ -87,8 +87,8 @@ const propTypes = { willAlertModalBecomeVisible: PropTypes.bool, }), + ...withCurrentReportIDPropTypes, ...withLocalizePropTypes, - ...withCurrentReportIdPropTypes, ...withNavigationPropTypes, }; @@ -101,6 +101,7 @@ const defaultProps = { }, priorityMode: CONST.PRIORITY_MODE.DEFAULT, modal: {}, + ...withCurrentReportIDDefaultProps, }; class SidebarLinks extends React.Component { @@ -180,8 +181,7 @@ class SidebarLinks extends React.Component { render() { const isLoading = _.isEmpty(this.props.personalDetails) || _.isEmpty(this.props.chatReports); - const optionListItems = SidebarUtils.getOrderedReportIDs(this.props.currentReportId); - + const optionListItems = SidebarUtils.getOrderedReportIDs(this.props.currentReportID); const skeletonPlaceholder = ; return ( @@ -245,7 +245,7 @@ class SidebarLinks extends React.Component { option.toString() === this.props.currentReportId)} + focusedIndex={_.findIndex(optionListItems, (option) => option.toString() === this.props.currentReportID)} onSelectRow={this.showReportPage} shouldDisableFocusOptions={this.props.isSmallScreenWidth} optionMode={this.props.priorityMode === CONST.PRIORITY_MODE.GSD ? CONST.OPTION_MODE.COMPACT : CONST.OPTION_MODE.DEFAULT} @@ -335,7 +335,7 @@ export default compose( withCurrentUserPersonalDetails, withNavigationFocus, withWindowDimensions, - withCurrentReportId, + withCurrentReportID, withNavigation, withOnyx({ // Note: It is very important that the keys subscribed to here are the same diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index a6dd710d9522..74ed87fb642c 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -165,9 +165,9 @@ function getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorksp } /** - * @param {String} [currentReportId] + * @param {String} [currentReportID] */ -function getDefaultRenderedSidebarLinks(currentReportId = '') { +function getDefaultRenderedSidebarLinks(currentReportID = '') { // An ErrorBoundary needs to be added to the rendering so that any errors that happen while the component // renders are logged to the console. Without an error boundary, Jest only reports the error like "The above error // occurred in your component", except, there is no "above error". It's just swallowed up by Jest somewhere. @@ -196,16 +196,16 @@ function getDefaultRenderedSidebarLinks(currentReportId = '') { // our app (App.js) is when the react application is wrapped in the context providers render( - + , ); } /** - * @param {String} [currentReportId] + * @param {String} [currentReportID] * @returns {JSX.Element} */ -function MockedSidebarLinks({currentReportId}) { +function MockedSidebarLinks({currentReportID}) { return ( ); } MockedSidebarLinks.propTypes = { - currentReportId: PropTypes.string, + currentReportID: PropTypes.string, }; MockedSidebarLinks.defaultProps = { - currentReportId: '', + currentReportID: '', }; export {fakePersonalDetails, getDefaultRenderedSidebarLinks, getAdvancedFakeReport, getFakeReport, getFakeReportAction, MockedSidebarLinks};