diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 3ace2ebeb436..dabf7a9f8d36 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -1,4 +1,4 @@ -import {useRoute} from '@react-navigation/native'; +import {useIsFocused, useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; @@ -149,6 +149,18 @@ function ReportActionsList({ const route = useRoute(); const opacity = useSharedValue(0); const userActiveSince = useRef(null); + const lastMessageTime = useRef(null); + + const [isVisible, setIsVisible] = useState(false); + const isFocused = useIsFocused(); + + useEffect(() => { + const unsubscriber = Visibility.onVisibilityChange(() => { + setIsVisible(Visibility.isVisible()); + }); + + return unsubscriber; + }, []); const markerInit = () => { if (!cacheUnreadMarkers.has(report.reportID)) { @@ -393,7 +405,7 @@ function ReportActionsList({ [currentUnreadMarker, sortedVisibleReportActions, report.reportID, messageManuallyMarkedUnread], ); - useEffect(() => { + const calculateUnreadMarker = useCallback(() => { // Iterate through the report actions and set appropriate unread marker. // This is to avoid a warning of: // Cannot update a component (ReportActionsList) while rendering a different component (CellRenderer). @@ -411,7 +423,56 @@ function ReportActionsList({ if (!markerFound) { setCurrentUnreadMarker(null); } - }, [sortedVisibleReportActions, report.lastReadTime, report.reportID, messageManuallyMarkedUnread, shouldDisplayNewMarker, currentUnreadMarker]); + }, [sortedVisibleReportActions, report.reportID, shouldDisplayNewMarker, currentUnreadMarker]); + + useEffect(() => { + calculateUnreadMarker(); + }, [calculateUnreadMarker, report.lastReadTime, messageManuallyMarkedUnread]); + + useEffect(() => { + if (!userActiveSince.current || report.reportID !== prevReportID) { + return; + } + + if (!isVisible || !isFocused) { + if (!lastMessageTime.current) { + lastMessageTime.current = lodashGet(sortedVisibleReportActions, '[0].created', ''); + } + return; + } + + // In case the user read new messages (after being inactive) with other device we should + // show marker based on report.lastReadTime + const newMessageTimeReference = lastMessageTime.current > report.lastReadTime ? userActiveSince.current : report.lastReadTime; + lastMessageTime.current = null; + if ( + scrollingVerticalOffset.current >= MSG_VISIBLE_THRESHOLD || + !( + sortedVisibleReportActions && + _.some( + sortedVisibleReportActions, + (reportAction) => + newMessageTimeReference < reportAction.created && + (ReportActionsUtils.isReportPreviewAction(reportAction) ? reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID(), + ) + ) + ) { + return; + } + + Report.readNewestAction(report.reportID); + userActiveSince.current = DateUtils.getDBTime(); + lastReadTimeRef.current = newMessageTimeReference; + setCurrentUnreadMarker(null); + cacheUnreadMarkers.delete(report.reportID); + calculateUnreadMarker(); + + // This effect logic to `mark as read` will only run when the report focused has new messages and the App visibility + // is changed to visible(meaning user switched to app/web, while user was previously using different tab or application). + // We will mark the report as read in the above case which marks the LHN report item as read while showing the new message + // marker for the chat messages received while the user wasn't focused on the report or on another browser tab for web. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isFocused, isVisible]); const renderItem = useCallback( ({item: reportAction, index}) => ( diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js index c760b81b2373..1555f2032275 100644 --- a/tests/perf-test/ReportActionsList.perf-test.js +++ b/tests/perf-test/ReportActionsList.perf-test.js @@ -40,6 +40,7 @@ jest.mock('@react-navigation/native', () => { return { ...actualNav, useRoute: () => mockedNavigate, + useIsFocused: () => true, }; });