diff --git a/src/DeepLinkHandler.tsx b/src/DeepLinkHandler.tsx index 3f23afdefabe..270589b63bf3 100644 --- a/src/DeepLinkHandler.tsx +++ b/src/DeepLinkHandler.tsx @@ -36,7 +36,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { const [allReports, allReportsMetadata] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [isLoadingApp = true] = useOnyx(ONYXKEYS.IS_LOADING_APP); - const [, sessionMetadata] = useOnyx(ONYXKEYS.SESSION); + const [session, sessionMetadata] = useOnyx(ONYXKEYS.SESSION); const [conciergeReportID, conciergeReportIDMetadata] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const [introSelected, introSelectedMetadata] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [isSelfTourViewed, isSelfTourViewedMetadata] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); @@ -184,8 +184,13 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) { return; } hasRefetchedPublicRoom.current = true; - Report.openReport({reportID, introSelected, betas}); - }, [isLoadingApp, allReports, introSelected, betas]); + Report.openReport({ + reportID, + introSelected, + betas, + currentUserAccountID: session?.accountID, + }); + }, [isLoadingApp, allReports, introSelected, betas, session?.accountID]); return null; } diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx index 1c9778815139..0e05b2d98b41 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx @@ -622,7 +622,13 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) setIsFloatingMessageCounterVisible(false); if (!hasNewestReportAction) { - openReport({reportID, introSelected, betas, hasReportActions: true}); + openReport({ + reportID, + introSelected, + betas, + hasReportActions: true, + currentUserAccountID, + }); reportScrollManager.scrollToEnd(); return; } @@ -630,7 +636,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps) reportScrollManager.scrollToEnd(); readActionSkipped.current = false; readNewestAction(reportID, true); - }, [setIsFloatingMessageCounterVisible, hasNewestReportAction, reportScrollManager, reportID, introSelected, betas]); + }, [setIsFloatingMessageCounterVisible, hasNewestReportAction, reportScrollManager, reportID, introSelected, betas, currentUserAccountID]); const scrollToNewTransaction = useCallback( (pageY: number) => { diff --git a/src/components/TestDrive/TestDriveDemo.tsx b/src/components/TestDrive/TestDriveDemo.tsx index cb7dd2908d8f..1da647771a80 100644 --- a/src/components/TestDrive/TestDriveDemo.tsx +++ b/src/components/TestDrive/TestDriveDemo.tsx @@ -68,7 +68,13 @@ function TestDriveDemo() { setSelfTourViewed(); if (conciergeReportID && !hasCalledOpenReportRef.current) { hasCalledOpenReportRef.current = true; - openReport({reportID: conciergeReportID, introSelected, betas, hasReportActions: hasConciergeReportActions}); + openReport({ + reportID: conciergeReportID, + introSelected, + betas, + hasReportActions: hasConciergeReportActions, + currentUserAccountID: currentUserPersonalDetails.accountID, + }); } return; } diff --git a/src/hooks/useReportActionsScroll.ts b/src/hooks/useReportActionsScroll.ts index a18676a267d6..7d2a1cab5767 100644 --- a/src/hooks/useReportActionsScroll.ts +++ b/src/hooks/useReportActionsScroll.ts @@ -29,6 +29,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useRoute} from '@react-navigation/native'; import {useEffect, useEffectEvent, useState} from 'react'; +import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; import useNetworkWithOfflineStatus from './useNetworkWithOfflineStatus'; import useOnyx from './useOnyx'; import usePrevious from './usePrevious'; @@ -164,6 +165,7 @@ function useReportActionsScroll({ const {isOffline} = useNetworkWithOfflineStatus(); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); const [betas] = useOnyx(ONYXKEYS.BETAS); + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); const [reportLoadingState] = useOnyx(`${ONYXKEYS.COLLECTION.RAM_ONLY_REPORT_LOADING_STATE}${reportID}`); const [reportActionPages] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_PAGES}${getNonEmptyStringOnyxID(reportID)}`); const prevIsLoadingInitialReportActions = usePrevious(reportLoadingState?.isLoadingInitialReportActions); @@ -347,7 +349,7 @@ function useReportActionsScroll({ if (!Navigation.getReportRHPActiveRoute()) { Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID, undefined, undefined, backTo)); } - openReport({reportID, introSelected, betas, hasReportActions: true}); + openReport({reportID, introSelected, betas, hasReportActions: true, currentUserAccountID}); reportScrollManager.scrollToBottom(); return; } diff --git a/src/libs/Navigation/AppNavigator/AuthScreensInitHandler.tsx b/src/libs/Navigation/AppNavigator/AuthScreensInitHandler.tsx index 7f4a1179f96f..8a6662aef34c 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreensInitHandler.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreensInitHandler.tsx @@ -170,7 +170,7 @@ function AuthScreensInitHandler() { } else if (SessionUtils.didUserLogInDuringSession()) { const reportID = getReportIDFromLink(initialURL ?? null); if (reportID && !isAuthenticatedAtStartup) { - Report.openReport({reportID, introSelected, betas, hasReportActions: false}); + Report.openReport({reportID, introSelected, betas, hasReportActions: false, currentUserAccountID: session?.accountID}); // Don't want to call `openReport` again when logging out and then logging in setIsAuthenticatedAtStartup(true); } diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index 3ae815e31bd9..13be9e3c4ae3 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -2382,6 +2382,7 @@ function navigateToAndOpenReport( newReportObject: fallbackChat, isSelfTourViewed, betas, + currentUserAccountID, }); navigateToReport(fallbackChat.reportID, {shouldDismissModal, ...linkToOptions}); @@ -2418,7 +2419,7 @@ function navigateToAndOpenReport( }); // Re-open existing chats to re-validate server-side access and refresh stale local state. - openReport({reportID: chat.reportID, introSelected, isSelfTourViewed, betas}); + openReport({reportID: chat.reportID, introSelected, isSelfTourViewed, betas, currentUserAccountID}); navigateToReport(chat.reportID, {shouldDismissModal, ...linkToOptions}); } @@ -2515,6 +2516,7 @@ function navigateToAndOpenReportWithAccountIDs( participants, personalDetails, betas, + currentUserAccountID, }); navigateToReport(fallbackChat.reportID, {shouldDismissModal: false}); @@ -2551,7 +2553,7 @@ function navigateToAndOpenReportWithAccountIDs( }); // Re-open existing chats to re-validate server-side access and refresh stale local state. - openReport({reportID: chat.reportID, introSelected, isSelfTourViewed, hasCompletedGuidedSetupFlow, betas}); + openReport({reportID: chat.reportID, introSelected, isSelfTourViewed, hasCompletedGuidedSetupFlow, betas, currentUserAccountID}); navigateToReport(chat.reportID, {shouldDismissModal: false}); } @@ -2641,6 +2643,7 @@ function createChildReport( isNewThread: true, betas, isSelfTourViewed, + currentUserAccountID, }); } else { Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${childReportID}`, newChat); @@ -3576,7 +3579,7 @@ function toggleSubscribeToChildReport( personalDetails: OnyxEntry, ) { if (childReportID) { - openReport({reportID: childReportID, introSelected, betas, isSelfTourViewed, hasCompletedGuidedSetupFlow}); + openReport({reportID: childReportID, introSelected, betas, isSelfTourViewed, hasCompletedGuidedSetupFlow, currentUserAccountID}); const parentReportActionID = parentReportAction.reportActionID; if (!prevNotificationPreference || isHiddenForCurrentUser(prevNotificationPreference)) { updateNotificationPreference( @@ -3623,6 +3626,7 @@ function toggleSubscribeToChildReport( isSelfTourViewed, hasCompletedGuidedSetupFlow, betas, + currentUserAccountID, }); const notificationPreference = isHiddenForCurrentUser(prevNotificationPreference) ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; updateNotificationPreference(newChat.reportID, prevNotificationPreference, notificationPreference, currentUserAccountID, parentReport?.reportID, parentReportAction.reportActionID); diff --git a/src/pages/inbox/ReportFetchHandler.tsx b/src/pages/inbox/ReportFetchHandler.tsx index 1c0763cb29f1..9a458989a0ef 100644 --- a/src/pages/inbox/ReportFetchHandler.tsx +++ b/src/pages/inbox/ReportFetchHandler.tsx @@ -178,7 +178,7 @@ function ReportFetchHandler() { return; } - openReport({reportID: reportIDFromRoute, introSelected, reportActionID: reportActionIDFromRoute, betas, hasReportActions}); + openReport({reportID: reportIDFromRoute, introSelected, reportActionID: reportActionIDFromRoute, betas, hasReportActions, currentUserAccountID}); }); const createOneTransactionThread = useEffectEvent(() => { @@ -210,7 +210,7 @@ function ReportFetchHandler() { if (!shouldUseNarrowLayout || !isChatThread(report) || !isHiddenForCurrentUser(report) || isTransactionThreadView) { return; } - openReport({reportID, introSelected, betas, hasReportActions}); + openReport({reportID, introSelected, betas, hasReportActions, currentUserAccountID}); }); const joinPublicRoomIfNeeded = useEffectEvent(() => { @@ -218,7 +218,7 @@ function ReportFetchHandler() { if (!viewingPublicRoomReportID || viewingPublicRoomReportID === reportIDFromRoute) { return; } - openReport({reportID: viewingPublicRoomReportID, introSelected, betas, hasReportActions: hasViewingPublicRoomReportActions}); + openReport({reportID: viewingPublicRoomReportID, introSelected, betas, hasReportActions: hasViewingPublicRoomReportActions, currentUserAccountID}); }); // Effect order below matches the original declaration order in ReportScreen.tsx. diff --git a/src/pages/inbox/report/useReportActionsNewActionLiveTail.ts b/src/pages/inbox/report/useReportActionsNewActionLiveTail.ts index f9a6674b0d17..b43a18e04122 100644 --- a/src/pages/inbox/report/useReportActionsNewActionLiveTail.ts +++ b/src/pages/inbox/report/useReportActionsNewActionLiveTail.ts @@ -1,3 +1,4 @@ +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import type useReportScrollManager from '@hooks/useReportScrollManager'; import type {OpenReportActionParams} from '@libs/actions/Report'; @@ -75,6 +76,7 @@ function useReportActionsNewActionLiveTail({ prevIsLoadingInitialReportActions, reportLoadingState, }: UseReportActionsNewActionLiveTailParams) { + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); const liveTailJumpRef = useRef<{stage: LiveTailJumpStage}>({stage: 'idle'}); const [isScrollToBottomEnabled, setIsScrollToBottomEnabled] = useState(false); @@ -107,6 +109,7 @@ function useReportActionsNewActionLiveTail({ introSelected, betas, hasReportActions: true, + currentUserAccountID, }); } return; diff --git a/src/pages/inbox/report/withReportAndReportActionOrNotFound.tsx b/src/pages/inbox/report/withReportAndReportActionOrNotFound.tsx index 7cb8592cade2..c98d67c263aa 100644 --- a/src/pages/inbox/report/withReportAndReportActionOrNotFound.tsx +++ b/src/pages/inbox/report/withReportAndReportActionOrNotFound.tsx @@ -1,5 +1,6 @@ import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useOnyx from '@hooks/useOnyx'; import useParentReportAction from '@hooks/useParentReportAction'; import useReportIsArchived from '@hooks/useReportIsArchived'; @@ -55,6 +56,7 @@ function WithReportOrNotFoundImpl = reportActions?.[`${props.route.params.reportActionID}`]; @@ -72,9 +74,14 @@ function WithReportOrNotFoundImpl { const actual = ReportActionsUtils.shouldReportActionBeVisible(reportAction, reportAction.reportActionID, true); expect(actual).toBe(true); }); + + it('should return false for a whisper targeted to another user when currentUserAccountID is provided', () => { + const OTHER_USER_ACCOUNT_ID = 999; + const CURRENT_USER_ACCOUNT_ID = 123; + const reportAction = { + actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, + reportActionID: '1', + created: '2025-09-29', + message: [{html: 'secret', type: 'COMMENT', text: 'secret', whisperedTo: [OTHER_USER_ACCOUNT_ID]}], + originalMessage: {html: 'secret', whisperedTo: [OTHER_USER_ACCOUNT_ID]}, + } as ReportAction; + + const actual = ReportActionsUtils.shouldReportActionBeVisible(reportAction, reportAction.reportActionID, true, CURRENT_USER_ACCOUNT_ID); + expect(actual).toBe(false); + }); + + it('should return true for a whisper targeted to the current user when currentUserAccountID is provided', () => { + const CURRENT_USER_ACCOUNT_ID = 123; + const reportAction = { + actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT, + reportActionID: '1', + created: '2025-09-29', + message: [{html: 'secret', type: 'COMMENT', text: 'secret', whisperedTo: [CURRENT_USER_ACCOUNT_ID]}], + originalMessage: {html: 'secret', whisperedTo: [CURRENT_USER_ACCOUNT_ID]}, + } as ReportAction; + + const actual = ReportActionsUtils.shouldReportActionBeVisible(reportAction, reportAction.reportActionID, true, CURRENT_USER_ACCOUNT_ID); + expect(actual).toBe(true); + }); }); describe('getPolicyChangeLogUpdateEmployee', () => {