diff --git a/config/eslint/eslint.config.mjs b/config/eslint/eslint.config.mjs index e7c48b76e50d..d122c3137804 100644 --- a/config/eslint/eslint.config.mjs +++ b/config/eslint/eslint.config.mjs @@ -304,6 +304,7 @@ const config = defineConfig([ 'rulesdir/require-a11y-disable-justification': 'error', 'rulesdir/no-direct-pre-insert-fullscreen-under-rhp': 'error', 'rulesdir/no-raw-typography': 'error', + 'rulesdir/no-direct-personal-details-list': 'error', 'rulesdir/require-locale-for-localized-date-format': 'error', 'rulesdir/prefer-narrow-hook-dependencies': [ 'error', @@ -652,6 +653,28 @@ const config = defineConfig([ rules: {'report-name-utils/no-function-call-in-get-report-name': 'error'}, }, + // Everything else must read personal details through `@hooks/usePersonalDetails`, `@libs/PersonalDetailsStore` or + // `buildPersonalDetailsUpdate`, so that changing the shape of the personal details data means changing those + // wrappers instead of ~200 call sites. The files below are exempt because they are the wrappers themselves, the + // place the key is declared, or test setup that has to seed Onyx by key. + { + files: [ + 'src/ONYXKEYS.ts', + 'src/hooks/usePersonalDetails.ts', + 'src/libs/PersonalDetailsStore.ts', + 'src/libs/PersonalDetailsUtils.ts', + 'src/components/OnyxListItemProvider.tsx', + 'src/libs/ExportOnyxState/common.ts', + 'tests/**/*.{ts,tsx}', + 'jest/**/*.{ts,tsx}', + '__mocks__/**/*.{ts,tsx}', + 'src/**/__mocks__/**/*.{ts,tsx}', + ], + rules: { + 'rulesdir/no-direct-personal-details-list': 'off', + }, + }, + // The typography token files are where raw font sizes and line heights are defined. { files: ['src/styles/typography.ts', 'src/styles/variables.ts'], diff --git a/config/eslint/eslint.seatbelt.tsv b/config/eslint/eslint.seatbelt.tsv index 94379e2e7a06..277191eee328 100644 --- a/config/eslint/eslint.seatbelt.tsv +++ b/config/eslint/eslint.seatbelt.tsv @@ -64,6 +64,7 @@ "../../src/components/AnimatedSubmitButton/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AnimatedSubmitButton/index.tsx" "react-hooks/refs" 4 "../../src/components/AnimatedSubmitButton/index.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/components/ArchivedReportFooter.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/AttachmentPicker/index.native.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AttachmentPicker/index.native.tsx" "react-hooks/refs" 1 "../../src/components/AttachmentPicker/index.tsx" "react-hooks/refs" 1 @@ -79,9 +80,11 @@ "../../src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/AutoCompleteSuggestions/index.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/AutoSubmitModal.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/components/Avatar/primitives/AvatarLetter.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../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" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/AvatarWithImagePicker.tsx" "react-hooks/set-state-in-effect" 2 "../../src/components/BookTravelButton.tsx" "no-restricted-imports" 1 "../../src/components/ButtonWithDropdownMenu/index.tsx" "react-hooks/set-state-in-effect" 1 @@ -108,6 +111,7 @@ "../../src/components/CountryPicker/CountrySelectorModal.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/CountryPicker/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/createOnyxContext.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/components/CurrentUserPersonalDetailsProvider.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/DatePicker/CalendarPicker/MonthPickerModal.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/DatePicker/CalendarPicker/YearPickerModal.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/DatePicker/DatePickerModal.tsx" "react-hooks/set-state-in-effect" 1 @@ -143,6 +147,7 @@ "../../src/components/Form/FormProvider.tsx" "react-hooks/refs" 2 "../../src/components/Form/InputWrapper.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/Form/InputWrapper.tsx" "react-hooks/refs" 1 +"../../src/components/FrozenCardHeader.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/GPSInProgressModal/index.native.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/components/GPSTripStateChecker/index.native.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/components/HeaderWithBackButton/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -163,6 +168,7 @@ "../../src/components/HTMLEngineProvider/HTMLRenderers/RBRRenderer.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/HTMLEngineProvider/HTMLRenderers/ShortMentionRenderer.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/HTMLEngineProvider/HTMLRenderers/TransactionHistoryLinkRenderer.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/HTMLEngineProvider/HTMLRenderers/UserDetailsRenderer.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/components/VictoryChartPie.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/HTMLEngineProvider/HTMLRenderers/VictoryChartRenderer/utils/getSkiaLineMetrics.ts" "rulesdir/no-raw-typography" 1 "../../src/components/HTMLEngineProvider/index.tsx" "no-restricted-syntax" 1 @@ -183,7 +189,9 @@ "../../src/components/InitialURLContextProvider.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/KYCWall/BaseKYCWall.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/components/KYCWall/BaseKYCWall.tsx" "react-hooks/refs" 2 +"../../src/components/KYCWall/BaseKYCWall.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/components/LHNOptionsList/LHNEmptyState.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/LHNOptionsList/LHNOptionsList.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/LHNOptionsList/OptionRowLHN/OptionRow/Pressable.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/LocaleContextProvider.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/LocaleContextProvider.tsx" "react-hooks/set-state-in-effect" 1 @@ -198,6 +206,11 @@ "../../src/components/Modal/Global/ModalContext.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/Modal/ReanimatedModal/Container/index.web.tsx" "react-hooks/refs" 1 "../../src/components/MoneyReportHeaderActions/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/components/MoneyReportHeaderActions/MoneyReportHeaderSecondaryActions.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyReportHeaderActions/MoneyReportHeaderSelectionDropdown.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyReportHeaderPrimaryAction/ReviewDuplicatesPrimaryAction.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyReportHeaderPrimaryAction/SubmitPrimaryAction.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyReportHeaderPrimaryAction/useConfirmApproval.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/MoneyRequestAmountInput.tsx" "react-hooks/immutability" 2 "../../src/components/MoneyRequestConfirmationList.tsx" "react-hooks/set-state-in-effect" 2 "../../src/components/MoneyRequestConfirmationList/ConfirmationFooterContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -211,8 +224,12 @@ "../../src/components/MoneyRequestConfirmationListFooter/hooks/useReceiptThumbnailSource.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MoneyRequestConfirmationListFooter/sections/DistanceMapSection.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/MoneyRequestHeader.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyRequestHeaderPrimaryAction.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/MoneyRequestHeaderSecondaryActions.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/MoneyRequestReportView/MoneyRequestReportTransactionsNavigation.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/MoneyRequestReportView/MoneyRequestViewReportFields.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/MultifactorAuthentication/components/Modals/createCancelConfirmModal.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 @@ -238,6 +255,7 @@ "../../src/components/PDFView/index.native.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/PDFView/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/PDFView/index.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/components/PersonalDetailsByLoginProvider.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Picker/BasePicker.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/components/Picker/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/PopoverMenu/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -253,17 +271,25 @@ "../../src/components/RadioButtonWithLabel.tsx" "no-restricted-syntax" 1 "../../src/components/Reactions/AddReactionBubble.tsx" "react-hooks/refs" 1 "../../src/components/Reactions/MiniQuickEmojiReactions.tsx" "react-hooks/refs" 1 +"../../src/components/Reactions/ReactionTooltipContent.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/ReceiptCropView/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/ReceiptHoverZoom/useReceiptHoverZoom.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/ReportActionAvatars/useReportActionAvatars.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/ReportActionAvatars/useReportPreviewSenderID.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/ReportActionItem/IssueCardMessage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/ReportActionItem/MoneyReportView.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/ReportActionItem/MoneyRequestReceiptView.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/ReportActionItem/MoneyRequestReceiptView.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/components/ReportActionItem/MoneyRequestReceiptView.tsx" "rulesdir/no-direct-personal-details-list" 3 +"../../src/components/ReportActionItem/MoneyRequestReportPreview/useReportPreviewActionButtonData.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/ReportActionItem/MoneyRequestReportPreview/useReportPreviewActionDecision.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/ReportActionItem/MoneyRequestReportPreview/useReportPreviewCarousel.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/components/ReportActionItem/MoneyRequestView.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/ReportActionItem/receiptHoverUtils/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 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" "@typescript-eslint/no-deprecated/fontSize" 2 +"../../src/components/ReportWelcomeText.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/RNMarkdownTextInput.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/RNMaskedTextInput.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/RoomHeaderAvatars.tsx" "no-restricted-syntax" 2 @@ -279,7 +305,9 @@ "../../src/components/Search/FilterComponents/SingleSelect.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/FilterComponents/TypeSelector.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/FilterDropdowns/SortByPopup.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/Search/hooks/useFilterUserValue.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Search/hooks/useOptimisticSearchTracking.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/components/Search/hooks/useSearchSnapshot.ts" "rulesdir/no-direct-personal-details-list" 1 "../../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 "../../src/components/Search/index.tsx" "react-hooks/preserve-manual-memoization" 2 @@ -293,15 +321,18 @@ "../../src/components/Search/SearchList/ListItem/CardListItemHeader.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/components/Search/SearchList/ListItem/ChatListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 5 +"../../src/components/Search/SearchList/ListItem/ExpenseReportListItem.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Search/SearchList/ListItem/ExpenseReportListItemRow/ExpenseReportListItemRowWide.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/GroupChildrenContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/components/Search/SearchList/ListItem/MemberListItemHeader.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/components/Search/SearchList/ListItem/ReportListItemHeader.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Search/SearchList/ListItem/SearchMergeReportsListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/TaskListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/TransactionGroupListExpanded.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/TransactionGroupListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 18 "../../src/components/Search/SearchList/ListItem/TransactionListItem/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/components/Search/SearchList/ListItem/TransactionListItem/index.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Search/SearchList/ListItem/TransactionListItem/TransactionListItemNarrow.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/TransactionListItem/TransactionListItemWide.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchList/ListItem/WithdrawalIDListItemHeader.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -312,6 +343,7 @@ "../../src/components/Search/SearchRouter/getQueryWithSubstitutions.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchRouter/getUpdatedSubstitutionsMap.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchRouter/SearchRouter.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/Search/SearchRouter/SearchRouterOptionsWarmer.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Search/SearchRouter/SearchRouterUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/Search/SearchSingleSelectionPicker.tsx" "react-hooks/set-state-in-effect" 1 "../../src/components/SelectionButton.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -347,7 +379,9 @@ "../../src/components/Table/Table.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/components/Table/TableContext.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/components/Tables/WorkspaceCategoryRulesTable/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/Tables/WorkspaceCompanyCardsTable/index.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/Tables/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableRow.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/components/Tables/WorkspaceListTable/LeaveWorkspaceFlow.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/components/TabSelector/getBackground.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/TagPicker/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/TaxPicker.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -401,6 +435,7 @@ "../../src/components/withViewportOffsetTop.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/components/ZeroWidthView/index.tsx" "no-restricted-syntax" 2 "../../src/CONST/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/CONST/runtimeConfigured.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/DeepLinkHandler.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/DeepLinkHandler.tsx" "no-restricted-syntax" 1 "../../src/Expensify.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -408,6 +443,7 @@ "../../src/Expensify.tsx" "react-hooks/refs" 1 "../../src/Expensify.tsx" "react-hooks/set-state-in-effect" 1 "../../src/GlobalModals.tsx" "no-restricted-syntax" 2 +"../../src/hooks/useAccountIDToNameMap.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useAccountIndicatorChecks.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useAdvancedSearchFilters.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useAnimatedHighlightStyle/index.ts" "react-hooks/set-state-in-effect" 2 @@ -416,6 +452,8 @@ "../../src/hooks/useAutoCreateTrackWorkspace.ts" "no-restricted-imports" 1 "../../src/hooks/useAutoUpdateTimezone.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useBulkDuplicateAction.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useBulkDuplicateAction.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useBulkDuplicateReportAction.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useBulkPayOptions.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/hooks/useCachedImageSource.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useCachedImageSource.ts" "react-hooks/set-state-in-effect" 1 @@ -424,44 +462,63 @@ "../../src/hooks/useCardFeedsForActivePolicies.ts" "no-restricted-imports" 1 "../../src/hooks/useCardFeedsForDisplay.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useCardFeedsForDisplay.ts" "no-restricted-imports" 1 +"../../src/hooks/useChatWithAgent.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useCreateReport.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useDebounce.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useDebouncedState.ts" "react-hooks/refs" 2 "../../src/hooks/useDebouncedValue.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useDebounceNonReactive.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useDelegateAccountID.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useDeleteTransactions.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useDragAndDrop/types.ts" "@typescript-eslint/no-deprecated/React.MutableRefObject" 1 "../../src/hooks/useDynamicBackPath.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useExpenseActions.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useExpensifyCardRulesList.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useExportedToFilterOptions.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useFilteredOptions.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useFilterFormValues.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/hooks/useGeographicalStateAndCountryFromRoute.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 +"../../src/hooks/useHoldMenuSubmit.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useHtmlPaste/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useHydrateReportsFromSnapshot.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useImportSpreadsheetConfirmModal.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useInitial.ts" "react-hooks/refs" 4 "../../src/hooks/useInitialSelection.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useIsAgentAccount.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useIsBlockedToAddFeed.ts" "react-hooks/set-state-in-effect" 1 "../../src/hooks/useIsOwnWorkspaceChatRef.ts" "react-hooks/refs" 2 "../../src/hooks/useIsPaidPolicyAdmin.ts" "no-restricted-imports" 1 "../../src/hooks/useKeyboardShortcut.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useLazyAsset.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/hooks/useLazyAsset.ts" "react-hooks/set-state-in-effect" 1 +"../../src/hooks/useLifecycleActions.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useListKeyboardNav.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useMarkdownStyle.ts" "rulesdir/no-raw-typography" 3 +"../../src/hooks/useMoneyReportHeaderStatusBar.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useNativeCamera.ts" "react-hooks/refs" 1 "../../src/hooks/useNewTransactions.ts" "react-hooks/refs" 2 "../../src/hooks/useOnyx.ts" "@typescript-eslint/no-unsafe-type-assertion" 10 "../../src/hooks/useOptimisticDraftTransactions.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useOptimisticNextStep.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useOptimisticPersonalDetails.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useOtherFeedsForFeedSelector.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useOutstandingBalanceGuard.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 1 "../../src/hooks/usePageRefresh/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useParticipantSubmission.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/usePaymentOptions.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/hooks/usePaymentOptions.ts" "react-hooks/refs" 1 +"../../src/hooks/usePersonalDetailsByEmail.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/usePersonalDetailsByLogin.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/usePersonalPolicy.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/usePolicyData/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/usePreferredCurrency.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/usePreferredCurrency.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/usePrevious.ts" "react-hooks/refs" 1 +"../../src/hooks/useReportOwnerAsAttendee.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useReportPrimaryAction.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useReportRecipientLocalTime.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useReportScrollManager/index.native.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useReportSubmitToPopover.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useResetBankAccountModal.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useResponsiveLayout/index.native.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useResponsiveLayout/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -469,7 +526,12 @@ "../../src/hooks/useReviewDuplicatesNavigation.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useReviewDuplicatesNavigation.tsx" "react-hooks/set-state-in-effect" 1 "../../src/hooks/useSearchBulkActions.ts" "@typescript-eslint/no-unsafe-type-assertion" 10 +"../../src/hooks/useSearchBulkActions.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useSearchHighlightAndScroll.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/hooks/useSelectedTransactionsActions.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useSelectionModePayment.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useSelectionModeReportActions.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useShortMentionsList.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useSidebarOrderedReports.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useSidebarOrderedReports.tsx" "react-hooks/refs" 5 "../../src/hooks/useSidebarOrderedReports.tsx" "react-hooks/set-state-in-effect" 1 @@ -479,7 +541,12 @@ "../../src/hooks/useSubPage/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/hooks/useTackInputFocus/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useTextWithMiddleEllipsis.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/hooks/useTodoCounts.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useTodoSearchResults.ts" "rulesdir/no-direct-personal-details-list" 2 +"../../src/hooks/useTransactionInlineEdit.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/hooks/useTransactionsAndViolationsForReport.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useTransactionViolationOfWorkspace.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/hooks/useTransactionViolations.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/hooks/useViolations.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/hooks/useWindowDimensions/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/hooks/useWorkletStateMachine/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -489,6 +556,7 @@ "../../src/libs/actions/__mocks__/App.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/__mocks__/App.ts" "no-restricted-syntax" 2 "../../src/libs/actions/__mocks__/OnyxUpdates.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/Agent.ts" "rulesdir/no-direct-personal-details-list" 9 "../../src/libs/actions/App.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/App.ts" "no-restricted-syntax" 1 "../../src/libs/actions/applyOnyxUpdatesReliably.ts" "no-restricted-syntax" 1 @@ -511,8 +579,10 @@ "../../src/libs/actions/connections/SageIntacct.ts" "no-restricted-syntax" 2 "../../src/libs/actions/connections/Xero.ts" "no-restricted-syntax" 2 "../../src/libs/actions/Delegate.ts" "no-restricted-syntax" 4 +"../../src/libs/actions/Delegate.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/actions/Domain.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/Domain.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/Domain.ts" "rulesdir/no-direct-personal-details-list" 6 "../../src/libs/actions/ExitSurvey.ts" "no-restricted-syntax" 1 "../../src/libs/actions/getCompanyCardBankConnection/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/libs/actions/getCompanyCardBankConnection/index.tsx" "no-restricted-imports" 1 @@ -531,11 +601,13 @@ "../../src/libs/actions/IOU/Duplicate.ts" "no-restricted-syntax" 2 "../../src/libs/actions/IOU/Hold.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/IOU/Hold.ts" "no-restricted-syntax" 2 +"../../src/libs/actions/IOU/index.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/IOU/index.ts" "rulesdir/no-onyx-connect" 11 "../../src/libs/actions/IOU/MoneyRequest.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/IOU/MoneyRequestBuilder.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 2 "../../src/libs/actions/IOU/MoneyRequestBuilder.ts" "@typescript-eslint/no-deprecated/translateLocal" 1 "../../src/libs/actions/IOU/MoneyRequestBuilder.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/libs/actions/IOU/MoneyRequestBuilder.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/IOU/PayMoneyRequest.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 2 "../../src/libs/actions/IOU/PayMoneyRequest.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/actions/IOU/PayMoneyRequest.ts" "no-restricted-imports" 1 @@ -549,14 +621,18 @@ "../../src/libs/actions/IOU/ReportWorkflow.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 5 "../../src/libs/actions/IOU/ReportWorkflow.ts" "no-restricted-imports" 1 "../../src/libs/actions/IOU/ReportWorkflow.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/IOU/SearchUpdate.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/IOU/SendInvoice.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/IOU/SendInvoice.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/IOU/SendInvoice.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/IOU/SendMoney.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/IOU/SendMoney.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/IOU/SendMoney.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/IOU/Split.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 1 "../../src/libs/actions/IOU/Split.ts" "@typescript-eslint/no-deprecated/Localize.translateLocal" 2 "../../src/libs/actions/IOU/Split.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/actions/IOU/Split.ts" "no-restricted-syntax" 3 +"../../src/libs/actions/IOU/Split.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/actions/IOU/SplitExpenseItems.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/IOU/SplitTransactionUpdate.ts" "@typescript-eslint/no-unsafe-type-assertion" 20 "../../src/libs/actions/IOU/TrackExpense.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 1 @@ -574,6 +650,9 @@ "../../src/libs/actions/MergeTransaction.ts" "no-restricted-imports" 1 "../../src/libs/actions/MergeTransaction.ts" "no-restricted-syntax" 1 "../../src/libs/actions/OdometerTransactionUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/libs/actions/OnyxDerived/configs/guideAccountIDs.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/libs/actions/OnyxDerived/configs/loginToAccountIDMap.ts" "rulesdir/no-direct-personal-details-list" 1 +"../../src/libs/actions/OnyxDerived/configs/reportAttributes.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/OnyxDerived/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/OnyxUpdateManager/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/OnyxUpdateManager/utils/__mocks__/applyUpdates.ts" "no-restricted-syntax" 1 @@ -585,12 +664,14 @@ "../../src/libs/actions/PersonalCards.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/PersonalDetails.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/PersonalDetails.ts" "no-restricted-syntax" 5 +"../../src/libs/actions/PersonalDetails.ts" "rulesdir/no-direct-personal-details-list" 15 "../../src/libs/actions/Plaid.ts" "no-restricted-syntax" 1 "../../src/libs/actions/Policy/Category.ts" "no-restricted-syntax" 5 "../../src/libs/actions/Policy/DistanceRate.ts" "no-restricted-syntax" 2 "../../src/libs/actions/Policy/Member.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/actions/Policy/Member.ts" "no-restricted-imports" 1 "../../src/libs/actions/Policy/Member.ts" "no-restricted-syntax" 7 +"../../src/libs/actions/Policy/Member.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/Policy/Member.ts" "rulesdir/no-onyx-connect" 1 "../../src/libs/actions/Policy/PerDiem.ts" "no-restricted-syntax" 1 "../../src/libs/actions/Policy/Plan.ts" "no-restricted-syntax" 1 @@ -610,11 +691,13 @@ "../../src/libs/actions/QueuedOnyxUpdates.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/actions/ReimbursementAccount/resetNonUSDBankAccount.ts" "no-restricted-syntax" 1 "../../src/libs/actions/ReimbursementAccount/resetUSDBankAccount.ts" "no-restricted-syntax" 1 +"../../src/libs/actions/replaceOptimisticAgentWithActualAgent.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/actions/replaceOptimisticReportWithActualReport.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/actions/Report/index.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 3 "../../src/libs/actions/Report/index.ts" "@typescript-eslint/no-deprecated/reportAction.originalMessage" 1 "../../src/libs/actions/Report/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 19 "../../src/libs/actions/Report/index.ts" "no-restricted-syntax" 7 +"../../src/libs/actions/Report/index.ts" "rulesdir/no-direct-personal-details-list" 8 "../../src/libs/actions/Report/index.ts" "rulesdir/no-onyx-connect" 3 "../../src/libs/actions/Report/MarkAllMessageAsRead.tsx" "no-restricted-syntax" 1 "../../src/libs/actions/ReportLayout.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -625,6 +708,7 @@ "../../src/libs/actions/Search.ts" "@typescript-eslint/no-unsafe-type-assertion" 16 "../../src/libs/actions/Session/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/Session/index.ts" "no-restricted-syntax" 9 +"../../src/libs/actions/Session/index.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/actions/Session/index.ts" "rulesdir/no-onyx-connect" 2 "../../src/libs/actions/SplitExpenses.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/actions/StatsCounter.ts" "no-restricted-syntax" 2 @@ -636,6 +720,7 @@ "../../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" 5 +"../../src/libs/actions/Task.ts" "rulesdir/no-direct-personal-details-list" 2 "../../src/libs/actions/TaxRate.ts" "no-restricted-syntax" 1 "../../src/libs/actions/TeachersUnite.ts" "no-restricted-syntax" 1 "../../src/libs/actions/Transaction.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 2 @@ -648,6 +733,7 @@ "../../src/libs/actions/User.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/libs/actions/User.ts" "no-restricted-imports" 1 "../../src/libs/actions/User.ts" "no-restricted-syntax" 7 +"../../src/libs/actions/User.ts" "rulesdir/no-direct-personal-details-list" 3 "../../src/libs/actions/VacationDelegate.ts" "no-restricted-syntax" 2 "../../src/libs/actions/Wallet.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/libs/actions/Wallet.ts" "no-restricted-syntax" 1 @@ -720,6 +806,7 @@ "../../src/libs/MergeTransactionUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 5 "../../src/libs/Middleware/HandleUnusedOptimisticID.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/libs/Middleware/HandleUnusedOptimisticID.ts" "no-restricted-syntax" 1 +"../../src/libs/Middleware/HandleUnusedOptimisticID.ts" "rulesdir/no-direct-personal-details-list" 4 "../../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 @@ -808,12 +895,13 @@ "../../src/libs/OptionsListUtils/index.ts" "rulesdir/no-onyx-connect" 2 "../../src/libs/OptionsListUtils/searchMatchUtils.ts" "@typescript-eslint/no-deprecated/translateLocal" 2 "../../src/libs/PageHTMLCapture/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/libs/Parser.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/Parser.ts" "rulesdir/no-onyx-connect" 2 "../../src/libs/ParsingUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/PaymentUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/PersonalDetailsUtils.ts" "@typescript-eslint/no-deprecated/translateLocal" 2 "../../src/libs/PersonalDetailsUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 -"../../src/libs/PersonalDetailsUtils.ts" "rulesdir/no-onyx-connect" 2 +"../../src/libs/PersonalDetailsUtils.ts" "rulesdir/no-onyx-connect" 1 "../../src/libs/PhoneNumber.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/PolicyUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 9 "../../src/libs/prepareRequestPayload/index.native.ts" "@typescript-eslint/no-unsafe-type-assertion" 5 @@ -838,6 +926,7 @@ "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 17 "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-deprecated/translateLocal" 8 "../../src/libs/ReportUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 32 +"../../src/libs/ReportUtils.ts" "rulesdir/no-direct-personal-details-list" 6 "../../src/libs/ReportUtils.ts" "rulesdir/no-onyx-connect" 15 "../../src/libs/sanitizeLogParams.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/SearchAutocompleteUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -846,6 +935,7 @@ "../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 71 "../../src/libs/SearchUIUtils.ts" "no-restricted-imports" 1 +"../../src/libs/ShortMentionLogins.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/SidebarUtils.ts" "@typescript-eslint/no-deprecated/deprecatedGetReportName" 2 "../../src/libs/SidebarUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/Sound/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -855,6 +945,7 @@ "../../src/libs/StatusBar/types.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/StringUtils/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/libs/telemetry/forwardLogsToSentry.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/libs/telemetry/TelemetrySynchronizer.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/libs/TransactionPreviewUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/libs/TransactionUtils/index.ts" "@typescript-eslint/no-deprecated/getReportTransactions" 1 "../../src/libs/TransactionUtils/index.ts" "@typescript-eslint/no-deprecated/translateLocal" 3 @@ -878,32 +969,69 @@ "../../src/pages/Debug/ConstantSelector.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Debug/DateTimeSelector.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Debug/DebugDetails.tsx" "@typescript-eslint/no-unsafe-type-assertion" 8 +"../../src/pages/Debug/Report/DebugReportActions.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/Debug/Report/DebugReportPage.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 +"../../src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/Debug/ReportAction/DebugReportActionPreview.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/Debug/Transaction/DebugTransactionViolations.tsx" "no-restricted-syntax" 1 "../../src/pages/Debug/TransactionViolation/DebugTransactionViolationCreatePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/domain/Admins/DomainAddAdminPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Admins/DomainAddPrimaryContactPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Admins/DomainAdminDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Admins/DomainAdminsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/BaseDomainMemberDetailsComponent.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/DomainAddMemberPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/DomainMemberDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/DomainMembersPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/DomainMemberVacationDelegatePage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/DomainReportSuspiciousActivityPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/MoveUserBetweenGroupsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/MoveUsersBetweenGroupsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/TwoFactorAuth/DomainMemberForceTwoFactorAuthPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/domain/Members/TwoFactorAuth/DomainMemberResetTwoFactorAuthPage.tsx" "rulesdir/no-direct-personal-details-list" 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-direct-personal-details-list" 3 "../../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-direct-personal-details-list" 1 "../../src/pages/DynamicReportParticipantDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/DynamicReportParticipantDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/DynamicReportParticipantsInvitePage.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/DynamicReportParticipantsPage.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/DynamicRoomInvitePage.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/DynamicRoomMemberDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/DynamicRoomMemberDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/DynamicRoomMembersPage.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/DynamicRoomMembersPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/EnablePayments/shared/IdologyQuestions.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/EnablePayments/Wallet/PersonalInfo/substeps/DateOfBirthStep.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/EnablePayments/Wallet/utils/getSubstepValues.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/home/ForYouSection/ConciergePromptBox.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/home/GettingStartedSection/hooks/useGettingStartedItems.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/home/GettingStartedSection/hooks/useGettingStartedItems.ts" "no-restricted-imports" 1 +"../../src/pages/home/report/ConciergeThinkingMessage.tsx" "rulesdir/no-direct-personal-details-list" 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/AccountManagerBanner.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/AgentZeroStatusContext.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/cleanStaleReportActionBackToParam.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 +"../../src/pages/inbox/ConciergeDraftContext.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/HeaderView.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/inbox/hooks/useReportWasDeleted.ts" "react-hooks/set-state-in-effect" 1 "../../src/pages/inbox/ReactionListWrapper.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/inbox/report/actionContents/ActionContentRouter.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/inbox/report/actionContents/JoinRequestContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/report/actionContents/JoinRequestContent.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/actionContents/MemberChangeContent.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/inbox/report/actionContents/MentionWhisperContent.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/actionContents/ReimbursedContent.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/inbox/report/actionContents/ReimbursementDeQueuedContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/report/actionContents/ReimbursementQueuedContent.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/actionContents/RemovedFromApprovalChainContent.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/AncestorReportActionItem.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/comment/TextCommentFragment.tsx" "@typescript-eslint/no-deprecated/fontSize" 1 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx" "react-hooks/refs" 1 @@ -911,9 +1039,13 @@ "../../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 "../../src/pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx" "react-hooks/refs" 28 +"../../src/pages/inbox/report/DelegateOnBehalfOfText.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/HumanAgentAssistedByText.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/LinkPreviewer.tsx" "@typescript-eslint/no-deprecated/fontSize" 3 "../../src/pages/inbox/report/ReactionList/HeaderReactionList.tsx" "no-restricted-syntax" 1 +"../../src/pages/inbox/report/ReactionList/PopoverReactionList.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/report/ReportActionCompose/ComposerLocalTime.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions.tsx" "@typescript-eslint/no-unsafe-type-assertion" 5 "../../src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions.tsx" "react-hooks/refs" 7 "../../src/pages/inbox/report/ReportActionCompose/SuggestionEmoji.tsx" "react-hooks/refs" 1 @@ -921,13 +1053,18 @@ "../../src/pages/inbox/report/ReportActionCompose/SuggestionMention.tsx" "react-hooks/refs" 3 "../../src/pages/inbox/report/ReportActionCompose/useAttachmentPicker.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/inbox/report/ReportActionCompose/useComposerFocus.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/inbox/report/ReportActionCompose/useEditMessage.ts" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/ReportActionCompose/useReceiptDrop.ts" "@typescript-eslint/no-unsafe-type-assertion" 5 "../../src/pages/inbox/report/ReportActionItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/inbox/report/ReportActionItem.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/inbox/report/ReportActionItem.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/inbox/report/ReportActionItemCreated.tsx" "rulesdir/no-direct-personal-details-list" 3 "../../src/pages/inbox/report/ReportActionItemMessageEdit.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/inbox/report/ReportActionItemMessageEdit.tsx" "no-restricted-syntax" 1 "../../src/pages/inbox/report/ReportActionItemMessageEdit.tsx" "react-hooks/refs" 5 "../../src/pages/inbox/report/ReportActionItemMessageEdit.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/inbox/report/ReportActionItemParentAction.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/inbox/report/ReportActionItemSingle.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/inbox/report/SearchActionHeader.tsx" "@typescript-eslint/no-deprecated/fontSize" 1 "../../src/pages/inbox/report/shouldUseEmojiPickerSelection/index.web.ts" "no-restricted-syntax" 1 "../../src/pages/inbox/report/TripSummary.tsx" "rulesdir/no-default-id-values" 1 @@ -942,31 +1079,52 @@ "../../src/pages/inbox/sidebar/FABPopoverContent/menuItems/CreateReportMenuItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 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" "rulesdir/no-direct-personal-details-list" 1 "../../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 +"../../src/pages/iou/DynamicSplitBillDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/DynamicSplitExpensePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/iou/DynamicSplitExpensePage.tsx" "react-hooks/set-state-in-effect" 3 +"../../src/pages/iou/DynamicSplitExpensePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/MoneyRequestAmountForm.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/iou/request/ParticipantSearchResults.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/pages/iou/request/step/AmountSubmitDataSync.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/DistanceManualTabContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/DynamicIOURequestEditReport.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepAttendees.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepCategory.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepCategoryCreate.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepDate.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepDescription.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/DynamicIOURequestStepDistance.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepDistance.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/iou/request/step/DynamicIOURequestStepDistanceManual.tsx" "rulesdir/no-direct-personal-details-list" 2 +"../../src/pages/iou/request/step/DynamicIOURequestStepDistanceRate.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepMerchant.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/DynamicIOURequestStepReport.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/iou/request/step/DynamicIOURequestStepSubrate.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/DynamicIOURequestStepSubrate.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepTag.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepTaxAmountPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/DynamicIOURequestStepTaxRatePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/DynamicIOURequestStepUpgrade.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/iou/request/step/DynamicIOURequestStepWaypoint.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/iou/request/step/IOURequestEditReportCommon.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/IOURequestStepAmount.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/iou/request/step/IOURequestStepAmount.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/IOURequestStepConfirmation.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/iou/request/step/IOURequestStepConfirmation.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/iou/request/step/IOURequestStepDistanceGPS/BackgroundLocationPermissionsFlow/index.android.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 3 "../../src/pages/iou/request/step/IOURequestStepDistanceGPS/BackgroundLocationPermissionsFlow/index.ios.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 2 "../../src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSButtons/index.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 3 +"../../src/pages/iou/request/step/IOURequestStepDistanceGPS/index.native.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/IOURequestStepDistanceMap.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/iou/request/step/IOURequestStepDistanceMap.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/iou/request/step/IOURequestStepDistanceOdometer.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/iou/request/step/IOURequestStepOdometerImage/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/IOURequestStepScan/components/NavigationAwareCamera/WebCamera.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/IOURequestStepScan/components/ScanEditReceipt.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/iou/request/step/IOURequestStepScan/components/ScanSkipConfirmation.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/iou/request/step/IOURequestStepScan/DynamicReceiptView/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/iou/request/step/IOURequestStepScan/DynamicReceiptView/index.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/iou/request/step/IOURequestStepScan/hooks/useScanRouteParams.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -981,6 +1139,7 @@ "../../src/pages/media/AttachmentModalScreen/AttachmentModalContext.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/media/AttachmentModalScreen/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 16 "../../src/pages/media/AttachmentModalScreen/routes/hooks/useReportAttachmentModalType.ts" "react-hooks/set-state-in-effect" 1 +"../../src/pages/media/AttachmentModalScreen/routes/ProfileAvatarModalContent.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 7 "../../src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx" "react-hooks/set-state-in-effect" 2 "../../src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -988,9 +1147,12 @@ "../../src/pages/MissingPersonalDetails/subPages/Address.tsx" "@typescript-eslint/no-unsafe-type-assertion" 5 "../../src/pages/MissingPersonalDetails/subPages/Address.tsx" "react-hooks/refs" 4 "../../src/pages/MultifactorAuthentication/AuthorizeTransactionPage/AuthorizeCardTransactionPreview.tsx" "@typescript-eslint/no-deprecated/fontSize" 2 +"../../src/pages/NewChatConfirmPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/OnboardingPrivateDomain/BaseOnboardingPrivateDomain.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/PrivateNotes/PrivateNotesListPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/ProfilePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/ProfilePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/ReimbursementAccount/AddressFormFields.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/ReimbursementAccount/EnterSignerInfo/subSteps/Address.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/ReimbursementAccount/NonUSD/BankInfo/subSteps/AccountHolderDetails.tsx" "@typescript-eslint/no-unsafe-type-assertion" 7 @@ -1021,21 +1183,30 @@ "../../src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/BankAccountValidationForm.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/ReimbursementAccount/utils/getSubStepValues.ts" "@typescript-eslint/no-unsafe-type-assertion" 4 +"../../src/pages/RejectExpenseReportPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/ReportAddApproverPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/ReportDescriptionPage.tsx" "no-restricted-imports" 1 "../../src/pages/ReportDescriptionPage.tsx" "no-restricted-syntax" 1 +"../../src/pages/ReportSubmitToContent.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/ScheduleCall/ScheduleCallPage.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/Search/EmptySearchView.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/Search/SavedSearchRenamePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/Search/SearchAddApproverPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/Search/SearchChangeApproverPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/Search/SearchEditMultiple/SearchEditMultiplePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../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/SearchMoneyRequestReportPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/Search/SearchPage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/Search/SearchTransactionsChangeReport.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/settings/AboutPage/AboutPage.tsx" "react-hooks/refs" 1 +"../../src/pages/settings/Agents/EditAgentPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/settings/Agents/Fields/EditAgentAvatarPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/settings/Agents/Fields/EditNamePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/settings/Agents/Fields/EditPromptPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/settings/Copilot/CopilotPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/settings/ExitSurvey/DynamicExitSurveyConfirmPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/settings/HelpPage/HelpPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/settings/Profile/AgentAIPromptSection.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/settings/Profile/Contacts/DynamicContactMethodDetailsPage.tsx" "react-hooks/refs" 3 "../../src/pages/settings/Profile/Contacts/DynamicContactMethodDetailsPage.tsx" "react-hooks/set-state-in-effect" 3 @@ -1066,6 +1237,8 @@ "../../src/pages/settings/Wallet/InternationalDepositAccount/utils.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/settings/Wallet/PaymentMethodList.tsx" "@typescript-eslint/no-unsafe-type-assertion" 7 "../../src/pages/settings/Wallet/PersonalCardDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/pages/settings/Wallet/PersonalCardDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/settings/Wallet/PersonalCardEditNamePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/settings/Wallet/PersonalCards/FixPersonalCardConnectionPage/useFixPersonalCardConnection.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/settings/Wallet/PersonalCards/steps/SelectCountryStep.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/settings/Wallet/PersonalCards/steps/SelectCountryStep.tsx" "react-hooks/set-state-in-effect" 1 @@ -1077,6 +1250,7 @@ "../../src/pages/settings/Wallet/WalletPage/index.tsx" "react-hooks/set-state-in-effect" 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/Share/SubmitDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/ShareCodePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/signin/SAMLSignInPage/index.native.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/signin/SignInPage.tsx" "react-hooks/set-state-in-effect" 1 @@ -1086,6 +1260,8 @@ "../../src/pages/signin/SignInPageLayout/SignInPageContent.tsx" "rulesdir/no-raw-typography" 2 "../../src/pages/signin/SMSDeliveryFailurePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx" "react-hooks/set-state-in-effect" 4 +"../../src/pages/tasks/DynamicNewTaskDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/tasks/DynamicNewTaskPage.tsx" "rulesdir/no-direct-personal-details-list" 2 "../../src/pages/tasks/DynamicTaskShareDestinationSelectorModal.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/TeachersUnite/SaveTheWorldPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1095,10 +1271,13 @@ "../../src/pages/TransactionDuplicate/DynamicConfirmationPage.tsx" "react-hooks/refs" 12 "../../src/pages/TransactionDuplicate/ReviewFields.tsx" "@typescript-eslint/no-deprecated/fontSize" 1 "../../src/pages/TransactionMerge/DynamicConfirmationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/TransactionMerge/DynamicConfirmationPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/TransactionMerge/DynamicDetailsReviewPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/TransactionMerge/MergeTransactionItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/TransactionMerge/MergeTransactionsListContent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/TransactionMerge/MergeTransactionsListContent.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/Travel/DynamicTravelUpgrade.tsx" "no-restricted-imports" 1 +"../../src/pages/Travel/DynamicTripDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/Travel/DynamicWorkspaceConfirmationForTravelPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/UnreportedExpenseListItem.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/ValidateLoginPage/index.web.tsx" "react-hooks/set-state-in-effect" 1 @@ -1193,8 +1372,10 @@ "../../src/pages/workspace/categories/CategorySettingsPage.tsx" "react-hooks/preserve-manual-memoization" 1 "../../src/pages/workspace/categories/WorkspaceCategoriesPage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/workspace/companyCards/addNew/SelectCountryStep.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/companyCards/assignCard/AssigneeStep.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/companyCards/BankConnection/index.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/companyCards/WorkspaceCompanyCardAddWorkEmailPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/companyCards/WorkspaceCompanyCardEditTransactionStartDatePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 @@ -1202,16 +1383,23 @@ "../../src/pages/workspace/companyCards/WorkspaceCompanyCardsSettingsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/companyCards/WorkspaceVerifyWorkAccountPage.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/workspace/copyPolicySettings/CopyPolicySettingsSelectFeaturesPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/workspace/deleteWorkspace/DeleteWorkspaceFlow.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx" "react-hooks/preserve-manual-memoization" 2 "../../src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/DynamicWorkspaceConfirmationPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 +"../../src/pages/workspace/DynamicWorkspaceInvitePage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/DynamicWorkspaceOverviewPlanTypePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/DynamicWorkspaceOverviewPlanTypePage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/workspace/expensifyCard/DynamicExpensifyCardLimitTypePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/expensifyCard/DynamicWorkspaceExpensifyCardDetailsPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/expensifyCard/DynamicWorkspaceSettlementAccountPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 +"../../src/pages/workspace/expensifyCard/issueNew/AssigneeStep.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/expensifyCard/issueNew/LimitTypeStep.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/expensifyCard/issueNew/spendRules/SetSpendRulesStep.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/hr/utils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/invoices/WorkspaceInvoiceVBASection.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/members/DynamicWorkspaceOwnerChangeErrorPage.tsx" "react-hooks/refs" 2 @@ -1222,12 +1410,15 @@ "../../src/pages/workspace/members/ImportMembersPage.tsx" "rulesdir/no-default-id-values" 1 "../../src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx" "react-hooks/set-state-in-effect" 1 +"../../src/pages/workspace/members/WorkspaceInviteMessageComponent.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4 "../../src/pages/workspace/members/WorkspaceOwnerChangeCheck.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/workspace/members/WorkspaceOwnerPaymentCardForm.tsx" "react-hooks/set-state-in-effect" 2 "../../src/pages/workspace/receiptPartners/DynamicEditInviteReceiptPartnerPolicyPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/receiptPartners/WorkspaceReceiptPartnersPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/reports/TypeSelector/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/rules/SpendRules/SpendRuleCardPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/workspace/rules/SpendRules/SpendRulePageBase.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/tags/WorkspaceTagsPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/workspace/tags/WorkspaceTagsPage.tsx" "react-hooks/set-state-in-effect" 1 "../../src/pages/workspace/taxes/WorkspaceTaxesPage.tsx" "react-hooks/set-state-in-effect" 1 @@ -1236,7 +1427,11 @@ "../../src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx" "no-restricted-imports" 1 "../../src/pages/workspace/withPolicy.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3 "../../src/pages/workspace/withPolicyAndFullscreenLoading.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/withPolicyAndFullscreenLoading.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/withPolicyConnections.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/workflows/approvals/DynamicWorkspaceWorkflowsApprovalsExpensesFromPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx" "rulesdir/no-direct-personal-details-list" 1 +"../../src/pages/workspace/workflows/tabs/WorkflowsApprovalsTab.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/pages/workspace/workflows/tabs/WorkflowsPaymentsTab.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 @@ -1247,6 +1442,7 @@ "../../src/pages/workspace/WorkspaceOverviewCurrencyPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/pages/workspace/WorkspaceOverviewPage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/pages/workspace/WorkspaceOverviewSharePage.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 +"../../src/pages/workspace/WorkspacesListPage.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/polyfills/requestIdleCallback.ts" "@typescript-eslint/no-unsafe-type-assertion" 2 "../../src/ROUTES.ts" "@typescript-eslint/no-deprecated/getUrlWithBackToParam" 52 "../../src/ROUTES.ts" "@typescript-eslint/no-unsafe-type-assertion" 3 @@ -1261,6 +1457,7 @@ "../../src/stories/DragAndDrop.stories.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/stories/EReceipt.stories.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1 "../../src/stories/Form.stories.tsx" "@typescript-eslint/no-unsafe-type-assertion" 10 +"../../src/stories/MenuItemComparison.stories.tsx" "rulesdir/no-direct-personal-details-list" 1 "../../src/stories/ReportActionItemImages.stories.tsx" "no-restricted-syntax" 1 "../../src/stories/TextInput.stories.tsx" "react-hooks/set-state-in-effect" 1 "../../src/styles/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 1 diff --git a/cspell.json b/cspell.json index f41de7c5f970..f49f431b9d67 100644 --- a/cspell.json +++ b/cspell.json @@ -920,6 +920,7 @@ "QAPR", "QBWC", "qrcode", + "quasis", "quotepath", "rach", "reactnative", diff --git a/eslint-plugin-local-rules/no-direct-personal-details-list.js b/eslint-plugin-local-rules/no-direct-personal-details-list.js new file mode 100644 index 000000000000..e7798f05a117 --- /dev/null +++ b/eslint-plugin-local-rules/no-direct-personal-details-list.js @@ -0,0 +1,61 @@ +const name = 'no-direct-personal-details-list'; + +const meta = { + type: 'problem', + docs: { + description: + 'Disallow direct use of `ONYXKEYS.PERSONAL_DETAILS_LIST`. Personal details are being reshaped into an Onyx collection, so access has to go through a wrapper that can absorb the change.', + recommended: 'error', + }, + schema: [], + messages: { + directUsage: + '`ONYXKEYS.PERSONAL_DETAILS_LIST` is migrating to an Onyx collection, so do not reference it directly. In React use @hooks/usePersonalDetails, outside React use @libs/PersonalDetailsStore, and for writes use `buildPersonalDetailsUpdate` from @libs/PersonalDetailsUtils.', + }, +}; + +const ONYXKEYS_IDENTIFIER = 'ONYXKEYS'; +const PERSONAL_DETAILS_LIST_PROPERTY = 'PERSONAL_DETAILS_LIST'; + +/** + * Resolves the property name of a member expression when it is statically known, so `ONYXKEYS.PERSONAL_DETAILS_LIST`, + * `ONYXKEYS['PERSONAL_DETAILS_LIST']` and ``ONYXKEYS[`PERSONAL_DETAILS_LIST`]`` are all treated as the same access. + * A computed access through a variable stays unresolved, because its value is only known at runtime. + * + * @param {import('estree').MemberExpression} node + * @returns {string | undefined} + */ +function getStaticPropertyName(node) { + if (!node.computed) { + return node.property.type === 'Identifier' ? node.property.name : undefined; + } + if (node.property.type === 'Literal') { + return typeof node.property.value === 'string' ? node.property.value : undefined; + } + if (node.property.type === 'TemplateLiteral' && node.property.expressions.length === 0 && node.property.quasis.length === 1) { + return node.property.quasis[0].value.cooked; + } + return undefined; +} + +/** + * @param {import('eslint').Rule.RuleContext} context + * @returns {import('eslint').Rule.RuleListener} + */ +function create(context) { + return { + // Type positions parse as TSTypeQuery, not MemberExpression, so `typeof ONYXKEYS.PERSONAL_DETAILS_LIST` + // is allowed: it neither reads nor writes, and it follows the key definition when that is reshaped. + MemberExpression(node) { + if (node.object.type !== 'Identifier' || node.object.name !== ONYXKEYS_IDENTIFIER) { + return; + } + if (getStaticPropertyName(node) !== PERSONAL_DETAILS_LIST_PROPERTY) { + return; + } + context.report({node, messageId: 'directUsage'}); + }, + }; +} + +export {name, meta, create}; diff --git a/knip.json b/knip.json index 1f84a7fa0b71..3192b63a8934 100644 --- a/knip.json +++ b/knip.json @@ -1,4 +1,9 @@ { + "ignoreIssues": { + "src/hooks/usePersonalDetails.ts": ["files"], + "src/libs/PersonalDetailsStore.ts": ["exports"], + "src/libs/PersonalDetailsUtils.ts": ["exports"] + }, "workspaces": { ".": { "entry": [ diff --git a/src/hooks/usePersonalDetails.ts b/src/hooks/usePersonalDetails.ts new file mode 100644 index 000000000000..f122f338b29f --- /dev/null +++ b/src/hooks/usePersonalDetails.ts @@ -0,0 +1,25 @@ +/** Personal details reads for components, so nothing touches PERSONAL_DETAILS_LIST directly */ +import ONYXKEYS from '@src/ONYXKEYS'; +import {personalDetailsListSelector, personalDetailsSelector} from '@src/selectors/PersonalDetails'; +import type {PersonalDetails, PersonalDetailsList} from '@src/types/onyx'; + +import type {UseOnyxResult} from 'react-native-onyx'; + +import useOnyx from './useOnyx'; + +function usePersonalDetail(accountID: number | undefined): UseOnyxResult { + return useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsSelector(accountID)}); +} + +function usePersonalDetailsByIDs(accountIDs: Array | undefined): UseOnyxResult { + return useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsListSelector(accountIDs)}); +} + +// Re-renders on any account change, prefer usePersonalDetail/usePersonalDetailsByIDs when the accounts are known +function useAllPersonalDetails(): UseOnyxResult; +function useAllPersonalDetails(selector: (value: PersonalDetailsList | undefined) => TReturn): UseOnyxResult; +function useAllPersonalDetails(selector?: (value: PersonalDetailsList | undefined) => TReturn) { + return useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector}); +} + +export {usePersonalDetail, usePersonalDetailsByIDs, useAllPersonalDetails}; diff --git a/src/libs/PersonalDetailsStore.ts b/src/libs/PersonalDetailsStore.ts new file mode 100644 index 000000000000..ae0896e89190 --- /dev/null +++ b/src/libs/PersonalDetailsStore.ts @@ -0,0 +1,49 @@ +/** Personal details for non-React callers, and the one place the coming Onyx-collection reshape has to land */ +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PersonalDetails, PersonalDetailsList} from '@src/types/onyx'; + +import Onyx from 'react-native-onyx'; + +let allPersonalDetails: PersonalDetailsList = {}; +let loginToPersonalDetails: Record = {}; + +function buildLoginMapping(personalDetailsList: PersonalDetailsList): Record { + const mapping: Record = {}; + for (const personalDetail of Object.values(personalDetailsList)) { + if (!personalDetail?.login) { + continue; + } + const login = personalDetail.login.toLowerCase(); + const existing = mapping[login]; + if (!existing || existing.isClosed || existing.isOptimisticPersonalDetail) { + mapping[login] = personalDetail; + } + } + return mapping; +} + +// Only sanctioned connectWithoutView for personal details, don't add another: React uses @hooks/usePersonalDetails, everything else uses this store +Onyx.connectWithoutView({ + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + callback: (value) => { + allPersonalDetails = value ?? {}; + loginToPersonalDetails = buildLoginMapping(allPersonalDetails); + }, +}); + +function getAllPersonalDetails(): PersonalDetailsList { + return allPersonalDetails; +} + +function getPersonalDetail(accountID: number | undefined): PersonalDetails | undefined { + return accountID ? (allPersonalDetails[accountID] ?? undefined) : undefined; +} + +function getPersonalDetailByLogin(login: string | undefined): PersonalDetails | undefined { + if (!login) { + return undefined; + } + return loginToPersonalDetails[login.toLowerCase()]; +} + +export {getAllPersonalDetails, getPersonalDetail, getPersonalDetailByLogin}; diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 0c61943ecc1c..71434f65e7c6 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -9,7 +9,7 @@ import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import type {OnyxData} from '@src/types/onyx/Request'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; +import type {OnyxEntry, OnyxMergeInput, OnyxUpdate} from 'react-native-onyx'; import type {SetNonNullable} from 'type-fest'; import {Str} from 'expensify-common'; @@ -18,6 +18,7 @@ import Onyx from 'react-native-onyx'; import {getCountryCode} from './CountryUtils'; import {translateLocal} from './Localize'; import {areEmailsFromSamePrivateDomain} from './LoginUtils'; +import {getPersonalDetailByLogin} from './PersonalDetailsStore'; import {addSMSDomainIfPhoneNumber, parsePhoneNumber} from './PhoneNumber'; import {getDefaultAvatarURL} from './UserAvatarUtils'; import {generateAccountID} from './UserUtils'; @@ -27,24 +28,6 @@ type FirstAndLastName = { lastName: string; }; -let emailToPersonalDetailsCache: Record = {}; -Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - callback: (val) => { - const personalDetails = Object.values(val ?? {}); - emailToPersonalDetailsCache = personalDetails.reduce((acc: Record, detail) => { - if (detail?.login) { - const key = detail.login.toLowerCase(); - const existing = acc[key]; - if (!existing || existing.isClosed || existing.isOptimisticPersonalDetail) { - acc[key] = detail; - } - } - return acc; - }, {}); - }, -}); - let hiddenTranslation = ''; let youTranslation = ''; @@ -264,10 +247,7 @@ function getDisplayNameOrYou(displayName: string, accountID: number, currentUser } function getPersonalDetailByEmail(email: string | undefined): PersonalDetails | undefined { - if (!email) { - return undefined; - } - return emailToPersonalDetailsCache[email.toLowerCase()]; + return getPersonalDetailByLogin(email); } /** @@ -337,6 +317,17 @@ function getNewAccountIDsAndLogins(invitedEmailsToAccountIDs: InvitedEmailsToAcc ); } +type PersonalDetailsUpdate = OnyxMergeInput; + +// All writes are merges, and the builder is what turns one list update into one update per account after the reshape +function buildPersonalDetailsUpdate(personalDetails: PersonalDetailsUpdate): OnyxUpdate { + return { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: personalDetails, + }; +} + /** * Given a list of logins and accountIDs, return Onyx data for users with no existing personal details stored. These users might be brand new or unknown. * They will have an "optimistic" accountID that must be cleaned up later. @@ -637,4 +628,5 @@ export { areAddressAndPersonalDetailsMissing, areTravelPersonalDetailsMissing, temporaryGetDisplayNameOrDefault, + buildPersonalDetailsUpdate, }; diff --git a/tests/unit/NoDirectPersonalDetailsListRuleTest.ts b/tests/unit/NoDirectPersonalDetailsListRuleTest.ts new file mode 100644 index 000000000000..4763d024c0ab --- /dev/null +++ b/tests/unit/NoDirectPersonalDetailsListRuleTest.ts @@ -0,0 +1,96 @@ +import type {Rule} from 'eslint'; + +import {RuleTester} from 'eslint'; +import {parser as tsParser} from 'typescript-eslint'; + +type LocalRuleModule = Rule.RuleModule & { + name: string; +}; + +function isLocalRuleModule(ruleModule: unknown): ruleModule is LocalRuleModule { + if (typeof ruleModule !== 'object' || ruleModule === null) { + return false; + } + + const ruleName: unknown = Reflect.get(ruleModule, 'name'); + const create: unknown = Reflect.get(ruleModule, 'create'); + const meta: unknown = Reflect.get(ruleModule, 'meta'); + + return typeof ruleName === 'string' && typeof create === 'function' && typeof meta === 'object' && meta !== null; +} + +const ruleModule: unknown = require('../../eslint-plugin-local-rules/no-direct-personal-details-list'); + +if (!isLocalRuleModule(ruleModule)) { + throw new TypeError('Expected no-direct-personal-details-list to export an ESLint rule module.'); +} + +const tsRuleTester = new RuleTester({ + languageOptions: { + ecmaVersion: 2022, + sourceType: 'module', + parser: tsParser, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, +}); + +describe('no-direct-personal-details-list', () => { + tsRuleTester.run(ruleModule.name, ruleModule, { + valid: [ + 'const [personalDetail] = usePersonalDetail(accountID);', + 'const [personalDetails] = usePersonalDetailsByIDs(accountIDs);', + 'const personalDetail = getPersonalDetail(accountID);', + // Type positions parse as TSTypeQuery, not MemberExpression. + 'type Update = OnyxUpdate;', + 'type Data = Partial>;', + 'const [metadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_METADATA);', + 'const [list] = useOnyx(ONYXKEYS.COLLECTION.REPORT);', + 'const key = SOME_OTHER_KEYS.PERSONAL_DETAILS_LIST;', + // Only known at runtime, so there is nothing to resolve statically. + 'const key = ONYXKEYS[PERSONAL_DETAILS_LIST];', + ], + invalid: [ + { + code: 'const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);', + errors: [{messageId: 'directUsage'}], + }, + { + code: 'const [login] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {selector: personalDetailsLoginSelector(accountID)});', + errors: [{messageId: 'directUsage'}], + }, + { + code: "const [personalDetails] = useOnyx(ONYXKEYS['PERSONAL_DETAILS_LIST']);", + errors: [{messageId: 'directUsage'}], + }, + { + code: 'const [personalDetails] = useOnyx(ONYXKEYS[`PERSONAL_DETAILS_LIST`]);', + errors: [{messageId: 'directUsage'}], + }, + { + code: 'Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {[accountID]: null});', + errors: [{messageId: 'directUsage'}], + }, + { + code: 'const update = {onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: personalDetails};', + errors: [{messageId: 'directUsage'}], + }, + { + code: 'Onyx.connectWithoutView({key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (value) => value});', + errors: [{messageId: 'directUsage'}], + }, + { + code: 'const masks = {[ONYXKEYS.PERSONAL_DETAILS_LIST]: {allowList: []}};', + errors: [{messageId: 'directUsage'}], + }, + { + // Reported per usage, so the seatbelt count is per usage too. + code: 'const [all] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {});', + errors: [{messageId: 'directUsage'}, {messageId: 'directUsage'}], + }, + ], + }); +});