diff --git a/src/pages/DynamicReportDetailsPage.tsx b/src/pages/DynamicReportDetailsPage.tsx index be8239c32a55..a30fe3221af7 100644 --- a/src/pages/DynamicReportDetailsPage.tsx +++ b/src/pages/DynamicReportDetailsPage.tsx @@ -1,7 +1,7 @@ -import {StackActions} from '@react-navigation/native'; +import {StackActions, useFocusEffect} from '@react-navigation/native'; import {delegateEmailSelector} from '@selectors/Account'; import {validTransactionDraftIDsSelector} from '@selectors/TransactionDraft'; -import React, {useCallback, useEffect, useMemo} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; // eslint-disable-next-line no-restricted-imports import {InteractionManager, View} from 'react-native'; @@ -382,8 +382,12 @@ function DynamicReportDetailsPage({policy, report, route, reportMetadata, report const shouldShowLeaveButton = canLeaveChat(report, policy, currentUserPersonalDetails?.accountID, !!reportNameValuePairs?.private_isArchived); - // Only show the "Go to room" row when the Details page was opened from a screen other than the room report itself (e.g. the Workspace rooms list). - const isRoomCurrentlyOpen = isReportTopmostSplitNavigator() && Navigation.getTopmostReportId() === report?.reportID; + // Snapshot on focus whether the room is the screen behind the Details page, so the row doesn't flip while the page + // is closing after it's tapped, yet still reflects the correct screen on later visits. + const [isRoomCurrentlyOpen, setIsRoomCurrentlyOpen] = useState(() => isReportTopmostSplitNavigator() && Navigation.getTopmostReportId() === report?.reportID); + useFocusEffect(() => { + setIsRoomCurrentlyOpen(isReportTopmostSplitNavigator() && Navigation.getTopmostReportId() === report?.reportID); + }); const shouldShowGoToRoom = (isChatRoom || isPolicyExpenseChat) && !isRoomCurrentlyOpen; const shouldShowGoToWorkspace = shouldShowPolicy(policy, false, currentUserPersonalDetails?.email) && !policy?.isJoinRequestPending && !shouldShowGoToRoom; diff --git a/tests/ui/DynamicReportDetailsPageTest.tsx b/tests/ui/DynamicReportDetailsPageTest.tsx index 9666d7cf03f3..9158fbfd0591 100644 --- a/tests/ui/DynamicReportDetailsPageTest.tsx +++ b/tests/ui/DynamicReportDetailsPageTest.tsx @@ -3,7 +3,8 @@ import React from 'react'; import Onyx from 'react-native-onyx'; import {LocaleContextProvider} from '@components/LocaleContextProvider'; import OnyxListItemProvider from '@components/OnyxListItemProvider'; -import type Navigation from '@libs/Navigation/Navigation'; +import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator'; +import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types'; import DynamicReportDetailsPage from '@pages/DynamicReportDetailsPage'; @@ -24,11 +25,18 @@ jest.mock('@react-navigation/native', () => { return { ...actualNav, useIsFocused: jest.fn(), + useFocusEffect: jest.fn(), useRoute: jest.fn(), usePreventRemove: jest.fn(), }; }); +jest.mock('@libs/Navigation/helpers/isReportTopmostSplitNavigator'); +const mockIsReportTopmostSplitNavigator = jest.mocked(isReportTopmostSplitNavigator); + +const navigationMock = {} as PlatformStackScreenProps['navigation']; +const getRouteMock = (reportID: string) => ({params: {reportID}}) as PlatformStackScreenProps['route']; + describe('DynamicReportDetailsPage', () => { beforeAll(() => { Onyx.init({ @@ -77,12 +85,12 @@ describe('DynamicReportDetailsPage', () => { ['navigation']} + navigation={navigationMock} policy={undefined} report={trackExpenseReport} reportMetadata={undefined} reportLoadingState={undefined} - route={{params: {reportID: trackExpenseReportID}} as PlatformStackScreenProps['route']} + route={getRouteMock(trackExpenseReportID)} /> , @@ -112,12 +120,12 @@ describe('DynamicReportDetailsPage', () => { ['navigation']} + navigation={navigationMock} policy={undefined} report={movedTrackExpenseReport} reportMetadata={undefined} reportLoadingState={undefined} - route={{params: {reportID: trackExpenseReportID}} as PlatformStackScreenProps['route']} + route={getRouteMock(trackExpenseReportID)} /> , @@ -129,4 +137,57 @@ describe('DynamicReportDetailsPage', () => { // expect(screen.queryByText(categorizeText)).not.toBeVisible(); // expect(screen.queryByText(shareText)).not.toBeVisible(); }); + + describe('"Go to room" option visibility', () => { + const roomReportID = '10'; + const policyRoom: Report = createRandomReport(Number(roomReportID), CONST.REPORT.CHAT_TYPE.POLICY_ROOM); + + const renderDetailsPage = () => + render( + + + + + , + ); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('shows "Go to room" when the room is not the screen behind the Details page', async () => { + mockIsReportTopmostSplitNavigator.mockReturnValue(false); + jest.spyOn(Navigation, 'getTopmostReportId').mockReturnValue(undefined); + await act(async () => { + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${roomReportID}`, policyRoom); + }); + + renderDetailsPage(); + await waitForBatchedUpdatesWithAct(); + + expect(await screen.findByText(translateLocal('reportDetailsPage.goToRoom'))).toBeVisible(); + }); + + it('does not show "Go to room" when the Details page is on top of its own room', async () => { + mockIsReportTopmostSplitNavigator.mockReturnValue(true); + jest.spyOn(Navigation, 'getTopmostReportId').mockReturnValue(roomReportID); + await act(async () => { + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${roomReportID}`, policyRoom); + }); + + renderDetailsPage(); + await waitForBatchedUpdatesWithAct(); + + expect(screen.queryByText(translateLocal('reportDetailsPage.goToRoom'))).toBeNull(); + }); + }); });