diff --git a/src/components/Search/SearchList.tsx b/src/components/Search/SearchList.tsx index 2033aa44b83f..e9dd032cfdaf 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; @@ -125,6 +127,10 @@ 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, { + canBeMissing: true, + }); + useEffect(() => { selectionRef.current = selectedItemsLength; @@ -311,10 +317,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..8db07b2a89b7 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -22,9 +22,13 @@ 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}`); + const reportID = Number(reportActionItem?.reportID ?? CONST.DEFAULT_NUMBER_ID); + const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { + canBeMissing: true, + }); const styles = useThemeStyles(); const theme = useTheme(); const animatedHighlightStyle = useAnimatedHighlightStyle({ @@ -87,6 +91,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 8cafec56adc3..3d48880c6755 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'; @@ -365,6 +367,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 f7939dc6cfb4..13f555a86761 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'; @@ -333,6 +333,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 @@ -392,6 +395,7 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, + policies, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -1227,6 +1231,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..c99ead1a2e44 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,20 +99,26 @@ function ReportActionItemSingle({ iouReport, isHovered = false, isActive = false, + policies, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, { + canBeMissing: true, + }); + const [innerPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { + canBeMissing: true, + }); + const activePolicies = policies ?? innerPolicies; const policy = usePolicy(report?.policyID); const delegatePersonalDetails = action?.delegateAccountID ? personalDetails?.[action?.delegateAccountID] : undefined; 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 ? activePolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiver.policyID}`] : undefined; let displayName = getDisplayNameForParticipant({accountID: actorAccountID, personalDetailsData: personalDetails}); const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {};