From 513f681dc735a4a967f1f764ea5c63e85fdff9e0 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 25 Jul 2025 20:14:06 +0530 Subject: [PATCH 01/14] Remove call to getReportNameValuePairs() in method getIcons from ReportUtils.ts. Signed-off-by: krishna2323 --- src/components/AvatarWithDisplayName.tsx | 4 ++-- src/hooks/useReportAvatarDetails.ts | 10 +++++++--- src/libs/OptionsListUtils.ts | 2 +- src/libs/ReportUtils.ts | 9 ++------- src/libs/SearchUIUtils.ts | 1 + src/libs/SidebarUtils.ts | 11 ++++++++++- src/libs/actions/Task.ts | 1 + src/pages/ReportDetailsPage.tsx | 2 +- src/pages/home/HeaderView.tsx | 2 +- src/pages/home/report/ReportActionItemCreated.tsx | 4 +++- .../home/sidebar/FloatingActionButtonAndPopover.tsx | 9 +++++---- src/pages/workspace/WorkspaceInitialPage.tsx | 4 +++- 12 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 1833077975b1..07e25c95c03d 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -192,10 +192,10 @@ function AvatarWithDisplayName({ const subtitle = getChatRoomSubtitle(report, {isCreateExpenseFlow: true}); const parentNavigationSubtitleData = getParentNavigationSubtitle(report); const isMoneyRequestOrReport = isMoneyRequestReport(report) || isMoneyRequest(report) || isTrackExpenseReport(report) || isInvoiceReport(report); - const icons = getIcons(report, personalDetails, null, '', -1, policy, invoiceReceiverPolicy); + const isReportArchived = useReportIsArchived(report?.reportID); + const icons = getIcons(report, personalDetails, null, '', -1, policy, invoiceReceiverPolicy, isReportArchived); const ownerPersonalDetails = getPersonalDetailsForAccountIDs(report?.ownerAccountID ? [report.ownerAccountID] : [], personalDetails); const displayNamesWithTooltips = getDisplayNamesWithTooltips(Object.values(ownerPersonalDetails), false); - const isReportArchived = useReportIsArchived(report?.reportID); const shouldShowSubscriptAvatar = shouldReportShowSubscript(report, isReportArchived); const avatarBorderColor = avatarBorderColorProp ?? (isAnonymous ? theme.highlightBG : theme.componentBG); diff --git a/src/hooks/useReportAvatarDetails.ts b/src/hooks/useReportAvatarDetails.ts index 8ce24c1bc19e..eedf582ff447 100644 --- a/src/hooks/useReportAvatarDetails.ts +++ b/src/hooks/useReportAvatarDetails.ts @@ -23,6 +23,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Policy, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; import useOnyx from './useOnyx'; +import useReportIsArchived from './useReportIsArchived'; import useTransactionsAndViolationsForReport from './useTransactionsAndViolationsForReport'; type ReportAvatarDetails = { @@ -72,11 +73,11 @@ function getIconDetails({ reportPreviewSenderID, innerPolicies, policy, -}: AvatarDetailsProps & {reportPreviewSenderID: number | undefined}) { + isReportArchived = false, +}: AvatarDetailsProps & {reportPreviewSenderID: number | undefined; isReportArchived?: boolean}) { const delegatePersonalDetails = action?.delegateAccountID ? personalDetails?.[action?.delegateAccountID] : undefined; const actorAccountID = getReportActionActorAccountID(action, iouReport, report, delegatePersonalDetails); const accountID = reportPreviewSenderID ?? actorAccountID ?? CONST.DEFAULT_NUMBER_ID; - const activePolicies = policies ?? innerPolicies; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; @@ -177,7 +178,7 @@ function getIconDetails({ if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = getIcons(report, personalDetails, undefined, undefined, undefined, policy); + const reportIcons = getIcons(report, personalDetails, undefined, undefined, undefined, policy, undefined, isReportArchived); return reportIcons.at(avatarIconIndex) ?? defaultAvatar; } @@ -221,6 +222,7 @@ function useReportAvatarDetails({iouReport, report, action, ...rest}: AvatarDeta canBeMissing: true, selector: (actions) => Object.values(actions ?? {}).filter(isMoneyRequestAction), }); + const isReportArchived = useReportIsArchived(report?.reportID); const {transactions: reportTransactions} = useTransactionsAndViolationsForReport(action?.childReportID); const transactions = useMemo(() => getAllNonDeletedTransactions(reportTransactions, iouActions ?? []), [reportTransactions, iouActions]); @@ -243,6 +245,7 @@ function useReportAvatarDetails({iouReport, report, action, ...rest}: AvatarDeta report, iouReport, reportPreviewSenderID: undefined, + isReportArchived, }), }; } @@ -280,6 +283,7 @@ function useReportAvatarDetails({iouReport, report, action, ...rest}: AvatarDeta report, iouReport, reportPreviewSenderID, + isReportArchived, }), }; } diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 1185b3af520e..cdef2b0858ae 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1028,7 +1028,7 @@ function createOption(accountIDs: number[], personalDetails: OnyxInputOrEntry, invoiceReceiverPolicy?: OnyxInputOrEntry, + isReportArchived = false, ): Icon[] { if (isEmptyObject(report)) { return [ @@ -3270,15 +3271,9 @@ function getIcons( if (isDomainRoom(report)) { return getIconsForDomainRoom(report); } - const reportNameValuePairs = allReportNameValuePair?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]; // This will get removed as part of https://github.com/Expensify/App/issues/59961 // eslint-disable-next-line deprecation/deprecation - if ( - isAdminRoom(report) || - isAnnounceRoom(report) || - isChatRoom(report) || - (isArchivedNonExpenseReport(report, !!reportNameValuePairs?.private_isArchived) && !chatIncludesConcierge(report)) - ) { + if (isAdminRoom(report) || isAnnounceRoom(report) || isChatRoom(report) || (isArchivedNonExpenseReport(report, isReportArchived) && !chatIncludesConcierge(report))) { return getIconsForPolicyRoom(report, personalDetails, policy, invoiceReceiverPolicy); } if (isPolicyExpenseChat(report)) { diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index e2f35e400dd5..d578dbe1f9eb 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1050,6 +1050,7 @@ function getTaskSections(data: OnyxTypes.SearchResults['data']): TaskListItemTyp // eslint-disable-next-line deprecation/deprecation const policy = getPolicy(parentReport.policyID); const parentReportName = getReportName(parentReport, policy, undefined, undefined); + // No need to pass `isReportArchived`, archived tasks are not shown on reports page const icons = getIcons(parentReport, personalDetails, null, '', -1, policy); const parentReportIcon = icons?.at(0); diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 3fa05841c51a..b6d72c67985f 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -821,7 +821,16 @@ function getOptionData({ result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; - result.icons = getIcons(report, personalDetails, personalDetail?.avatar, personalDetail?.login, personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID, policy, invoiceReceiverPolicy); + result.icons = getIcons( + report, + personalDetails, + personalDetail?.avatar, + personalDetail?.login, + personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID, + policy, + invoiceReceiverPolicy, + !!result.private_isArchived, + ); result.displayNamesWithTooltips = displayNamesWithTooltips; if (status) { diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index f2809d2997fd..80bacabab6ab 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -1000,6 +1000,7 @@ function getShareDestination(reportID: string, reports: OnyxCollection getIcons(report, personalDetails, null, '', -1, policy), [report, personalDetails, policy]); + const icons = useMemo(() => getIcons(report, personalDetails, null, '', -1, policy, undefined, isReportArchived), [report, personalDetails, policy, isReportArchived]); const chatRoomSubtitleText = chatRoomSubtitle ? ( canSendInvoicePolicyUtils(allPolicies as OnyxCollection, session?.email), [allPolicies, session?.email]); - const isValidReport = !(isEmptyObject(quickActionReport) || isArchivedReport(reportNameValuePairs)); + const isArchivedReport = isArchivedReportUtil(reportNameValuePairs); + const isValidReport = !(isEmptyObject(quickActionReport) || isArchivedReport); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true}); const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { selector: hasSeenTourSelector, @@ -151,11 +152,11 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const quickActionAvatars = useMemo(() => { if (isValidReport) { - const avatars = getIcons(quickActionReport, personalDetails); + const avatars = getIcons(quickActionReport, personalDetails, null, undefined, undefined, undefined, undefined, isArchivedReport); return avatars.length <= 1 || isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== session?.accountID); } if (!isEmptyObject(policyChatForActivePolicy)) { - return getIcons(policyChatForActivePolicy, personalDetails); + return getIcons(policyChatForActivePolicy, personalDetails, null, undefined, undefined, undefined, undefined, isArchivedReport); } return []; // Policy is needed as a dependency in order to update the shortcut details when the workspace changes diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index a21eeeb405f8..45a2c9bd7ae5 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -36,6 +36,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import usePrevious from '@hooks/usePrevious'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSingleExecution from '@hooks/useSingleExecution'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -128,6 +129,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const currentUserPolicyExpenseChatReportID = getPolicyExpenseChat(accountID, policy?.id, allReports)?.reportID; const [currentUserPolicyExpenseChat] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${currentUserPolicyExpenseChatReportID}`, {canBeMissing: true}); + const isUserPolicyExpenseChatArchived = useReportIsArchived(currentUserPolicyExpenseChatReportID); const {reportPendingAction} = getReportOfflinePendingActionAndErrors(currentUserPolicyExpenseChat); const isPolicyExpenseChatEnabled = !!policy?.isPolicyExpenseChatEnabled; const prevPendingFields = usePrevious(policy?.pendingFields); @@ -495,7 +497,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(currentUserPolicyExpenseChat?.reportID))} shouldShowRightIcon wrapperStyle={[styles.br2, styles.pl2, styles.pr0, styles.pv3, styles.mt1, styles.alignItemsCenter]} From 13ad5922aec9dec8add827cdbc360f6008323d0d Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 25 Jul 2025 21:07:36 +0530 Subject: [PATCH 02/14] add test for archieved workspace report icon. Signed-off-by: krishna2323 --- tests/unit/ReportUtilsGetIconsTest.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/unit/ReportUtilsGetIconsTest.ts b/tests/unit/ReportUtilsGetIconsTest.ts index 05c35d317733..48bbaf6bdfaf 100644 --- a/tests/unit/ReportUtilsGetIconsTest.ts +++ b/tests/unit/ReportUtilsGetIconsTest.ts @@ -5,6 +5,7 @@ import { getIcons, isAdminRoom, isAnnounceRoom, + isArchivedNonExpenseReport, isChatReport, isChatRoom, isChatThread, @@ -144,6 +145,22 @@ describe('getIcons', () => { expect(icons.at(0)?.name).toBe('Email One'); }); + it('should return the correct icons for archieved non expesnse request/report', () => { + const report: Report = { + ...LHNTestUtils.getFakeReport([1], 0, true), + type: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + }; + const policy = LHNTestUtils.getFakePolicy('1'); + + // Verify report type conditions + expect(isArchivedNonExpenseReport(report, true)).toBe(true); + + const icons = getIcons(report, FAKE_PERSONAL_DETAILS, null, '', -1, policy, undefined, true); + expect(icons).toHaveLength(1); + expect(icons.at(0)?.name).toBe(policy.name); + expect(icons.at(0)?.type).toBe('workspace'); + }); + it('should return the correct icons for a chat thread', () => { const report: Report = { ...LHNTestUtils.getFakeReport([1], 0, true), From 6a8fb519b86abcb9efcedf1ef84693aab6efd4a5 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 25 Jul 2025 21:18:11 +0530 Subject: [PATCH 03/14] fix spell check. Signed-off-by: krishna2323 --- tests/unit/ReportUtilsGetIconsTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportUtilsGetIconsTest.ts b/tests/unit/ReportUtilsGetIconsTest.ts index 48bbaf6bdfaf..e558721c4bea 100644 --- a/tests/unit/ReportUtilsGetIconsTest.ts +++ b/tests/unit/ReportUtilsGetIconsTest.ts @@ -145,7 +145,7 @@ describe('getIcons', () => { expect(icons.at(0)?.name).toBe('Email One'); }); - it('should return the correct icons for archieved non expesnse request/report', () => { + it('should return the correct icons for archieved non expense request/report', () => { const report: Report = { ...LHNTestUtils.getFakeReport([1], 0, true), type: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, From 940e06e0152266025922f56a7d414adae5c23d45 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sat, 26 Jul 2025 00:23:28 +0530 Subject: [PATCH 04/14] fix spell check. Signed-off-by: krishna2323 --- tests/unit/ReportUtilsGetIconsTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportUtilsGetIconsTest.ts b/tests/unit/ReportUtilsGetIconsTest.ts index e558721c4bea..cb15a26c86b8 100644 --- a/tests/unit/ReportUtilsGetIconsTest.ts +++ b/tests/unit/ReportUtilsGetIconsTest.ts @@ -145,7 +145,7 @@ describe('getIcons', () => { expect(icons.at(0)?.name).toBe('Email One'); }); - it('should return the correct icons for archieved non expense request/report', () => { + it('should return the correct icons for archived non expense request/report', () => { const report: Report = { ...LHNTestUtils.getFakeReport([1], 0, true), type: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, From fd31912ba97641b3eb2c083f52158b95959164bf Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sat, 26 Jul 2025 23:17:24 +0530 Subject: [PATCH 05/14] use isArchivedReport for task parent report. Signed-off-by: krishna2323 --- src/libs/ReportUtils.ts | 27 ------------------- src/libs/SearchUIUtils.ts | 5 ++-- src/libs/actions/Task.ts | 1 - .../FloatingActionButtonAndPopover.tsx | 6 ++--- tests/unit/ReportUtilsTest.ts | 22 --------------- 5 files changed, 6 insertions(+), 55 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 79bc13779e8b..897c41c8e37c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3271,8 +3271,6 @@ function getIcons( if (isDomainRoom(report)) { return getIconsForDomainRoom(report); } - // This will get removed as part of https://github.com/Expensify/App/issues/59961 - // eslint-disable-next-line deprecation/deprecation if (isAdminRoom(report) || isAnnounceRoom(report) || isChatRoom(report) || (isArchivedNonExpenseReport(report, isReportArchived) && !chatIncludesConcierge(report))) { return getIconsForPolicyRoom(report, personalDetails, policy, invoiceReceiverPolicy); } @@ -9566,30 +9564,6 @@ function getOptimisticDataForParentReportAction(reportID: string | undefined, la }); } -function getQuickActionDetails( - quickActionReport: Report, - personalDetails: PersonalDetailsList | undefined, - policyChatForActivePolicy: Report | undefined, - reportNameValuePairs: ReportNameValuePairs, -): {quickActionAvatars: Icon[]; hideQABSubtitle: boolean} { - const isValidQuickActionReport = !(isEmptyObject(quickActionReport) || isArchivedReport(reportNameValuePairs)); - let hideQABSubtitle = false; - let quickActionAvatars: Icon[] = []; - if (isValidQuickActionReport) { - const avatars = getIcons(quickActionReport, personalDetails); - quickActionAvatars = avatars.length <= 1 || isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== currentUserAccountID); - } else { - hideQABSubtitle = true; - } - if (!isEmptyObject(policyChatForActivePolicy)) { - quickActionAvatars = getIcons(policyChatForActivePolicy, personalDetails); - } - return { - quickActionAvatars, - hideQABSubtitle, - }; -} - function canBeAutoReimbursed(report: OnyxInputOrEntry, policy: OnyxInputOrEntry | SearchPolicy): boolean { if (isEmptyObject(policy)) { return false; @@ -11274,7 +11248,6 @@ export { getInvoicePayerName, getInvoicesChatName, getPayeeName, - getQuickActionDetails, hasActionWithErrorsForTransaction, hasAutomatedExpensifyAccountIDs, hasExpensifyGuidesEmails, diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index d578dbe1f9eb..09bb236c1465 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1050,8 +1050,9 @@ function getTaskSections(data: OnyxTypes.SearchResults['data']): TaskListItemTyp // eslint-disable-next-line deprecation/deprecation const policy = getPolicy(parentReport.policyID); const parentReportName = getReportName(parentReport, policy, undefined, undefined); - // No need to pass `isReportArchived`, archived tasks are not shown on reports page - const icons = getIcons(parentReport, personalDetails, null, '', -1, policy); + const parentReportNameValuePairs = getReportNameValuePairsFromKey(data, parentReport); + const isParentReportArchived = isArchivedReport(parentReportNameValuePairs); + const icons = getIcons(parentReport, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); result.parentReportName = parentReportName; diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 80bacabab6ab..f2809d2997fd 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -1000,7 +1000,6 @@ function getShareDestination(reportID: string, reports: OnyxCollection ({email: onyxSession?.email, accountID: onyxSession?.accountID})}); const [quickAction] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, {canBeMissing: true}); const [quickActionReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`, {canBeMissing: true}); - const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID}`, {canBeMissing: true}); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: true}); const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true}); @@ -126,7 +126,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS, {canBeMissing: true}); const canSendInvoice = useMemo(() => canSendInvoicePolicyUtils(allPolicies as OnyxCollection, session?.email), [allPolicies, session?.email]); - const isArchivedReport = isArchivedReportUtil(reportNameValuePairs); + const isArchivedReport = useReportIsArchived(quickActionReport?.reportID); const isValidReport = !(isEmptyObject(quickActionReport) || isArchivedReport); const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {canBeMissing: true}); const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 837928f3458e..628a6bd2d711 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -44,7 +44,6 @@ import { getMostRecentlyVisitedReport, getParticipantsList, getPolicyExpenseChat, - getQuickActionDetails, getReasonAndReportActionThatRequiresAttention, getReportIDFromLink, getReportName, @@ -1884,27 +1883,6 @@ describe('ReportUtils', () => { }); }); - describe('getQuickActionDetails', () => { - it('if the report is archived, the quick action will hide the subtitle and avatar', () => { - // Create a fake archived report as quick action report - const archivedReport: Report = { - ...LHNTestUtils.getFakeReport(), - reportID: '1', - }; - const reportNameValuePairs = { - type: 'chat', - private_isArchived: DateUtils.getDBTime(), - }; - - // Get the quick action detail - const quickActionDetails = getQuickActionDetails(archivedReport, undefined, undefined, reportNameValuePairs); - - // Expect the quickActionAvatars is empty array and hideQABSubtitle is true since the quick action report is archived - expect(quickActionDetails.quickActionAvatars.length).toEqual(0); - expect(quickActionDetails.hideQABSubtitle).toEqual(true); - }); - }); - describe('getChatByParticipants', () => { const userAccountID = 1; const userAccountID2 = 2; From 98f0688cb6329a1acea264a7260516945f3b455e Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Sat, 26 Jul 2025 23:27:58 +0530 Subject: [PATCH 06/14] remove useReportIsArchived from HeaderView.tsx. Signed-off-by: krishna2323 --- src/pages/home/HeaderView.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 6b0d794a96fe..c21c8adf8162 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -27,7 +27,6 @@ import useLoadingBarVisibility from '@hooks/useLoadingBarVisibility'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; -import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSubscriptionPlan from '@hooks/useSubscriptionPlan'; import useTheme from '@hooks/useTheme'; @@ -122,7 +121,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`, {canBeMissing: true}); const [reportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report?.reportID}`, {canBeMissing: true}); - const isReportArchived = useReportIsArchived(report?.reportID); + const isReportArchived = isArchivedReport(reportNameValuePairs); const {translate} = useLocalize(); const theme = useTheme(); @@ -216,10 +215,9 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, [firstDayFreeTrial, lastDayFreeTrial, hasTeam2025Pricing, reportNameValuePairs, subscriptionPlan], ); - const isArchived = isArchivedReport(reportNameValuePairs); - const shouldShowSubscript = shouldReportShowSubscript(report, isArchived); + const shouldShowSubscript = shouldReportShowSubscript(report, isReportArchived); const defaultSubscriptSize = isExpenseRequest(report) ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT; - const icons = getIcons(reportHeaderData, personalDetails, null, '', -1, policy, invoiceReceiverPolicy, isArchived); + const icons = getIcons(reportHeaderData, personalDetails, null, '', -1, policy, invoiceReceiverPolicy, isReportArchived); const brickRoadIndicator = hasReportNameError(report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; const shouldDisableDetailPage = shouldDisableDetailPageReportUtils(report); const shouldUseGroupTitle = isGroupChat && (!!report?.reportName || !isMultipleParticipant); @@ -231,7 +229,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, {canBeMissing: true}); const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboardingPurposeSelected); const shouldShowRegisterForWebinar = introSelected?.companySize === CONST.ONBOARDING_COMPANY_SIZE.MICRO && (isChatUsedForOnboarding || (isAdminRoom(report) && !isChatThread)); - const shouldShowOnBoardingHelpDropdownButton = (shouldShowRegisterForWebinar || shouldShowGuideBooking) && !isArchived; + const shouldShowOnBoardingHelpDropdownButton = (shouldShowRegisterForWebinar || shouldShowGuideBooking) && !isReportArchived; const shouldShowEarlyDiscountBanner = shouldShowDiscount && isChatUsedForOnboarding; const latestScheduledCall = reportNameValuePairs?.calendlyCalls?.at(-1); const hasActiveScheduledCall = latestScheduledCall && !isPast(latestScheduledCall.eventTime) && latestScheduledCall.status !== CONST.SCHEDULE_CALL_STATUS.CANCELLED; @@ -308,7 +306,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, tooltipEnabled numberOfLines={1} textStyles={[styles.headerText, styles.pre]} - shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isChatThread || isTaskReport || shouldUseGroupTitle || isArchived} + shouldUseFullTitle={isChatRoom || isPolicyExpenseChat || isChatThread || isTaskReport || shouldUseGroupTitle || isReportArchived} renderAdditionalText={renderAdditionalText} shouldAddEllipsis={shouldAddEllipsis} /> From 0fa17143982e804f0df79db785819fa025c053a9 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Mon, 28 Jul 2025 10:11:32 +0530 Subject: [PATCH 07/14] minor update. Signed-off-by: krishna2323 --- src/pages/home/HeaderView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index c21c8adf8162..8ccb07239541 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -209,7 +209,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // If the onboarding report is directly loaded, shouldShowDiscountBanner can return wrong value as it is not // linked to the react lifecycle directly. Wait for trial dates to load, before calculating. const shouldShowDiscount = useMemo( - () => shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan) && !isArchivedReport(reportNameValuePairs), + () => shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan) && !isReportArchived, // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/exhaustive-deps [firstDayFreeTrial, lastDayFreeTrial, hasTeam2025Pricing, reportNameValuePairs, subscriptionPlan], From 7e5b159ee806cce8af3015f7c0e6bf2b96c255ef Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Mon, 28 Jul 2025 10:28:55 +0530 Subject: [PATCH 08/14] pass ReportNameValuePairs collection from Search page. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 5 +++-- src/libs/SearchUIUtils.ts | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index e5a29ba43d80..bdaeab2662e5 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -166,6 +166,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true}); const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: true}); + const [reportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {canBeMissing: true}); // Create a selector for only the reportActions needed to determine if a report has been exported or not, grouped by report const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { canEvict: false, @@ -298,8 +299,8 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS return []; } - return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey); - }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type]); + return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey, reportNameValuePairs); + }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, reportNameValuePairs]); useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 09bb236c1465..60ec2972c2aa 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -1010,7 +1010,7 @@ function getAction( * * Do not use directly, use only via `getSections()` facade. */ -function getTaskSections(data: OnyxTypes.SearchResults['data']): TaskListItemType[] { +function getTaskSections(data: OnyxTypes.SearchResults['data'], reportNameValuePairs?: OnyxCollection): TaskListItemType[] { return ( Object.keys(data) .filter(isReportEntry) @@ -1050,7 +1050,7 @@ function getTaskSections(data: OnyxTypes.SearchResults['data']): TaskListItemTyp // eslint-disable-next-line deprecation/deprecation const policy = getPolicy(parentReport.policyID); const parentReportName = getReportName(parentReport, policy, undefined, undefined); - const parentReportNameValuePairs = getReportNameValuePairsFromKey(data, parentReport); + const parentReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${parentReport?.reportID}`]; const isParentReportArchived = isArchivedReport(parentReportNameValuePairs); const icons = getIcons(parentReport, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); @@ -1263,12 +1263,13 @@ function getSections( groupBy?: SearchGroupBy, reportActions: Record = {}, currentSearch: SearchKey = CONST.SEARCH.SEARCH_KEYS.EXPENSES, + reportNameValuePairs?: OnyxCollection, ) { if (type === CONST.SEARCH.DATA_TYPES.CHAT) { return getReportActionsSections(data); } if (type === CONST.SEARCH.DATA_TYPES.TASK) { - return getTaskSections(data); + return getTaskSections(data, reportNameValuePairs); } if (groupBy) { From 3f8c48f466ea31221b7caea84d0201b82f01a7c6 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Mon, 28 Jul 2025 22:45:38 +0530 Subject: [PATCH 09/14] fix ESLint. Signed-off-by: krishna2323 --- tests/unit/ReportUtilsTest.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 7231b6b70da7..7582a567b6a5 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -1885,27 +1885,6 @@ describe('ReportUtils', () => { }); }); - describe('getQuickActionDetails', () => { - it('if the report is archived, the quick action will hide the subtitle and avatar', () => { - // Create a fake archived report as quick action report - const archivedReport: Report = { - ...LHNTestUtils.getFakeReport(), - reportID: '1', - }; - const reportNameValuePairs = { - type: 'chat', - private_isArchived: DateUtils.getDBTime(), - }; - - // Get the quick action detail - const quickActionDetails = getQuickActionDetails(archivedReport, undefined, undefined, reportNameValuePairs); - - // Expect the quickActionAvatars is empty array and hideQABSubtitle is true since the quick action report is archived - expect(quickActionDetails.quickActionAvatars.length).toEqual(0); - expect(quickActionDetails.hideQABSubtitle).toEqual(true); - }); - }); - describe('canEditMoneyRequest', () => { it('it should return false for archived invoice', async () => { const invoiceReport: Report = { From 4bd3af4f34ec2262436bf90722fe7a3fd6796859 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Wed, 30 Jul 2025 03:20:39 +0530 Subject: [PATCH 10/14] add selector for NVPs. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 22 +++++++++++++++++++--- src/libs/ReportUtils.ts | 3 ++- src/libs/SearchUIUtils.ts | 10 +++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9ebfeb65571f..5228d8c4b7cd 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -42,7 +42,7 @@ import { shouldShowEmptyState, shouldShowYear as shouldShowYearUtil, } from '@libs/SearchUIUtils'; -import type {SearchKey} from '@libs/SearchUIUtils'; +import type {ReportNameValuePairsArchivedMap, SearchKey} from '@libs/SearchUIUtils'; import {isOnHold, isTransactionPendingDelete} from '@libs/TransactionUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import type {SearchFullscreenNavigatorParamList} from '@navigation/types'; @@ -54,7 +54,7 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type {ReportAction} from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import {getEmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import {useSearchContext} from './SearchContext'; import SearchList from './SearchList'; import SearchScopeProvider from './SearchScopeProvider'; @@ -168,7 +168,23 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true}); const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: true}); - const [reportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {canBeMissing: true}); + + // Create a selector for only returning the required field `private_isArchived` + const [reportNameValuePairs = getEmptyObject()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { + canBeMissing: true, + selector: (all): ReportNameValuePairsArchivedMap => { + if (!all) { + return {}; + } + + const result: ReportNameValuePairsArchivedMap = {}; + for (const [key, value] of Object.entries(all)) { + result[key] = {private_isArchived: value?.private_isArchived}; + } + return result; + }, + }); + // Create a selector for only the reportActions needed to determine if a report has been exported or not, grouped by report const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { canEvict: false, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4dad967335d5..e4f2b46e7ff8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -210,6 +210,7 @@ import { wasActionTakenByCurrentUser, } from './ReportActionsUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; +import type {RNVPArchivedOnly} from './SearchUIUtils'; import {shouldRestrictUserBillableActions} from './SubscriptionUtils'; import { getAttendees, @@ -2055,7 +2056,7 @@ function isArchivedNonExpenseReport(report: OnyxInputOrEntry | SearchRep * Whether the provided report is an archived report */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -function isArchivedReport(reportNameValuePairs?: OnyxInputOrEntry): boolean { +function isArchivedReport(reportNameValuePairs?: OnyxInputOrEntry | RNVPArchivedOnly): boolean { return !!reportNameValuePairs?.private_isArchived; } diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index b8d9f0d84c66..1bca3a73025e 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -221,6 +221,10 @@ type SearchDateModifier = ValueOf; type SearchDateModifierLower = Lowercase; +type RNVPArchivedOnly = Pick; + +type ReportNameValuePairsArchivedMap = Record; + /** * Returns a list of all possible searches in the LHN, along with their query & hash. * *NOTE* When rendering the LHN, you should use the "createTypeMenuSections" method, which @@ -1010,7 +1014,7 @@ function getAction( * * Do not use directly, use only via `getSections()` facade. */ -function getTaskSections(data: OnyxTypes.SearchResults['data'], reportNameValuePairs?: OnyxCollection): TaskListItemType[] { +function getTaskSections(data: OnyxTypes.SearchResults['data'], reportNameValuePairs?: ReportNameValuePairsArchivedMap): TaskListItemType[] { return ( Object.keys(data) .filter(isReportEntry) @@ -1263,7 +1267,7 @@ function getSections( groupBy?: SearchGroupBy, reportActions: Record = {}, currentSearch: SearchKey = CONST.SEARCH.SEARCH_KEYS.EXPENSES, - reportNameValuePairs?: OnyxCollection, + reportNameValuePairs?: ReportNameValuePairsArchivedMap, ) { if (type === CONST.SEARCH.DATA_TYPES.CHAT) { return getReportActionsSections(data); @@ -1782,4 +1786,4 @@ export { isTransactionAmountTooLong, isTransactionTaxAmountTooLong, }; -export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey}; +export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ReportNameValuePairsArchivedMap, RNVPArchivedOnly}; From cda53f1200d61da5eb61adcac7710d2216d3fce9 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Wed, 30 Jul 2025 17:28:15 +0530 Subject: [PATCH 11/14] create an array of archived reports id. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 22 ++++++++++++---------- src/libs/ReportUtils.ts | 3 +-- src/libs/SearchUIUtils.ts | 15 ++++++--------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 5228d8c4b7cd..571f2cfe9b99 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -42,7 +42,7 @@ import { shouldShowEmptyState, shouldShowYear as shouldShowYearUtil, } from '@libs/SearchUIUtils'; -import type {ReportNameValuePairsArchivedMap, SearchKey} from '@libs/SearchUIUtils'; +import type {ArchivedReportsIDList, SearchKey} from '@libs/SearchUIUtils'; import {isOnHold, isTransactionPendingDelete} from '@libs/TransactionUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import type {SearchFullscreenNavigatorParamList} from '@navigation/types'; @@ -54,7 +54,8 @@ import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type {ReportAction} from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; -import {getEmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import getEmptyArray from '@src/types/utils/getEmptyArray'; import {useSearchContext} from './SearchContext'; import SearchList from './SearchList'; import SearchScopeProvider from './SearchScopeProvider'; @@ -169,17 +170,18 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: true}); - // Create a selector for only returning the required field `private_isArchived` - const [reportNameValuePairs = getEmptyObject()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { + const [archivedReportsIDList = getEmptyArray()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { canBeMissing: true, - selector: (all): ReportNameValuePairsArchivedMap => { + selector: (all): ArchivedReportsIDList => { if (!all) { - return {}; + return []; } - const result: ReportNameValuePairsArchivedMap = {}; + const result: ArchivedReportsIDList = []; for (const [key, value] of Object.entries(all)) { - result[key] = {private_isArchived: value?.private_isArchived}; + if (value?.private_isArchived) { + result.push(key.replace(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, '')); + } } return result; }, @@ -319,8 +321,8 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS if (groupBy && (isChat || isTask)) { return []; } - return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey, reportNameValuePairs); - }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, reportNameValuePairs]); + return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey, archivedReportsIDList); + }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, archivedReportsIDList]); useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e4f2b46e7ff8..4dad967335d5 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -210,7 +210,6 @@ import { wasActionTakenByCurrentUser, } from './ReportActionsUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; -import type {RNVPArchivedOnly} from './SearchUIUtils'; import {shouldRestrictUserBillableActions} from './SubscriptionUtils'; import { getAttendees, @@ -2056,7 +2055,7 @@ function isArchivedNonExpenseReport(report: OnyxInputOrEntry | SearchRep * Whether the provided report is an archived report */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -function isArchivedReport(reportNameValuePairs?: OnyxInputOrEntry | RNVPArchivedOnly): boolean { +function isArchivedReport(reportNameValuePairs?: OnyxInputOrEntry): boolean { return !!reportNameValuePairs?.private_isArchived; } diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 1bca3a73025e..b5a206af6a61 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -221,9 +221,7 @@ type SearchDateModifier = ValueOf; type SearchDateModifierLower = Lowercase; -type RNVPArchivedOnly = Pick; - -type ReportNameValuePairsArchivedMap = Record; +type ArchivedReportsIDList = string[]; /** * Returns a list of all possible searches in the LHN, along with their query & hash. @@ -1014,7 +1012,7 @@ function getAction( * * Do not use directly, use only via `getSections()` facade. */ -function getTaskSections(data: OnyxTypes.SearchResults['data'], reportNameValuePairs?: ReportNameValuePairsArchivedMap): TaskListItemType[] { +function getTaskSections(data: OnyxTypes.SearchResults['data'], archivedReportsIDList?: ArchivedReportsIDList): TaskListItemType[] { return ( Object.keys(data) .filter(isReportEntry) @@ -1054,8 +1052,7 @@ function getTaskSections(data: OnyxTypes.SearchResults['data'], reportNameValueP // eslint-disable-next-line deprecation/deprecation const policy = getPolicy(parentReport.policyID); const parentReportName = getReportName(parentReport, policy, undefined, undefined); - const parentReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${parentReport?.reportID}`]; - const isParentReportArchived = isArchivedReport(parentReportNameValuePairs); + const isParentReportArchived = archivedReportsIDList?.includes(parentReport?.reportID); const icons = getIcons(parentReport, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); @@ -1267,13 +1264,13 @@ function getSections( groupBy?: SearchGroupBy, reportActions: Record = {}, currentSearch: SearchKey = CONST.SEARCH.SEARCH_KEYS.EXPENSES, - reportNameValuePairs?: ReportNameValuePairsArchivedMap, + archivedReportsIDList?: ArchivedReportsIDList, ) { if (type === CONST.SEARCH.DATA_TYPES.CHAT) { return getReportActionsSections(data); } if (type === CONST.SEARCH.DATA_TYPES.TASK) { - return getTaskSections(data, reportNameValuePairs); + return getTaskSections(data, archivedReportsIDList); } if (groupBy) { @@ -1786,4 +1783,4 @@ export { isTransactionAmountTooLong, isTransactionTaxAmountTooLong, }; -export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ReportNameValuePairsArchivedMap, RNVPArchivedOnly}; +export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ArchivedReportsIDList}; From a707ef485016ba57db1deb80aa9f22dc5e2f022c Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 31 Jul 2025 02:24:52 +0530 Subject: [PATCH 12/14] convert archived reports id array to set. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 23 +++++++++++------------ src/libs/SearchUIUtils.ts | 10 +++++----- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 571f2cfe9b99..8523a4a4f24e 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -25,7 +25,7 @@ import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTop import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import Performance from '@libs/Performance'; import {getIOUActionForTransactionID, isExportIntegrationAction, isIntegrationMessageAction} from '@libs/ReportActionsUtils'; -import {canEditFieldOfMoneyRequest, generateReportID} from '@libs/ReportUtils'; +import {canEditFieldOfMoneyRequest, generateReportID, isArchivedReport} from '@libs/ReportUtils'; import {buildSearchQueryString} from '@libs/SearchQueryUtils'; import { getListItem, @@ -42,7 +42,7 @@ import { shouldShowEmptyState, shouldShowYear as shouldShowYearUtil, } from '@libs/SearchUIUtils'; -import type {ArchivedReportsIDList, SearchKey} from '@libs/SearchUIUtils'; +import type {ArchivedReportsIDSet, SearchKey} from '@libs/SearchUIUtils'; import {isOnHold, isTransactionPendingDelete} from '@libs/TransactionUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import type {SearchFullscreenNavigatorParamList} from '@navigation/types'; @@ -55,7 +55,6 @@ import SCREENS from '@src/SCREENS'; import type {ReportAction} from '@src/types/onyx'; import type SearchResults from '@src/types/onyx/SearchResults'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import getEmptyArray from '@src/types/utils/getEmptyArray'; import {useSearchContext} from './SearchContext'; import SearchList from './SearchList'; import SearchScopeProvider from './SearchScopeProvider'; @@ -170,20 +169,20 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: true}); - const [archivedReportsIDList = getEmptyArray()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { + const [archivedReportsIdSet = new Set()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { canBeMissing: true, - selector: (all): ArchivedReportsIDList => { + selector: (all): ArchivedReportsIDSet => { if (!all) { - return []; + return new Set(); } - const result: ArchivedReportsIDList = []; + const ids = new Set(); for (const [key, value] of Object.entries(all)) { - if (value?.private_isArchived) { - result.push(key.replace(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, '')); + if (isArchivedReport(value)) { + ids.add(key.slice(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS.length)); } } - return result; + return ids; }, }); @@ -321,8 +320,8 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS if (groupBy && (isChat || isTask)) { return []; } - return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey, archivedReportsIDList); - }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, archivedReportsIDList]); + return getSections(type, searchResults.data, searchResults.search, groupBy, exportReportActions, searchKey, archivedReportsIdSet); + }, [searchKey, exportReportActions, groupBy, isDataLoaded, searchResults, type, archivedReportsIdSet]); useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index b5a206af6a61..56e58a8c8c49 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -221,7 +221,7 @@ type SearchDateModifier = ValueOf; type SearchDateModifierLower = Lowercase; -type ArchivedReportsIDList = string[]; +type ArchivedReportsIDSet = ReadonlySet; /** * Returns a list of all possible searches in the LHN, along with their query & hash. @@ -1012,7 +1012,7 @@ function getAction( * * Do not use directly, use only via `getSections()` facade. */ -function getTaskSections(data: OnyxTypes.SearchResults['data'], archivedReportsIDList?: ArchivedReportsIDList): TaskListItemType[] { +function getTaskSections(data: OnyxTypes.SearchResults['data'], archivedReportsIDList?: ArchivedReportsIDSet): TaskListItemType[] { return ( Object.keys(data) .filter(isReportEntry) @@ -1052,7 +1052,7 @@ function getTaskSections(data: OnyxTypes.SearchResults['data'], archivedReportsI // eslint-disable-next-line deprecation/deprecation const policy = getPolicy(parentReport.policyID); const parentReportName = getReportName(parentReport, policy, undefined, undefined); - const isParentReportArchived = archivedReportsIDList?.includes(parentReport?.reportID); + const isParentReportArchived = archivedReportsIDList?.has(parentReport?.reportID); const icons = getIcons(parentReport, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); @@ -1264,7 +1264,7 @@ function getSections( groupBy?: SearchGroupBy, reportActions: Record = {}, currentSearch: SearchKey = CONST.SEARCH.SEARCH_KEYS.EXPENSES, - archivedReportsIDList?: ArchivedReportsIDList, + archivedReportsIDList?: ArchivedReportsIDSet, ) { if (type === CONST.SEARCH.DATA_TYPES.CHAT) { return getReportActionsSections(data); @@ -1783,4 +1783,4 @@ export { isTransactionAmountTooLong, isTransactionTaxAmountTooLong, }; -export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ArchivedReportsIDList}; +export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ArchivedReportsIDSet}; From 112e39e0be3a0fd9ca5f925a53882c9d898ff838 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Thu, 31 Jul 2025 13:07:57 +0530 Subject: [PATCH 13/14] minor update. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index ce8b6c4aee9c..1e83719cc880 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -172,14 +172,16 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS const [archivedReportsIdSet = new Set()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { canBeMissing: true, selector: (all): ArchivedReportsIDSet => { + const ids = new Set(); if (!all) { - return new Set(); + return ids; } - const ids = new Set(); + const prefixLength = ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS.length; for (const [key, value] of Object.entries(all)) { if (isArchivedReport(value)) { - ids.add(key.slice(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS.length)); + const reportID = key.slice(prefixLength); + ids.add(reportID); } } return ids; From b31bb0741e24f5d30c2a6809c98819ad3eaa12a3 Mon Sep 17 00:00:00 2001 From: krishna2323 Date: Fri, 1 Aug 2025 09:07:24 +0530 Subject: [PATCH 14/14] fix ESlint. Signed-off-by: krishna2323 --- src/components/Search/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 6dd9f72e4f68..e039eeabce0f 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -27,7 +27,7 @@ import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNa import Performance from '@libs/Performance'; import {getIOUActionForTransactionID, getOriginalMessage, getReportAction, isExportIntegrationAction, isIntegrationMessageAction, isMoneyRequestAction} from '@libs/ReportActionsUtils'; import {canEditFieldOfMoneyRequest, generateReportID, isArchivedReport} from '@libs/ReportUtils'; -import {buildSearchQueryString, buildSearchQueryString} from '@libs/SearchQueryUtils'; +import {buildCannedSearchQuery, buildSearchQueryString} from '@libs/SearchQueryUtils'; import { getColumnsToShow, getListItem,