diff --git a/src/libs/UnreadIndicatorUpdater/index.ts b/src/libs/UnreadIndicatorUpdater/index.ts index 11472ce3e385..2a7019686308 100644 --- a/src/libs/UnreadIndicatorUpdater/index.ts +++ b/src/libs/UnreadIndicatorUpdater/index.ts @@ -2,31 +2,40 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as ReportUtils from '@libs/ReportUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; import updateUnread from './updateUnread'; let allReports: OnyxCollection = {}; +export default function getUnreadReportsForUnreadIndicator(reports: OnyxCollection, currentReportID: string) { + return Object.values(reports ?? {}).filter( + (report) => + ReportUtils.isUnread(report) && + ReportUtils.shouldReportBeInOptionList({ + report, + currentReportId: currentReportID ?? '', + betas: [], + policies: {}, + doesReportHaveViolations: false, + isInGSDMode: false, + excludeEmptyChats: false, + }) && + /** + * Chats with hidden preference remain invisible in the LHN and are not considered "unread." + * They are excluded from the LHN rendering, but not filtered from the "option list." + * This ensures they appear in Search, but not in the LHN or unread count. + */ + report?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ); +} + const triggerUnreadUpdate = () => { - const currentReportID = navigationRef.isReady() ? Navigation.getTopmostReportId() : ''; + const currentReportID = navigationRef.isReady() ? Navigation.getTopmostReportId() ?? '' : ''; // We want to keep notification count consistent with what can be accessed from the LHN list - const unreadReports = Object.values(allReports ?? {}).filter((report) => { - if (!ReportUtils.isUnread(report)) { - return false; - } - - return ReportUtils.shouldReportBeInOptionList({ - report, - currentReportId: currentReportID ?? '', - betas: [], - policies: {}, - doesReportHaveViolations: false, - isInGSDMode: false, - excludeEmptyChats: false, - }); - }); + const unreadReports = getUnreadReportsForUnreadIndicator(allReports, currentReportID); updateUnread(unreadReports.length); }; diff --git a/tests/unit/UnreadIndicatorUpdaterTest.ts b/tests/unit/UnreadIndicatorUpdaterTest.ts new file mode 100644 index 000000000000..a5f58b57793a --- /dev/null +++ b/tests/unit/UnreadIndicatorUpdaterTest.ts @@ -0,0 +1,41 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import CONST from '../../src/CONST'; +import getUnreadReportsForUnreadIndicator from '../../src/libs/UnreadIndicatorUpdater'; + +describe('UnreadIndicatorUpdaterTest', () => { + describe('should return correct number of unread reports', () => { + it('given last read time < last visible action created', () => { + const reportsToBeUsed = { + 1: {reportID: '1', reportName: 'test', type: CONST.REPORT.TYPE.EXPENSE, lastReadTime: '2023-07-08 07:15:44.030', lastVisibleActionCreated: '2023-08-08 07:15:44.030'}, + 2: {reportID: '2', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastReadTime: '2023-02-05 09:12:05.000', lastVisibleActionCreated: '2023-02-06 07:15:44.030'}, + 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK}, + }; + expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(2); + }); + + it('given some reports are incomplete', () => { + const reportsToBeUsed = { + 1: {reportID: '1', type: CONST.REPORT.TYPE.EXPENSE, lastReadTime: '2023-07-08 07:15:44.030', lastVisibleActionCreated: '2023-08-08 07:15:44.030'}, + 2: {reportID: '2', type: CONST.REPORT.TYPE.TASK, lastReadTime: '2023-02-05 09:12:05.000', lastVisibleActionCreated: '2023-02-06 07:15:44.030'}, + 3: {reportID: '3', type: CONST.REPORT.TYPE.TASK}, + }; + expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(0); + }); + + it('given notification preference of some reports is hidden', () => { + const reportsToBeUsed = { + 1: { + reportID: '1', + reportName: 'test', + type: CONST.REPORT.TYPE.EXPENSE, + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + lastReadTime: '2023-07-08 07:15:44.030', + lastVisibleActionCreated: '2023-08-08 07:15:44.030', + }, + 2: {reportID: '2', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastReadTime: '2023-02-05 09:12:05.000', lastVisibleActionCreated: '2023-02-06 07:15:44.030'}, + 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK}, + }; + expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(1); + }); + }); +});