From 8769b23b2e3b57ef02f8aea1038477d2439a066b Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 10 Apr 2025 17:40:32 +0300 Subject: [PATCH 1/2] Enhance Search and Report Components with Policy Integration - Added `useOnyx` hook to fetch policies in `SearchList` and passed it to relevant components. - Updated `ChatListItem`, `PureReportActionItem`, and `ReportActionItemSingle` to accept and utilize policies prop. - Modified type definitions to include policies for better type safety and clarity. --- src/components/Search/SearchList.tsx | 19 ++++++++++++++++++- src/components/SelectionList/ChatListItem.tsx | 2 ++ src/components/SelectionList/types.ts | 5 +++++ .../home/report/PureReportActionItem.tsx | 7 ++++++- .../home/report/ReportActionItemSingle.tsx | 15 ++++++++++----- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/components/Search/SearchList.tsx b/src/components/Search/SearchList.tsx index 3808c13253f7..cdafe5dd3e8c 100644 --- a/src/components/Search/SearchList.tsx +++ b/src/components/Search/SearchList.tsx @@ -3,6 +3,7 @@ import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, import type {ForwardedRef} from 'react'; import {View} from 'react-native'; import type {FlatList, ListRenderItemInfo, NativeSyntheticEvent, StyleProp, ViewStyle, ViewToken} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import Animated from 'react-native-reanimated'; import type {FlatListPropsWithLayout} from 'react-native-reanimated'; import Checkbox from '@components/Checkbox'; @@ -28,6 +29,7 @@ import {isMobileChrome} from '@libs/Browser'; import {addKeyDownPressListener, removeKeyDownPressListener} from '@libs/KeyboardShortcut/KeyDownPressListener'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; type SearchListItem = TransactionListItemType | ReportListItemType | ReportActionListItemType; type SearchListItemComponentType = typeof TransactionListItem | typeof ChatListItem | typeof ReportListItem; @@ -120,6 +122,8 @@ function SearchList( // Keep track of the number of selected items to determine if we should turn off selection mode const selectionRef = useRef(0); + const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + useEffect(() => { selectionRef.current = selectedItemsLength; @@ -299,10 +303,23 @@ function SearchList( }} shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow} queryJSONHash={queryJSONHash} + policies={policies} /> ); }, - [ListItem, canSelectMultiple, focusedIndex, handleLongPressRow, itemsToHighlight, onCheckboxPress, onSelectRow, queryJSONHash, setFocusedIndex, shouldPreventDefaultFocusOnSelectRow], + [ + ListItem, + canSelectMultiple, + focusedIndex, + handleLongPressRow, + itemsToHighlight, + onCheckboxPress, + onSelectRow, + policies, + queryJSONHash, + setFocusedIndex, + shouldPreventDefaultFocusOnSelectRow, + ], ); return ( diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 634b34897311..2bec4ab0f2a5 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -22,6 +22,7 @@ function ChatListItem({ onFocus, onLongPressRow, shouldSyncFocus, + policies, }: ChatListItemProps) { const reportActionItem = item as unknown as ReportActionListItemType; const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportActionItem?.reportID ?? CONST.DEFAULT_NUMBER_ID}`); @@ -87,6 +88,7 @@ function ChatListItem({ CONST.REPORT.ACTIONS.TYPE.FORWARDED, ].some((type) => type === reportActionItem.actionName) } + policies={policies} /> ); diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 7e80c5ebebe5..e9272453c23a 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -12,6 +12,7 @@ import type { TextStyle, ViewStyle, } from 'react-native'; +import type {OnyxCollection} from 'react-native-onyx'; import type {AnimatedStyle} from 'react-native-reanimated'; import type {SearchRouterItem} from '@components/Search/SearchAutocompleteList'; import type {SearchColumnType} from '@components/Search/types'; @@ -19,6 +20,7 @@ import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; // eslint-disable-next-line no-restricted-imports import type CursorStyles from '@styles/utils/cursor/types'; import type CONST from '@src/CONST'; +import type {Policy} from '@src/types/onyx'; import type {Attendee} from '@src/types/onyx/IOU'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {SearchPersonalDetails, SearchReport, SearchReportAction, SearchTransaction} from '@src/types/onyx/SearchResults'; @@ -362,6 +364,9 @@ type ReportListItemProps = ListItemProps & { type ChatListItemProps = ListItemProps & { queryJSONHash?: number; + + /** The policies which the user has access to */ + policies: OnyxCollection; }; type ValidListItem = diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index b9e74bfc4ac8..9d63e67f03c6 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -3,7 +3,7 @@ import mapValues from 'lodash/mapValues'; import React, {memo, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'; import type {GestureResponderEvent, TextInput} from 'react-native'; import {InteractionManager, Keyboard, View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type {Emoji} from '@assets/emojis/types'; import {AttachmentContext} from '@components/AttachmentContext'; @@ -326,6 +326,9 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; + + /** Policies */ + policies?: OnyxCollection; }; // This is equivalent to returning a negative boolean in normal functions, but we can keep the element return type @@ -397,6 +400,7 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, + policies, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -1199,6 +1203,7 @@ function PureReportActionItem({ hasBeenFlagged={ ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && !isPendingRemove(action) } + policies={policies} > {content} diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 8cac03f609e3..e889099a6313 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -1,7 +1,7 @@ import React, {useCallback, useMemo} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; @@ -39,7 +39,7 @@ import { import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Report, ReportAction} from '@src/types/onyx'; +import type {Policy, Report, ReportAction} from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; @@ -72,6 +72,9 @@ type ReportActionItemSingleProps = Partial & { /** If the action is being actived */ isActive?: boolean; + + /** Policies */ + policies?: OnyxCollection; }; const showUserDetails = (accountID: number | undefined) => { @@ -96,6 +99,7 @@ function ReportActionItemSingle({ iouReport, isHovered = false, isActive = false, + policies, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -107,9 +111,10 @@ function ReportActionItemSingle({ const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; const actorAccountID = getReportActionActorAccountID(action, iouReport, report, delegatePersonalDetails); - const [invoiceReceiverPolicy] = useOnyx( - `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, - ); + const invoiceReceiverPolicy = + report?.invoiceReceiver && 'policyID' in report.invoiceReceiver + ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiver.policyID}`] + : policies?.[`${ONYXKEYS.COLLECTION.POLICY}${CONST.DEFAULT_NUMBER_ID}`]; let displayName = getDisplayNameForParticipant({accountID: actorAccountID, personalDetailsData: personalDetails}); const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {}; From cd79248833b80a3773a4cfe8982461091127ebcd Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 11 Apr 2025 12:01:32 +0300 Subject: [PATCH 2/2] Update ChatListItemProps to make policies optional --- src/components/SelectionList/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index e9272453c23a..f02e804c15cd 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -366,7 +366,7 @@ type ChatListItemProps = ListItemProps & { queryJSONHash?: number; /** The policies which the user has access to */ - policies: OnyxCollection; + policies?: OnyxCollection; }; type ValidListItem =