From e46851db1cfae7794c4486836db6d77413921812 Mon Sep 17 00:00:00 2001 From: VH Date: Wed, 15 Jul 2026 03:58:07 +0700 Subject: [PATCH 1/3] refactor: quarantine Record-form getReportName behind a deprecated wrapper getReportName only ever read one field from the whole ReportAttributes Record it accepted, forcing callers to subscribe to every report's attributes and re-render when any of them changed. Narrowing it to take just the name string is an atomic signature change: the moment the 2nd param becomes `string`, ~40 callers break at once, which is too large to migrate in one reviewable PR. Split the mechanical part ("make getReportName misuse-proof") from the real per-site work ("migrate each caller"), and enforce at both levels: - getReportName is now string-only, `(report?, derivedReportName?: string)`, so passing a Record is rejected at compile time (TS2345). - deprecatedGetReportName wraps it for the un-migrated call sites, resolving `reportAttributes?.[reportID]?.reportName` and delegating. Behavior is identical, including the `!report?.reportID -> ''` guard. - All 44 remaining Record-form references (42 calls + 2 callback passes) now go through the wrapper and are pinned in the seatbelt baseline, so a new usage exceeds the recorded count and fails CI. The @deprecated tag ratchets independently of the 112 other baselined deprecations: the stratify processor rewrites it to a per-API rule ID, @typescript-eslint/no-deprecated/deprecatedGetReportName. ReportActionsUtils threads the function as a callback to break a dependency cycle, so its parameter type propagates the deprecation under its own getReportNameCallback rule ID, baselined separately. Counts only ratchet down from here. Subsequent sub-PRs migrate callers to getReportName with an O(1) name selector -- where the re-render win actually lands -- and the final one deletes the wrapper. Part of #66427. --- config/eslint/eslint.seatbelt.tsv | 33 +++++++++ src/components/AvatarWithDisplayName.tsx | 4 +- .../sections/ReportField.tsx | 4 +- .../ReportActionItem/MoneyRequestView.tsx | 6 +- src/components/ReportWelcomeText.tsx | 4 +- .../Search/hooks/useFilterReportValue.tsx | 4 +- src/libs/ModifiedExpenseMessage.ts | 4 +- .../LocalNotification/BrowserNotifications.ts | 4 +- src/libs/OptionsListUtils/index.ts | 8 +- src/libs/ReportActionsUtils.ts | 8 +- src/libs/ReportNameUtils.ts | 23 +++++- src/libs/ReportUtils.ts | 12 +-- src/libs/SearchQueryUtils.ts | 4 +- src/libs/SearchUIUtils.ts | 6 +- src/libs/SidebarUtils.ts | 10 +-- src/libs/actions/Task.ts | 4 +- src/pages/DynamicEditReportFieldPage.tsx | 4 +- src/pages/DynamicReportDetailsPage.tsx | 4 +- src/pages/DynamicReportParticipantsPage.tsx | 4 +- src/pages/DynamicRoomInvitePage.tsx | 4 +- src/pages/DynamicRoomMembersPage.tsx | 4 +- .../Search/SearchMoneyRequestReportPage.tsx | 4 +- src/pages/ShareCodePage.tsx | 4 +- src/pages/TripChatNameEditPage.tsx | 4 +- src/pages/inbox/HeaderView.tsx | 4 +- src/pages/inbox/ReportHeader.tsx | 4 +- .../report/ContextMenu/ContextMenuActions.tsx | 4 +- .../actionContents/MemberChangeContent.tsx | 4 +- .../menuItems/QuickActionMenuItem.tsx | 6 +- src/pages/iou/SplitExpenseEditPage.tsx | 4 +- .../report/ReportAvatarModalContent.tsx | 6 +- .../workspace/rooms/WorkspaceRoomsPage.tsx | 4 +- tests/unit/ReportNameUtilsTest.ts | 73 +++++++++++++++++-- 33 files changed, 196 insertions(+), 83 deletions(-) diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index bb50cfc8063d..e5b5544a9952 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -109,6 +109,7 @@ "../../src/components/AvatarCropModal/ImageCropView.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AvatarCropModal/Slider.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AvatarSelector.tsx" "no-restricted-syntax" 2 +"../../src/components/AvatarWithDisplayName.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/components/AvatarWithImagePicker.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AvatarWithImagePicker.tsx" "react-hooks/set-state-in-effect" 2 "../../src/components/BookTravelButton.tsx" "no-restricted-imports" 1 @@ -275,6 +276,7 @@ "../../src/components/MoneyRequestConfirmationList/sections/AmountField.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MoneyRequestConfirmationList/sections/AttendeeField.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 +"../../src/components/MoneyRequestConfirmationList/sections/ReportField.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/components/MoneyRequestConfirmationList/sections/ReportField.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/components/MoneyRequestConfirmationList/sections/TaxFields.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MoneyRequestConfirmationList/sections/selectors.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -362,11 +364,13 @@ "../../src/components/ReportActionItem/MoneyRequestReportPreview/ReportPreviewActionButton.tsx" "no-restricted-imports" 1 "../../src/components/ReportActionItem/MoneyRequestReportPreview/SubmitActionButton.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/components/ReportActionItem/MoneyRequestReportPreview/useReportPreviewActionDecision.ts" "rulesdir/no-useOnyx-dependencies-arg" 1 +"../../src/components/ReportActionItem/MoneyRequestView.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/components/ReportActionItem/TaskPreview.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/ReportActionItem/TaskView.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/ReportActionItem/TransactionPreview/TransactionPreviewContent.tsx" "no-restricted-imports" 1 "../../src/components/ReportActionItem/TripRoomPreview.tsx" "no-restricted-imports" 1 "../../src/components/ReportActionItem/receiptHoverUtils/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/components/ReportWelcomeText.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/components/RoomHeaderAvatars.tsx" "no-restricted-syntax" 2 "../../src/components/Rule/RuleBooleanBase.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Rule/TextBase.tsx" "@typescript-eslint/no-unsafe-type-assertion" 5 @@ -438,6 +442,7 @@ "../../src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchSingleSelectionPicker.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/Search/chartGroupByConfig.ts" "@typescript-eslint/no-unsafe-type-assertion" 20 +"../../src/components/Search/hooks/useFilterReportValue.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/components/Search/hooks/useOptimisticSearchTracking.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/components/Search/hooks/useStableOptimisticSortedData.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 @@ -708,6 +713,7 @@ "../../src/libs/Middleware/Logging.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/Middleware/Pagination.ts" "@typescript-eslint/no-unsafe-type-assertion" 5 "../../src/libs/Middleware/SaveResponseInOnyx.ts" "no-restricted-syntax" 1 +"../../src/libs/ModifiedExpenseMessage.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/libs/ModifiedExpenseMessage.ts" "@typescript-eslint/no-unsafe-type-assertion" 6 "../../src/libs/MoneyRequestReportUtils.ts" "no-restricted-imports" 1 "../../src/libs/Navigation/AppNavigator/AuthScreens.tsx" "no-restricted-syntax" 1 @@ -782,6 +788,7 @@ "../../src/libs/Network/enhanceParameters.ts" "no-restricted-syntax" 1 "../../src/libs/Network/index.ts" "no-restricted-syntax" 1 "../../src/libs/NextStepUtils.ts" "@typescript-eslint/no-deprecated/buildNextStepNew" 2 +"../../src/libs/Notification/LocalNotification/BrowserNotifications.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/libs/Notification/LocalNotification/BrowserNotifications.ts" "@typescript-eslint/no-deprecated/translateLocal" 1 "../../src/libs/Notification/LocalNotification/BrowserNotifications.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/Notification/LocalNotification/BrowserNotifications.ts" "no-restricted-imports" 1 @@ -793,6 +800,7 @@ "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/deprecatedAllReportActions" 2 "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/deprecatedAllSortedReportActions[reportID]" 1 "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/deprecatedCachedOneTransactionThreadReportIDs[reportID]" 2 +"../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 3 "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/deprecatedLastReportActions[reportID]" 3 "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-deprecated/translateLocal" 17 "../../src/libs/OptionsListUtils/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 6 @@ -813,23 +821,30 @@ "../../src/libs/ReceiptUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/ReportActionFollowupUtils/tokenizeForReveal.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/ReportActionItemEventHandler/index.android.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1 +"../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 +"../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/getReportNameCallback" 1 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/reportAction.sequenceNumber" 1 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-deprecated/reportAction?.originalMessage" 2 "../../src/libs/ReportActionsUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 111 "../../src/libs/ReportActionsUtils.ts" "rulesdir/no-onyx-connect" 3 +"../../src/libs/ReportNameUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/libs/ReportNameUtils.ts" "@typescript-eslint/no-deprecated/translateLocal" 3 "../../src/libs/ReportNameUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/ReportPrimaryActionUtils.ts" "no-restricted-imports" 1 "../../src/libs/ReportTitleUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/libs/ReportUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 5 "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-deprecated/getPolicy" 27 "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-deprecated/translateLocal" 28 "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 34 "../../src/libs/ReportUtils.ts" "rulesdir/no-onyx-connect" 16 "../../src/libs/SearchAutocompleteUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/libs/SearchQueryUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/libs/SearchQueryUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 49 +"../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 76 "../../src/libs/SearchUIUtils.ts" "no-restricted-imports" 1 "../../src/libs/SelectionScraper/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/libs/SidebarUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 4 "../../src/libs/SidebarUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/Sound/index.native.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/libs/Sound/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -985,6 +1000,7 @@ "../../src/libs/actions/Subscription.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/Subscription.ts" "no-restricted-syntax" 1 "../../src/libs/actions/Tab.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/libs/actions/Task.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/libs/actions/Task.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/Task.ts" "no-restricted-imports" 1 "../../src/libs/actions/Task.ts" "no-restricted-syntax" 7 @@ -1081,19 +1097,24 @@ "../../src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx" "no-restricted-imports" 1 "../../src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/DynamicEditReportFieldPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/DynamicEditReportFieldPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/DynamicReportChangeApproverPage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/DynamicReportChangeWorkspacePage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 3 +"../../src/pages/DynamicReportDetailsPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/DynamicReportDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/DynamicReportDetailsPage.tsx" "react-hooks/preserve-manual-memoization" 4 "../../src/pages/DynamicReportDetailsPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/DynamicReportParticipantDetailsPage.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/pages/DynamicReportParticipantDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/DynamicReportParticipantDetailsPage.tsx" "no-restricted-imports" 1 +"../../src/pages/DynamicReportParticipantsPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/DynamicReportParticipantsPage.tsx" "no-restricted-imports" 1 +"../../src/pages/DynamicRoomInvitePage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/DynamicRoomMemberDetailsPage.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/pages/DynamicRoomMemberDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/DynamicRoomMemberDetailsPage.tsx" "no-restricted-imports" 1 +"../../src/pages/DynamicRoomMembersPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/pages/DynamicRoomMembersPage.tsx" "no-restricted-imports" 1 "../../src/pages/DynamicRoomMembersPage.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/DynamicRoomMembersPage.tsx" "react-hooks/set-state-in-effect" 1 @@ -1201,6 +1222,7 @@ "../../src/pages/Search/SearchEditMultiple/SearchEditMultipleTagPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Search/SearchEditMultiple/SearchEditMultipleUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/Search/SearchHoldReasonPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 +"../../src/pages/Search/SearchMoneyRequestReportPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/Search/SearchMoneyRequestReportPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/Search/SearchPage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/Search/SearchSavePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -1208,6 +1230,7 @@ "../../src/pages/Share/ShareButton.tsx" "no-restricted-imports" 1 "../../src/pages/Share/ShareRootPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Share/ShareTab.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/ShareCodePage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/ShareCodePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/TeachersUnite/ImTeacherUpdateEmailPage.tsx" "no-restricted-imports" 1 "../../src/pages/TeachersUnite/SaveTheWorldPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -1233,6 +1256,7 @@ "../../src/pages/Travel/TravelUpgrade.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/Travel/TripDetailsPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/Travel/WorkspaceConfirmationForTravelPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/pages/TripChatNameEditPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/UnreportedExpenseListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/ValidateLoginPage/index.web.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/domain/Admins/DomainAdminsPage.tsx" "no-restricted-imports" 1 @@ -1257,8 +1281,10 @@ "../../src/pages/home/TimeSensitiveSection/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/home/TimeSensitiveSection/items/FixCompanyCardConnection.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/home/YourSpendSection/useYourSpendData.ts" "no-restricted-imports" 1 +"../../src/pages/inbox/HeaderView.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/HeaderView.tsx" "no-restricted-imports" 1 "../../src/pages/inbox/ReactionListWrapper.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/ReportHeader.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/ReportHeader.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/inbox/ReportNavigateAwayHandler.tsx" "react-hooks/exhaustive-deps" 1 "../../src/pages/inbox/cleanStaleReportActionBackToParam.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -1266,6 +1292,7 @@ "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/refs" 1 +"../../src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1303,6 +1330,7 @@ "../../src/pages/inbox/report/actionContents/ChatActionableButtons.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/inbox/report/actionContents/ChatMessageContent.tsx" "no-restricted-imports" 1 "../../src/pages/inbox/report/actionContents/JoinRequestContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/report/actionContents/MemberChangeContent.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/report/actionContents/ReimbursementDeQueuedContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/inbox/report/actionContents/ReimbursementQueuedContent.tsx" "no-restricted-imports" 1 "../../src/pages/inbox/report/actionContents/ReimbursementQueuedContent.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 @@ -1315,6 +1343,7 @@ "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/CreateReportMenuItem.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/InvoiceMenuItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/NewWorkspaceMenuItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/TravelMenuItem.tsx" "no-restricted-imports" 1 "../../src/pages/inbox/sidebar/FABPopoverContent/useScanActions.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1322,6 +1351,7 @@ "../../src/pages/inbox/sidebar/SignInButton.tsx" "no-restricted-imports" 1 "../../src/pages/iou/MoneyRequestAmountForm.tsx" "no-restricted-imports" 1 "../../src/pages/iou/MoneyRequestAmountForm.tsx" "react-hooks/set-state-in-effect" 3 +"../../src/pages/iou/SplitExpenseEditPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/iou/SplitExpenseEditPage.tsx" "no-restricted-imports" 1 "../../src/pages/iou/SplitExpenseEditPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/iou/SplitExpensePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1394,6 +1424,7 @@ "../../src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx" "no-restricted-imports" 1 "../../src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx" "react-hooks/set-state-in-effect" 2 "../../src/pages/media/AttachmentModalScreen/routes/hooks/useReportAttachmentModalType.ts" "react-hooks/set-state-in-effect" 1 +"../../src/pages/media/AttachmentModalScreen/routes/report/ReportAvatarModalContent.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/pages/settings/AboutPage/AboutPage.tsx" "react-hooks/refs" 1 "../../src/pages/settings/Agents/AgentsListRow.tsx" "no-restricted-imports" 1 "../../src/pages/settings/Agents/AgentsPage.tsx" "no-restricted-imports" 1 @@ -1693,6 +1724,7 @@ "../../src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx" "no-restricted-imports" 1 "../../src/pages/workspace/reports/ReportFieldsListValuesPage.tsx" "no-restricted-imports" 1 "../../src/pages/workspace/reports/TypeSelector/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/pages/workspace/rooms/WorkspaceRoomsPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/workspace/rooms/WorkspaceRoomsPage.tsx" "no-restricted-imports" 1 "../../src/pages/workspace/rooms/WorkspaceRoomsPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/workspace/rules/AgentRules/EditAgentRulePage.tsx" "no-restricted-imports" 1 @@ -2094,6 +2126,7 @@ "../../tests/unit/ReportActionsListPaddingViewTest.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../tests/unit/ReportActionsUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 36 "../../tests/unit/ReportLayoutUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../tests/unit/ReportNameUtilsTest.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 3 "../../tests/unit/ReportNameUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 23 "../../tests/unit/ReportPrimaryActionUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 35 "../../tests/unit/ReportPrimaryActionUtilsTest.ts" "no-restricted-imports" 1 diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 3b87836fdb3e..bb22c76f2fc4 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -14,7 +14,7 @@ import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/crea import Navigation from '@libs/Navigation/Navigation'; import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; import {getHumanAgentAccountIDFromReportAction, getHumanAgentFirstName} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import type {DisplayNameWithTooltips} from '@libs/ReportUtils'; import { canEditReportTitle, @@ -208,7 +208,7 @@ function AvatarWithDisplayName({ const reportAttributes = useReportAttributes(); const derivedParentReportName = useDerivedReportNameByReportID(report?.parentReportID); const isReportArchived = useReportIsArchived(report?.reportID); - const title = getReportName(report, reportAttributes); + const title = deprecatedGetReportName(report, reportAttributes); const isParentReportArchived = useReportIsArchived(report?.parentReportID); const subtitle = getChatRoomSubtitle(report, policy, conciergeReportID, translate, true, isReportArchived); const parentNavigationSubtitleData = getParentNavigationSubtitle(report, policy, conciergeReportID, translate, derivedParentReportName, isParentReportArchived); diff --git a/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx b/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx index 379a8574dc3c..32ca0b9ddf32 100644 --- a/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx +++ b/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx @@ -7,7 +7,7 @@ import useReportAttributes from '@hooks/useReportAttributes'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {generateReportID, getOutstandingReportsForUser, isMoneyRequestReport, isReportOutstanding} from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -108,7 +108,7 @@ function ReportField({selectedParticipants, iouType, reportID, reportActionID, a })(); const reportName = (() => { - const name = getReportName(selectedReport, reportAttributes); + const name = deprecatedGetReportName(selectedReport, reportAttributes); if (!name) { return isUnreported ? translate('common.none') : translate('iou.newReport'); } diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 6162074c44d4..93e5a1297cc7 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -74,7 +74,7 @@ import { isTaxTrackingEnabled, } from '@libs/PolicyUtils'; import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {isMarkAsCashActionForTransaction} from '@libs/ReportPrimaryActionUtils'; import {isSplitAction} from '@libs/ReportSecondaryActionUtils'; import { @@ -553,7 +553,7 @@ function MoneyRequestView({ } return { reportID: match.reportID, - name: getReportName(match, reportAttributes) || match.reportName, + name: deprecatedGetReportName(match, reportAttributes) || match.reportName, }; }; const [tripRoomInfo] = originalUseOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: tripRoomReportSelector}, [transactionTripID, grandparentReportID, reportAttributes]); @@ -1123,7 +1123,7 @@ function MoneyRequestView({ const reportNameToDisplay = isFromMergeTransaction ? (updatedTransaction?.reportName ?? translate('common.none')) - : getReportName(parentReport, reportAttributes) || parentReport?.reportName; + : deprecatedGetReportName(parentReport, reportAttributes) || parentReport?.reportName; const shouldShowReport = !!parentReportID || (isFromMergeTransaction && !!reportNameToDisplay); const reportCopyValue = !canEditReport && reportNameToDisplay !== translate('common.none') ? reportNameToDisplay : undefined; const shouldShowCategoryAnalyzing = isCategoryBeingAnalyzed(updatedTransaction ?? transaction); diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index b63b4e89167f..179e5ede7fd5 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -10,7 +10,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { getInvoiceReceiverPolicyID, getParticipantsAccountIDsForDisplay, @@ -91,7 +91,7 @@ function ReportWelcomeText({report, policy}: ReportWelcomeTextProps) { )}`, ) .join(', '); - const reportName = getReportName(report, reportAttributes); + const reportName = deprecatedGetReportName(report, reportAttributes); const shouldShowUsePlusButtonText = moneyRequestOptions.includes(CONST.IOU.TYPE.PAY) || moneyRequestOptions.includes(CONST.IOU.TYPE.SUBMIT) || diff --git a/src/components/Search/hooks/useFilterReportValue.tsx b/src/components/Search/hooks/useFilterReportValue.tsx index 0db6b67d3e19..aa095223f7e8 100644 --- a/src/components/Search/hooks/useFilterReportValue.tsx +++ b/src/components/Search/hooks/useFilterReportValue.tsx @@ -1,6 +1,6 @@ import useOnyx from '@hooks/useOnyx'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import type {SearchFilter} from '@libs/SearchUIUtils'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -14,7 +14,7 @@ function useFilterReportValue(reportIDs: SearchFilter['value']): string { } return reportIDs - .map((id) => getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportAttributes?.reports)) + .map((id) => deprecatedGetReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportAttributes?.reports)) .filter(Boolean) .join(', '); } diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 27e8fc9923f8..26d30948ea54 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -25,7 +25,7 @@ import {getOriginalMessage, isModifiedExpenseAction} from './ReportActionsUtils' // The functions imported here are pure utility functions that don't create initialization-time dependencies. // ReportNameUtils imports helper functions from ReportUtils, and ReportUtils imports name generation functions from ReportNameUtils. // eslint-disable-next-line import/no-cycle -import {buildReportNameFromParticipantNames, getPolicyExpenseChatName, getReportName} from './ReportNameUtils'; +import {buildReportNameFromParticipantNames, deprecatedGetReportName, getPolicyExpenseChatName} from './ReportNameUtils'; import {getPolicyName, getRootParentReport, isPolicyExpenseChat, isSelfDM} from './ReportUtils'; import {getFormattedAttendees, getTagArrayFromName} from './TransactionUtils'; import {isInvalidMerchantValue} from './ValidationUtils'; @@ -188,7 +188,7 @@ function getMovedFromOrToReportMessage( } if (movedFromReport) { - const originReportName = getReportName(movedFromReport, reportAttributes); + const originReportName = deprecatedGetReportName(movedFromReport, reportAttributes); return originReportName ? translate('iou.movedFromReport', originReportName) : translate('iou.movedFromReportNoName'); } } diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index d5ffedc02089..441abb9bd5ff 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -5,7 +5,7 @@ import {translateLocal} from '@libs/Localize'; import {getForReportAction} from '@libs/ModifiedExpenseMessage'; import NotificationPermission from '@libs/Notification/notificationPermission'; import {getTextFromHtml} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; @@ -116,7 +116,7 @@ export default { } if (isRoomOrGroupChat) { - const roomName = getReportName(report, reportAttributes); + const roomName = deprecatedGetReportName(report, reportAttributes); title = roomName; body = `${plainTextPerson}: ${plainTextMessage}`; } else { diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index eb494afcf9d7..b0d0edde339e 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -111,7 +111,7 @@ import { wasActionTakenByCurrentUser, withDEWRoutedActionsArray, } from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import type {OptionData} from '@libs/ReportUtils'; import { canUserPerformWriteAction, @@ -1218,7 +1218,7 @@ function createOption({ }, ); - const computedReportName = getReportName(report, reportAttributesDerived); + const computedReportName = deprecatedGetReportName(report, reportAttributesDerived); reportName = showPersonalDetails ? getDisplayNameForParticipant({accountID: accountIDs.at(0), formatPhoneNumber: formatPhoneNumberPhoneUtils, translate: translateFn}) || @@ -1301,7 +1301,7 @@ function getReportOption( if (option.isSelfDM) { option.alternateText = translateLocal('reportActionsView.yourSpace'); } else if (option.isInvoiceRoom) { - option.text = getReportName(report, reportAttributesDerived); + option.text = deprecatedGetReportName(report, reportAttributesDerived); option.alternateText = translateLocal('workspace.common.invoices'); } else { option.text = getPolicyName({report, policy}); @@ -1358,7 +1358,7 @@ function getReportDisplayOption( if (option.isSelfDM) { option.alternateText = translateLocal('reportActionsView.yourSpace'); } else if (option.isInvoiceRoom) { - option.text = getReportName(report, reportAttributesDerived); + option.text = deprecatedGetReportName(report, reportAttributesDerived); option.alternateText = translateLocal('workspace.common.invoices'); } else if (unknownUserDetails) { option.text = unknownUserDetails.text ?? unknownUserDetails.login; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 6ad46a887e6b..dea0d991f5cb 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -51,7 +51,7 @@ import isEmpty from 'lodash/isEmpty'; import Onyx from 'react-native-onyx'; import type {MessageElementBase, MessageTextElement} from './MessageElement'; -import type {getReportName} from './ReportNameUtils'; +import type {deprecatedGetReportName} from './ReportNameUtils'; import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils'; import {getBankName, isCardPendingActivate} from './CardUtils'; @@ -2015,13 +2015,13 @@ function isReportActionAttachment(reportAction: OnyxInputOrEntry): return false; } -// We pass getReportName as a param to avoid cyclic dependency. +// We pass deprecatedGetReportName as a param to avoid cyclic dependency. function getMemberChangeMessageElements( translate: LocalizedTranslate, reportAction: OnyxEntry, actorDetails: OnyxEntry, targetAccountDetailsList: OnyxEntry, - getReportNameCallback: typeof getReportName, + getReportNameCallback: typeof deprecatedGetReportName, reportAttributes?: ReportAttributesDerivedValue['reports'], ): readonly MemberChangeMessageElement[] { const isInviteAction = isInviteMemberAction(reportAction); @@ -2366,7 +2366,7 @@ function getMemberChangeMessageFragment( reportAction: OnyxEntry, actorDetails: OnyxEntry, targetAccountDetailsList: OnyxEntry, - getReportNameCallback: typeof getReportName, + getReportNameCallback: typeof deprecatedGetReportName, reportAttributes?: ReportAttributesDerivedValue['reports'], ): Message { const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements( diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index 554243bc18af..49b69740b156 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -1103,20 +1103,37 @@ function computeReportName({ /** * Returns the report name from OnyxDerived `reportAttributes` when available, falling back to the raw report object. * - * **Always prefer passing `reportAttributesDerivedValue` from the derived Onyx key** (`ONYXKEYS.DERIVED.REPORT_ATTRIBUTES`). + * **Always prefer passing `derivedReportName`**, sourced from the derived Onyx key (`ONYXKEYS.DERIVED.REPORT_ATTRIBUTES`) + * i.e. `reportAttributes?.[reportID]?.reportName`. Prefer the O(1) selectors (`useDerivedReportNameByReportID`) over + * subscribing to the whole attributes Record just to read one name. * The fallback to `report.reportName` exists only for edge-cases where the derived value is not yet populated. * Do NOT compute any part of the name here. Adjust `computeReportName` (internal) function if any change to report name are required. + * + * @param derivedReportName the cached name for this report from `ONYXKEYS.DERIVED.REPORT_ATTRIBUTES`. */ -function getReportName(report?: Report, reportAttributesDerivedValue?: ReportAttributesDerivedValue['reports']): string { +function getReportName(report?: Report, derivedReportName?: string): string { if (!report?.reportID) { return ''; } - return reportAttributesDerivedValue?.[report.reportID]?.reportName ?? report.reportName ?? ''; + return derivedReportName ?? report.reportName ?? ''; +} + +/** + * Transitional wrapper for call sites that still hold the whole attributes `Record`. Passing the Record forces a + * caller to subscribe to *every* report's attributes and re-render when any of them change, when all it needs is one + * name. Each call site is migrated to `getReportName` incrementally; this wrapper is removed once none remain. + * See https://github.com/Expensify/App/issues/66427. + * + * @deprecated Use `getReportName(report, derivedReportName)`, sourcing the name via `useDerivedReportNameByReportID`. + */ +function deprecatedGetReportName(report?: Report, reportAttributesDerivedValue?: ReportAttributesDerivedValue['reports']): string { + return getReportName(report, report?.reportID ? reportAttributesDerivedValue?.[report.reportID]?.reportName : undefined); } export { computeReportName, getReportName, + deprecatedGetReportName, getInvoiceReportName, getMoneyRequestReportName, buildReportNameFromParticipantNames, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5d6f210efc27..fd3e4541be69 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -233,7 +233,7 @@ import { // The functions imported here are pure utility functions that don't create initialization-time dependencies. // ReportNameUtils imports helper functions from ReportUtils, and ReportUtils imports name generation functions from ReportNameUtils. // eslint-disable-next-line import/no-cycle -import {getGroupChatName, getInvoicePayerName, getInvoiceReportName, getReportName} from './ReportNameUtils'; +import {deprecatedGetReportName, getGroupChatName, getInvoicePayerName, getInvoiceReportName} from './ReportNameUtils'; import {shouldRestrictUserBillableActions} from './SubscriptionUtils'; import {isTaskCompleted} from './TaskUtils'; import { @@ -5653,7 +5653,7 @@ function getReportPreviewMessage(params: GetReportPreviewMessageBaseParams & {is const reportActionMessage = getReportActionHtml(iouReportAction); if (params.isCopyAction) { if (report) { - return getReportName(report, params.reportAttributes ?? reportAttributesDerivedValue) || (originalReportAction?.childReportName ?? ''); + return deprecatedGetReportName(report, params.reportAttributes ?? reportAttributesDerivedValue) || (originalReportAction?.childReportName ?? ''); } return originalReportAction?.childReportName ?? ''; } @@ -6914,7 +6914,7 @@ function getMovedTransactionMessage(translate: LocalizedTranslate, action: Repor const report = fromReport ?? toReport; - const reportName = Parser.htmlToText(getReportName(report, reportAttributes) ?? report?.reportName ?? ''); + const reportName = Parser.htmlToText(deprecatedGetReportName(report, reportAttributes) ?? report?.reportName ?? ''); const reportUrl = getReportURLForCurrentContext(report?.reportID); if (typeof fromReportID === 'undefined') { return reportName ? translate('iou.movedTransactionTo', reportUrl, reportName) : translate('iou.movedTransactionToAnotherReport'); @@ -6928,7 +6928,7 @@ function getUnreportedTransactionMessage(translate: LocalizedTranslate, action: const fromReport = deprecatedAllReports?.[`${ONYXKEYS.COLLECTION.REPORT}${fromReportID}`]; - const reportName = Parser.htmlToText(getReportName(fromReport, reportAttributes) ?? fromReport?.reportName ?? ''); + const reportName = Parser.htmlToText(deprecatedGetReportName(fromReport, reportAttributes) ?? fromReport?.reportName ?? ''); let reportUrl = getReportURLForCurrentContext(fromReportID); @@ -12810,10 +12810,10 @@ function getChatListItemReportName(action: ReportAction & {reportName?: string}, } if (report?.reportID) { - return getReportName(getReport(report?.reportID, deprecatedAllReports), reportAttributesDerivedValue); + return deprecatedGetReportName(getReport(report?.reportID, deprecatedAllReports), reportAttributesDerivedValue); } - return getReportName(report, reportAttributesDerivedValue); + return deprecatedGetReportName(report, reportAttributesDerivedValue); } /** diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index bfb2dc086470..0d72081250fd 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -65,7 +65,7 @@ import navigationRef from './Navigation/navigationRef'; import {isRecord} from './ObjectUtils'; import {getPersonalDetailByEmail, temporaryGetDisplayNameOrDefault} from './PersonalDetailsUtils'; import {getCleanedTagName, getValidConnectedIntegration} from './PolicyUtils'; -import {getReportName} from './ReportNameUtils'; +import {deprecatedGetReportName} from './ReportNameUtils'; import {parse as parseSearchQuery} from './SearchParser/searchParser'; import StringUtils from './StringUtils'; import {hashText} from './UserUtils'; @@ -1623,7 +1623,7 @@ function getFilterDisplayValue({ return getBankAccountSearchLabel(bankAccount); } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { - return getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filterValue}`], reportAttributes) || filterValue; + return deprecatedGetReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filterValue}`], reportAttributes) || filterValue; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TOTAL || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.PURCHASE_AMOUNT) { // Added 2 here as this is the maximum number of decimals an amount can have. So, we can run a search with 2 decimals here. diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 4662b5aae58f..6d53dc6a7553 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -140,7 +140,7 @@ import { isResolvedActionableWhisper, isWhisperActionTargetedToOthers, } from './ReportActionsUtils'; -import {getReportName} from './ReportNameUtils'; +import {deprecatedGetReportName} from './ReportNameUtils'; import {isExportAction} from './ReportPrimaryActionUtils'; import { canDeleteMoneyRequestReport, @@ -2611,7 +2611,7 @@ function getTaskSections( if (parentReport && personalDetails) { const policy = data[`${ONYXKEYS.COLLECTION.POLICY}${parentReport.policyID}`]; const isParentReportArchived = isArchivedReport(reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${parentReport?.reportID}`]); - const parentReportName = getReportName(parentReport, reportAttributesDerivedValue); + const parentReportName = deprecatedGetReportName(parentReport, reportAttributesDerivedValue); const icons = getIcons(parentReport, formatPhoneNumber, translate, personalDetails, null, '', -1, policy, undefined, isParentReportArchived); const parentReportIcon = icons?.at(0); @@ -2783,7 +2783,7 @@ function getReportActionsSections( ...reportAction, reportID, from, - reportName: getReportName(report, reportAttributesDerivedValue), + reportName: deprecatedGetReportName(report, reportAttributesDerivedValue), formattedFrom: from?.displayName ?? from?.login ?? '', date: reportAction.created, keyForList: reportAction.reportActionID, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index a537e7923d49..4b57f9ea6ae0 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -151,7 +151,7 @@ import { isTagModificationAction, isTaskAction, } from './ReportActionsUtils'; -import {getReportName as getReportNameFromDerived} from './ReportNameUtils'; +import {deprecatedGetReportName} from './ReportNameUtils'; import { canUserPerformWriteAction as canUserPerformWriteActionUtil, excludeParticipantsForDisplay, @@ -567,7 +567,7 @@ function categorizeReportsForLHN( } const reportID = report.reportID; - const displayName = getReportNameFromDerived(report, reportAttributes); + const displayName = deprecatedGetReportName(report, reportAttributes); const miniReport: MiniReport = { reportID, displayName, @@ -1056,7 +1056,7 @@ function getOptionData({ : translate('workspace.invite.removed'); const users = translate(targetAccountIDsLength > 1 ? 'common.members' : 'common.member')?.toLocaleLowerCase(); result.alternateText = formatReportLastMessageText(`${actorDisplayName ?? lastActorDisplayName}: ${verb} ${targetAccountIDsLength} ${users}`); - const roomName = getReportNameFromDerived(lastActionReport ?? undefined, reportAttributesDerived) || lastActionOriginalMessage?.roomName; + const roomName = deprecatedGetReportName(lastActionReport ?? undefined, reportAttributesDerived) || lastActionOriginalMessage?.roomName; if (roomName) { const preposition = lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOM_CHANGE_LOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.INVITE_TO_ROOM @@ -1374,7 +1374,7 @@ function getOptionData({ result.phoneNumber = personalDetail?.phoneNumber ?? ''; } - const reportName = getReportNameFromDerived(report, reportAttributesDerived); + const reportName = deprecatedGetReportName(report, reportAttributesDerived); result.text = reportName; result.subtitle = subtitle; @@ -1505,7 +1505,7 @@ function getRoomWelcomeMessage( ): WelcomeMessage { const welcomeMessage: WelcomeMessage = {}; const workspaceName = getPolicyName({report}); - const reportName = getReportNameFromDerived(report ?? undefined, reportAttributes); + const reportName = deprecatedGetReportName(report ?? undefined, reportAttributes); if (report?.description) { welcomeMessage.messageHtml = getReportDescription(report); diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 9bf35e4221a3..b7eb0da3db16 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -14,7 +14,7 @@ import {getDBTimeWithSkew} from '@libs/NetworkState'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import * as ReportUtils from '@libs/ReportUtils'; import {buildOptimisticSnapshotData} from '@libs/SearchQueryUtils'; import playSound, {SOUNDS} from '@libs/Sound'; @@ -1155,7 +1155,7 @@ function getShareDestination( } return { icons: ReportUtils.getIcons(report, LocalePhoneNumber.formatPhoneNumber, translate, personalDetails, FallbackAvatar), - displayName: getReportName(report, reportAttributes), + displayName: deprecatedGetReportName(report, reportAttributes), subtitle, displayNamesWithTooltips, shouldUseFullTitleToDisplay: ReportUtils.shouldUseFullTitleToDisplay(report), diff --git a/src/pages/DynamicEditReportFieldPage.tsx b/src/pages/DynamicEditReportFieldPage.tsx index 3c4d89f04f5e..dfd963580f01 100644 --- a/src/pages/DynamicEditReportFieldPage.tsx +++ b/src/pages/DynamicEditReportFieldPage.tsx @@ -19,7 +19,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; import {isPolicyFieldListEmpty} from '@libs/PolicyUtils'; -import {getReportName as getReportNameFromReportNameUtils} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { getReportFieldKey, getTitleFieldWithFallback, @@ -126,7 +126,7 @@ function DynamicEditReportFieldPage({route}: DynamicEditReportFieldPageProps) { // Provide a default when the report name and the policy field list are empty const fieldValue = isReportFieldTitle - ? getReportNameFromReportNameUtils(report, reportAttributesByReportID) || (isPolicyFieldListEmpty(policy) ? CONST.REPORT.DEFAULT_EXPENSE_REPORT_NAME : '') + ? deprecatedGetReportName(report, reportAttributesByReportID) || (isPolicyFieldListEmpty(policy) ? CONST.REPORT.DEFAULT_EXPENSE_REPORT_NAME : '') : (reportField.value ?? reportField.defaultValue); const handleReportFieldChange = (form: FormOnyxValues) => { diff --git a/src/pages/DynamicReportDetailsPage.tsx b/src/pages/DynamicReportDetailsPage.tsx index 9aea8205858a..34685cc81a95 100644 --- a/src/pages/DynamicReportDetailsPage.tsx +++ b/src/pages/DynamicReportDetailsPage.tsx @@ -49,7 +49,7 @@ import Parser from '@libs/Parser'; import Permissions from '@libs/Permissions'; import {isPolicyAdmin as isPolicyAdminUtil, isPolicyEmployee as isPolicyEmployeeUtil, shouldShowPolicy} from '@libs/PolicyUtils'; import {getOneTransactionThreadReportID, getOriginalMessage, getTrackExpenseActionableWhisper, isDeletedAction, isMoneyRequestAction, isTrackExpenseAction} from '@libs/ReportActionsUtils'; -import {getReportName as getReportNameFromReportNameUtils} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { canDeleteCardTransactionByLiabilityType, canDeleteTransaction, @@ -407,7 +407,7 @@ function DynamicReportDetailsPage({policy, report, route, reportMetadata, report const reportForHeader = useMemo(() => getReportForHeader(report), [report]); const shouldParseFullTitle = parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !isGroupChat; - const rawReportName = getReportNameFromReportNameUtils(reportForHeader, reportAttributes); + const rawReportName = deprecatedGetReportName(reportForHeader, reportAttributes); const reportName = shouldParseFullTitle ? Parser.htmlToText(rawReportName) : rawReportName; const additionalRoomDetails = isExpenseReportUtil(report) || isPolicyExpenseChat || isInvoiceRoom ? chatRoomSubtitle : `${translate('threads.in')} ${chatRoomSubtitle}`; diff --git a/src/pages/DynamicReportParticipantsPage.tsx b/src/pages/DynamicReportParticipantsPage.tsx index 2c5f1ddc64d8..c009cb955ecf 100755 --- a/src/pages/DynamicReportParticipantsPage.tsx +++ b/src/pages/DynamicReportParticipantsPage.tsx @@ -30,7 +30,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types'; import {temporaryGetDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { getReportPersonalDetailsParticipants, isAnnounceRoom, @@ -247,7 +247,7 @@ function DynamicReportParticipantsPage({report}: DynamicReportParticipantsPagePr navigateBackToReportDetails(); } }} - subtitle={StringUtils.lineBreaksToSpaces(getReportName(report, reportAttributes))} + subtitle={StringUtils.lineBreaksToSpaces(deprecatedGetReportName(report, reportAttributes))} /> {isGroupChat && ( diff --git a/src/pages/DynamicRoomInvitePage.tsx b/src/pages/DynamicRoomInvitePage.tsx index 2b5beb4d90e8..4fbe11464deb 100644 --- a/src/pages/DynamicRoomInvitePage.tsx +++ b/src/pages/DynamicRoomInvitePage.tsx @@ -36,7 +36,7 @@ import {getLoginsByAccountIDs} from '@libs/PersonalDetailsUtils'; import {addSMSDomainIfPhoneNumber, parsePhoneNumber} from '@libs/PhoneNumber'; import type {MemberEmailsToAccountIDs} from '@libs/PolicyUtils'; import {isPolicyEmployee as isPolicyEmployeeUtil} from '@libs/PolicyUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {getParticipantsAccountIDsForDisplay, isPolicyExpenseChat} from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -133,7 +133,7 @@ function DynamicRoomInvitePage({report, policy, didScreenTransitionEnd}: Dynamic const isPolicyEmployee = isPolicyEmployeeUtil(report?.policyID, policy); const reportDetailsRoute = reportID ? createDynamicRoute(DYNAMIC_ROUTES.REPORT_DETAILS.path, ROUTES.REPORT_WITH_ID.getRoute(reportID)) : undefined; const backRoute = reportID && (!isPolicyEmployee || isReportArchived) ? reportDetailsRoute : backPath; - const reportName = getReportName(report, reportAttributes); + const reportName = deprecatedGetReportName(report, reportAttributes); const ancestors = useAncestors(report); diff --git a/src/pages/DynamicRoomMembersPage.tsx b/src/pages/DynamicRoomMembersPage.tsx index a94c8b4eea2d..5140113b0d47 100644 --- a/src/pages/DynamicRoomMembersPage.tsx +++ b/src/pages/DynamicRoomMembersPage.tsx @@ -38,7 +38,7 @@ import Parser from '@libs/Parser'; import {temporaryGetDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; import {isPolicyAdmin, isPolicyEmployee as isPolicyEmployeeUtils} from '@libs/PolicyUtils'; import {getReportAction} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { getReportForHeader, getReportPersonalDetailsParticipants, @@ -451,7 +451,7 @@ function DynamicRoomMembersPage({report, policy}: DynamicRoomMembersPageProps) { { if (isMobileSelectionModeEnabled) { diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index 2856303eb4da..29ecc86ddbd7 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -28,7 +28,7 @@ import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavig import TransitionTracker from '@libs/Navigation/TransitionTracker'; import type {RightModalNavigatorParamList} from '@libs/Navigation/types'; import {getIOUActionForTransactionID, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {isMoneyRequestReportPendingDeletion, isValidReportIDFromPath} from '@libs/ReportUtils'; import {cancelSpansByPrefix} from '@libs/telemetry/activeSpans'; import {doesDeleteNavigateBackUrlIncludeDuplicatesReview, getParentReportActionDeletionStatus, hasLoadedReportActions, isThreadReportDeleted} from '@libs/TransactionNavigationUtils'; @@ -138,7 +138,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { const reportAttributesSelector = useCallback((attributes: OnyxEntry) => reportByIDsSelector(reportID ? [reportID] : [])(attributes), [reportID]); const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {selector: reportAttributesSelector}); - useDocumentTitle(getReportName(report, reportAttributes)); + useDocumentTitle(deprecatedGetReportName(report, reportAttributes)); const doesReportIDLookValid = isValidReportIDFromPath(reportID); const hasLoadedReportActionsForAccessError = hasLoadedReportActions(reportLoadingState, isOffline); diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx index 28e282f8e95d..f4a5f3dba585 100644 --- a/src/pages/ShareCodePage.tsx +++ b/src/pages/ShareCodePage.tsx @@ -22,7 +22,7 @@ import Clipboard from '@libs/Clipboard'; import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {BackToParams} from '@libs/Navigation/types'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { getChatRoomSubtitle, getDefaultWorkspaceAvatar, @@ -116,7 +116,7 @@ function ShareCodePage({report, policy, backTo}: ShareCodePageProps) { const reportForTitle = useMemo(() => getReportForHeader(report), [report]); - const title = isReport ? getReportName(reportForTitle, reportAttributes) : (currentUserPersonalDetails.displayName ?? ''); + const title = isReport ? deprecatedGetReportName(reportForTitle, reportAttributes) : (currentUserPersonalDetails.displayName ?? ''); const urlWithTrailingSlash = addTrailingForwardSlash(environmentURL); const url = isReport ? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(report.reportID)}` diff --git a/src/pages/TripChatNameEditPage.tsx b/src/pages/TripChatNameEditPage.tsx index 1ea0e5a7b21d..78ec1388456d 100644 --- a/src/pages/TripChatNameEditPage.tsx +++ b/src/pages/TripChatNameEditPage.tsx @@ -14,7 +14,7 @@ import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/crea import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {NewChatNavigatorParamList} from '@libs/Navigation/types'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import StringUtils from '@libs/StringUtils'; import {updateChatName} from '@userActions/Report'; @@ -40,7 +40,7 @@ function TripChatNameEditPage({report}: TripChatNameEditPageProps) { const {inputCallbackRef} = useAutoFocusInput(); const reportID = report?.reportID; - const currentChatName = getReportName(report, reportAttributes); + const currentChatName = deprecatedGetReportName(report, reportAttributes); const validate = (values: FormOnyxValues): Errors => { const errors: Errors = {}; diff --git a/src/pages/inbox/HeaderView.tsx b/src/pages/inbox/HeaderView.tsx index 774416635fa7..77947efebe77 100644 --- a/src/pages/inbox/HeaderView.tsx +++ b/src/pages/inbox/HeaderView.tsx @@ -35,7 +35,7 @@ import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; import {getHumanAgentAccountIDFromReportAction, getHumanAgentFirstName} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { canJoinChat, canUserPerformWriteAction, @@ -161,7 +161,7 @@ function HeaderView({onNavigationMenuButtonClicked, reportID}: HeaderViewProps) const reportHeaderDataPolicy = usePolicy(reportHeaderData?.policyID); const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); // Use sorted display names for the title for group chats on native small screen widths - const title = getReportName(reportHeaderData, reportAttributes); + const title = deprecatedGetReportName(reportHeaderData, reportAttributes); const subtitle = getChatRoomSubtitle(reportHeaderData, reportHeaderDataPolicy, conciergeReportID, translate, false, isReportHeaderDataArchived); // This is used to get the status badge for invoice report subtitle. const statusTextForInvoiceReport = isParentInvoiceAndIsChatThread diff --git a/src/pages/inbox/ReportHeader.tsx b/src/pages/inbox/ReportHeader.tsx index 484625e13af6..49a2266c2481 100644 --- a/src/pages/inbox/ReportHeader.tsx +++ b/src/pages/inbox/ReportHeader.tsx @@ -10,7 +10,7 @@ import useSidePanelActions from '@hooks/useSidePanelActions'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import Navigation from '@libs/Navigation/Navigation'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {getReportOfflinePendingActionAndErrors, isInvoiceReport, isMoneyRequestReport, isReportTransactionThread} from '@libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -45,7 +45,7 @@ function ReportHeader() { const reportAttributesSelector = (attributes: OnyxEntry) => reportByIDsSelector(reportID ? [reportID] : [])(attributes); const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES, {selector: reportAttributesSelector}); - useDocumentTitle(getReportName(report, reportAttributes)); + useDocumentTitle(deprecatedGetReportName(report, reportAttributes)); const isTransactionThreadView = isReportTransactionThread(report); const isMoneyRequestOrInvoiceReport = isMoneyRequestReport(report) || isInvoiceReport(report); diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index 6ca9df4815b4..1e5eccd17404 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -165,7 +165,7 @@ import { isWhisperAction as isWhisperActionReportActionsUtils, wasActionTakenByCurrentUser, } from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName, getReportName} from '@libs/ReportNameUtils'; import { canDeleteReportAction, canEditReportAction, @@ -988,7 +988,7 @@ const ContextMenuActions: ContextMenuAction[] = [ reportAction, getPersonalDetailsByID(reportAction.actorAccountID, personalDetails), getPersonalDetailsListByIDs(targetAccountIDs, personalDetails), - getReportName, + deprecatedGetReportName, reportAttributes, ).html ?? ''; setClipboardMessage(logMessage); diff --git a/src/pages/inbox/report/actionContents/MemberChangeContent.tsx b/src/pages/inbox/report/actionContents/MemberChangeContent.tsx index 2cc2b3ed2d65..f902e0c887a5 100644 --- a/src/pages/inbox/report/actionContents/MemberChangeContent.tsx +++ b/src/pages/inbox/report/actionContents/MemberChangeContent.tsx @@ -4,7 +4,7 @@ import useReportAttributes from '@hooks/useReportAttributes'; import useThemeStyles from '@hooks/useThemeStyles'; import {getMemberChangeMessageFragment, getOriginalMessage} from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import TextCommentFragment from '@pages/inbox/report/comment/TextCommentFragment'; @@ -28,7 +28,7 @@ function MemberChangeContent({action}: MemberChangeContentProps) { const reportAttributes = useReportAttributes(); const [actorDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsSelector(action.actorAccountID)}); const [targetAccountDetailsList] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsListSelector(getOriginalMessage(action)?.targetAccountIDs)}); - const fragment = getMemberChangeMessageFragment(translate, action, actorDetails, targetAccountDetailsList, getReportName, reportAttributes); + const fragment = getMemberChangeMessageFragment(translate, action, actorDetails, targetAccountDetailsList, deprecatedGetReportName, reportAttributes); return ( diff --git a/src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx b/src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx index 7651391d8c4c..a14b34a76c9a 100644 --- a/src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx +++ b/src/pages/inbox/sidebar/FABPopoverContent/menuItems/QuickActionMenuItem.tsx @@ -15,7 +15,7 @@ import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import {getQuickActionIcon, getQuickActionTitle, isQuickActionAllowed} from '@libs/QuickActionUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {getDisplayNameForParticipant, getIcons, getWorkspaceChats, isPolicyExpenseChat} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; @@ -115,7 +115,7 @@ function QuickActionMenuItem({reportID}: QuickActionMenuItemProps) { } } - const quickActionSubtitle = !hideQABSubtitle ? getReportName(quickActionReport, reportAttributes) || translate('quickAction.updateDestination') : ''; + const quickActionSubtitle = !hideQABSubtitle ? deprecatedGetReportName(quickActionReport, reportAttributes) || translate('quickAction.updateDestination') : ''; const selectOption = (onSelected: () => void, shouldRestrictAction: boolean) => { if ( @@ -194,7 +194,7 @@ function QuickActionMenuItem({reportID}: QuickActionMenuItemProps) { shouldTeleportPortalToModalLayer icon={icons.ReceiptScan} title={translate('quickAction.scanReceipt')} - description={getReportName(policyChatForActivePolicy, reportAttributes)} + description={deprecatedGetReportName(policyChatForActivePolicy, reportAttributes)} rightIconReportID={policyChatForActivePolicy?.reportID} onPress={() => interceptAnonymousUser(() => { diff --git a/src/pages/iou/SplitExpenseEditPage.tsx b/src/pages/iou/SplitExpenseEditPage.tsx index 1a7bb504f36a..71fc3cdc6ae5 100644 --- a/src/pages/iou/SplitExpenseEditPage.tsx +++ b/src/pages/iou/SplitExpenseEditPage.tsx @@ -35,7 +35,7 @@ import type {SplitExpenseParamList} from '@libs/Navigation/types'; import {hasEnabledOptions} from '@libs/OptionsListUtils'; import Parser from '@libs/Parser'; import {arePolicyRulesEnabled, getDistanceRateCustomUnitRate, getTagLists, hasAnyPaidPolicy, isGroupPolicyByType} from '@libs/PolicyUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {isSplitAction} from '@libs/ReportSecondaryActionUtils'; import type {TransactionDetails} from '@libs/ReportUtils'; import {getParsedComment, getReportOrDraftReport, getTransactionDetails, isSelfDM} from '@libs/ReportUtils'; @@ -147,7 +147,7 @@ function SplitExpenseEditPage({route}: SplitExpensePageProps) { const isCategoryRequired = !!effectivePolicy?.requiresCategory && !isSelfDMSplit; const reportAttributes = useReportAttributes(); - const reportName = getReportName(currentReport, reportAttributes) || parentReport?.reportName; + const reportName = deprecatedGetReportName(currentReport, reportAttributes) || parentReport?.reportName; const isDescriptionRequired = isCategoryDescriptionRequired(policyCategories, splitExpenseDraftTransactionDetails?.category, arePolicyRulesEnabled(effectivePolicy, policyCategories)); // Mirror MoneyRequestView's `shouldShowTag`, plus always surface the row when the original diff --git a/src/pages/media/AttachmentModalScreen/routes/report/ReportAvatarModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/report/ReportAvatarModalContent.tsx index 2174bb760139..7ff4a6e4ac22 100644 --- a/src/pages/media/AttachmentModalScreen/routes/report/ReportAvatarModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/report/ReportAvatarModalContent.tsx @@ -3,7 +3,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportAttributes from '@hooks/useReportAttributes'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {getDefaultGroupAvatar, getPolicyName, getWorkspaceIcon, isGroupChat, isThread, isUserCreatedPolicyRoom} from '@libs/ReportUtils'; import {getFullSizeAvatar} from '@libs/UserAvatarUtils'; @@ -31,14 +31,14 @@ function ReportAvatarModalContent({navigation, route}: AttachmentModalScreenProp if (isGroupChat(report) && !isThread(report)) { return { source: report?.avatarUrl ? getFullSizeAvatar({avatarSource: report.avatarUrl, defaultAvatars}) : getDefaultGroupAvatar(report?.reportID), - headerTitle: getReportName(report, reportAttributes), + headerTitle: deprecatedGetReportName(report, reportAttributes), isWorkspaceAvatar: false, }; } if (isUserCreatedPolicyRoom(report) && report?.avatarUrl) { return { source: getFullSizeAvatar({avatarSource: report.avatarUrl, defaultAvatars}), - headerTitle: getReportName(report, reportAttributes), + headerTitle: deprecatedGetReportName(report, reportAttributes), isWorkspaceAvatar: false, }; } diff --git a/src/pages/workspace/rooms/WorkspaceRoomsPage.tsx b/src/pages/workspace/rooms/WorkspaceRoomsPage.tsx index e8a244d6a9a6..4893645c3512 100644 --- a/src/pages/workspace/rooms/WorkspaceRoomsPage.tsx +++ b/src/pages/workspace/rooms/WorkspaceRoomsPage.tsx @@ -20,7 +20,7 @@ import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/crea import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import {isPolicyAdmin} from '@libs/PolicyUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import {getParticipantsAccountIDsForDisplay} from '@libs/ReportUtils'; import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; @@ -71,7 +71,7 @@ function WorkspaceRoomsPage({route}: WorkspaceRoomsPageProps) { const rooms: WorkspaceRoomRowData[] = (policyReports ?? []).map((report) => ({ keyForList: report.reportID, reportID: report.reportID, - name: getReportName(report, reportAttributes), + name: deprecatedGetReportName(report, reportAttributes), memberCount: getParticipantsAccountIDsForDisplay(report, true, false, false, undefined, personalDetails).length, action: () => { const targetRoute = isAdmin ? createDynamicRoute(DYNAMIC_ROUTES.REPORT_DETAILS.getRoute(report.reportID)) : ROUTES.REPORT_WITH_ID.getRoute(report.reportID); diff --git a/tests/unit/ReportNameUtilsTest.ts b/tests/unit/ReportNameUtilsTest.ts index 49cf56e69e2c..e93af18f2f40 100644 --- a/tests/unit/ReportNameUtilsTest.ts +++ b/tests/unit/ReportNameUtilsTest.ts @@ -10,7 +10,8 @@ import { getInvoicesChatName, getMoneyRequestReportName, getPolicyExpenseChatName, - getReportName as getSimpleReportName, + getReportName, + deprecatedGetReportName, } from '@libs/ReportNameUtils'; import CONST from '@src/CONST'; @@ -975,7 +976,7 @@ describe('ReportNameUtils', () => { }); }); - describe('getReportName (derived value vs fallback)', () => { + describe('deprecatedGetReportName (resolves the name out of the attributes Record)', () => { test('Returns derived value when provided', () => { const report: Report = { ...createPolicyExpenseChat(60, true), @@ -993,7 +994,7 @@ describe('ReportNameUtils', () => { }, }; - expect(getSimpleReportName(report, derived)).toBe("Ragnar Lothbrok's expenses"); + expect(deprecatedGetReportName(report, derived)).toBe("Ragnar Lothbrok's expenses"); }); test('Falls back to report.reportName when derived missing', () => { @@ -1004,7 +1005,7 @@ describe('ReportNameUtils', () => { ownerAccountID: currentUserAccountID, }; - expect(getSimpleReportName(report, {} as never)).toBe('Custom Report Name'); + expect(deprecatedGetReportName(report, {} as never)).toBe('Custom Report Name'); }); test('Returns empty string when neither present', () => { @@ -1015,7 +1016,69 @@ describe('ReportNameUtils', () => { reportName: undefined, }; - expect(getSimpleReportName(report, {} as never)).toBe(''); + expect(deprecatedGetReportName(report, {} as never)).toBe(''); + }); + }); + + describe('getReportName (derived name vs fallback)', () => { + test('Returns the derived name when provided', () => { + const report: Report = { + ...createPolicyExpenseChat(70, true), + reportID: '70', + reportName: 'Raw Report Name', + ownerAccountID: 1, + }; + + expect(getReportName(report, "Ragnar Lothbrok's expenses")).toBe("Ragnar Lothbrok's expenses"); + }); + + test('Falls back to report.reportName when no derived name is passed', () => { + const report: Report = { + ...createRegularChat(71, [currentUserAccountID, 1]), + reportID: '71', + reportName: 'Custom Report Name', + ownerAccountID: currentUserAccountID, + }; + + expect(getReportName(report)).toBe('Custom Report Name'); + expect(getReportName(report, undefined)).toBe('Custom Report Name'); + }); + + test('Returns empty string when neither the derived name nor report.reportName is present', () => { + const report: Report = { + ...createRegularChat(72, [currentUserAccountID, 1]), + reportID: '72', + ownerAccountID: currentUserAccountID, + reportName: undefined, + }; + + expect(getReportName(report)).toBe(''); + }); + + test('Returns empty string when the report is missing or has no reportID', () => { + const reportWithoutID: Report = { + ...createRegularChat(74, [currentUserAccountID, 1]), + reportID: '', + reportName: 'Custom Report Name', + ownerAccountID: currentUserAccountID, + }; + + expect(getReportName(undefined, 'Derived Name')).toBe(''); + // reportID is the lookup key, so a report without one has no name even if it carries a reportName + expect(getReportName(reportWithoutID, 'Derived Name')).toBe(''); + }); + + test('Keeps an empty derived name rather than falling back to report.reportName', () => { + const report: Report = { + ...createRegularChat(73, [currentUserAccountID, 1]), + reportID: '73', + reportName: 'Custom Report Name', + ownerAccountID: currentUserAccountID, + }; + + // `??` only falls through on null/undefined, so a derived empty name wins. This mirrors the + // pre-migration behavior of indexing the attributes Record inline. + expect(getReportName(report, '')).toBe(''); }); }); From 8e9186eec2cbe64430bb8e566d3c547511dc4790 Mon Sep 17 00:00:00 2001 From: VH Date: Sat, 18 Jul 2026 21:49:02 +0700 Subject: [PATCH 2/3] refactor(reports): finish getReportName quarantine (#66427) Rename the two remaining Record-form callers the mechanical quarantine rename missed, which were failing to compile against the now string-only getReportName signature: - ReportUtils.getReportPreviewMessageForCopy - BaseReportActionContextMenu (memberChangeLogRoomReportName) Both now call deprecatedGetReportName. Also drop the now-unused deprecatedGetReportName import from ContextMenuActions (fully migrated to the string-form getReportName), and reconcile the eslint-seatbelt baseline: +1 SplitExpenseEditPage (a caller that was never baselined), -1 ContextMenuActions (auto-tightened). Refs: https://github.com/Expensify/App/issues/66427 --- config/eslint/eslint.seatbelt.tsv | 2 +- src/libs/ReportUtils.ts | 2 +- .../inbox/report/ContextMenu/BaseReportActionContextMenu.tsx | 4 ++-- src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index 88d804fc56f9..a8889fbb3873 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -1286,7 +1286,6 @@ "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/refs" 1 -"../../src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1347,6 +1346,7 @@ "../../src/pages/inbox/sidebar/SignInButton.tsx" "no-restricted-imports" 1 "../../src/pages/iou/MoneyRequestAmountForm.tsx" "no-restricted-imports" 1 "../../src/pages/iou/MoneyRequestAmountForm.tsx" "react-hooks/set-state-in-effect" 3 +"../../src/pages/iou/SplitExpenseEditPage.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/iou/SplitExpenseEditPage.tsx" "no-restricted-imports" 1 "../../src/pages/iou/SplitExpenseEditPage.tsx" "rulesdir/no-useOnyx-dependencies-arg" 1 "../../src/pages/iou/SplitExpensePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bfc1254223e0..0d9240717873 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5678,7 +5678,7 @@ function getReportPreviewMessageForCopy( const originalReportAction = params.originalReportAction ?? iouReportAction; const report = typeof reportOrID === 'string' ? getReport(reportOrID, deprecatedAllReports) : reportOrID; if (report) { - return getReportName(report, reportAttributes ?? reportAttributesDerivedValue) || (originalReportAction?.childReportName ?? ''); + return deprecatedGetReportName(report, reportAttributes ?? reportAttributesDerivedValue) || (originalReportAction?.childReportName ?? ''); } return originalReportAction?.childReportName ?? ''; } diff --git a/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx index a18d4f1baaf5..f02a125ee5bc 100755 --- a/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -36,7 +36,7 @@ import { isMemberChangeAction, withDEWRoutedActionsObject, } from '@libs/ReportActionsUtils'; -import {getReportName} from '@libs/ReportNameUtils'; +import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import { chatIncludesChronosWithID, getHarvestOriginalReportID, @@ -287,7 +287,7 @@ function BaseReportActionContextMenu({ const isHarvestReport = isHarvestCreatedExpenseReport(reportNameValuePairs?.origin, reportNameValuePairs?.originalID); const memberChangeLogReportActionMessage = isMemberChangeAction(reportAction) ? getOriginalMessage(reportAction) : undefined; const [memberChangeLogRoomReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(`${memberChangeLogReportActionMessage?.reportID}`)}`); - const memberChangeLogRoomReportName = getReportName(memberChangeLogRoomReport, reportAttributes) || memberChangeLogReportActionMessage?.roomName; + const memberChangeLogRoomReportName = deprecatedGetReportName(memberChangeLogRoomReport, reportAttributes) || memberChangeLogReportActionMessage?.roomName; let filteredContextMenuActions = ContextMenuActions.filter( (contextAction) => diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index bf1598411049..a78ff43799c1 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -165,7 +165,7 @@ import { isWhisperAction as isWhisperActionReportActionsUtils, wasActionTakenByCurrentUser, } from '@libs/ReportActionsUtils'; -import {deprecatedGetReportName, getReportName} from '@libs/ReportNameUtils'; +import {getReportName} from '@libs/ReportNameUtils'; import { canDeleteReportAction, canEditReportAction, From 38bdb7d55549853d543a8898d24a1dcf5e0ff9e9 Mon Sep 17 00:00:00 2001 From: VH Date: Sun, 19 Jul 2026 07:00:17 +0700 Subject: [PATCH 3/3] fix(reports): baseline deprecatedGetReportName in BaseReportActionContextMenu The Sub-PR 1 quarantine rename of this call site (#66427) was committed without its eslint-seatbelt entry, because the file's edit was uncommitted when lint-changed last ran and so was excluded from the merge-base diff. CI lint on the committed file then flagged the un-baselined usage. --- config/eslint/eslint.seatbelt.tsv | 1 + 1 file changed, 1 insertion(+) diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index a8889fbb3873..092567133bc8 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -1283,6 +1283,7 @@ "../../src/pages/inbox/ReportNavigateAwayHandler.tsx" "react-hooks/exhaustive-deps" 1 "../../src/pages/inbox/cleanStaleReportActionBackToParam.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/hooks/useReportWasDeleted.ts" "react-hooks/set-state-in-effect" 1 +"../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 1 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/refs" 1