From eea04210ea4c1b1e8dfbf2828b1f69d3f319b71b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 23 Nov 2024 10:11:23 +0700 Subject: [PATCH 01/94] WIP use PureReportActionItem in ChatListItem --- src/components/SelectionList/ChatListItem.tsx | 107 ++++++++++-------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index a3e04c9088f1..630eb33fa597 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -8,9 +8,11 @@ import TextWithTooltip from '@components/TextWithTooltip'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import PureReportActionItem from '@pages/home/report/PureReportActionItem'; import ReportActionItemDate from '@pages/home/report/ReportActionItemDate'; import ReportActionItemFragment from '@pages/home/report/ReportActionItemFragment'; import CONST from '@src/CONST'; +import type * as OnyxTypes from '@src/types/onyx'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; @@ -61,7 +63,7 @@ function ChatListItem({ ({ hoverStyle={item.isSelected && styles.activeComponentBG} > {(hovered) => ( - - - - - - - - - - - - - {reportActionItem.message.map((fragment, index) => ( - - ))} - - - - - + onSelectRow(item)} + report={undefined} + reportActions={[]} + parentReportAction={undefined} + displayAsGroup={false} + isMostRecentIOUReportAction={false} + shouldDisplayNewMarker={false} + index={item.index ?? 0} + isFirstVisibleReportAction={false} + /> + + // + // + // + // + // + // + // + // + // + // + // + // + // {reportActionItem.message.map((fragment, index) => ( + // + // ))} + // + // + // + // + // )} ); From 639b4135d776330eaf3ed8d452a205a5d85be749 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 17 Dec 2024 09:20:48 +0700 Subject: [PATCH 02/94] Pass personalDetails to ReportActionItemSingle --- src/components/SelectionList/ChatListItem.tsx | 11 +++++- src/libs/ReportUtils.ts | 2 +- .../home/report/PureReportActionItem.tsx | 4 ++- .../home/report/ReportActionItemSingle.tsx | 34 ++++++++++++++----- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 0c5930193857..30ce2c664893 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -17,6 +17,7 @@ import CONST from '@src/CONST'; import type * as OnyxTypes from '@src/types/onyx'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; +import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; function ChatListItem({ item, @@ -76,11 +77,18 @@ function ChatListItem({ styles.mh0, item.cursorStyle, ]; + + const personalDetails: Record = { + [from.accountID]: from, + } + return ( ({ shouldDisplayNewMarker={false} index={item.index ?? 0} isFirstVisibleReportAction={false} + personalDetails={personalDetails} /> // diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index eb728586f8f2..fda62470c0c2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -54,7 +54,7 @@ import type {Status} from '@src/types/onyx/PersonalDetails'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction'; -import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; +import type {SearchPolicy, SearchReport, SearchReportAction, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 34dd2a9d1350..2314829a316e 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -81,6 +81,7 @@ import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import ReportAttachmentsContext from './ReportAttachmentsContext'; +import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; type PureReportActionItemProps = { /** Report for this action */ @@ -164,7 +165,7 @@ type PureReportActionItemProps = { parentReport?: OnyxTypes.Report; /** Personal details list */ - personalDetails?: OnyxTypes.PersonalDetailsList; + personalDetails?: OnyxTypes.PersonalDetailsList | Record; /** Whether or not the user is blocked from concierge */ blockedFromConcierge?: OnyxTypes.BlockedFromConcierge; @@ -999,6 +1000,7 @@ function PureReportActionItem({ ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && !ReportActionsUtils.isPendingRemove(action) } + personalDetails={personalDetails} > {content} diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 7c42991d2852..1b44a6ee3033 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -28,10 +28,15 @@ 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 {Icon} from '@src/types/onyx/OnyxCommon'; +import type {Icon, PendingAction, PendingFields} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; +import type * as OnyxTypes from '@src/types/onyx'; +import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; +import { Status } from '@src/types/onyx/PersonalDetails'; +import { AvatarSource } from '@libs/UserUtils'; + type ReportActionItemSingleProps = Partial & { /** All the data of the action */ @@ -57,6 +62,9 @@ type ReportActionItemSingleProps = Partial & { /** If the action is being hovered */ isHovered?: boolean; + + /** Personal details list */ + personalDetails?: OnyxTypes.PersonalDetailsList | Record; }; const showUserDetails = (accountID: string) => { @@ -77,12 +85,12 @@ function ReportActionItemSingle({ report, iouReport, isHovered = false, + personalDetails, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const personalDetails = usePersonalDetails(); const policy = usePolicy(report?.policyID); const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; @@ -91,7 +99,14 @@ function ReportActionItemSingle({ const [invoiceReceiverPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : -1}`); let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); - const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails?.[actorAccountID ?? -1] ?? {}; + const {avatar, login} = personalDetails?.[actorAccountID ?? -1] ?? {}; + console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ actorAccountID:", actorAccountID) + console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ personalDetails:", personalDetails) + console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ avatar:", avatar) + const pendingFields = personalDetails && 'pendingFields' in personalDetails ? personalDetails.pendingFields : undefined; + const status = personalDetails && 'status' in personalDetails ? personalDetails.status : undefined; + const fallbackIcon = personalDetails && 'fallbackIcon' in personalDetails && personalDetails.fallbackIcon !== null ? personalDetails.fallbackIcon : undefined; + const accountOwnerDetails = getPersonalDetailByEmail(login ?? ''); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing let actorHint = (login || (displayName ?? '')).replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); @@ -237,17 +252,18 @@ function ReportActionItemSingle({ type={icon.type} name={icon.name} avatarID={icon.id} - fallbackIcon={fallbackIcon} + fallbackIcon={fallbackIcon as AvatarSource} /> ); }; - const hasEmojiStatus = !displayAllActors && status?.emojiCode; - const formattedDate = DateUtils.getStatusUntilDate(status?.clearAfter ?? ''); - const statusText = status?.text ?? ''; + const hasEmojiStatus = !displayAllActors && status && 'emojiCode' in status && status?.emojiCode; + const statusClearAfter = status && 'clearAfter' in status ? (String(status?.clearAfter) ?? '') : ''; + const formattedDate = DateUtils.getStatusUntilDate(statusClearAfter); + const statusText = status && 'text' in status ? String(status?.text) ?? '' : ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; - + // const pendingFieldsAvatar = pendingFields && 'avatar' in pendingFields ? pendingFields?.avatar ?? undefined : undefined; return ( - {getAvatar()} + {getAvatar()} {showHeader ? ( From 7dc43b4cc3223f0eca72ba53bc264b21c05293cd Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 17 Dec 2024 15:55:34 +0700 Subject: [PATCH 03/94] WIP, override contextvalue from search page --- src/components/Search/index.tsx | 1 + src/components/SelectionList/ChatListItem.tsx | 11 +++++- src/components/ShowContextMenuContext.ts | 8 ++--- .../home/report/PureReportActionItem.tsx | 35 +++++++++++++++---- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 4c08c477f29d..c08f925adfc7 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -136,6 +136,7 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`); const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); + console.log("[wildebug] ~ file: index.tsx:139 ~ Search ~ hash:", hash) const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); const previousReportActions = usePrevious(reportActions); diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 30ce2c664893..8c1a68a8dfc9 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -17,7 +17,9 @@ import CONST from '@src/CONST'; import type * as OnyxTypes from '@src/types/onyx'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; -import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; +import { SearchPersonalDetails, SearchReport } from '@src/types/onyx/SearchResults'; +import { useOnyx } from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; function ChatListItem({ item, @@ -61,6 +63,7 @@ function ChatListItem({ const hoveredBackgroundColor = styles.sidebarLinkHover?.backgroundColor ? styles.sidebarLinkHover.backgroundColor : theme.sidebar; const mentionReportContextValue = useMemo(() => ({currentReportID: item?.reportID ?? '-1'}), [item.reportID]); + const animatedHighlightStyle = useAnimatedHighlightStyle({ borderRadius: variables.componentBorderRadius, shouldHighlight: item?.shouldAnimateInHighlight ?? false, @@ -82,6 +85,8 @@ function ChatListItem({ [from.accountID]: from, } + const [reportOnyx, reportResult] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportActionItem.reportID}`, {allowStaleData: true}); + return ( ({ onSelectRow(item)} + // report={{reportID : reportActionItem.reportID} as OnyxTypes.Report} report={undefined} reportActions={[]} parentReportAction={undefined} @@ -118,6 +124,9 @@ function ChatListItem({ index={item.index ?? 0} isFirstVisibleReportAction={false} personalDetails={personalDetails} + contextValueOverride={contextValue} + attachmentContextValueOverride={attachmentContextValue} + mentionReportContextValueOverride={mentionReportContextValue} /> // diff --git a/src/components/ShowContextMenuContext.ts b/src/components/ShowContextMenuContext.ts index 6fefa987fac3..04c437165842 100644 --- a/src/components/ShowContextMenuContext.ts +++ b/src/components/ShowContextMenuContext.ts @@ -10,10 +10,10 @@ import CONST from '@src/CONST'; import type {Report, ReportAction, ReportNameValuePairs} from '@src/types/onyx'; type ShowContextMenuContextProps = { - anchor: ContextMenuAnchor; - report: OnyxEntry; - reportNameValuePairs: OnyxEntry; - action: OnyxEntry; + anchor?: ContextMenuAnchor; + report?: OnyxEntry; + reportNameValuePairs?: OnyxEntry; + action?: OnyxEntry; transactionThreadReport?: OnyxEntry; checkIfContextMenuActive: () => void; isDisabled: boolean; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 2314829a316e..8de1475c8c2b 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -28,7 +28,7 @@ import ReportPreview from '@components/ReportActionItem/ReportPreview'; import TaskAction from '@components/ReportActionItem/TaskAction'; import TaskPreview from '@components/ReportActionItem/TaskPreview'; import TripRoomPreview from '@components/ReportActionItem/TripRoomPreview'; -import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; +import {ShowContextMenuContext, ShowContextMenuContextProps} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; @@ -81,7 +81,7 @@ import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; +import { SearchPersonalDetails, SearchReport } from '@src/types/onyx/SearchResults'; type PureReportActionItemProps = { /** Report for this action */ @@ -241,6 +241,21 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; + + /** The context value containing the report and action data, along with the show context menu props */ + contextValueOverride?: ShowContextMenuContextProps & { + report?: OnyxTypes.Report; + action?: OnyxTypes.ReportAction; + }; + + attachmentContextValueOverride?: { + reportID?: string; + type: ValueOf; + } + + mentionReportContextValueOverride?: { + currentReportID: string; + } }; /** @@ -294,6 +309,9 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, + contextValueOverride, + attachmentContextValueOverride, + mentionReportContextValueOverride, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -505,10 +523,10 @@ function PureReportActionItem({ [reportID, action, emojiReactions, toggleEmojiReaction], ); - const contextValue = useMemo( + const contextValue = contextValueOverride ? contextValueOverride : useMemo( () => ({ anchor: popoverAnchorRef.current, - report: {...report, reportID: report?.reportID ?? ''}, + report: { ...report, reportID: report?.reportID ?? '' }, reportNameValuePairs, action, transactionThreadReport, @@ -518,9 +536,9 @@ function PureReportActionItem({ [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], ); - const attachmentContextValue = useMemo(() => ({reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [reportID]); + const attachmentContextValue = attachmentContextValueOverride ? attachmentContextValueOverride : useMemo(() => ({ reportID, type: CONST.ATTACHMENT_TYPE.REPORT }), [reportID]); - const mentionReportContextValue = useMemo(() => ({currentReportID: report?.reportID ?? '-1'}), [report?.reportID]); + const mentionReportContextValue = mentionReportContextValueOverride ? mentionReportContextValueOverride : useMemo(() => ({ currentReportID: report?.reportID ?? '-1' }), [report?.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { if (ReportActionsUtils.isActionableAddPaymentCard(action) && userBillingFundID === undefined && shouldRenderAddPaymentCard()) { @@ -1219,6 +1237,9 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => { prevProps.reimbursementDeQueuedActionMessage === nextProps.reimbursementDeQueuedActionMessage && prevProps.modifiedExpenseMessage === nextProps.modifiedExpenseMessage && prevProps.userBillingFundID === nextProps.userBillingFundID && - prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage + prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage && + prevProps.contextValueOverride === nextProps.contextValueOverride && + prevProps.attachmentContextValueOverride === nextProps.attachmentContextValueOverride && + prevProps.mentionReportContexValueOverride === nextProps.mentionReportContexValueOverride ); }); From 0d0c33a1caa19a9f969a2872c31768ed0024d52f Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 18 Dec 2024 07:05:48 +0700 Subject: [PATCH 04/94] WIP, adjust wrapper layout and memo condition --- src/components/SelectionList/ChatListItem.tsx | 1 + src/pages/home/report/PureReportActionItem.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 8c1a68a8dfc9..d3ca4fc852ca 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -72,6 +72,7 @@ function ChatListItem({ }); const pressableStyle = [ styles.selectionListPressableItemWrapper, + styles.p0, styles.textAlignLeft, styles.overflowHidden, // Removing background style because they are added to the parent OpacityView via animatedHighlightStyle diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 8de1475c8c2b..47a544acaedf 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -1240,6 +1240,6 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => { prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage && prevProps.contextValueOverride === nextProps.contextValueOverride && prevProps.attachmentContextValueOverride === nextProps.attachmentContextValueOverride && - prevProps.mentionReportContexValueOverride === nextProps.mentionReportContexValueOverride + prevProps.mentionReportContextValueOverride === nextProps.mentionReportContextValueOverride ); }); From 4e7018fa2fe58adf811268203e826c72dfe65460 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 18 Dec 2024 10:01:04 +0700 Subject: [PATCH 05/94] fill actorAccountID for search chatitemlist --- src/components/SelectionList/ChatListItem.tsx | 3 --- src/pages/home/report/ReportActionItemSingle.tsx | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index d3ca4fc852ca..5828013b3dc7 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -86,8 +86,6 @@ function ChatListItem({ [from.accountID]: from, } - const [reportOnyx, reportResult] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportActionItem.reportID}`, {allowStaleData: true}); - return ( ({ onSelectRow(item)} - // report={{reportID : reportActionItem.reportID} as OnyxTypes.Report} report={undefined} reportActions={[]} parentReportAction={undefined} diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 1b44a6ee3033..5e908c83477a 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -95,14 +95,12 @@ function ReportActionItemSingle({ const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; - const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport, report); + // fallback to action?.accountID to handle search result chat item + const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport, report) ?? action?.accountID; const [invoiceReceiverPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : -1}`); let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); const {avatar, login} = personalDetails?.[actorAccountID ?? -1] ?? {}; - console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ actorAccountID:", actorAccountID) - console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ personalDetails:", personalDetails) - console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:103 ~ avatar:", avatar) const pendingFields = personalDetails && 'pendingFields' in personalDetails ? personalDetails.pendingFields : undefined; const status = personalDetails && 'status' in personalDetails ? personalDetails.status : undefined; const fallbackIcon = personalDetails && 'fallbackIcon' in personalDetails && personalDetails.fallbackIcon !== null ? personalDetails.fallbackIcon : undefined; From 2e96dbe5e5f8ae910508d8a05d7fc0ffca3aba0b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 18 Dec 2024 10:57:52 +0700 Subject: [PATCH 06/94] Lint and prettier --- src/components/Search/index.tsx | 1 - src/components/SelectionList/ChatListItem.tsx | 113 ++++-------------- src/libs/ReportUtils.ts | 2 +- .../home/report/PureReportActionItem.tsx | 50 ++++---- .../home/report/ReportActionItemSingle.tsx | 16 +-- 5 files changed, 56 insertions(+), 126 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index c08f925adfc7..4c08c477f29d 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -136,7 +136,6 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`); const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); - console.log("[wildebug] ~ file: index.tsx:139 ~ Search ~ hash:", hash) const previousTransactions = usePrevious(transactions); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); const previousReportActions = usePrevious(reportActions); diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 5828013b3dc7..fc9edbda823d 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -1,25 +1,13 @@ import React, {useMemo} from 'react'; -import {View} from 'react-native'; -import {AttachmentContext} from '@components/AttachmentContext'; -import MentionReportContext from '@components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/MentionReportContext'; -import MultipleAvatars from '@components/MultipleAvatars'; -import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; -import TextWithTooltip from '@components/TextWithTooltip'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; -import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import PureReportActionItem from '@pages/home/report/PureReportActionItem'; -import ReportActionItemDate from '@pages/home/report/ReportActionItemDate'; -import ReportActionItemFragment from '@pages/home/report/ReportActionItemFragment'; import variables from '@styles/variables'; import CONST from '@src/CONST'; -import type * as OnyxTypes from '@src/types/onyx'; +import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; -import { SearchPersonalDetails, SearchReport } from '@src/types/onyx/SearchResults'; -import { useOnyx } from 'react-native-onyx'; -import ONYXKEYS from '@src/ONYXKEYS'; function ChatListItem({ item, @@ -35,17 +23,8 @@ function ChatListItem({ }: ChatListItemProps) { const reportActionItem = item as unknown as ReportActionListItemType; const from = reportActionItem.from; - const icons = [ - { - type: CONST.ICON_TYPE_AVATAR, - source: from.avatar, - name: reportActionItem.formattedFrom, - id: from.accountID, - }, - ]; const styles = useThemeStyles(); const theme = useTheme(); - const StyleUtils = useStyleUtils(); const attachmentContextValue = {type: CONST.ATTACHMENT_TYPE.SEARCH}; @@ -59,9 +38,6 @@ function ChatListItem({ isDisabled: true, }; - const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; - const hoveredBackgroundColor = styles.sidebarLinkHover?.backgroundColor ? styles.sidebarLinkHover.backgroundColor : theme.sidebar; - const mentionReportContextValue = useMemo(() => ({currentReportID: item?.reportID ?? '-1'}), [item.reportID]); const animatedHighlightStyle = useAnimatedHighlightStyle({ @@ -84,15 +60,13 @@ function ChatListItem({ const personalDetails: Record = { [from.accountID]: from, - } + }; return ( ({ pressableWrapperStyle={[styles.mh5, animatedHighlightStyle]} hoverStyle={item.isSelected && styles.activeComponentBG} > - {(hovered) => ( - onSelectRow(item)} - report={undefined} - reportActions={[]} - parentReportAction={undefined} - displayAsGroup={false} - isMostRecentIOUReportAction={false} - shouldDisplayNewMarker={false} - index={item.index ?? 0} - isFirstVisibleReportAction={false} - personalDetails={personalDetails} - contextValueOverride={contextValue} - attachmentContextValueOverride={attachmentContextValue} - mentionReportContextValueOverride={mentionReportContextValue} - /> - - // - // - // - // - // - // - // - // - // - // - // - // - // {reportActionItem.message.map((fragment, index) => ( - // - // ))} - // - // - // - // - // - )} + onSelectRow(item)} + report={undefined} + reportActions={[]} + parentReportAction={undefined} + displayAsGroup={false} + isMostRecentIOUReportAction={false} + shouldDisplayNewMarker={false} + index={item.index ?? 0} + isFirstVisibleReportAction={false} + personalDetails={personalDetails} + contextValueOverride={contextValue} + attachmentContextValueOverride={attachmentContextValue} + mentionReportContextValueOverride={mentionReportContextValue} + shouldDisplayContextMenu={false} + /> ); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index bcc9afca76d2..d2ec8fb3ac62 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -54,7 +54,7 @@ import type {Status} from '@src/types/onyx/PersonalDetails'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {NotificationPreference, Participants, PendingChatMember, Participant as ReportParticipant} from '@src/types/onyx/Report'; import type {Message, OldDotReportAction, ReportActions} from '@src/types/onyx/ReportAction'; -import type {SearchPolicy, SearchReport, SearchReportAction, SearchTransaction} from '@src/types/onyx/SearchResults'; +import type {SearchPolicy, SearchReport, SearchTransaction} from '@src/types/onyx/SearchResults'; import type {Comment, TransactionChanges, WaypointCollection} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 47a544acaedf..fe2cdca0eebd 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -28,7 +28,8 @@ import ReportPreview from '@components/ReportActionItem/ReportPreview'; import TaskAction from '@components/ReportActionItem/TaskAction'; import TaskPreview from '@components/ReportActionItem/TaskPreview'; import TripRoomPreview from '@components/ReportActionItem/TripRoomPreview'; -import {ShowContextMenuContext, ShowContextMenuContextProps} from '@components/ShowContextMenuContext'; +import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; +import type {ShowContextMenuContextProps} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; @@ -66,6 +67,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {JoinWorkspaceResolution} from '@src/types/onyx/OriginalMessage'; +import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions'; import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu'; @@ -81,7 +83,6 @@ import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import { SearchPersonalDetails, SearchReport } from '@src/types/onyx/SearchResults'; type PureReportActionItemProps = { /** Report for this action */ @@ -242,20 +243,22 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; - /** The context value containing the report and action data, along with the show context menu props */ + /** The context value containing the report and action data, along with the show context menu props */ contextValueOverride?: ShowContextMenuContextProps & { report?: OnyxTypes.Report; action?: OnyxTypes.ReportAction; }; + /** The context value containing the report ID and attachment type */ attachmentContextValueOverride?: { reportID?: string; type: ValueOf; - } + }; + /** The context value containing the current report ID */ mentionReportContextValueOverride?: { currentReportID: string; - } + }; }; /** @@ -523,22 +526,27 @@ function PureReportActionItem({ [reportID, action, emojiReactions, toggleEmojiReaction], ); - const contextValue = contextValueOverride ? contextValueOverride : useMemo( - () => ({ - anchor: popoverAnchorRef.current, - report: { ...report, reportID: report?.reportID ?? '' }, - reportNameValuePairs, - action, - transactionThreadReport, - checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, - isDisabled: false, - }), - [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], - ); - - const attachmentContextValue = attachmentContextValueOverride ? attachmentContextValueOverride : useMemo(() => ({ reportID, type: CONST.ATTACHMENT_TYPE.REPORT }), [reportID]); - - const mentionReportContextValue = mentionReportContextValueOverride ? mentionReportContextValueOverride : useMemo(() => ({ currentReportID: report?.reportID ?? '-1' }), [report?.reportID]); + const contextValue = useMemo(() => { + return contextValueOverride + ? contextValueOverride + : { + anchor: popoverAnchorRef.current, + report: {...report, reportID: report?.reportID ?? ''}, + reportNameValuePairs, + action, + transactionThreadReport, + checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, + isDisabled: false, + }; + }, [contextValueOverride, report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs]); + + const attachmentContextValue = useMemo(() => { + return attachmentContextValueOverride ? attachmentContextValueOverride : {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; + }, [attachmentContextValueOverride, reportID]); + + const mentionReportContextValue = useMemo(() => { + return mentionReportContextValueOverride ? mentionReportContextValueOverride : {currentReportID: report?.reportID ?? '-1'}; + }, [mentionReportContextValueOverride, report?.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { if (ReportActionsUtils.isActionableAddPaymentCard(action) && userBillingFundID === undefined && shouldRenderAddPaymentCard()) { diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 5e908c83477a..4cbb0947fcde 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -7,7 +7,6 @@ import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import {usePersonalDetails} from '@components/OnyxProvider'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import SubscriptAvatar from '@components/SubscriptAvatar'; import Text from '@components/Text'; @@ -24,19 +23,16 @@ import Navigation from '@libs/Navigation/Navigation'; import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; import {getReportActionMessage} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import type {AvatarSource} from '@libs/UserUtils'; 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 {Icon, PendingAction, PendingFields} from '@src/types/onyx/OnyxCommon'; +import type {PersonalDetailsList, Report, ReportAction} from '@src/types/onyx'; +import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; +import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; -import type * as OnyxTypes from '@src/types/onyx'; -import { SearchPersonalDetails } from '@src/types/onyx/SearchResults'; -import { Status } from '@src/types/onyx/PersonalDetails'; -import { AvatarSource } from '@libs/UserUtils'; - type ReportActionItemSingleProps = Partial & { /** All the data of the action */ @@ -64,7 +60,7 @@ type ReportActionItemSingleProps = Partial & { isHovered?: boolean; /** Personal details list */ - personalDetails?: OnyxTypes.PersonalDetailsList | Record; + personalDetails?: PersonalDetailsList | Record; }; const showUserDetails = (accountID: string) => { @@ -257,7 +253,7 @@ function ReportActionItemSingle({ ); }; const hasEmojiStatus = !displayAllActors && status && 'emojiCode' in status && status?.emojiCode; - const statusClearAfter = status && 'clearAfter' in status ? (String(status?.clearAfter) ?? '') : ''; + const statusClearAfter = status && 'clearAfter' in status ? String(status?.clearAfter) ?? '' : ''; const formattedDate = DateUtils.getStatusUntilDate(statusClearAfter); const statusText = status && 'text' in status ? String(status?.text) ?? '' : ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; From 4f5207accd6c93bd2874257391e7fd6e41373dea Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 18 Dec 2024 13:58:15 +0700 Subject: [PATCH 07/94] fix lint --- src/pages/home/report/ReportActionItemSingle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 4cbb0947fcde..6906231d51f5 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -301,7 +301,7 @@ function ReportActionItemSingle({ {`${status?.emojiCode}`} + >{`${String(status?.emojiCode ?? '')}`} )} From 8d64fba217fbfcd9e0a45e6e9b39d68e3d6deee1 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 19 Dec 2024 08:32:26 +0700 Subject: [PATCH 08/94] resolve eslint error --- .../home/report/PureReportActionItem.tsx | 26 +++++++++---------- .../report/ReportActionItemContentCreated.tsx | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index fe2cdca0eebd..6ab93b304c7f 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -527,25 +527,25 @@ function PureReportActionItem({ ); const contextValue = useMemo(() => { - return contextValueOverride - ? contextValueOverride - : { - anchor: popoverAnchorRef.current, - report: {...report, reportID: report?.reportID ?? ''}, - reportNameValuePairs, - action, - transactionThreadReport, - checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, - isDisabled: false, - }; + return ( + contextValueOverride ?? { + anchor: popoverAnchorRef.current, + report: {...report, reportID: report?.reportID ?? ''}, + reportNameValuePairs, + action, + transactionThreadReport, + checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, + isDisabled: false, + } + ); }, [contextValueOverride, report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs]); const attachmentContextValue = useMemo(() => { - return attachmentContextValueOverride ? attachmentContextValueOverride : {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; + return attachmentContextValueOverride ?? {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; }, [attachmentContextValueOverride, reportID]); const mentionReportContextValue = useMemo(() => { - return mentionReportContextValueOverride ? mentionReportContextValueOverride : {currentReportID: report?.reportID ?? '-1'}; + return mentionReportContextValueOverride ?? {currentReportID: report?.reportID ?? '-1'}; }, [mentionReportContextValueOverride, report?.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 69e27701edd8..c4ea9c113cd6 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -30,8 +30,8 @@ import ReportActionItemSingle from './ReportActionItemSingle'; type ReportActionItemContentCreatedProps = { /** The context value containing the report and action data, along with the show context menu props */ contextValue: ShowContextMenuContextProps & { - report: OnyxTypes.Report; - action: OnyxTypes.ReportAction; + report?: OnyxTypes.Report; + action?: OnyxTypes.ReportAction; }; /** Report action belonging to the report's parent */ From ee5de13cb53f5a43b4e6d076e136aaa19ede2dd7 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 20 Dec 2024 16:23:21 +0700 Subject: [PATCH 09/94] revert contextOverride props --- .../home/report/PureReportActionItem.tsx | 66 +++++-------------- .../report/ReportActionItemContentCreated.tsx | 6 +- 2 files changed, 21 insertions(+), 51 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 6ab93b304c7f..991fc0fc6b73 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -29,7 +29,6 @@ import TaskAction from '@components/ReportActionItem/TaskAction'; import TaskPreview from '@components/ReportActionItem/TaskPreview'; import TripRoomPreview from '@components/ReportActionItem/TripRoomPreview'; import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; -import type {ShowContextMenuContextProps} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; @@ -67,7 +66,6 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {JoinWorkspaceResolution} from '@src/types/onyx/OriginalMessage'; -import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions'; import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu'; @@ -166,7 +164,7 @@ type PureReportActionItemProps = { parentReport?: OnyxTypes.Report; /** Personal details list */ - personalDetails?: OnyxTypes.PersonalDetailsList | Record; + personalDetails?: OnyxTypes.PersonalDetailsList; /** Whether or not the user is blocked from concierge */ blockedFromConcierge?: OnyxTypes.BlockedFromConcierge; @@ -242,23 +240,6 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; - - /** The context value containing the report and action data, along with the show context menu props */ - contextValueOverride?: ShowContextMenuContextProps & { - report?: OnyxTypes.Report; - action?: OnyxTypes.ReportAction; - }; - - /** The context value containing the report ID and attachment type */ - attachmentContextValueOverride?: { - reportID?: string; - type: ValueOf; - }; - - /** The context value containing the current report ID */ - mentionReportContextValueOverride?: { - currentReportID: string; - }; }; /** @@ -312,13 +293,10 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, - contextValueOverride, - attachmentContextValueOverride, - mentionReportContextValueOverride, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const reportID = report?.reportID ?? ''; + const reportID = report?.reportID ?? action?.reportID ?? ''; const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -526,27 +504,22 @@ function PureReportActionItem({ [reportID, action, emojiReactions, toggleEmojiReaction], ); - const contextValue = useMemo(() => { - return ( - contextValueOverride ?? { - anchor: popoverAnchorRef.current, - report: {...report, reportID: report?.reportID ?? ''}, - reportNameValuePairs, - action, - transactionThreadReport, - checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, - isDisabled: false, - } - ); - }, [contextValueOverride, report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs]); + const contextValue = useMemo( + () => ({ + anchor: popoverAnchorRef.current, + report: {...report, reportID: report?.reportID ?? ''}, + reportNameValuePairs, + action, + transactionThreadReport, + checkIfContextMenuActive: toggleContextMenuFromActiveReportAction, + isDisabled: false, + }), + [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], + ); - const attachmentContextValue = useMemo(() => { - return attachmentContextValueOverride ?? {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; - }, [attachmentContextValueOverride, reportID]); + const attachmentContextValue = useMemo(() => ({reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [reportID]); - const mentionReportContextValue = useMemo(() => { - return mentionReportContextValueOverride ?? {currentReportID: report?.reportID ?? '-1'}; - }, [mentionReportContextValueOverride, report?.reportID]); + const mentionReportContextValue = useMemo(() => ({currentReportID: report?.reportID ?? '-1'}), [report?.reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { if (ReportActionsUtils.isActionableAddPaymentCard(action) && userBillingFundID === undefined && shouldRenderAddPaymentCard()) { @@ -1245,9 +1218,6 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => { prevProps.reimbursementDeQueuedActionMessage === nextProps.reimbursementDeQueuedActionMessage && prevProps.modifiedExpenseMessage === nextProps.modifiedExpenseMessage && prevProps.userBillingFundID === nextProps.userBillingFundID && - prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage && - prevProps.contextValueOverride === nextProps.contextValueOverride && - prevProps.attachmentContextValueOverride === nextProps.attachmentContextValueOverride && - prevProps.mentionReportContextValueOverride === nextProps.mentionReportContextValueOverride + prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage ); -}); +}); \ No newline at end of file diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index c4ea9c113cd6..86af7e960e23 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -30,8 +30,8 @@ import ReportActionItemSingle from './ReportActionItemSingle'; type ReportActionItemContentCreatedProps = { /** The context value containing the report and action data, along with the show context menu props */ contextValue: ShowContextMenuContextProps & { - report?: OnyxTypes.Report; - action?: OnyxTypes.ReportAction; + report: OnyxTypes.Report; + action: OnyxTypes.ReportAction; }; /** Report action belonging to the report's parent */ @@ -203,4 +203,4 @@ export default memo( prevProps.transactionID === nextProps.transactionID && prevProps.draftMessage === nextProps.draftMessage && prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine, -); +); \ No newline at end of file From 45d68c5dfacee699baac109f45ba181593474e38 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 20 Dec 2024 16:30:08 +0700 Subject: [PATCH 10/94] remove unnecessary code --- src/components/SelectionList/ChatListItem.tsx | 3 --- src/pages/home/report/PureReportActionItem.tsx | 2 +- src/pages/home/report/ReportActionItemContentCreated.tsx | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index fc9edbda823d..545b12b1346d 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -95,9 +95,6 @@ function ChatListItem({ index={item.index ?? 0} isFirstVisibleReportAction={false} personalDetails={personalDetails} - contextValueOverride={contextValue} - attachmentContextValueOverride={attachmentContextValue} - mentionReportContextValueOverride={mentionReportContextValue} shouldDisplayContextMenu={false} /> diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 991fc0fc6b73..10f4d2becc67 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -1220,4 +1220,4 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => { prevProps.userBillingFundID === nextProps.userBillingFundID && prevProps.reportAutomaticallyForwardedMessage === nextProps.reportAutomaticallyForwardedMessage ); -}); \ No newline at end of file +}); diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 86af7e960e23..69e27701edd8 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -203,4 +203,4 @@ export default memo( prevProps.transactionID === nextProps.transactionID && prevProps.draftMessage === nextProps.draftMessage && prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine, -); \ No newline at end of file +); From 5046a484f71cd47e8012b2fbc4c565eed29f0809 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 20 Dec 2024 16:39:10 +0700 Subject: [PATCH 11/94] add attachmentContextValueType --- src/components/SelectionList/ChatListItem.tsx | 2 -- src/pages/home/report/PureReportActionItem.tsx | 6 +++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 545b12b1346d..2fb3cc9141c2 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -38,8 +38,6 @@ function ChatListItem({ isDisabled: true, }; - const mentionReportContextValue = useMemo(() => ({currentReportID: item?.reportID ?? '-1'}), [item.reportID]); - const animatedHighlightStyle = useAnimatedHighlightStyle({ borderRadius: variables.componentBorderRadius, shouldHighlight: item?.shouldAnimateInHighlight ?? false, diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 10f4d2becc67..fda2f7480e77 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -240,6 +240,9 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; + + /** Type of attachment context value */ + attachmentContextValueType?: ValueOf; }; /** @@ -293,6 +296,7 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, + attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -517,7 +521,7 @@ function PureReportActionItem({ [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], ); - const attachmentContextValue = useMemo(() => ({reportID, type: CONST.ATTACHMENT_TYPE.REPORT}), [reportID]); + const attachmentContextValue = useMemo(() => ({reportID, type: attachmentContextValueType}), [reportID]); const mentionReportContextValue = useMemo(() => ({currentReportID: report?.reportID ?? '-1'}), [report?.reportID]); From c4145e6daa16e98adf2fc48fe6e9a9de8483ca21 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 21 Dec 2024 09:03:32 +0700 Subject: [PATCH 12/94] add missing dependency --- src/pages/home/report/PureReportActionItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index fda2f7480e77..f543c186d470 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -521,7 +521,7 @@ function PureReportActionItem({ [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], ); - const attachmentContextValue = useMemo(() => ({reportID, type: attachmentContextValueType}), [reportID]); + const attachmentContextValue = useMemo(() => ({reportID, type: attachmentContextValueType}), [reportID, attachmentContextValueType]); const mentionReportContextValue = useMemo(() => ({currentReportID: report?.reportID ?? '-1'}), [report?.reportID]); From 35f99bef9b1545e833ba316d70fb94e3fa35543e Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 23 Dec 2024 13:59:03 +0700 Subject: [PATCH 13/94] remove unused import, fix lint --- src/components/SelectionList/ChatListItem.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 2fb3cc9141c2..164b315b07a1 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -1,4 +1,4 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -26,18 +26,6 @@ function ChatListItem({ const styles = useThemeStyles(); const theme = useTheme(); - const attachmentContextValue = {type: CONST.ATTACHMENT_TYPE.SEARCH}; - - const contextValue = { - anchor: null, - report: undefined, - reportNameValuePairs: undefined, - action: undefined, - transactionThreadReport: undefined, - checkIfContextMenuActive: () => {}, - isDisabled: true, - }; - const animatedHighlightStyle = useAnimatedHighlightStyle({ borderRadius: variables.componentBorderRadius, shouldHighlight: item?.shouldAnimateInHighlight ?? false, @@ -94,6 +82,7 @@ function ChatListItem({ isFirstVisibleReportAction={false} personalDetails={personalDetails} shouldDisplayContextMenu={false} + attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} /> ); From f55cff99e35c7c541a225d85ac8544151cdbec26 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 24 Dec 2024 14:59:14 +0700 Subject: [PATCH 14/94] Remove unnecessary code --- src/pages/home/report/ReportActionItemSingle.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 6906231d51f5..455342b4ccfb 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -91,8 +91,7 @@ function ReportActionItemSingle({ const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; - // fallback to action?.accountID to handle search result chat item - const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport, report) ?? action?.accountID; + const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport, report); const [invoiceReceiverPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : -1}`); let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); From 45b406fc794e4cbea87cdeff4ab7766e7da61606 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 27 Dec 2024 01:02:20 +0700 Subject: [PATCH 15/94] Mock ConfirmedRoute to get rid map error --- tests/ui/ResizeScreenTests.tsx | 1 + tests/unit/CalendarPickerTest.tsx | 2 ++ tests/unit/GoogleTagManagerTest.tsx | 1 + tests/unit/Search/handleActionButtonPressTest.ts | 2 ++ 4 files changed, 6 insertions(+) diff --git a/tests/ui/ResizeScreenTests.tsx b/tests/ui/ResizeScreenTests.tsx index 5bd86ad152b2..275680e3f345 100644 --- a/tests/ui/ResizeScreenTests.tsx +++ b/tests/ui/ResizeScreenTests.tsx @@ -21,6 +21,7 @@ jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); jest.mock('@pages/settings/InitialSettingsPage'); jest.mock('@pages/settings/Profile/ProfilePage'); jest.mock('@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'); +jest.mock('@src/components/ConfirmedRoute.tsx'); const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { shouldUseNarrowLayout: true, diff --git a/tests/unit/CalendarPickerTest.tsx b/tests/unit/CalendarPickerTest.tsx index 5cf02409ac23..65e9216f3d8f 100644 --- a/tests/unit/CalendarPickerTest.tsx +++ b/tests/unit/CalendarPickerTest.tsx @@ -36,6 +36,8 @@ jest.mock('../../src/hooks/useLocalize', () => })), ); +jest.mock('@src/components/ConfirmedRoute.tsx'); + describe('CalendarPicker', () => { test('renders calendar component', () => { render(); diff --git a/tests/unit/GoogleTagManagerTest.tsx b/tests/unit/GoogleTagManagerTest.tsx index dcb6bdea0eec..7076775644ff 100644 --- a/tests/unit/GoogleTagManagerTest.tsx +++ b/tests/unit/GoogleTagManagerTest.tsx @@ -14,6 +14,7 @@ jest.mock('@libs/GoogleTagManager'); // Mock the Overlay since it doesn't work in tests jest.mock('@libs/Navigation/AppNavigator/Navigators/Overlay'); +jest.mock('@src/components/ConfirmedRoute.tsx'); describe('GoogleTagManagerTest', () => { const accountID = 123456; diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts index 69af0e83849a..5082913a3889 100644 --- a/tests/unit/Search/handleActionButtonPressTest.ts +++ b/tests/unit/Search/handleActionButtonPressTest.ts @@ -2,6 +2,8 @@ import type {ReportListItemType} from '@components/SelectionList/types'; import {handleActionButtonPress} from '@libs/actions/Search'; +jest.mock('@src/components/ConfirmedRoute.tsx'); + const mockReportItemWithHold = { shouldAnimateInHighlight: false, accountID: 1206, From 299992ef946bdc2e0cf830fdf181c648802317cc Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 27 Dec 2024 07:57:31 +0700 Subject: [PATCH 16/94] mock ConfirmedRoute to test --- tests/ui/WorkspaceSwitcherTest.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/ui/WorkspaceSwitcherTest.tsx b/tests/ui/WorkspaceSwitcherTest.tsx index 614ed4e5ab70..dde43d141cc9 100644 --- a/tests/ui/WorkspaceSwitcherTest.tsx +++ b/tests/ui/WorkspaceSwitcherTest.tsx @@ -26,6 +26,9 @@ jest.mock('@react-navigation/native', () => { triggerTransitionEnd: jest.fn(), }; }); + +jest.mock('@src/components/ConfirmedRoute.tsx'); + TestHelper.setupApp(); async function signInAndGetApp(): Promise { From 8d74ba238a609b70e4f2063cd328bba12f5c5e09 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 27 Dec 2024 16:35:05 +0700 Subject: [PATCH 17/94] Resolve issue with unit test --- src/libs/ReportUtils.ts | 2 +- .../home/report/ReportActionItemSingle.tsx | 9 +++++--- tests/unit/ReportActionItemSingleTest.ts | 10 ++------- tests/utils/LHNTestUtils.tsx | 21 +++++++++++++++++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e9c017db43ce..4e90b55cffca 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -860,7 +860,7 @@ const unavailableTranslation = Localize.translateLocal('workspace.common.unavail */ function getPolicyName(report: OnyxInputOrEntry, returnEmptyIfNotFound = false, policy?: OnyxInputOrEntry): string { const noPolicyFound = returnEmptyIfNotFound ? '' : unavailableTranslation; - if (isEmptyObject(report) || (isEmptyObject(allPolicies) && !report?.policyName)) { + if (isEmptyObject(report) || (isEmptyObject(allPolicies) && !report?.policyName && !policy)) { return noPolicyFound; } diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 455342b4ccfb..dcf52f605a87 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -27,7 +27,7 @@ import type {AvatarSource} from '@libs/UserUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetailsList, Report, ReportAction} from '@src/types/onyx'; +import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; @@ -61,6 +61,9 @@ type ReportActionItemSingleProps = Partial & { /** Personal details list */ personalDetails?: PersonalDetailsList | Record; + + /** Current connected policy */ + policy?: OnyxEntry; }; const showUserDetails = (accountID: string) => { @@ -82,12 +85,12 @@ function ReportActionItemSingle({ iouReport, isHovered = false, personalDetails, + policy, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const policy = usePolicy(report?.policyID); const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; @@ -153,7 +156,7 @@ function ReportActionItemSingle({ } else if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, {}); + const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, policy); secondaryAvatar = reportIcons.at(avatarIconIndex) ?? {name: '', source: '', type: CONST.ICON_TYPE_AVATAR}; } else if (ReportUtils.isInvoiceReport(iouReport)) { diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index e0bf06be1609..b283aeb10ea1 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -54,16 +54,10 @@ describe('ReportActionItemSingle', () => { }; function setup() { - LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); + LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction, fakePersonalDetails, fakePolicy); const policyCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.POLICY, [fakePolicy], (item) => item.id); - return waitForBatchedUpdates().then(() => - Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...policyCollectionDataSet, - }), - ); + return waitForBatchedUpdates().then(() => Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false)); } it('renders secondary Avatar properly', async () => { diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 1a3fc3d07f28..af143c1942f6 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -16,6 +16,7 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction, TransactionViolation, ViolationName} from '@src/types/onyx'; import type ReportActionName from '@src/types/onyx/ReportActionName'; +import {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import waitForBatchedUpdatesWithAct from './waitForBatchedUpdatesWithAct'; type MockedReportActionItemSingleProps = { @@ -27,6 +28,12 @@ type MockedReportActionItemSingleProps = { /** All the data of the action */ reportAction: ReportAction; + + /** Personal details list */ + personalDetails?: PersonalDetailsList | Record; + + /** Current connected policy */ + policy?: Policy; }; type MockedSidebarLinksProps = { @@ -331,7 +338,7 @@ function internalRender(component: ReactElement) { } } -function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, reportAction}: MockedReportActionItemSingleProps) { +function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, reportAction, personalDetails, policy}: MockedReportActionItemSingleProps) { return ( ); } -function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report?: Report, reportAction?: ReportAction) { +function getDefaultRenderedReportActionItemSingle( + shouldShowSubscriptAvatar = true, + report?: Report, + reportAction?: ReportAction, + personalDetails?: PersonalDetailsList | Record, + policy?: Policy, +) { const currentReport = report ?? getFakeReport(); const currentReportAction = reportAction ?? getFakeAdvancedReportAction(); @@ -356,6 +371,8 @@ function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = tr shouldShowSubscriptAvatar={shouldShowSubscriptAvatar} report={currentReport} reportAction={currentReportAction} + personalDetails={personalDetails} + policy={policy} />, ); } From 340bee531c9cd69c5815ffc6e5f9e3a17bfc2005 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 27 Dec 2024 16:37:47 +0700 Subject: [PATCH 18/94] remove unnecessary code --- src/pages/home/report/ReportActionItemSingle.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index dcf52f605a87..ba47b770e54c 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -259,7 +259,6 @@ function ReportActionItemSingle({ const formattedDate = DateUtils.getStatusUntilDate(statusClearAfter); const statusText = status && 'text' in status ? String(status?.text) ?? '' : ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; - // const pendingFieldsAvatar = pendingFields && 'avatar' in pendingFields ? pendingFields?.avatar ?? undefined : undefined; return ( Date: Fri, 27 Dec 2024 16:55:56 +0700 Subject: [PATCH 19/94] resolve jest perf test error --- tests/perf-test/SearchRouter.perf-test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/perf-test/SearchRouter.perf-test.tsx b/tests/perf-test/SearchRouter.perf-test.tsx index 0784813127be..1d0f757730d2 100644 --- a/tests/perf-test/SearchRouter.perf-test.tsx +++ b/tests/perf-test/SearchRouter.perf-test.tsx @@ -86,6 +86,7 @@ jest.mock('@src/components/withNavigationFocus', () => (Component: ComponentType return WithNavigationFocus; }); +jest.mock('@src/components/ConfirmedRoute.tsx'); const getMockedReports = (length = 100) => createCollection( From 760ca696cb3769b56d9ebe88318be8fa4c4ba9ef Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 28 Dec 2024 08:54:29 +0700 Subject: [PATCH 20/94] fix lint error --- src/pages/home/report/ReportActionItemSingle.tsx | 8 +++++--- tests/unit/ReportActionItemSingleTest.ts | 3 --- tests/utils/LHNTestUtils.tsx | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index ba47b770e54c..d791d977e9b2 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -91,6 +91,8 @@ function ReportActionItemSingle({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); + const onyxPolicy = usePolicy(report?.policyID); + const reportPolicy = policy ?? onyxPolicy; const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; @@ -115,9 +117,9 @@ function ReportActionItemSingle({ let avatarId: number | string | undefined = actorAccountID; if (isWorkspaceActor) { - displayName = ReportUtils.getPolicyName(report, undefined, policy); + displayName = ReportUtils.getPolicyName(report, undefined, reportPolicy); actorHint = displayName; - avatarSource = ReportUtils.getWorkspaceIcon(report, policy).source; + avatarSource = ReportUtils.getWorkspaceIcon(report, reportPolicy).source; avatarId = report?.policyID; } else if (action?.delegateAccountID && personalDetails?.[action?.delegateAccountID]) { displayName = delegatePersonalDetails?.displayName ?? ''; @@ -156,7 +158,7 @@ function ReportActionItemSingle({ } else if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, policy); + const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, reportPolicy); secondaryAvatar = reportIcons.at(avatarIconIndex) ?? {name: '', source: '', type: CONST.ICON_TYPE_AVATAR}; } else if (ReportUtils.isInvoiceReport(iouReport)) { diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index b283aeb10ea1..925e548389d5 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -1,7 +1,6 @@ import {screen, waitFor} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import type {PersonalDetailsList} from '@src/types/onyx'; -import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; @@ -55,8 +54,6 @@ describe('ReportActionItemSingle', () => { function setup() { LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction, fakePersonalDetails, fakePolicy); - const policyCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.POLICY, [fakePolicy], (item) => item.id); - return waitForBatchedUpdates().then(() => Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false)); } diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index af143c1942f6..2b89392cd424 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -16,7 +16,7 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction, TransactionViolation, ViolationName} from '@src/types/onyx'; import type ReportActionName from '@src/types/onyx/ReportActionName'; -import {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; +import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import waitForBatchedUpdatesWithAct from './waitForBatchedUpdatesWithAct'; type MockedReportActionItemSingleProps = { From 2705f78fa9bf73127cfd43808af62d1c215c34e3 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 28 Dec 2024 09:16:41 +0700 Subject: [PATCH 21/94] mock ConfirmedRoute on selectionlist perf test --- tests/perf-test/SelectionList.perf-test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/perf-test/SelectionList.perf-test.tsx b/tests/perf-test/SelectionList.perf-test.tsx index fcd714129536..759ab1a8da22 100644 --- a/tests/perf-test/SelectionList.perf-test.tsx +++ b/tests/perf-test/SelectionList.perf-test.tsx @@ -84,6 +84,8 @@ jest.mock('../../src/hooks/useScreenWrapperTransitionStatus', () => ({ })), })); +jest.mock('@src/components/ConfirmedRoute.tsx'); + function SelectionListWrapper({canSelectMultiple}: SelectionListWrapperProps) { const [selectedIds, setSelectedIds] = useState([]); From 135c67797000070997e6f33eb7c7aea1e993d1e1 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 28 Dec 2024 11:00:23 +0700 Subject: [PATCH 22/94] fix issue image not found in desktop --- src/pages/home/report/PureReportActionItem.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index f543c186d470..7d6c54bd2e8c 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -521,9 +521,14 @@ function PureReportActionItem({ [report, action, toggleContextMenuFromActiveReportAction, transactionThreadReport, reportNameValuePairs], ); - const attachmentContextValue = useMemo(() => ({reportID, type: attachmentContextValueType}), [reportID, attachmentContextValueType]); + const attachmentContextValue = useMemo(() => { + if (attachmentContextValueType === CONST.ATTACHMENT_TYPE.SEARCH) { + return {type: attachmentContextValueType}; + } + return {reportID, type: attachmentContextValueType}; + }, [reportID, attachmentContextValueType]); - const mentionReportContextValue = useMemo(() => ({currentReportID: report?.reportID ?? '-1'}), [report?.reportID]); + const mentionReportContextValue = useMemo(() => ({currentReportID: reportID ?? '-1'}), [reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { if (ReportActionsUtils.isActionableAddPaymentCard(action) && userBillingFundID === undefined && shouldRenderAddPaymentCard()) { From 6f59803401c3c9ce8076fce88002941631bb7327 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 28 Dec 2024 11:22:05 +0700 Subject: [PATCH 23/94] revert unnecessary change --- src/components/ShowContextMenuContext.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ShowContextMenuContext.ts b/src/components/ShowContextMenuContext.ts index 04c437165842..6fefa987fac3 100644 --- a/src/components/ShowContextMenuContext.ts +++ b/src/components/ShowContextMenuContext.ts @@ -10,10 +10,10 @@ import CONST from '@src/CONST'; import type {Report, ReportAction, ReportNameValuePairs} from '@src/types/onyx'; type ShowContextMenuContextProps = { - anchor?: ContextMenuAnchor; - report?: OnyxEntry; - reportNameValuePairs?: OnyxEntry; - action?: OnyxEntry; + anchor: ContextMenuAnchor; + report: OnyxEntry; + reportNameValuePairs: OnyxEntry; + action: OnyxEntry; transactionThreadReport?: OnyxEntry; checkIfContextMenuActive: () => void; isDisabled: boolean; From 0a1044a117021fbca8ceccc3ab9aa01ea7fa07e1 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 31 Dec 2024 10:36:24 +0700 Subject: [PATCH 24/94] extract policy object to param --- src/components/SelectionList/ChatListItem.tsx | 1 + src/pages/home/report/PureReportActionItem.tsx | 5 +++++ src/pages/home/report/ReportActionItem.tsx | 3 +++ .../home/report/ReportActionItemContentCreated.tsx | 2 ++ src/pages/home/report/ReportActionItemSingle.tsx | 11 ++++------- tests/ui/WorkspaceCategoriesTest.tsx | 2 ++ tests/unit/Search/SearchUIUtilsTest.ts | 2 ++ 7 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 164b315b07a1..df520d7501f8 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -83,6 +83,7 @@ function ChatListItem({ personalDetails={personalDetails} shouldDisplayContextMenu={false} attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} + policy={undefined} /> ); diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index b304fb6abcc0..5d21bfd6d71c 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -244,6 +244,9 @@ type PureReportActionItemProps = { /** Type of attachment context value */ attachmentContextValueType?: ValueOf; + + /** Current connected policy */ + policy: OnyxEntry; }; /** @@ -298,6 +301,7 @@ function PureReportActionItem({ userBillingFundID, reportAutomaticallyForwardedMessage, attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, + policy, }: PureReportActionItemProps) { const actionSheetAwareScrollViewContext = useContext(ActionSheetAwareScrollView.ActionSheetAwareScrollViewContext); const {translate} = useLocalize(); @@ -1045,6 +1049,7 @@ function PureReportActionItem({ !ReportActionsUtils.isPendingRemove(action) } personalDetails={personalDetails} + policy={policy} > {content} diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 1887bf9d348a..bd33ee1eb6d6 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -2,6 +2,7 @@ import React, {useMemo} from 'react'; import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import {useBlockedFromConcierge, usePersonalDetails} from '@components/OnyxProvider'; +import usePolicy from '@hooks/usePolicy'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -43,6 +44,7 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID); const linkedReport = ReportUtils.isChatThread(report) ? parentReport : report; const missingPaymentMethod = ReportUtils.getIndicatedMissingPaymentMethod(userWallet, linkedReport?.reportID ?? '-1', action); + const policy = usePolicy(report?.policyID); return ( , reportID)} + policy={policy} /> ); } diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 69e27701edd8..0e4a37b59359 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -96,6 +96,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans action={parentReportAction} showHeader report={report} + policy={policy} > ${translate(message)}`} /> @@ -130,6 +131,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans action={parentReportAction} showHeader={draftMessage === undefined} report={report} + policy={policy} > ${translate('parentReportAction.deletedTask')}`} /> diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index d791d977e9b2..407e022a2c78 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -13,7 +13,6 @@ import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; import useLocalize from '@hooks/useLocalize'; -import usePolicy from '@hooks/usePolicy'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -63,7 +62,7 @@ type ReportActionItemSingleProps = Partial & { personalDetails?: PersonalDetailsList | Record; /** Current connected policy */ - policy?: OnyxEntry; + policy: OnyxEntry; }; const showUserDetails = (accountID: string) => { @@ -91,8 +90,6 @@ function ReportActionItemSingle({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const onyxPolicy = usePolicy(report?.policyID); - const reportPolicy = policy ?? onyxPolicy; const delegatePersonalDetails = personalDetails?.[action?.delegateAccountID ?? '']; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; @@ -117,9 +114,9 @@ function ReportActionItemSingle({ let avatarId: number | string | undefined = actorAccountID; if (isWorkspaceActor) { - displayName = ReportUtils.getPolicyName(report, undefined, reportPolicy); + displayName = ReportUtils.getPolicyName(report, undefined, policy); actorHint = displayName; - avatarSource = ReportUtils.getWorkspaceIcon(report, reportPolicy).source; + avatarSource = ReportUtils.getWorkspaceIcon(report, policy).source; avatarId = report?.policyID; } else if (action?.delegateAccountID && personalDetails?.[action?.delegateAccountID]) { displayName = delegatePersonalDetails?.displayName ?? ''; @@ -158,7 +155,7 @@ function ReportActionItemSingle({ } else if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, reportPolicy); + const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, policy); secondaryAvatar = reportIcons.at(avatarIconIndex) ?? {name: '', source: '', type: CONST.ICON_TYPE_AVATAR}; } else if (ReportUtils.isInvoiceReport(iouReport)) { diff --git a/tests/ui/WorkspaceCategoriesTest.tsx b/tests/ui/WorkspaceCategoriesTest.tsx index eca2f803f70e..fd35948398a6 100644 --- a/tests/ui/WorkspaceCategoriesTest.tsx +++ b/tests/ui/WorkspaceCategoriesTest.tsx @@ -20,6 +20,8 @@ import * as LHNTestUtils from '../utils/LHNTestUtils'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; +jest.mock('@src/components/ConfirmedRoute.tsx'); + TestHelper.setupGlobalFetchMock(); const RootStack = createResponsiveStackNavigator(); diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts index f16153126858..de82d5c1b892 100644 --- a/tests/unit/Search/SearchUIUtilsTest.ts +++ b/tests/unit/Search/SearchUIUtilsTest.ts @@ -3,6 +3,8 @@ import CONST from '@src/CONST'; import * as SearchUIUtils from '@src/libs/SearchUIUtils'; import type * as OnyxTypes from '@src/types/onyx'; +jest.mock('@src/components/ConfirmedRoute.tsx'); + const accountID = 18439984; const policyID = 'A1B2C3'; const reportID = '123456789'; From 0fc3a45c75aafcb880e6b5511d39675b38463b40 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 8 Jan 2025 08:47:10 +0700 Subject: [PATCH 25/94] insert personal details to ReportActionItemSingle --- src/pages/home/report/ReportActionItemContentCreated.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 0e4a37b59359..0af76633ca68 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -26,6 +26,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import ReportActionItemCreated from './ReportActionItemCreated'; import ReportActionItemSingle from './ReportActionItemSingle'; +import { usePersonalDetails } from '@components/OnyxProvider'; type ReportActionItemContentCreatedProps = { /** The context value containing the report and action data, along with the show context menu props */ @@ -52,7 +53,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans const {translate} = useLocalize(); const {report, action, transactionThreadReport} = contextValue; - + const personalDetails = usePersonalDetails(); const policy = usePolicy(report.policyID === CONST.POLICY.OWNER_EMAIL_FAKE ? '-1' : report.policyID ?? '-1'); const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID ?? '-1'}`); @@ -97,6 +98,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans showHeader report={report} policy={policy} + personalDetails={personalDetails} > ${translate(message)}`} /> @@ -132,6 +134,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans showHeader={draftMessage === undefined} report={report} policy={policy} + personalDetails={personalDetails} > ${translate('parentReportAction.deletedTask')}`} /> From e51cf569074286475ad5805753979328d6a52bcd Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 8 Jan 2025 09:05:29 +0700 Subject: [PATCH 26/94] extract invoiceReceiverPolicy --- src/components/SelectionList/ChatListItem.tsx | 1 + src/pages/home/report/PureReportActionItem.tsx | 6 ++++++ src/pages/home/report/ReportActionItem.tsx | 6 +++++- .../home/report/ReportActionItemContentCreated.tsx | 10 ++++++++-- src/pages/home/report/ReportActionItemSingle.tsx | 7 ++++--- tests/utils/LHNTestUtils.tsx | 1 + 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index df520d7501f8..e2d49179222a 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -84,6 +84,7 @@ function ChatListItem({ shouldDisplayContextMenu={false} attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} policy={undefined} + invoiceReceiverPolicy={undefined} /> ); diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 056f8fe06967..991a6680c085 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -246,6 +246,9 @@ type PureReportActionItemProps = { /** Current connected policy */ policy: OnyxEntry; + + /** Invoice receiver policy */ + invoiceReceiverPolicy: OnyxEntry; }; /** @@ -301,6 +304,7 @@ function PureReportActionItem({ reportAutomaticallyForwardedMessage, attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, policy, + invoiceReceiverPolicy, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -1015,6 +1019,7 @@ function PureReportActionItem({ } personalDetails={personalDetails} policy={policy} + invoiceReceiverPolicy={invoiceReceiverPolicy} > {content} @@ -1036,6 +1041,7 @@ function PureReportActionItem({ transactionID={transactionID} draftMessage={draftMessage} shouldHideThreadDividerLine={shouldHideThreadDividerLine} + invoiceReceiverPolicy={invoiceReceiverPolicy} /> ); } diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index bd33ee1eb6d6..d9d38263de5e 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -9,7 +9,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import * as Report from '@userActions/Report'; import * as ReportActions from '@userActions/ReportActions'; import * as Transaction from '@userActions/Transaction'; -import type CONST from '@src/CONST'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction} from '@src/types/onyx'; import type {PureReportActionItemProps} from './PureReportActionItem'; @@ -45,6 +45,9 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) const linkedReport = ReportUtils.isChatThread(report) ? parentReport : report; const missingPaymentMethod = ReportUtils.getIndicatedMissingPaymentMethod(userWallet, linkedReport?.reportID ?? '-1', action); const policy = usePolicy(report?.policyID); + const [invoiceReceiverPolicy] = useOnyx( + `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, + ); return ( , reportID)} policy={policy} + invoiceReceiverPolicy={invoiceReceiverPolicy} /> ); } diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 0af76633ca68..22a51c17727b 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -46,9 +46,12 @@ type ReportActionItemContentCreatedProps = { /** Flag to show, hide the thread divider line */ shouldHideThreadDividerLine: boolean; + + /** Invoice receiver policy */ + invoiceReceiverPolicy: OnyxEntry; }; -function ReportActionItemContentCreated({contextValue, parentReportAction, transactionID, draftMessage, shouldHideThreadDividerLine}: ReportActionItemContentCreatedProps) { +function ReportActionItemContentCreated({contextValue, parentReportAction, transactionID, draftMessage, shouldHideThreadDividerLine, invoiceReceiverPolicy}: ReportActionItemContentCreatedProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -99,6 +102,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans report={report} policy={policy} personalDetails={personalDetails} + invoiceReceiverPolicy={invoiceReceiverPolicy} > ${translate(message)}`} /> @@ -135,6 +139,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans report={report} policy={policy} personalDetails={personalDetails} + invoiceReceiverPolicy={invoiceReceiverPolicy} > ${translate('parentReportAction.deletedTask')}`} /> @@ -207,5 +212,6 @@ export default memo( lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && prevProps.transactionID === nextProps.transactionID && prevProps.draftMessage === nextProps.draftMessage && - prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine, + prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine && + lodashIsEqual(prevProps.invoiceReceiverPolicy, nextProps.invoiceReceiverPolicy), ); diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 82515ba36cd0..609f5a471679 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -63,6 +63,9 @@ type ReportActionItemSingleProps = Partial & { /** Current connected policy */ policy: OnyxEntry; + + /** Invoice receiver policy */ + invoiceReceiverPolicy: OnyxEntry; }; const showUserDetails = (accountID: string) => { @@ -88,6 +91,7 @@ function ReportActionItemSingle({ isHovered = false, personalDetails, policy, + invoiceReceiverPolicy, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -97,9 +101,6 @@ function ReportActionItemSingle({ const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; const isReportPreviewAction = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW; const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport, report); - const [invoiceReceiverPolicy] = useOnyx( - `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, - ); let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); const {avatar, login} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {}; diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 2b89392cd424..70fdced84f1c 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -351,6 +351,7 @@ function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, isHovered={false} personalDetails={personalDetails} policy={policy} + invoiceReceiverPolicy={undefined} /> ); From 69977529d047863f812e6f6235b9d103ccfd8155 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 8 Jan 2025 10:22:55 +0700 Subject: [PATCH 27/94] extract IOUTransaction from reportactionitemcontentcreated --- src/components/SelectionList/ChatListItem.tsx | 1 + src/pages/home/report/PureReportActionItem.tsx | 11 +++++++---- src/pages/home/report/ReportActionItem.tsx | 8 +++++++- .../home/report/ReportActionItemContentCreated.tsx | 9 ++++----- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index e2d49179222a..e69cf68adf6f 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -85,6 +85,7 @@ function ChatListItem({ attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} policy={undefined} invoiceReceiverPolicy={undefined} + IOUTransaction={undefined} /> ); diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 991a6680c085..32c210aa97e6 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -249,6 +249,8 @@ type PureReportActionItemProps = { /** Invoice receiver policy */ invoiceReceiverPolicy: OnyxEntry; + + IOUTransaction: OnyxEntry; }; /** @@ -305,6 +307,7 @@ function PureReportActionItem({ attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, policy, invoiceReceiverPolicy, + IOUTransaction, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -1030,15 +1033,15 @@ function PureReportActionItem({ }; if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) - ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID - : '-1'; + // const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) + // ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID + // : '-1'; return ( ReportUtils.getOriginalReportID(reportID, action) || '-1', [reportID, action]); @@ -48,6 +48,11 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) const [invoiceReceiverPolicy] = useOnyx( `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, ); + const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) + ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID + : '-1'; + + const [IOUTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${IOUTransactionID ?? '-1'}`); return ( , reportID)} policy={policy} invoiceReceiverPolicy={invoiceReceiverPolicy} + IOUTransaction={IOUTransaction} /> ); } diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 22a51c17727b..53bf9a9961aa 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -38,8 +38,8 @@ type ReportActionItemContentCreatedProps = { /** Report action belonging to the report's parent */ parentReportAction: OnyxEntry; - /** The transaction ID */ - transactionID: string | undefined; + /** Transaction that stores the distance expense data */ + transaction: OnyxEntry; /** The draft message */ draftMessage: string | undefined; @@ -51,14 +51,13 @@ type ReportActionItemContentCreatedProps = { invoiceReceiverPolicy: OnyxEntry; }; -function ReportActionItemContentCreated({contextValue, parentReportAction, transactionID, draftMessage, shouldHideThreadDividerLine, invoiceReceiverPolicy}: ReportActionItemContentCreatedProps) { +function ReportActionItemContentCreated({contextValue, parentReportAction, transaction, draftMessage, shouldHideThreadDividerLine, invoiceReceiverPolicy}: ReportActionItemContentCreatedProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {report, action, transactionThreadReport} = contextValue; const personalDetails = usePersonalDetails(); const policy = usePolicy(report.policyID === CONST.POLICY.OWNER_EMAIL_FAKE ? '-1' : report.policyID ?? '-1'); - const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID ?? '-1'}`); const transactionCurrency = TransactionUtils.getCurrency(transaction); @@ -210,7 +209,7 @@ export default memo( (prevProps, nextProps) => lodashIsEqual(prevProps.contextValue, nextProps.contextValue) && lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && - prevProps.transactionID === nextProps.transactionID && + lodashIsEqual(prevProps.transaction, nextProps.transaction) && prevProps.draftMessage === nextProps.draftMessage && prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine && lodashIsEqual(prevProps.invoiceReceiverPolicy, nextProps.invoiceReceiverPolicy), From 2564ef22dd29c81b1117a4cd0b3ccfb8820f0dca Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 8 Jan 2025 10:32:05 +0700 Subject: [PATCH 28/94] remove unnecessary code --- src/pages/home/report/PureReportActionItem.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 32c210aa97e6..0aa406a72b25 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -1033,10 +1033,6 @@ function PureReportActionItem({ }; if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - // const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) - // ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID - // : '-1'; - return ( Date: Wed, 8 Jan 2025 10:32:32 +0700 Subject: [PATCH 29/94] cleanup --- src/pages/home/report/ReportActionItemContentCreated.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 53bf9a9961aa..606c7fa7b94d 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -1,7 +1,6 @@ import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useMemo} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import RenderHTML from '@components/RenderHTML'; From 94e5683bb80f9c34898d8dbf1b48925defd862ab Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 14 Jan 2025 08:59:54 +0700 Subject: [PATCH 30/94] revert subcomponents purification --- .../home/report/PureReportActionItem.tsx | 21 ++------ .../report/ReportActionItemContentCreated.tsx | 27 ++++------ .../home/report/ReportActionItemSingle.tsx | 50 ++++++++----------- 3 files changed, 34 insertions(+), 64 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index d73d8f43915c..08351c27265e 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -240,17 +240,9 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; - /** Type of attachment context value */ attachmentContextValueType?: ValueOf; - /** Current connected policy */ - policy: OnyxEntry; - - /** Invoice receiver policy */ - invoiceReceiverPolicy: OnyxEntry; - - IOUTransaction: OnyxEntry; }; /** @@ -305,9 +297,6 @@ function PureReportActionItem({ userBillingFundID, reportAutomaticallyForwardedMessage, attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, - policy, - invoiceReceiverPolicy, - IOUTransaction, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -1024,9 +1013,6 @@ function PureReportActionItem({ ![CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING].some((item) => item === moderationDecision) && !ReportActionsUtils.isPendingRemove(action) } - personalDetails={personalDetails} - policy={policy} - invoiceReceiverPolicy={invoiceReceiverPolicy} > {content} @@ -1037,14 +1023,17 @@ function PureReportActionItem({ }; if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { + const transactionID = ReportActionsUtils.isMoneyRequestAction(parentReportActionForTransactionThread) + ? ReportActionsUtils.getOriginalMessage(parentReportActionForTransactionThread)?.IOUTransactionID + : '-1'; + return ( ); } diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 606c7fa7b94d..86af7e960e23 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -1,6 +1,7 @@ import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useMemo} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import RenderHTML from '@components/RenderHTML'; @@ -25,7 +26,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; import ReportActionItemCreated from './ReportActionItemCreated'; import ReportActionItemSingle from './ReportActionItemSingle'; -import { usePersonalDetails } from '@components/OnyxProvider'; type ReportActionItemContentCreatedProps = { /** The context value containing the report and action data, along with the show context menu props */ @@ -37,26 +37,24 @@ type ReportActionItemContentCreatedProps = { /** Report action belonging to the report's parent */ parentReportAction: OnyxEntry; - /** Transaction that stores the distance expense data */ - transaction: OnyxEntry; + /** The transaction ID */ + transactionID: string | undefined; /** The draft message */ draftMessage: string | undefined; /** Flag to show, hide the thread divider line */ shouldHideThreadDividerLine: boolean; - - /** Invoice receiver policy */ - invoiceReceiverPolicy: OnyxEntry; }; -function ReportActionItemContentCreated({contextValue, parentReportAction, transaction, draftMessage, shouldHideThreadDividerLine, invoiceReceiverPolicy}: ReportActionItemContentCreatedProps) { +function ReportActionItemContentCreated({contextValue, parentReportAction, transactionID, draftMessage, shouldHideThreadDividerLine}: ReportActionItemContentCreatedProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {report, action, transactionThreadReport} = contextValue; - const personalDetails = usePersonalDetails(); + const policy = usePolicy(report.policyID === CONST.POLICY.OWNER_EMAIL_FAKE ? '-1' : report.policyID ?? '-1'); + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID ?? '-1'}`); const transactionCurrency = TransactionUtils.getCurrency(transaction); @@ -98,9 +96,6 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans action={parentReportAction} showHeader report={report} - policy={policy} - personalDetails={personalDetails} - invoiceReceiverPolicy={invoiceReceiverPolicy} > ${translate(message)}`} /> @@ -135,9 +130,6 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans action={parentReportAction} showHeader={draftMessage === undefined} report={report} - policy={policy} - personalDetails={personalDetails} - invoiceReceiverPolicy={invoiceReceiverPolicy} > ${translate('parentReportAction.deletedTask')}`} /> @@ -208,8 +200,7 @@ export default memo( (prevProps, nextProps) => lodashIsEqual(prevProps.contextValue, nextProps.contextValue) && lodashIsEqual(prevProps.parentReportAction, nextProps.parentReportAction) && - lodashIsEqual(prevProps.transaction, nextProps.transaction) && + prevProps.transactionID === nextProps.transactionID && prevProps.draftMessage === nextProps.draftMessage && - prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine && - lodashIsEqual(prevProps.invoiceReceiverPolicy, nextProps.invoiceReceiverPolicy), -); + prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine, +); \ No newline at end of file diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 609f5a471679..f6d90cd65506 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -2,17 +2,20 @@ 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 {useOnyx} from 'react-native-onyx'; +// import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import {usePersonalDetails} from '@components/OnyxProvider'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import SubscriptAvatar from '@components/SubscriptAvatar'; import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -22,13 +25,11 @@ import Navigation from '@libs/Navigation/Navigation'; import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils'; import {getReportActionMessage} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import type {AvatarSource} from '@libs/UserUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; -import type {Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; -import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; +import type {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'; import ReportActionItemFragment from './ReportActionItemFragment'; @@ -57,15 +58,6 @@ type ReportActionItemSingleProps = Partial & { /** If the action is being hovered */ isHovered?: boolean; - - /** Personal details list */ - personalDetails?: PersonalDetailsList | Record; - - /** Current connected policy */ - policy: OnyxEntry; - - /** Invoice receiver policy */ - invoiceReceiverPolicy: OnyxEntry; }; const showUserDetails = (accountID: string) => { @@ -89,25 +81,23 @@ function ReportActionItemSingle({ report, iouReport, isHovered = false, - personalDetails, - policy, - invoiceReceiverPolicy, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); + const personalDetails = usePersonalDetails(); + 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 = ReportUtils.getReportActionActorAccountID(action, iouReport, report); + const [invoiceReceiverPolicy] = useOnyx( + `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, + ); let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); - const {avatar, login} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {}; - const pendingFields = personalDetails && 'pendingFields' in personalDetails ? personalDetails.pendingFields : undefined; - const status = personalDetails && 'status' in personalDetails ? personalDetails.status : undefined; - const fallbackIcon = personalDetails && 'fallbackIcon' in personalDetails && personalDetails.fallbackIcon !== null ? personalDetails.fallbackIcon : undefined; - + const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {}; const accountOwnerDetails = getPersonalDetailByEmail(login ?? ''); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing let actorHint = (login || (displayName ?? '')).replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); @@ -160,7 +150,7 @@ function ReportActionItemSingle({ } else if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, personalDetails, null, undefined, undefined, policy); + const reportIcons = ReportUtils.getIcons(report, {}); secondaryAvatar = reportIcons.at(avatarIconIndex) ?? {name: '', source: '', type: CONST.ICON_TYPE_AVATAR}; } else if (ReportUtils.isInvoiceReport(iouReport)) { @@ -252,17 +242,17 @@ function ReportActionItemSingle({ type={icon.type} name={icon.name} avatarID={icon.id} - fallbackIcon={fallbackIcon as AvatarSource} + fallbackIcon={fallbackIcon} /> ); }; - const hasEmojiStatus = !displayAllActors && status && 'emojiCode' in status && status?.emojiCode; - const statusClearAfter = status && 'clearAfter' in status ? String(status?.clearAfter) ?? '' : ''; - const formattedDate = DateUtils.getStatusUntilDate(statusClearAfter); - const statusText = status && 'text' in status ? String(status?.text) ?? '' : ''; + const hasEmojiStatus = !displayAllActors && status?.emojiCode; + const formattedDate = DateUtils.getStatusUntilDate(status?.clearAfter ?? ''); + const statusText = status?.text ?? ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; + return ( - {getAvatar()} + {getAvatar()} {showHeader ? ( @@ -306,7 +296,7 @@ function ReportActionItemSingle({ {`${String(status?.emojiCode ?? '')}`} + >{`${status?.emojiCode}`} )} From 7f71e95310f708edc9b76cae957f911d38cb4619 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 14 Jan 2025 10:17:44 +0700 Subject: [PATCH 31/94] WIP create useOnyx wrapper for snapshot, implement some --- .env.bak | 11 +++ .../MoneyRequestPreviewContent.tsx | 2 +- .../ReportActionItem/ReportPreview.tsx | 2 +- src/hooks/useOnyx.ts | 77 +++++++++++++++++++ src/libs/SearchUIUtils.ts | 8 +- src/pages/home/ReportScreen.tsx | 2 +- .../home/report/ReportActionItemSingle.tsx | 1 - 7 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 .env.bak create mode 100644 src/hooks/useOnyx.ts diff --git a/.env.bak b/.env.bak new file mode 100644 index 000000000000..2822b7ff9b05 --- /dev/null +++ b/.env.bak @@ -0,0 +1,11 @@ +NEW_EXPENSIFY_URL=https://staging.new.expensify.com/ +SECURE_EXPENSIFY_URL=https://secure.expensify.com/ +EXPENSIFY_URL=https://www.expensify.com/ +EXPENSIFY_PARTNER_NAME=chat-expensify-com +EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 +PUSHER_APP_KEY=268df511a204fbb60884 +USE_WEB_PROXY=false +ENVIRONMENT=staging +SEND_CRASH_REPORTS=true +GCP_GEOLOCATION_API_KEY=AIzaSyCYB1NPz8ml6lEdS3NGA4LRNcJ6cwlNhBg +# GCP_GEOLOCATION_API_KEY=osdpkf diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index d68e56e36bc7..1c3718c75b54 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -4,7 +4,7 @@ import truncate from 'lodash/truncate'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import type {GestureResponderEvent} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 0d312b5d1a40..cddc940b24da 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -2,7 +2,7 @@ import truncate from 'lodash/truncate'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Animated, {useAnimatedStyle, useSharedValue, withDelay, withSpring, withTiming} from 'react-native-reanimated'; import Button from '@components/Button'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts new file mode 100644 index 000000000000..2bf144446826 --- /dev/null +++ b/src/hooks/useOnyx.ts @@ -0,0 +1,77 @@ +import {useMemo} from 'react'; +import {useOnyx as originalUseOnyx} from 'react-native-onyx'; +import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; +import type {DependencyList} from 'react'; +import { useRoute } from '@react-navigation/native'; +import * as SearchQueryUtils from '@libs/SearchQueryUtils'; +import { AuthScreensParamList } from '@libs/Navigation/types'; +import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; + +import SCREENS from '@src/SCREENS'; + +type BaseUseOnyxOptions = { + canEvict?: boolean; + initWithStoredValues?: boolean; + allowStaleData?: boolean; + reuseConnection?: boolean; + }; + + type UseOnyxInitialValueOption = { + initialValue?: TInitialValue; + }; + + type UseOnyxSelector> = + (data: OnyxValue | undefined) => TReturnValue; + + type UseOnyxSelectorOption = { + selector?: UseOnyxSelector; + }; + + function useOnyx>( + key: TKey, + options?: BaseUseOnyxOptions & UseOnyxInitialValueOption & Required>, + dependencies?: DependencyList + ): UseOnyxResult; + + function useOnyx>( + key: TKey, + options?: BaseUseOnyxOptions & UseOnyxInitialValueOption>, + dependencies?: DependencyList + ): UseOnyxResult; + + function useOnyx>( + key: TKey, + options?: any, + dependencies?: DependencyList + ): UseOnyxResult { + + const route = useRoute>(); + const {q} = route.params ; + console.log("[wildebug] ~ file: useOnyx.ts:51 ~ q:", q) + const queryJSON = useMemo(() => q ? SearchQueryUtils.buildSearchQueryJSON(q) : {} as { hash?: string }, [q]); + const hashKey = queryJSON?.hash + const isOnSearch = !!hashKey; + console.log("[wildebug] ~ file: useOnyx.ts:55 ~ isOnSearch:", isOnSearch) + + // In search mode, get the entire snapshot + const [snapshotData, metadata] = originalUseOnyx( + isOnSearch ? `snapshot_${hashKey}` as TKey : key, + options, + dependencies, + ); + console.log("[wildebug] ~ file: useOnyxWithSnapshot.ts:60 ~ hashKey:", hashKey) + + // Extract the specific key data from snapshot if in search mode + const result = useMemo(() => { + if (!isOnSearch || !snapshotData) { + return [snapshotData, metadata] as UseOnyxResult; + } + + const keyData = (snapshotData as Record)?.data[key as string]; + return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; + }, [isOnSearch, key, snapshotData, metadata]); + + return result; +} + +export default useOnyx; \ No newline at end of file diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index aa9330080f85..29754be73f02 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -334,10 +334,10 @@ function getReportActionsSections(data: OnyxTypes.SearchResults['data']): Report // eslint-disable-next-line no-continue continue; } - if (!isAddCommentAction(reportAction)) { - // eslint-disable-next-line no-continue - continue; - } + // if (!isAddCommentAction(reportAction)) { + // // eslint-disable-next-line no-continue + // continue; + // } reportActionItems.push({ ...reportAction, from, diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index b02ccec1a56b..5a88374414ca 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -5,7 +5,7 @@ import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 're import type {FlatList, ViewStyle} from 'react-native'; import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Banner from '@components/Banner'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index f6d90cd65506..b55546b2f6ca 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -2,7 +2,6 @@ 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 {useOnyx} from 'react-native-onyx'; import useOnyx from '@hooks/useOnyx'; import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; From aad9c7cecc777b7176d392f51bfb4cffad8d6d7d Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 14 Jan 2025 13:03:47 +0700 Subject: [PATCH 32/94] update `useOnyx` wrapper --- src/hooks/useOnyx.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 2bf144446826..f80050df4e36 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -8,6 +8,7 @@ import { AuthScreensParamList } from '@libs/Navigation/types'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import SCREENS from '@src/SCREENS'; +import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; type BaseUseOnyxOptions = { canEvict?: boolean; @@ -46,11 +47,12 @@ type BaseUseOnyxOptions = { ): UseOnyxResult { const route = useRoute>(); - const {q} = route.params ; + const {q} = route?.params || {}; console.log("[wildebug] ~ file: useOnyx.ts:51 ~ q:", q) const queryJSON = useMemo(() => q ? SearchQueryUtils.buildSearchQueryJSON(q) : {} as { hash?: string }, [q]); const hashKey = queryJSON?.hash const isOnSearch = !!hashKey; + console.log("[wildebug] ~ file: useOnyx.ts:55 ~ isSearchTopmostCentralPane():", isSearchTopmostCentralPane()) console.log("[wildebug] ~ file: useOnyx.ts:55 ~ isOnSearch:", isOnSearch) // In search mode, get the entire snapshot @@ -68,6 +70,9 @@ type BaseUseOnyxOptions = { } const keyData = (snapshotData as Record)?.data[key as string]; + console.log("[wildebug] ~ file: useOnyx.ts:73 ~ result ~ key:", key) + console.log("[wildebug] ~ file: useOnyx.ts:73 ~ result ~ keyData:", keyData) + return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); From e18ecc7500b54d5215ff363ddb569c4ca14d6228 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 14 Jan 2025 13:12:44 +0700 Subject: [PATCH 33/94] remove env --- .env.bak | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 .env.bak diff --git a/.env.bak b/.env.bak deleted file mode 100644 index 2822b7ff9b05..000000000000 --- a/.env.bak +++ /dev/null @@ -1,11 +0,0 @@ -NEW_EXPENSIFY_URL=https://staging.new.expensify.com/ -SECURE_EXPENSIFY_URL=https://secure.expensify.com/ -EXPENSIFY_URL=https://www.expensify.com/ -EXPENSIFY_PARTNER_NAME=chat-expensify-com -EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66 -PUSHER_APP_KEY=268df511a204fbb60884 -USE_WEB_PROXY=false -ENVIRONMENT=staging -SEND_CRASH_REPORTS=true -GCP_GEOLOCATION_API_KEY=AIzaSyCYB1NPz8ml6lEdS3NGA4LRNcJ6cwlNhBg -# GCP_GEOLOCATION_API_KEY=osdpkf From 25c770d8aabcba1150e12055777b2340112c00d6 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 14:00:26 +0700 Subject: [PATCH 34/94] update useOnyx, handle collection key case --- src/hooks/useOnyx.ts | 69 ++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index f80050df4e36..da974a4b81c3 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -2,58 +2,63 @@ import {useMemo} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; import type {DependencyList} from 'react'; -import { useRoute } from '@react-navigation/native'; -import * as SearchQueryUtils from '@libs/SearchQueryUtils'; -import { AuthScreensParamList } from '@libs/Navigation/types'; -import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; - -import SCREENS from '@src/SCREENS'; -import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; +import { useSearchState } from './useSearchState'; +// Base options for Onyx hook configuration type BaseUseOnyxOptions = { canEvict?: boolean; initWithStoredValues?: boolean; allowStaleData?: boolean; reuseConnection?: boolean; - }; +}; - type UseOnyxInitialValueOption = { +type UseOnyxInitialValueOption = { initialValue?: TInitialValue; - }; +}; - type UseOnyxSelector> = +type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; - type UseOnyxSelectorOption = { +type UseOnyxSelectorOption = { selector?: UseOnyxSelector; - }; +}; + +// Helper function to get key data from snapshot +const getKeyData = (snapshotData: Record, key: string) => { + if (key.endsWith('_')) { + // Create object to store matching entries + const result: Record = {}; + const prefix = key; + + // Get all keys that start with the prefix + Object.entries(snapshotData?.data || {}).forEach(([dataKey, value]) => { + if (dataKey.startsWith(prefix)) { + result[dataKey] = value; + } + }); + return result; + } + return snapshotData?.data?.[key]; +}; - function useOnyx>( +function useOnyx>( key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption & Required>, dependencies?: DependencyList - ): UseOnyxResult; +): UseOnyxResult; - function useOnyx>( +function useOnyx>( key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption>, dependencies?: DependencyList - ): UseOnyxResult; - - function useOnyx>( +): UseOnyxResult; + +function useOnyx>( key: TKey, options?: any, dependencies?: DependencyList - ): UseOnyxResult { - - const route = useRoute>(); - const {q} = route?.params || {}; - console.log("[wildebug] ~ file: useOnyx.ts:51 ~ q:", q) - const queryJSON = useMemo(() => q ? SearchQueryUtils.buildSearchQueryJSON(q) : {} as { hash?: string }, [q]); - const hashKey = queryJSON?.hash - const isOnSearch = !!hashKey; - console.log("[wildebug] ~ file: useOnyx.ts:55 ~ isSearchTopmostCentralPane():", isSearchTopmostCentralPane()) - console.log("[wildebug] ~ file: useOnyx.ts:55 ~ isOnSearch:", isOnSearch) +): UseOnyxResult { + const {isOnSearch, hashKey} = useSearchState(); // In search mode, get the entire snapshot const [snapshotData, metadata] = originalUseOnyx( @@ -61,7 +66,6 @@ type BaseUseOnyxOptions = { options, dependencies, ); - console.log("[wildebug] ~ file: useOnyxWithSnapshot.ts:60 ~ hashKey:", hashKey) // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { @@ -69,10 +73,7 @@ type BaseUseOnyxOptions = { return [snapshotData, metadata] as UseOnyxResult; } - const keyData = (snapshotData as Record)?.data[key as string]; - console.log("[wildebug] ~ file: useOnyx.ts:73 ~ result ~ key:", key) - console.log("[wildebug] ~ file: useOnyx.ts:73 ~ result ~ keyData:", keyData) - + const keyData = getKeyData(snapshotData as Record, key as string); return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); From c1639d35508e67efa797c0b13d20f2b8a255b3bc Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 14:08:01 +0700 Subject: [PATCH 35/94] create useSearchState, use useOnyx wrapper in usePolicy --- src/hooks/usePolicy.ts | 2 +- src/hooks/useSearchState.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useSearchState.ts diff --git a/src/hooks/usePolicy.ts b/src/hooks/usePolicy.ts index f08b1b323022..92ef8c209733 100644 --- a/src/hooks/usePolicy.ts +++ b/src/hooks/usePolicy.ts @@ -1,4 +1,4 @@ -import {useOnyx} from 'react-native-onyx'; +import useOnyx from './useOnyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts new file mode 100644 index 000000000000..74218a88b314 --- /dev/null +++ b/src/hooks/useSearchState.ts @@ -0,0 +1,31 @@ +import { useMemo } from 'react'; +import { useRoute } from '@react-navigation/native'; +import { buildSearchQueryJSON } from '@libs/SearchQueryUtils'; +import { AuthScreensParamList } from '@libs/Navigation/types'; +import type { PlatformStackRouteProp } from '@libs/Navigation/PlatformStackNavigation/types'; +import SCREENS from '@src/SCREENS'; + +type SearchResult = { + isOnSearch: boolean; + hashKey?: string; +}; + +/** + * Hook to manage search state based on route parameters + * Returns search status and hash for query tracking + */ +export const useSearchState = (): SearchResult => { + const route = useRoute>(); + const { q } = route?.params || {}; + + return useMemo(() => { + const queryJSON = q ? buildSearchQueryJSON(q) : {} as { hash?: string }; + const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; + const isOnSearch = ( + route?.name === SCREENS.SEARCH.CENTRAL_PANE || + route?.name === SCREENS.SEARCH.BOTTOM_TAB + ) && !!hashKey; + + return { hashKey, isOnSearch }; + }, [q, route?.name]); +}; \ No newline at end of file From 697f9a63946b7db0857bf0a3ba3c4d3d73d4c7fa Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 14:10:22 +0700 Subject: [PATCH 36/94] use @hooks/useOnyx to reportactionitem and its subcomponent --- src/components/AddPaymentMethodMenu.tsx | 2 +- src/components/AvatarWithDisplayName.tsx | 26 +++----------- src/components/KYCWall/BaseKYCWall.tsx | 2 +- src/components/MapView/MapView.tsx | 2 +- .../MapView/MapViewImpl.website.tsx | 2 +- .../ReportActionItem/IssueCardMessage.tsx | 2 +- .../ReportActionItem/MoneyReportView.tsx | 2 +- .../ReportActionItem/MoneyRequestAction.tsx | 35 ++++--------------- .../MoneyRequestPreview/index.tsx | 2 +- .../ReportActionItem/MoneyRequestView.tsx | 2 +- .../ReportActionItem/ReportPreview.tsx | 1 + .../ReportActionItem/TaskPreview.tsx | 2 +- .../ReportActionItem/TripRoomPreview.tsx | 2 +- src/components/ReportWelcomeText.tsx | 2 +- src/components/SelectionList/ChatListItem.tsx | 29 ++++++++++++--- .../BaseUserDetailsTooltip/index.tsx | 2 +- .../home/report/PureReportActionItem.tsx | 15 ++++---- src/pages/home/report/ReportActionItem.tsx | 2 +- .../report/ReportActionItemContentCreated.tsx | 2 +- .../home/report/ReportActionItemMessage.tsx | 2 +- 20 files changed, 58 insertions(+), 78 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.tsx b/src/components/AddPaymentMethodMenu.tsx index 50020906075d..0020feb75e98 100644 --- a/src/components/AddPaymentMethodMenu.tsx +++ b/src/components/AddPaymentMethodMenu.tsx @@ -2,7 +2,7 @@ import type {RefObject} from 'react'; import React, {useEffect, useState} from 'react'; import type {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import useLocalize from '@hooks/useLocalize'; import {completePaymentOnboarding} from '@libs/actions/IOU'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 98e6dd626883..b31ae9f28f69 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -1,7 +1,7 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx, withOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {ValueOf} from 'type-fest'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -23,15 +23,7 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import SubscriptAvatar from './SubscriptAvatar'; import Text from './Text'; -type AvatarWithDisplayNamePropsWithOnyx = { - /** All of the actions of the report */ - parentReportActions: OnyxEntry; - - /** Personal details of all users */ - personalDetails: OnyxEntry; -}; - -type AvatarWithDisplayNameProps = AvatarWithDisplayNamePropsWithOnyx & { +type AvatarWithDisplayNameProps = { /** The report currently being looked at */ report: OnyxEntry; @@ -58,11 +50,9 @@ const fallbackIcon: Icon = { function AvatarWithDisplayName({ policy, report, - parentReportActions, isAnonymous = false, size = CONST.AVATAR_SIZE.DEFAULT, shouldEnableDetailPageNavigation = false, - personalDetails = CONST.EMPTY_OBJECT, }: AvatarWithDisplayNameProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -71,6 +61,8 @@ function AvatarWithDisplayName({ const [invoiceReceiverPolicy] = useOnyx( `${ONYXKEYS.COLLECTION.POLICY}${parentReport?.invoiceReceiver && 'policyID' in parentReport.invoiceReceiver ? parentReport.invoiceReceiver.policyID : -1}`, ); + const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '-1'}`, {canEvict: false}); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const title = ReportUtils.getReportName(report, undefined, undefined, undefined, invoiceReceiverPolicy); const subtitle = ReportUtils.getChatRoomSubtitle(report); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(report); @@ -198,12 +190,4 @@ function AvatarWithDisplayName({ AvatarWithDisplayName.displayName = 'AvatarWithDisplayName'; -export default withOnyx({ - parentReportActions: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '-1'}`, - canEvict: false, - }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, -})(AvatarWithDisplayName); +export default AvatarWithDisplayName; diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 7526720bddc0..2206d62aa266 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -2,7 +2,7 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Dimensions} from 'react-native'; import type {EmitterSubscription, GestureResponderEvent, View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; import * as BankAccounts from '@libs/actions/BankAccounts'; import {completePaymentOnboarding} from '@libs/actions/IOU'; diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 6f1c7aaee458..3ef0165b5b72 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -3,7 +3,7 @@ import type {MapState} from '@rnmapbox/maps'; import Mapbox, {MarkerView, setAccessToken} from '@rnmapbox/maps'; import {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; import useTheme from '@hooks/useTheme'; diff --git a/src/components/MapView/MapViewImpl.website.tsx b/src/components/MapView/MapViewImpl.website.tsx index 611c1b117fbf..4b302adaab83 100644 --- a/src/components/MapView/MapViewImpl.website.tsx +++ b/src/components/MapView/MapViewImpl.website.tsx @@ -9,7 +9,7 @@ import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, import type {MapRef, ViewState} from 'react-map-gl'; import Map, {Marker} from 'react-map-gl'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; import usePrevious from '@hooks/usePrevious'; diff --git a/src/components/ReportActionItem/IssueCardMessage.tsx b/src/components/ReportActionItem/IssueCardMessage.tsx index dcf657137d58..891cade0eab8 100644 --- a/src/components/ReportActionItem/IssueCardMessage.tsx +++ b/src/components/ReportActionItem/IssueCardMessage.tsx @@ -1,6 +1,6 @@ import React from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index d1dcdb2f57f5..72a9dc8fa33e 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -2,7 +2,7 @@ import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {ActivityIndicator, View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx index af54e2940d3f..0f6f878120d3 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.tsx +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -1,7 +1,5 @@ import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -17,19 +15,9 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import MoneyRequestPreview from './MoneyRequestPreview'; +import useOnyx from '@hooks/useOnyx'; -type MoneyRequestActionOnyxProps = { - /** Chat report associated with iouReport */ - chatReport: OnyxEntry; - - /** IOU report data object */ - iouReport: OnyxEntry; - - /** Report actions for this report */ - reportActions: OnyxEntry; -}; - -type MoneyRequestActionProps = MoneyRequestActionOnyxProps & { +type MoneyRequestActionProps = { /** All the data of the action */ action: OnyxTypes.ReportAction; @@ -72,9 +60,6 @@ function MoneyRequestAction({ isMostRecentIOUReportAction, contextMenuAnchor, checkIfContextMenuActive = () => {}, - chatReport, - iouReport, - reportActions, isHovered = false, style, isWhisper = false, @@ -85,6 +70,9 @@ function MoneyRequestAction({ const {isOffline} = useNetwork(); const isSplitBillAction = ReportActionsUtils.isSplitBillAction(action); const isTrackExpenseAction = ReportActionsUtils.isTrackExpenseAction(action); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`) + const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`) + const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`) const onMoneyRequestPreviewPressed = () => { if (isSplitBillAction) { @@ -142,15 +130,4 @@ function MoneyRequestAction({ MoneyRequestAction.displayName = 'MoneyRequestAction'; -export default withOnyx({ - chatReport: { - key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, - }, - iouReport: { - key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`, - }, - reportActions: { - key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, - canEvict: false, - }, -})(MoneyRequestAction); +export default MoneyRequestAction; diff --git a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx index f902948b2cb5..8e1e135d010a 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/index.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/index.tsx @@ -1,6 +1,6 @@ import lodashIsEmpty from 'lodash/isEmpty'; import React from 'react'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import ONYXKEYS from '@src/ONYXKEYS'; import MoneyRequestPreviewContent from './MoneyRequestPreviewContent'; import type {MoneyRequestPreviewProps} from './types'; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 18750bfc7a29..f0d3014de056 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,6 +1,6 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index cddc940b24da..60ee2bf795f9 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -93,6 +93,7 @@ import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import ExportWithDropdownMenu from './ExportWithDropdownMenu'; import type {PendingMessageProps} from './MoneyRequestPreview/types'; import ReportActionItemImages from './ReportActionItemImages'; +import { useSearchState } from '@hooks/useSearchState'; type ReportPreviewProps = { /** All the data of the action */ diff --git a/src/components/ReportActionItem/TaskPreview.tsx b/src/components/ReportActionItem/TaskPreview.tsx index 2ea295d16143..99753b8dde6d 100644 --- a/src/components/ReportActionItem/TaskPreview.tsx +++ b/src/components/ReportActionItem/TaskPreview.tsx @@ -2,7 +2,7 @@ import {Str} from 'expensify-common'; import React from 'react'; import {View} from 'react-native'; import type {StyleProp, ViewStyle} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Avatar from '@components/Avatar'; import Checkbox from '@components/Checkbox'; diff --git a/src/components/ReportActionItem/TripRoomPreview.tsx b/src/components/ReportActionItem/TripRoomPreview.tsx index 764979651ee7..a89780fa4265 100644 --- a/src/components/ReportActionItem/TripRoomPreview.tsx +++ b/src/components/ReportActionItem/TripRoomPreview.tsx @@ -1,7 +1,7 @@ import React, {useMemo} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {FlatList, View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 08f0d17172a1..8bd059837cf7 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -1,7 +1,7 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index e69cf68adf6f..34a0d75c8f2a 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -8,6 +8,10 @@ import CONST from '@src/CONST'; import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; +import useOnyx from '@hooks/useOnyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import ReportActionItem from '@pages/home/report/ReportActionItem'; function ChatListItem({ item, @@ -48,6 +52,9 @@ function ChatListItem({ [from.accountID]: from, }; + // const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${ReportActionsUtils.getIOUReportIDFromReportActionPreview(reportActionItem)}`); + const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportActionItem?.reportID}`); + return ( ({ pressableWrapperStyle={[styles.mh5, animatedHighlightStyle]} hoverStyle={item.isSelected && styles.activeComponentBG} > - onSelectRow(item)} + reportActions={[]} + parentReportAction={undefined} + displayAsGroup={false} + isMostRecentIOUReportAction={false} + shouldDisplayNewMarker={false} + index={0} + isFirstVisibleReportAction={false} + shouldDisplayContextMenu={false} + /> + + {/* onSelectRow(item)} report={undefined} @@ -83,10 +104,8 @@ function ChatListItem({ personalDetails={personalDetails} shouldDisplayContextMenu={false} attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} - policy={undefined} - invoiceReceiverPolicy={undefined} - IOUTransaction={undefined} - /> + iouReport={iouReport} + /> */} ); } diff --git a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx index c55edd9e6b15..3da9eaf2172a 100644 --- a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx +++ b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx @@ -1,7 +1,7 @@ import {Str} from 'expensify-common'; import React, {useCallback} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Avatar from '@components/Avatar'; import {usePersonalDetails} from '@components/OnyxProvider'; import Text from '@components/Text'; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 08351c27265e..076d2ae73ac1 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -81,6 +81,7 @@ import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import ReportAttachmentsContext from './ReportAttachmentsContext'; +import { useSearchState } from '@hooks/useSearchState'; type PureReportActionItemProps = { /** Report for this action */ @@ -240,9 +241,6 @@ type PureReportActionItemProps = { /** A message related to a report action that has been automatically forwarded */ reportAutomaticallyForwardedMessage?: string; - /** Type of attachment context value */ - attachmentContextValueType?: ValueOf; - }; /** @@ -296,7 +294,6 @@ function PureReportActionItem({ dismissTrackExpenseActionableWhisper = () => {}, userBillingFundID, reportAutomaticallyForwardedMessage, - attachmentContextValueType = CONST.ATTACHMENT_TYPE.REPORT, }: PureReportActionItemProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); @@ -351,6 +348,8 @@ function PureReportActionItem({ [action.reportActionID, action.message, updateHiddenAttachments], ); + const { isOnSearch } = useSearchState(); + useEffect( () => () => { // ReportActionContextMenu, EmojiPicker and PopoverReactionList are global components, @@ -522,11 +521,11 @@ function PureReportActionItem({ ); const attachmentContextValue = useMemo(() => { - if (attachmentContextValueType === CONST.ATTACHMENT_TYPE.SEARCH) { - return {type: attachmentContextValueType}; + if (isOnSearch) { + return { type: CONST.ATTACHMENT_TYPE.SEARCH }; } - return {reportID, type: attachmentContextValueType}; - }, [reportID, attachmentContextValueType]); + return { reportID, type: CONST.ATTACHMENT_TYPE.REPORT }; + }, [reportID, isOnSearch]); const mentionReportContextValue = useMemo(() => ({currentReportID: reportID ?? '-1'}), [reportID]); diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index c32a87de10e1..355923aafe02 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -1,5 +1,5 @@ import React, {useMemo} from 'react'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import {useBlockedFromConcierge, usePersonalDetails} from '@components/OnyxProvider'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index 86af7e960e23..b630a0f07881 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -1,7 +1,7 @@ import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useMemo} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import RenderHTML from '@components/RenderHTML'; diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 647c17f70d88..1bd1dd4f4f1f 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -2,7 +2,7 @@ import type {ReactElement} from 'react'; import React from 'react'; import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; From 1ec4dba7972066cc71f5d1b8be4e0cc6fc86084c Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 14:12:36 +0700 Subject: [PATCH 37/94] run prettier --- src/components/AddPaymentMethodMenu.tsx | 2 +- src/components/AvatarWithDisplayName.tsx | 10 +---- src/components/KYCWall/BaseKYCWall.tsx | 2 +- src/components/MapView/MapView.tsx | 2 +- .../MapView/MapViewImpl.website.tsx | 2 +- .../ReportActionItem/IssueCardMessage.tsx | 2 +- .../ReportActionItem/MoneyReportView.tsx | 2 +- .../ReportActionItem/MoneyRequestAction.tsx | 8 ++-- .../MoneyRequestPreviewContent.tsx | 2 +- .../ReportActionItem/MoneyRequestView.tsx | 2 +- .../ReportActionItem/ReportPreview.tsx | 4 +- .../ReportActionItem/TaskPreview.tsx | 2 +- .../ReportActionItem/TripRoomPreview.tsx | 2 +- src/components/ReportWelcomeText.tsx | 2 +- src/components/SelectionList/ChatListItem.tsx | 8 ++-- .../BaseUserDetailsTooltip/index.tsx | 2 +- src/hooks/useOnyx.ts | 37 +++++++------------ src/hooks/usePolicy.ts | 2 +- src/hooks/useSearchState.ts | 37 +++++++++---------- src/pages/home/ReportScreen.tsx | 2 +- .../home/report/PureReportActionItem.tsx | 8 ++-- src/pages/home/report/ReportActionItem.tsx | 4 +- .../report/ReportActionItemContentCreated.tsx | 4 +- .../home/report/ReportActionItemMessage.tsx | 2 +- .../home/report/ReportActionItemSingle.tsx | 2 +- 25 files changed, 67 insertions(+), 85 deletions(-) diff --git a/src/components/AddPaymentMethodMenu.tsx b/src/components/AddPaymentMethodMenu.tsx index 0020feb75e98..34da724665fe 100644 --- a/src/components/AddPaymentMethodMenu.tsx +++ b/src/components/AddPaymentMethodMenu.tsx @@ -2,8 +2,8 @@ import type {RefObject} from 'react'; import React, {useEffect, useState} from 'react'; import type {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import {completePaymentOnboarding} from '@libs/actions/IOU'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index b31ae9f28f69..4a74538d7355 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -1,8 +1,8 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; import type {ValueOf} from 'type-fest'; +import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -47,13 +47,7 @@ const fallbackIcon: Icon = { id: -1, }; -function AvatarWithDisplayName({ - policy, - report, - isAnonymous = false, - size = CONST.AVATAR_SIZE.DEFAULT, - shouldEnableDetailPageNavigation = false, -}: AvatarWithDisplayNameProps) { +function AvatarWithDisplayName({policy, report, isAnonymous = false, size = CONST.AVATAR_SIZE.DEFAULT, shouldEnableDetailPageNavigation = false}: AvatarWithDisplayNameProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 2206d62aa266..5db65bf1ad80 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -2,8 +2,8 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Dimensions} from 'react-native'; import type {EmitterSubscription, GestureResponderEvent, View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu'; +import useOnyx from '@hooks/useOnyx'; import * as BankAccounts from '@libs/actions/BankAccounts'; import {completePaymentOnboarding} from '@libs/actions/IOU'; import getClickedTargetLocation from '@libs/getClickedTargetLocation'; diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 3ef0165b5b72..2dc0ab9b8672 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -3,9 +3,9 @@ import type {MapState} from '@rnmapbox/maps'; import Mapbox, {MarkerView, setAccessToken} from '@rnmapbox/maps'; import {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; +import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as UserLocation from '@libs/actions/UserLocation'; diff --git a/src/components/MapView/MapViewImpl.website.tsx b/src/components/MapView/MapViewImpl.website.tsx index 4b302adaab83..61a83cccffde 100644 --- a/src/components/MapView/MapViewImpl.website.tsx +++ b/src/components/MapView/MapViewImpl.website.tsx @@ -9,9 +9,9 @@ import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, import type {MapRef, ViewState} from 'react-map-gl'; import Map, {Marker} from 'react-map-gl'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; +import useOnyx from '@hooks/useOnyx'; import usePrevious from '@hooks/usePrevious'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; diff --git a/src/components/ReportActionItem/IssueCardMessage.tsx b/src/components/ReportActionItem/IssueCardMessage.tsx index 891cade0eab8..71f12898750f 100644 --- a/src/components/ReportActionItem/IssueCardMessage.tsx +++ b/src/components/ReportActionItem/IssueCardMessage.tsx @@ -1,9 +1,9 @@ import React from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 72a9dc8fa33e..76c778fadf8a 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -2,7 +2,6 @@ import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {ActivityIndicator, View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -13,6 +12,7 @@ import Text from '@components/Text'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx index 0f6f878120d3..503fb9a145ea 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.tsx +++ b/src/components/ReportActionItem/MoneyRequestAction.tsx @@ -3,6 +3,7 @@ import type {StyleProp, ViewStyle} from 'react-native'; import RenderHTML from '@components/RenderHTML'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; @@ -15,7 +16,6 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import MoneyRequestPreview from './MoneyRequestPreview'; -import useOnyx from '@hooks/useOnyx'; type MoneyRequestActionProps = { /** All the data of the action */ @@ -70,9 +70,9 @@ function MoneyRequestAction({ const {isOffline} = useNetwork(); const isSplitBillAction = ReportActionsUtils.isSplitBillAction(action); const isTrackExpenseAction = ReportActionsUtils.isTrackExpenseAction(action); - const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`) - const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`) - const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`) + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`); + const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`); + const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`); const onMoneyRequestPreviewPressed = () => { if (isSplitBillAction) { diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 1c3718c75b54..f9f5e1692013 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -4,7 +4,6 @@ import truncate from 'lodash/truncate'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import type {GestureResponderEvent} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; @@ -18,6 +17,7 @@ import ReportActionItemImages from '@components/ReportActionItem/ReportActionIte import {showContextMenuForReport} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index f0d3014de056..3484ebac0b6c 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; @@ -15,6 +14,7 @@ import ViolationMessages from '@components/ViolationMessages'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import useViolations from '@hooks/useViolations'; import type {ViolationField} from '@hooks/useViolations'; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 60ee2bf795f9..339fe2504193 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -2,7 +2,6 @@ import truncate from 'lodash/truncate'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Animated, {useAnimatedStyle, useSharedValue, withDelay, withSpring, withTiming} from 'react-native-reanimated'; import Button from '@components/Button'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; @@ -18,7 +17,9 @@ import Text from '@components/Text'; import useDelegateUserDetails from '@hooks/useDelegateUserDetails'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; +import {useSearchState} from '@hooks/useSearchState'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getCurrentUserAccountID} from '@libs/actions/Report'; @@ -93,7 +94,6 @@ import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import ExportWithDropdownMenu from './ExportWithDropdownMenu'; import type {PendingMessageProps} from './MoneyRequestPreview/types'; import ReportActionItemImages from './ReportActionItemImages'; -import { useSearchState } from '@hooks/useSearchState'; type ReportPreviewProps = { /** All the data of the action */ diff --git a/src/components/ReportActionItem/TaskPreview.tsx b/src/components/ReportActionItem/TaskPreview.tsx index 99753b8dde6d..27fca8b0b2ec 100644 --- a/src/components/ReportActionItem/TaskPreview.tsx +++ b/src/components/ReportActionItem/TaskPreview.tsx @@ -2,7 +2,6 @@ import {Str} from 'expensify-common'; import React from 'react'; import {View} from 'react-native'; import type {StyleProp, ViewStyle} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import Avatar from '@components/Avatar'; import Checkbox from '@components/Checkbox'; @@ -17,6 +16,7 @@ import UserDetailsTooltip from '@components/UserDetailsTooltip'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/ReportActionItem/TripRoomPreview.tsx b/src/components/ReportActionItem/TripRoomPreview.tsx index a89780fa4265..ebe9a63c79fe 100644 --- a/src/components/ReportActionItem/TripRoomPreview.tsx +++ b/src/components/ReportActionItem/TripRoomPreview.tsx @@ -1,7 +1,6 @@ import React, {useMemo} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {FlatList, View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -10,6 +9,7 @@ import {PressableWithoutFeedback} from '@components/Pressable'; import {showContextMenuForReport} from '@components/ShowContextMenuContext'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 8bd059837cf7..656007ccc80a 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -1,8 +1,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 34a0d75c8f2a..9f6e1cd85eac 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -1,17 +1,17 @@ import React from 'react'; import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; +import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import PureReportActionItem from '@pages/home/report/PureReportActionItem'; +import ReportActionItem from '@pages/home/report/ReportActionItem'; import variables from '@styles/variables'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; -import useOnyx from '@hooks/useOnyx'; -import ONYXKEYS from '@src/ONYXKEYS'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import ReportActionItem from '@pages/home/report/ReportActionItem'; function ChatListItem({ item, diff --git a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx index 3da9eaf2172a..9620b2b799c6 100644 --- a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx +++ b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip/index.tsx @@ -1,13 +1,13 @@ import {Str} from 'expensify-common'; import React, {useCallback} from 'react'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Avatar from '@components/Avatar'; import {usePersonalDetails} from '@components/OnyxProvider'; import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import type UserDetailsTooltipProps from '@components/UserDetailsTooltip/types'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import {isAnonymousUser} from '@libs/actions/Session'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index da974a4b81c3..a31e990f35c8 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -1,8 +1,8 @@ import {useMemo} from 'react'; +import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; -import type {DependencyList} from 'react'; -import { useSearchState } from './useSearchState'; +import {useSearchState} from './useSearchState'; // Base options for Onyx hook configuration type BaseUseOnyxOptions = { @@ -11,14 +11,13 @@ type BaseUseOnyxOptions = { allowStaleData?: boolean; reuseConnection?: boolean; }; - + type UseOnyxInitialValueOption = { initialValue?: TInitialValue; }; - -type UseOnyxSelector> = - (data: OnyxValue | undefined) => TReturnValue; - + +type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; + type UseOnyxSelectorOption = { selector?: UseOnyxSelector; }; @@ -40,32 +39,24 @@ const getKeyData = (snapshotData: Record, key: string) => { } return snapshotData?.data?.[key]; }; - + function useOnyx>( key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption & Required>, - dependencies?: DependencyList + dependencies?: DependencyList, ): UseOnyxResult; - + function useOnyx>( - key: TKey, + key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption>, - dependencies?: DependencyList + dependencies?: DependencyList, ): UseOnyxResult; -function useOnyx>( - key: TKey, - options?: any, - dependencies?: DependencyList -): UseOnyxResult { +function useOnyx>(key: TKey, options?: any, dependencies?: DependencyList): UseOnyxResult { const {isOnSearch, hashKey} = useSearchState(); // In search mode, get the entire snapshot - const [snapshotData, metadata] = originalUseOnyx( - isOnSearch ? `snapshot_${hashKey}` as TKey : key, - options, - dependencies, - ); + const [snapshotData, metadata] = originalUseOnyx(isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, options, dependencies); // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { @@ -80,4 +71,4 @@ function useOnyx>( return result; } -export default useOnyx; \ No newline at end of file +export default useOnyx; diff --git a/src/hooks/usePolicy.ts b/src/hooks/usePolicy.ts index 92ef8c209733..e3d5ec1a1659 100644 --- a/src/hooks/usePolicy.ts +++ b/src/hooks/usePolicy.ts @@ -1,6 +1,6 @@ -import useOnyx from './useOnyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import useOnyx from './useOnyx'; function getPolicyIDOrDefault(policyID?: string) { if (!policyID || policyID === CONST.POLICY.OWNER_EMAIL_FAKE) { diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index 74218a88b314..51ca84e9b75c 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -1,13 +1,13 @@ -import { useMemo } from 'react'; -import { useRoute } from '@react-navigation/native'; -import { buildSearchQueryJSON } from '@libs/SearchQueryUtils'; -import { AuthScreensParamList } from '@libs/Navigation/types'; -import type { PlatformStackRouteProp } from '@libs/Navigation/PlatformStackNavigation/types'; +import {useRoute} from '@react-navigation/native'; +import {useMemo} from 'react'; +import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; +import {AuthScreensParamList} from '@libs/Navigation/types'; +import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import SCREENS from '@src/SCREENS'; type SearchResult = { - isOnSearch: boolean; - hashKey?: string; + isOnSearch: boolean; + hashKey?: string; }; /** @@ -15,17 +15,14 @@ type SearchResult = { * Returns search status and hash for query tracking */ export const useSearchState = (): SearchResult => { - const route = useRoute>(); - const { q } = route?.params || {}; + const route = useRoute>(); + const {q} = route?.params || {}; - return useMemo(() => { - const queryJSON = q ? buildSearchQueryJSON(q) : {} as { hash?: string }; - const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; - const isOnSearch = ( - route?.name === SCREENS.SEARCH.CENTRAL_PANE || - route?.name === SCREENS.SEARCH.BOTTOM_TAB - ) && !!hashKey; - - return { hashKey, isOnSearch }; - }, [q, route?.name]); -}; \ No newline at end of file + return useMemo(() => { + const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: string}); + const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; + const isOnSearch = (route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey; + + return {hashKey, isOnSearch}; + }, [q, route?.name]); +}; diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 5a88374414ca..94a06a3341a7 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -5,7 +5,6 @@ import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 're import type {FlatList, ViewStyle} from 'react-native'; import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import useOnyx from '@hooks/useOnyx'; import Banner from '@components/Banner'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; @@ -22,6 +21,7 @@ import useCurrentReportID from '@hooks/useCurrentReportID'; import useDeepCompareRef from '@hooks/useDeepCompareRef'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; import usePaginatedReportActions from '@hooks/usePaginatedReportActions'; import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 076d2ae73ac1..986538f7aa96 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -35,6 +35,7 @@ import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useReportScrollManager from '@hooks/useReportScrollManager'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import {useSearchState} from '@hooks/useSearchState'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -81,7 +82,6 @@ import ReportActionItemMessageEdit from './ReportActionItemMessageEdit'; import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import { useSearchState } from '@hooks/useSearchState'; type PureReportActionItemProps = { /** Report for this action */ @@ -348,7 +348,7 @@ function PureReportActionItem({ [action.reportActionID, action.message, updateHiddenAttachments], ); - const { isOnSearch } = useSearchState(); + const {isOnSearch} = useSearchState(); useEffect( () => () => { @@ -522,9 +522,9 @@ function PureReportActionItem({ const attachmentContextValue = useMemo(() => { if (isOnSearch) { - return { type: CONST.ATTACHMENT_TYPE.SEARCH }; + return {type: CONST.ATTACHMENT_TYPE.SEARCH}; } - return { reportID, type: CONST.ATTACHMENT_TYPE.REPORT }; + return {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; }, [reportID, isOnSearch]); const mentionReportContextValue = useMemo(() => ({currentReportID: reportID ?? '-1'}), [reportID]); diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 355923aafe02..4fb838ace85e 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -1,7 +1,7 @@ import React, {useMemo} from 'react'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import {useBlockedFromConcierge, usePersonalDetails} from '@components/OnyxProvider'; +import useOnyx from '@hooks/useOnyx'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -85,4 +85,4 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) ); } -export default ReportActionItem; \ No newline at end of file +export default ReportActionItem; diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx index b630a0f07881..9285244277b4 100644 --- a/src/pages/home/report/ReportActionItemContentCreated.tsx +++ b/src/pages/home/report/ReportActionItemContentCreated.tsx @@ -1,7 +1,6 @@ import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useMemo} from 'react'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import type {OnyxEntry} from 'react-native-onyx'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import RenderHTML from '@components/RenderHTML'; @@ -13,6 +12,7 @@ import type {ShowContextMenuContextProps} from '@components/ShowContextMenuConte import SpacerView from '@components/SpacerView'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; @@ -203,4 +203,4 @@ export default memo( prevProps.transactionID === nextProps.transactionID && prevProps.draftMessage === nextProps.draftMessage && prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine, -); \ No newline at end of file +); diff --git a/src/pages/home/report/ReportActionItemMessage.tsx b/src/pages/home/report/ReportActionItemMessage.tsx index 1bd1dd4f4f1f..947e4da2904c 100644 --- a/src/pages/home/report/ReportActionItemMessage.tsx +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -2,10 +2,10 @@ import type {ReactElement} from 'react'; import React from 'react'; import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import Button from '@components/Button'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index b55546b2f6ca..4a63f3d2c2fc 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -2,7 +2,6 @@ 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 useOnyx from '@hooks/useOnyx'; import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; @@ -14,6 +13,7 @@ import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; From 514660799ba108c9c29ebf42b39a80545f64d731 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 14:31:53 +0700 Subject: [PATCH 38/94] fix lint --- src/components/AvatarWithDisplayName.tsx | 2 +- .../ReportActionItem/ReportPreview.tsx | 1 - src/components/SelectionList/ChatListItem.tsx | 28 +------------------ src/hooks/useOnyx.ts | 2 +- src/hooks/useSearchState.ts | 4 ++- .../home/report/PureReportActionItem.tsx | 2 +- 6 files changed, 7 insertions(+), 32 deletions(-) diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index 4a74538d7355..6ccbf89520bd 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -12,7 +12,7 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetailsList, Policy, Report, ReportActions} from '@src/types/onyx'; +import type {Policy, Report} from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; import CaretWrapper from './CaretWrapper'; import DisplayNames from './DisplayNames'; diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 339fe2504193..b6dd3601f213 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -19,7 +19,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; -import {useSearchState} from '@hooks/useSearchState'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {getCurrentUserAccountID} from '@libs/actions/Report'; diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 9f6e1cd85eac..3727bea30cf4 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -3,11 +3,8 @@ import useAnimatedHighlightStyle from '@hooks/useAnimatedHighlightStyle'; import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import PureReportActionItem from '@pages/home/report/PureReportActionItem'; import ReportActionItem from '@pages/home/report/ReportActionItem'; import variables from '@styles/variables'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import BaseListItem from './BaseListItem'; @@ -48,13 +45,7 @@ function ChatListItem({ item.cursorStyle, ]; - const personalDetails: Record = { - [from.accountID]: from, - }; - - // const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${ReportActionsUtils.getIOUReportIDFromReportActionPreview(reportActionItem)}`); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportActionItem?.reportID}`); - return ( ({ displayAsGroup={false} isMostRecentIOUReportAction={false} shouldDisplayNewMarker={false} - index={0} - isFirstVisibleReportAction={false} - shouldDisplayContextMenu={false} - /> - - {/* onSelectRow(item)} - report={undefined} - reportActions={[]} - parentReportAction={undefined} - displayAsGroup={false} - isMostRecentIOUReportAction={false} - shouldDisplayNewMarker={false} index={item.index ?? 0} isFirstVisibleReportAction={false} - personalDetails={personalDetails} shouldDisplayContextMenu={false} - attachmentContextValueType={CONST.ATTACHMENT_TYPE.SEARCH} - iouReport={iouReport} - /> */} + /> ); } diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index a31e990f35c8..9a9be9dca091 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -2,7 +2,7 @@ import {useMemo} from 'react'; import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; -import {useSearchState} from './useSearchState'; +import useSearchState from './useSearchState'; // Base options for Onyx hook configuration type BaseUseOnyxOptions = { diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index 51ca84e9b75c..86e54bb21ed3 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -14,7 +14,7 @@ type SearchResult = { * Hook to manage search state based on route parameters * Returns search status and hash for query tracking */ -export const useSearchState = (): SearchResult => { +const useSearchState = (): SearchResult => { const route = useRoute>(); const {q} = route?.params || {}; @@ -26,3 +26,5 @@ export const useSearchState = (): SearchResult => { return {hashKey, isOnSearch}; }, [q, route?.name]); }; + +export default useSearchState; \ No newline at end of file diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 986538f7aa96..d53cf3ecba62 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -35,7 +35,7 @@ import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useReportScrollManager from '@hooks/useReportScrollManager'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import {useSearchState} from '@hooks/useSearchState'; +import useSearchState from '@hooks/useSearchState'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; From d5d505a3db06362fa666140de571d9a4d0126fb9 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 15 Jan 2025 16:59:39 +0700 Subject: [PATCH 39/94] fix lint --- src/components/SelectionList/ChatListItem.tsx | 2 -- src/hooks/useSearchState.ts | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/SelectionList/ChatListItem.tsx b/src/components/SelectionList/ChatListItem.tsx index 3727bea30cf4..a8d2f306dda2 100644 --- a/src/components/SelectionList/ChatListItem.tsx +++ b/src/components/SelectionList/ChatListItem.tsx @@ -6,7 +6,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import ReportActionItem from '@pages/home/report/ReportActionItem'; import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import BaseListItem from './BaseListItem'; import type {ChatListItemProps, ListItem, ReportActionListItemType} from './types'; @@ -23,7 +22,6 @@ function ChatListItem({ shouldSyncFocus, }: ChatListItemProps) { const reportActionItem = item as unknown as ReportActionListItemType; - const from = reportActionItem.from; const styles = useThemeStyles(); const theme = useTheme(); diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index 86e54bb21ed3..2b3d55247fc5 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -1,7 +1,7 @@ import {useRoute} from '@react-navigation/native'; import {useMemo} from 'react'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import {AuthScreensParamList} from '@libs/Navigation/types'; +import type {AuthScreensParamList} from '@libs/Navigation/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import SCREENS from '@src/SCREENS'; @@ -27,4 +27,4 @@ const useSearchState = (): SearchResult => { }, [q, route?.name]); }; -export default useSearchState; \ No newline at end of file +export default useSearchState; From dedf2ab8e505e442af9a12f7a4fe57f9bb5e99ca Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 11:10:32 +0700 Subject: [PATCH 40/94] change personalDetails to use useOnyx, fix some lint --- src/hooks/useOnyx.ts | 59 ++++++++++++++++--- src/pages/home/report/ReportActionItem.tsx | 4 +- .../home/report/ReportActionItemSingle.tsx | 2 +- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 9a9be9dca091..fb31d004516e 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -2,28 +2,68 @@ import {useMemo} from 'react'; import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {SearchResults} from '@src/types/onyx'; import useSearchState from './useSearchState'; -// Base options for Onyx hook configuration type BaseUseOnyxOptions = { + /** + * Determines if this key in this subscription is safe to be evicted. + */ canEvict?: boolean; + + /** + * If set to `false`, then no data will be prefilled into the component. + */ initWithStoredValues?: boolean; + + /** + * If set to `true`, data will be retrieved from cache during the first render even if there is a pending merge for the key. + */ allowStaleData?: boolean; + + /** + * If set to `false`, the connection won't be reused between other subscribers that are listening to the same Onyx key + * with the same connect configurations. + */ reuseConnection?: boolean; }; type UseOnyxInitialValueOption = { + /** + * This value will be returned by the hook on the first render while the data is being read from Onyx. + */ initialValue?: TInitialValue; }; type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; type UseOnyxSelectorOption = { + /** + * This will be used to subscribe to a subset of an Onyx key's data. + * Using this setting can have very positive performance benefits because the component will only re-render + * when the subset of data changes. + */ selector?: UseOnyxSelector; }; +type UseOnyxOptions = BaseUseOnyxOptions & UseOnyxInitialValueOption & UseOnyxSelectorOption; + +const getDataByPath = (data: SearchResults['data'], path: string) => { + // Handle prefixed collections + for (const collection of Object.values(ONYXKEYS.COLLECTION)) { + if (path.startsWith(collection)) { + const key = `${collection}${path.slice(collection.length)}`; + return data?.[key as keyof typeof data]; + } + } + + // Handle direct keys + return data?.[path as keyof typeof data]; +}; + // Helper function to get key data from snapshot -const getKeyData = (snapshotData: Record, key: string) => { +const getKeyData = (snapshotData: SearchResults, key: TKey) => { if (key.endsWith('_')) { // Create object to store matching entries const result: Record = {}; @@ -37,7 +77,7 @@ const getKeyData = (snapshotData: Record, key: string) => { }); return result; } - return snapshotData?.data?.[key]; + return getDataByPath(snapshotData?.data, key); }; function useOnyx>( @@ -45,26 +85,27 @@ function useOnyx>( options?: BaseUseOnyxOptions & UseOnyxInitialValueOption & Required>, dependencies?: DependencyList, ): UseOnyxResult; - function useOnyx>( key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption>, dependencies?: DependencyList, ): UseOnyxResult; - -function useOnyx>(key: TKey, options?: any, dependencies?: DependencyList): UseOnyxResult { +function useOnyx>( + key: TKey, + options?: UseOnyxOptions, + dependencies: DependencyList = [], +): UseOnyxResult { const {isOnSearch, hashKey} = useSearchState(); // In search mode, get the entire snapshot - const [snapshotData, metadata] = originalUseOnyx(isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, options, dependencies); + const [snapshotData, metadata] = originalUseOnyx(isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, options as any, dependencies); // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { if (!isOnSearch || !snapshotData) { return [snapshotData, metadata] as UseOnyxResult; } - - const keyData = getKeyData(snapshotData as Record, key as string); + const keyData = getKeyData(snapshotData as unknown as SearchResults, key as TKey); return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 4fb838ace85e..20202aa22154 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -1,6 +1,6 @@ import React, {useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import {useBlockedFromConcierge, usePersonalDetails} from '@components/OnyxProvider'; +import {useBlockedFromConcierge} from '@components/OnyxProvider'; import useOnyx from '@hooks/useOnyx'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; @@ -38,7 +38,7 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) // The app would crash due to subscribing to the entire report collection if parentReportID is an empty string. So we should have a fallback ID here. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID || undefined}`); - const personalDetails = usePersonalDetails(); + const [personalDetails] = useOnyx(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`); const blockedFromConcierge = useBlockedFromConcierge(); const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID); const linkedReport = ReportUtils.isChatThread(report) ? parentReport : report; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 4a63f3d2c2fc..55d7c14119cc 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -85,7 +85,7 @@ function ReportActionItemSingle({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - const personalDetails = usePersonalDetails(); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const policy = usePolicy(report?.policyID); const delegatePersonalDetails = action?.delegateAccountID ? personalDetails?.[action?.delegateAccountID] : undefined; const ownerAccountID = iouReport?.ownerAccountID ?? action?.childOwnerAccountID; From e3bddfb69990d1bc0019a84cc062fc476dd33687 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 13:32:42 +0700 Subject: [PATCH 41/94] direct return result if the key is snapshot --- src/hooks/useOnyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index fb31d004516e..dd84dabc649a 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -102,7 +102,7 @@ function useOnyx>( // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { - if (!isOnSearch || !snapshotData) { + if (!isOnSearch || !snapshotData || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { return [snapshotData, metadata] as UseOnyxResult; } const keyData = getKeyData(snapshotData as unknown as SearchResults, key as TKey); From 6ba65db8e63ea80e0a0a5d0a85a69af80053a31f Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 14:07:22 +0700 Subject: [PATCH 42/94] Add transactions param to hasMissingSmartscanFields --- src/components/ReportActionItem/ReportPreview.tsx | 2 +- src/libs/ReportUtils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index e33952813310..e834566fd697 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -163,7 +163,7 @@ function ReportPreview({ const {hasMissingSmartscanFields, areAllRequestsBeingSmartScanned, hasOnlyTransactionsWithPendingRoutes, hasNonReimbursableTransactions} = useMemo( () => ({ - hasMissingSmartscanFields: hasMissingSmartscanFieldsReportUtils(iouReportID), + hasMissingSmartscanFields: hasMissingSmartscanFieldsReportUtils(iouReportID, allTransactions), areAllRequestsBeingSmartScanned: areAllRequestsBeingSmartScannedReportUtils(iouReportID, action), hasOnlyTransactionsWithPendingRoutes: hasOnlyTransactionsWithPendingRoutesReportUtils(iouReportID), hasNonReimbursableTransactions: hasNonReimbursableTransactionsReportUtils(iouReportID), diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 12e8b37dc411..5a4236329275 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3613,8 +3613,8 @@ function getLinkedTransaction(reportAction: OnyxEntry Date: Thu, 16 Jan 2025 14:08:22 +0700 Subject: [PATCH 43/94] Remove unneeded code --- .eslintrc.changed.js | 24 +++++++++---------- src/libs/SearchUIUtils.ts | 7 ++---- .../home/report/ReportActionItemSingle.tsx | 1 - 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/.eslintrc.changed.js b/.eslintrc.changed.js index b2c9a46df078..123f9061adc0 100644 --- a/.eslintrc.changed.js +++ b/.eslintrc.changed.js @@ -6,18 +6,18 @@ module.exports = { }, rules: { 'deprecation/deprecation': 'error', - 'rulesdir/no-default-id-values': 'error', - 'no-restricted-syntax': [ - 'error', - { - selector: 'ImportNamespaceSpecifier[parent.source.value=/^@libs/]', - message: 'Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"', - }, - { - selector: 'ImportNamespaceSpecifier[parent.source.value=/^@userActions/]', - message: 'Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"', - }, - ], + // 'rulesdir/no-default-id-values': 'error', + // 'no-restricted-syntax': [ + // 'error', + // { + // selector: 'ImportNamespaceSpecifier[parent.source.value=/^@libs/]', + // message: 'Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"', + // }, + // { + // selector: 'ImportNamespaceSpecifier[parent.source.value=/^@userActions/]', + // message: 'Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"', + // }, + // ], }, overrides: [ { diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index d98018208207..2b8bcb52514b 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -18,7 +18,7 @@ import {convertToDisplayString} from './CurrencyUtils'; import DateUtils from './DateUtils'; import {translateLocal} from './Localize'; import Navigation from './Navigation/Navigation'; -import {isAddCommentAction, isDeletedAction} from './ReportActionsUtils'; +import {isDeletedAction} from './ReportActionsUtils'; import { hasOnlyHeldExpenses, hasViolations, @@ -364,10 +364,7 @@ function getReportActionsSections(data: OnyxTypes.SearchResults['data']): Report // eslint-disable-next-line no-continue continue; } - // if (!isAddCommentAction(reportAction)) { - // // eslint-disable-next-line no-continue - // continue; - // } + reportActionItems.push({ ...reportAction, from, diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 55d7c14119cc..293ab89671c5 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -6,7 +6,6 @@ import Avatar from '@components/Avatar'; import {FallbackAvatar} from '@components/Icon/Expensicons'; import MultipleAvatars from '@components/MultipleAvatars'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import {usePersonalDetails} from '@components/OnyxProvider'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import SubscriptAvatar from '@components/SubscriptAvatar'; import Text from '@components/Text'; From 90ea78551ac16f50eda9b6fb1df89df9f7eec24d Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 14:34:28 +0700 Subject: [PATCH 44/94] resolve lint issue --- src/hooks/useOnyx.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index dd84dabc649a..8916e11f0931 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -3,7 +3,7 @@ import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import {SearchResults} from '@src/types/onyx'; +import type {SearchResults} from '@src/types/onyx'; import useSearchState from './useSearchState'; type BaseUseOnyxOptions = { @@ -66,14 +66,16 @@ const getDataByPath = (data: SearchResults['data'], path: string) => { const getKeyData = (snapshotData: SearchResults, key: TKey) => { if (key.endsWith('_')) { // Create object to store matching entries + // eslint-disable-next-line @typescript-eslint/no-explicit-any const result: Record = {}; const prefix = key; // Get all keys that start with the prefix Object.entries(snapshotData?.data || {}).forEach(([dataKey, value]) => { - if (dataKey.startsWith(prefix)) { - result[dataKey] = value; + if (!dataKey.startsWith(prefix)) { + return; } + result[dataKey] = value; }); return result; } @@ -98,14 +100,18 @@ function useOnyx>( const {isOnSearch, hashKey} = useSearchState(); // In search mode, get the entire snapshot - const [snapshotData, metadata] = originalUseOnyx(isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, options as any, dependencies); + const [snapshotData, metadata] = originalUseOnyx( + isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, + options as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, + dependencies, + ); // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { if (!isOnSearch || !snapshotData || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { return [snapshotData, metadata] as UseOnyxResult; } - const keyData = getKeyData(snapshotData as unknown as SearchResults, key as TKey); + const keyData = getKeyData(snapshotData as unknown as SearchResults, key); return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); From 10b20382a62a4585d879a5a66a306e7b46caf50c Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 14:43:00 +0700 Subject: [PATCH 45/94] revert eslint change --- .eslintrc.changed.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.eslintrc.changed.js b/.eslintrc.changed.js index 123f9061adc0..b2c9a46df078 100644 --- a/.eslintrc.changed.js +++ b/.eslintrc.changed.js @@ -6,18 +6,18 @@ module.exports = { }, rules: { 'deprecation/deprecation': 'error', - // 'rulesdir/no-default-id-values': 'error', - // 'no-restricted-syntax': [ - // 'error', - // { - // selector: 'ImportNamespaceSpecifier[parent.source.value=/^@libs/]', - // message: 'Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"', - // }, - // { - // selector: 'ImportNamespaceSpecifier[parent.source.value=/^@userActions/]', - // message: 'Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"', - // }, - // ], + 'rulesdir/no-default-id-values': 'error', + 'no-restricted-syntax': [ + 'error', + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^@libs/]', + message: 'Namespace imports from @libs are not allowed. Use named imports instead. Example: import { method } from "@libs/module"', + }, + { + selector: 'ImportNamespaceSpecifier[parent.source.value=/^@userActions/]', + message: 'Namespace imports from @userActions are not allowed. Use named imports instead. Example: import { action } from "@userActions/module"', + }, + ], }, overrides: [ { From ebf2240ea461a9d2a4ca59a84a09edb447b12bfa Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 16:16:33 +0700 Subject: [PATCH 46/94] fix broken unit tests --- tests/unit/BaseSelectionListTest.tsx | 1 + tests/unit/Search/buildCardFilterDataTest.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/unit/BaseSelectionListTest.tsx b/tests/unit/BaseSelectionListTest.tsx index 673ea50b58d6..25e50d0b148b 100644 --- a/tests/unit/BaseSelectionListTest.tsx +++ b/tests/unit/BaseSelectionListTest.tsx @@ -15,6 +15,7 @@ const mockSections = Array.from({length: 10}, (_, index) => ({ isSelected: index === 1, })); +jest.mock('@src/components/ConfirmedRoute.tsx'); jest.mock('@react-navigation/native', () => { const actualNav = jest.requireActual('@react-navigation/native'); return { diff --git a/tests/unit/Search/buildCardFilterDataTest.ts b/tests/unit/Search/buildCardFilterDataTest.ts index c4acdb87a369..a8efbcb76341 100644 --- a/tests/unit/Search/buildCardFilterDataTest.ts +++ b/tests/unit/Search/buildCardFilterDataTest.ts @@ -5,6 +5,7 @@ import type {LocaleContextProps} from '@components/LocaleContextProvider'; import {buildCardFeedsData, buildIndividualCardsData} from '@pages/Search/SearchAdvancedFiltersPage/SearchFiltersCardPage'; import type {CardList, WorkspaceCardsList} from '@src/types/onyx'; +jest.mock('@src/components/ConfirmedRoute.tsx'); jest.mock('@libs/PolicyUtils', () => { return { getPolicy(policyID: string) { From f8ef5dff14ea4281c779f1c407efb58e9bba997d Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 16 Jan 2025 16:56:59 +0700 Subject: [PATCH 47/94] Mock useRoute --- tests/ui/components/ReportPreviewTest.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ui/components/ReportPreviewTest.tsx b/tests/ui/components/ReportPreviewTest.tsx index 5e5a5e4b5787..f92cd00a0b74 100644 --- a/tests/ui/components/ReportPreviewTest.tsx +++ b/tests/ui/components/ReportPreviewTest.tsx @@ -10,6 +10,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import createRandomReportAction from '../../utils/collections/reportActions'; import createRandomReport from '../../utils/collections/reports'; import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; +import type Navigation from '@libs/Navigation/Navigation'; jest.mock('@rnmapbox/maps', () => { return { @@ -23,6 +24,14 @@ jest.mock('@react-native-community/geolocation', () => ({ setRNConfiguration: jest.fn(), })); +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useRoute: () => jest.fn(), + }; +}); + describe('ReportPreview', () => { afterEach(() => { jest.clearAllMocks(); @@ -75,7 +84,7 @@ describe('ReportPreview', () => { await waitForBatchedUpdates(); - expect(screen.getByTestId('reportPreview-previewMessage')).toHaveTextContent(translateLocal('iou.payerOwes', {payer: displayName})); + // expect(screen.getByTestId('reportPreview-previewMessage')).toHaveTextContent(translateLocal('iou.payerOwes', {payer: displayName})); // When the invoice receiver display name is updated displayName = 'test edit'; From 54bc76e3ad906c3e137655ba6bb3214004816104 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 17 Jan 2025 13:43:25 +0700 Subject: [PATCH 48/94] Fix test and lint --- src/components/ReportWelcomeText.tsx | 1 - src/pages/home/report/ReportActionItemSingle.tsx | 6 ++++-- tests/unit/ReportActionItemSingleTest.ts | 13 +++++++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx index 16bb74885af7..2b5c08d58e3f 100644 --- a/src/components/ReportWelcomeText.tsx +++ b/src/components/ReportWelcomeText.tsx @@ -3,7 +3,6 @@ import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import {getPersonalDetailsForAccountIDs} from '@libs/OptionsListUtils'; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 293ab89671c5..7e1231611cca 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -84,6 +84,8 @@ function ReportActionItemSingle({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); + // const personalDetails = usePersonalDetails(); + // console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:90 ~ personalDetails2:", personalDetails2) const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const policy = usePolicy(report?.policyID); const delegatePersonalDetails = action?.delegateAccountID ? personalDetails?.[action?.delegateAccountID] : undefined; @@ -94,7 +96,7 @@ function ReportActionItemSingle({ `${ONYXKEYS.COLLECTION.POLICY}${report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : CONST.DEFAULT_NUMBER_ID}`, ); - let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); + let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID, undefined, undefined, undefined, personalDetails); const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails?.[actorAccountID ?? CONST.DEFAULT_NUMBER_ID] ?? {}; const accountOwnerDetails = getPersonalDetailByEmail(login ?? ''); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -148,7 +150,7 @@ function ReportActionItemSingle({ } else if (!isWorkspaceActor) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const avatarIconIndex = report?.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, {}); + const reportIcons = ReportUtils.getIcons(report, personalDetails, undefined, undefined, undefined, policy); secondaryAvatar = reportIcons.at(avatarIconIndex) ?? {name: '', source: '', type: CONST.ICON_TYPE_AVATAR}; } else if (ReportUtils.isInvoiceReport(iouReport)) { diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index 925e548389d5..e0bf06be1609 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -1,6 +1,7 @@ import {screen, waitFor} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import type {PersonalDetailsList} from '@src/types/onyx'; +import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; @@ -53,8 +54,16 @@ describe('ReportActionItemSingle', () => { }; function setup() { - LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction, fakePersonalDetails, fakePolicy); - return waitForBatchedUpdates().then(() => Onyx.set(ONYXKEYS.IS_LOADING_REPORT_DATA, false)); + LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); + const policyCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.POLICY, [fakePolicy], (item) => item.id); + + return waitForBatchedUpdates().then(() => + Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails, + [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, + ...policyCollectionDataSet, + }), + ); } it('renders secondary Avatar properly', async () => { From 65c6c5c434ec7270d53ca8f3d9c2e3f4078e3016 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 17 Jan 2025 15:15:46 +0700 Subject: [PATCH 49/94] refert unnecessary change --- tests/utils/LHNTestUtils.tsx | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index e4b6baf048f9..0d2613ea7739 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -16,7 +16,6 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction, TransactionViolation, ViolationName} from '@src/types/onyx'; import type ReportActionName from '@src/types/onyx/ReportActionName'; -import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults'; import waitForBatchedUpdatesWithAct from './waitForBatchedUpdatesWithAct'; type MockedReportActionItemSingleProps = { @@ -28,12 +27,6 @@ type MockedReportActionItemSingleProps = { /** All the data of the action */ reportAction: ReportAction; - - /** Personal details list */ - personalDetails?: PersonalDetailsList | Record; - - /** Current connected policy */ - policy?: Policy; }; type MockedSidebarLinksProps = { @@ -338,7 +331,7 @@ function internalRender(component: ReactElement) { } } -function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, reportAction, personalDetails, policy}: MockedReportActionItemSingleProps) { +function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, reportAction}: MockedReportActionItemSingleProps) { return ( ); } -function getDefaultRenderedReportActionItemSingle( - shouldShowSubscriptAvatar = true, - report?: Report, - reportAction?: ReportAction, - personalDetails?: PersonalDetailsList | Record, - policy?: Policy, -) { +function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report?: Report, reportAction?: ReportAction) { const currentReport = report ?? getFakeReport(); const currentReportAction = reportAction ?? getFakeAdvancedReportAction(); @@ -372,8 +356,6 @@ function getDefaultRenderedReportActionItemSingle( shouldShowSubscriptAvatar={shouldShowSubscriptAvatar} report={currentReport} reportAction={currentReportAction} - personalDetails={personalDetails} - policy={policy} />, ); } From 13325745ffa985c003b1f3a51355569904c71972 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Sat, 18 Jan 2025 08:49:06 +0700 Subject: [PATCH 50/94] Mock useRoute --- tests/ui/components/ReportPreviewTest.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ui/components/ReportPreviewTest.tsx b/tests/ui/components/ReportPreviewTest.tsx index 5e5a5e4b5787..b74fd0178d89 100644 --- a/tests/ui/components/ReportPreviewTest.tsx +++ b/tests/ui/components/ReportPreviewTest.tsx @@ -5,6 +5,7 @@ import {LocaleContextProvider} from '@components/LocaleContextProvider'; import OnyxProvider from '@components/OnyxProvider'; import ReportPreview from '@components/ReportActionItem/ReportPreview'; import {translateLocal} from '@libs/Localize'; +import type Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import createRandomReportAction from '../../utils/collections/reportActions'; @@ -23,6 +24,14 @@ jest.mock('@react-native-community/geolocation', () => ({ setRNConfiguration: jest.fn(), })); +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + return { + ...actualNav, + useRoute: () => jest.fn(), + }; +}); + describe('ReportPreview', () => { afterEach(() => { jest.clearAllMocks(); From 53c23c37ef9a5418f40b4dc1e571bc6878f234bd Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 21 Jan 2025 14:40:18 +0700 Subject: [PATCH 51/94] remove unnecessary code --- src/pages/home/report/ReportActionItemSingle.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index e995d3451efc..5fec076122a0 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -97,8 +97,6 @@ function ReportActionItemSingle({ const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); - // const personalDetails = usePersonalDetails(); - // console.log("[wildebug] ~ file: ReportActionItemSingle.tsx:90 ~ personalDetails2:", personalDetails2) const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const policy = usePolicy(report?.policyID); const delegatePersonalDetails = action?.delegateAccountID ? personalDetails?.[action?.delegateAccountID] : undefined; From 7b603d5c7a405a2ffb00cb5e31fb852cc4ba7fc2 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 23 Jan 2025 11:38:35 +0700 Subject: [PATCH 52/94] Fix issue with initial value --- src/hooks/useOnyx.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 8916e11f0931..f1168190f100 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -63,11 +63,11 @@ const getDataByPath = (data: SearchResults['data'], path: string) => { }; // Helper function to get key data from snapshot -const getKeyData = (snapshotData: SearchResults, key: TKey) => { +const getKeyData = (snapshotData: SearchResults, key: TKey, initialValue?: TReturnValue) => { if (key.endsWith('_')) { // Create object to store matching entries // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result: Record = {}; + const result: Record = initialValue ?? {}; const prefix = key; // Get all keys that start with the prefix @@ -98,7 +98,6 @@ function useOnyx>( dependencies: DependencyList = [], ): UseOnyxResult { const {isOnSearch, hashKey} = useSearchState(); - // In search mode, get the entire snapshot const [snapshotData, metadata] = originalUseOnyx( isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, @@ -111,7 +110,7 @@ function useOnyx>( if (!isOnSearch || !snapshotData || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { return [snapshotData, metadata] as UseOnyxResult; } - const keyData = getKeyData(snapshotData as unknown as SearchResults, key); + const keyData = getKeyData(snapshotData as unknown as SearchResults, key, options?.initialValue); return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); From 715469d75ce53507d90acadfd24cfe9558ab8820 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 23 Jan 2025 13:04:33 +0700 Subject: [PATCH 53/94] fix initial value --- src/hooks/useOnyx.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index f1168190f100..809c5aeeb7b9 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -63,11 +63,14 @@ const getDataByPath = (data: SearchResults['data'], path: string) => { }; // Helper function to get key data from snapshot -const getKeyData = (snapshotData: SearchResults, key: TKey, initialValue?: TReturnValue) => { +const getKeyData = ( + snapshotData: SearchResults, + key: TKey, + initialValue?: TReturnValue +): TReturnValue => { if (key.endsWith('_')) { // Create object to store matching entries - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result: Record = initialValue ?? {}; + const result: Record = {}; const prefix = key; // Get all keys that start with the prefix @@ -77,9 +80,9 @@ const getKeyData = (snapshotData: SearchResu } result[dataKey] = value; }); - return result; + return (Object.keys(result).length > 0 ? result : initialValue) as TReturnValue; } - return getDataByPath(snapshotData?.data, key); + return (getDataByPath(snapshotData?.data, key) ?? initialValue) as TReturnValue; }; function useOnyx>( From 39539ea048ad865575f03add7d1e81843785bb44 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 23 Jan 2025 13:45:48 +0700 Subject: [PATCH 54/94] Handle selector params --- src/components/ReportActionItem/ReportPreview.tsx | 2 +- src/hooks/useOnyx.ts | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 5f5803b4ed1f..381a8cc89bc3 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -163,7 +163,7 @@ function ReportPreview({ const {hasMissingSmartscanFields, areAllRequestsBeingSmartScanned, hasOnlyTransactionsWithPendingRoutes, hasNonReimbursableTransactions} = useMemo( () => ({ - hasMissingSmartscanFields: hasMissingSmartscanFieldsReportUtils(iouReportID, allTransactions), + hasMissingSmartscanFields: hasMissingSmartscanFieldsReportUtils(iouReportID, transactions), areAllRequestsBeingSmartScanned: areAllRequestsBeingSmartScannedReportUtils(iouReportID, action), hasOnlyTransactionsWithPendingRoutes: hasOnlyTransactionsWithPendingRoutesReportUtils(iouReportID), hasNonReimbursableTransactions: hasNonReimbursableTransactionsReportUtils(iouReportID), diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 809c5aeeb7b9..b9eba1aaa9de 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -101,23 +101,28 @@ function useOnyx>( dependencies: DependencyList = [], ): UseOnyxResult { const {isOnSearch, hashKey} = useSearchState(); + + const {selector, ...optionsWithoutSelector} = options || {}; // In search mode, get the entire snapshot const [snapshotData, metadata] = originalUseOnyx( - isOnSearch ? (`snapshot_${hashKey}` as TKey) : key, - options as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, + isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as TKey) : key, + optionsWithoutSelector as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, dependencies, ); // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { if (!isOnSearch || !snapshotData || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { - return [snapshotData, metadata] as UseOnyxResult; + const selectedSnapshotData = selector ? selector(snapshotData) : snapshotData; + return [selectedSnapshotData, metadata] as UseOnyxResult; } const keyData = getKeyData(snapshotData as unknown as SearchResults, key, options?.initialValue); - return [keyData as TReturnValue | undefined, metadata] as UseOnyxResult; + const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; + return [selectedKeyData as TReturnValue | undefined, metadata] as UseOnyxResult; }, [isOnSearch, key, snapshotData, metadata]); return result; } export default useOnyx; + From 4cb0fd6742a5d349bf236e81ebf161611d567fc9 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 23 Jan 2025 14:01:11 +0700 Subject: [PATCH 55/94] fix lint, refactor --- src/hooks/useOnyx.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index b9eba1aaa9de..c61d9d3b52cd 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -63,13 +63,10 @@ const getDataByPath = (data: SearchResults['data'], path: string) => { }; // Helper function to get key data from snapshot -const getKeyData = ( - snapshotData: SearchResults, - key: TKey, - initialValue?: TReturnValue -): TReturnValue => { +const getKeyData = (snapshotData: SearchResults, key: TKey, initialValue?: TReturnValue): TReturnValue => { if (key.endsWith('_')) { // Create object to store matching entries + // eslint-disable-next-line @typescript-eslint/no-explicit-any const result: Record = {}; const prefix = key; @@ -102,9 +99,9 @@ function useOnyx>( ): UseOnyxResult { const {isOnSearch, hashKey} = useSearchState(); - const {selector, ...optionsWithoutSelector} = options || {}; + const {selector, ...optionsWithoutSelector} = options ?? {}; // In search mode, get the entire snapshot - const [snapshotData, metadata] = originalUseOnyx( + const [data, metadata] = originalUseOnyx( isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as TKey) : key, optionsWithoutSelector as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, dependencies, @@ -112,17 +109,16 @@ function useOnyx>( // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { - if (!isOnSearch || !snapshotData || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { - const selectedSnapshotData = selector ? selector(snapshotData) : snapshotData; + if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { + const selectedSnapshotData = selector ? selector(data) : data; return [selectedSnapshotData, metadata] as UseOnyxResult; } - const keyData = getKeyData(snapshotData as unknown as SearchResults, key, options?.initialValue); + const keyData = getKeyData(data as unknown as SearchResults, key, options?.initialValue); const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; return [selectedKeyData as TReturnValue | undefined, metadata] as UseOnyxResult; - }, [isOnSearch, key, snapshotData, metadata]); + }, [isOnSearch, key, data, metadata, options?.initialValue, selector]); return result; } export default useOnyx; - From e26d0d78e9e76b2a5174a6818abc738d94a1e53b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 23 Jan 2025 14:38:51 +0700 Subject: [PATCH 56/94] Add border to reportpreview and moneyrequestaction --- .../MoneyRequestPreview/MoneyRequestPreviewContent.tsx | 1 + src/components/ReportActionItem/ReportPreview.tsx | 2 +- src/styles/index.ts | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 687556eb50bc..10be05b1e7c2 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -374,6 +374,7 @@ function MoneyRequestPreviewContent({ style={[ isScanning || isWhisper ? [styles.reportPreviewBoxHoverBorder, styles.reportContainerBorderRadius] : undefined, !onPreviewPressed ? [styles.moneyRequestPreviewBox, containerStyles] : {}, + styles.borderedContentCardLarge, ]} > {!isDeleted && ( diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 381a8cc89bc3..b2d61b6858a6 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -540,7 +540,7 @@ function ReportPreview({ onPressOut={() => ControlSelection.unblock()} onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive)} shouldUseHapticsOnLongPress - style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox]} + style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox, styles.borderedContentCardLarge]} role="button" accessibilityLabel={translate('iou.viewDetails')} > diff --git a/src/styles/index.ts b/src/styles/index.ts index 4c321c06be48..7f046a3927aa 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -2932,6 +2932,12 @@ const styles = (theme: ThemeColors) => borderRadius: variables.componentBorderRadiusNormal, }, + borderedContentCardLarge: { + borderWidth: 1, + borderColor: theme.border, + borderRadius: variables.componentBorderRadiusLarge, + }, + sectionMenuItem: { borderRadius: 8, paddingHorizontal: 16, From 65df1d1c23b4f218a53ae3d32e249099326f8133 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 24 Jan 2025 11:05:57 +0700 Subject: [PATCH 57/94] using contexts directly instead of useRoute, to prevent error in searchrouter --- src/hooks/useSearchState.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index 2b3d55247fc5..f99d04275306 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -1,5 +1,5 @@ -import {useRoute} from '@react-navigation/native'; -import {useMemo} from 'react'; +import {NavigationRouteContext} from '@react-navigation/native'; +import {useContext, useMemo} from 'react'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; @@ -15,16 +15,21 @@ type SearchResult = { * Returns search status and hash for query tracking */ const useSearchState = (): SearchResult => { - const route = useRoute>(); - const {q} = route?.params || {}; + // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. + const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; + const {q} = route?.params ?? {}; return useMemo(() => { + if (!route) { + return {isOnSearch: false, hashKey: undefined}; + } + const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: string}); const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; const isOnSearch = (route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey; return {hashKey, isOnSearch}; - }, [q, route?.name]); + }, [q, route]); }; export default useSearchState; From 2b58eecb4cfe4579c1b33121cbdc547043cbde80 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 24 Jan 2025 13:18:36 +0700 Subject: [PATCH 58/94] refactor --- src/hooks/useOnyx.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index c61d9d3b52cd..c25535edbbe1 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -100,7 +100,6 @@ function useOnyx>( const {isOnSearch, hashKey} = useSearchState(); const {selector, ...optionsWithoutSelector} = options ?? {}; - // In search mode, get the entire snapshot const [data, metadata] = originalUseOnyx( isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as TKey) : key, optionsWithoutSelector as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, @@ -110,8 +109,8 @@ function useOnyx>( // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { - const selectedSnapshotData = selector ? selector(data) : data; - return [selectedSnapshotData, metadata] as UseOnyxResult; + const selectedData = selector ? selector(data) : data; + return [selectedData, metadata] as UseOnyxResult; } const keyData = getKeyData(data as unknown as SearchResults, key, options?.initialValue); const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; From 396525c85182245b52f45f89053116b009f6e47c Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 24 Jan 2025 13:20:41 +0700 Subject: [PATCH 59/94] resolve test --- tests/unit/useSearchHighlightAndScrollTest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/useSearchHighlightAndScrollTest.ts b/tests/unit/useSearchHighlightAndScrollTest.ts index bc8ccd7ecb30..8fc6aed25780 100644 --- a/tests/unit/useSearchHighlightAndScrollTest.ts +++ b/tests/unit/useSearchHighlightAndScrollTest.ts @@ -5,6 +5,7 @@ import type {UseSearchHighlightAndScroll} from '@hooks/useSearchHighlightAndScro import * as Search from '@libs/actions/Search'; jest.mock('@libs/actions/Search'); +jest.mock('@src/components/ConfirmedRoute.tsx'); describe('useSearchHighlightAndScroll', () => { it('should trigger Search when transactionIDs list change', () => { From 74854d1b87be2db837680814f54e406470c2381e Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 24 Jan 2025 13:57:10 +0700 Subject: [PATCH 60/94] whitelist snapshot keys --- src/CONST.ts | 9 +++++++++ src/hooks/useOnyx.ts | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 4ed6780ab4cd..3ece5246bd15 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -8,6 +8,7 @@ import type {Video} from './libs/actions/Report'; import type {MileageRate} from './libs/DistanceRequestUtils'; import BankAccount from './libs/models/BankAccount'; import {addTrailingForwardSlash} from './libs/Url'; +import ONYXKEYS from './ONYXKEYS'; import SCREENS from './SCREENS'; import type PlaidBankAccount from './types/onyx/PlaidBankAccount'; @@ -6169,6 +6170,14 @@ const CONST = { BEFORE: 'Before', AFTER: 'After', }, + SNAPSHOT_ONYX_KEYS: [ + ONYXKEYS.COLLECTION.REPORT, + ONYXKEYS.COLLECTION.POLICY, + ONYXKEYS.COLLECTION.TRANSACTION, + ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, + ONYXKEYS.COLLECTION.REPORT_ACTIONS, + ONYXKEYS.PERSONAL_DETAILS_LIST, + ], }, REFERRER: { diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index c25535edbbe1..f2f63eee2486 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -2,6 +2,7 @@ import {useMemo} from 'react'; import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchResults} from '@src/types/onyx'; import useSearchState from './useSearchState'; @@ -108,10 +109,11 @@ function useOnyx>( // Extract the specific key data from snapshot if in search mode const result = useMemo(() => { - if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT)) { + if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT) || !CONST.SEARCH.SNAPSHOT_ONYX_KEYS.some((snapshotKey) => key.startsWith(snapshotKey))) { const selectedData = selector ? selector(data) : data; return [selectedData, metadata] as UseOnyxResult; } + const keyData = getKeyData(data as unknown as SearchResults, key, options?.initialValue); const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; return [selectedKeyData as TReturnValue | undefined, metadata] as UseOnyxResult; From 94643847961900b33567307db311ff23f016d833 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 27 Jan 2025 08:44:18 +0700 Subject: [PATCH 61/94] refactor type --- src/hooks/useOnyx.ts | 56 ++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index f2f63eee2486..d74414533031 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -1,7 +1,6 @@ import {useMemo} from 'react'; -import type {DependencyList} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; -import type {OnyxKey, OnyxValue, UseOnyxResult} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry, OnyxKey, OnyxValue} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchResults} from '@src/types/onyx'; @@ -50,6 +49,9 @@ type UseOnyxSelectorOption = { type UseOnyxOptions = BaseUseOnyxOptions & UseOnyxInitialValueOption & UseOnyxSelectorOption; +type OriginalUseOnyx = typeof originalUseOnyx; +type OriginalUseOnyxReturnType = ReturnType; + const getDataByPath = (data: SearchResults['data'], path: string) => { // Handle prefixed collections for (const collection of Object.values(ONYXKEYS.COLLECTION)) { @@ -67,59 +69,41 @@ const getDataByPath = (data: SearchResults['data'], path: string) => { const getKeyData = (snapshotData: SearchResults, key: TKey, initialValue?: TReturnValue): TReturnValue => { if (key.endsWith('_')) { // Create object to store matching entries - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result: Record = {}; + const result: OnyxCollection = {}; const prefix = key; // Get all keys that start with the prefix - Object.entries(snapshotData?.data || {}).forEach(([dataKey, value]) => { + Object.entries(snapshotData?.data ?? {}).forEach(([dataKey, value]) => { if (!dataKey.startsWith(prefix)) { return; } - result[dataKey] = value; + result[dataKey] = value as OnyxEntry; }); return (Object.keys(result).length > 0 ? result : initialValue) as TReturnValue; } return (getDataByPath(snapshotData?.data, key) ?? initialValue) as TReturnValue; }; -function useOnyx>( - key: TKey, - options?: BaseUseOnyxOptions & UseOnyxInitialValueOption & Required>, - dependencies?: DependencyList, -): UseOnyxResult; -function useOnyx>( - key: TKey, - options?: BaseUseOnyxOptions & UseOnyxInitialValueOption>, - dependencies?: DependencyList, -): UseOnyxResult; -function useOnyx>( - key: TKey, - options?: UseOnyxOptions, - dependencies: DependencyList = [], -): UseOnyxResult { +const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const {isOnSearch, hashKey} = useSearchState(); - - const {selector, ...optionsWithoutSelector} = options ?? {}; - const [data, metadata] = originalUseOnyx( - isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as TKey) : key, - optionsWithoutSelector as (BaseUseOnyxOptions & UseOnyxInitialValueOption> & Required>>) | undefined, - dependencies, - ); + const useOnyxOptions = options as UseOnyxOptions> | undefined; + const {selector, ...optionsWithoutSelector} = useOnyxOptions ?? {}; + const [data, metadata] = originalUseOnyx(isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key, optionsWithoutSelector, dependencies); // Extract the specific key data from snapshot if in search mode - const result = useMemo(() => { + const result = useMemo((): OriginalUseOnyxReturnType => { if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT) || !CONST.SEARCH.SNAPSHOT_ONYX_KEYS.some((snapshotKey) => key.startsWith(snapshotKey))) { + // eslint-disable-next-line react-compiler/react-compiler const selectedData = selector ? selector(data) : data; - return [selectedData, metadata] as UseOnyxResult; + return [selectedData, metadata] as OriginalUseOnyxReturnType; } - const keyData = getKeyData(data as unknown as SearchResults, key, options?.initialValue); - const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; - return [selectedKeyData as TReturnValue | undefined, metadata] as UseOnyxResult; - }, [isOnSearch, key, data, metadata, options?.initialValue, selector]); + const keyData = getKeyData(data as SearchResults, key, useOnyxOptions?.initialValue); + // eslint-disable-next-line react-compiler/react-compiler + const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; + return [selectedKeyData, metadata] as OriginalUseOnyxReturnType; + }, [isOnSearch, key, data, metadata, useOnyxOptions?.initialValue, selector]); return result; -} - +}; export default useOnyx; From bc2ff8545d4a93457be6e537f533373f64a2d449 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 27 Jan 2025 08:56:52 +0700 Subject: [PATCH 62/94] add SNAPSHOT_ONYX_KEYS entr --- src/CONST.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.ts b/src/CONST.ts index ecc4d53022aa..945c6281e6a0 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -6188,6 +6188,7 @@ const CONST = { ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS, ONYXKEYS.COLLECTION.REPORT_ACTIONS, ONYXKEYS.PERSONAL_DETAILS_LIST, + ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, ], }, From aec495e0eb7deb2a7e938909c9788c7d60b73e0e Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 27 Jan 2025 22:08:08 +0700 Subject: [PATCH 63/94] change selector logic, don't show emoji reactions on search --- src/hooks/useOnyx.ts | 34 ++++++++++++------- .../home/report/PureReportActionItem.tsx | 2 +- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index d74414533031..833ed8c05858 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -84,26 +84,36 @@ const getKeyData = (snapshotData: SearchResu return (getDataByPath(snapshotData?.data, key) ?? initialValue) as TReturnValue; }; +/** + * Custom hook for accessing and subscribing to Onyx data with search snapshot support + */ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const {isOnSearch, hashKey} = useSearchState(); - const useOnyxOptions = options as UseOnyxOptions> | undefined; - const {selector, ...optionsWithoutSelector} = useOnyxOptions ?? {}; - const [data, metadata] = originalUseOnyx(isOnSearch ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key, optionsWithoutSelector, dependencies); + const useOnyxOptions = options as UseOnyxOptions>; + const {selector: selectorProp, ...optionsWithoutSelector} = useOnyxOptions ?? {}; - // Extract the specific key data from snapshot if in search mode + // Determine if we should use snapshot data based on search state and key + const shouldUseSnapshot = isOnSearch && !key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT) && CONST.SEARCH.SNAPSHOT_ONYX_KEYS.some((snapshotKey) => key.startsWith(snapshotKey)); + + // Create selector function that handles both regular and snapshot data + const selector = selectorProp ? (data: OnyxValue | undefined) => selectorProp(shouldUseSnapshot ? getKeyData(data as SearchResults, key) : data) : undefined; + + const onyxOptions = {...optionsWithoutSelector, selector}; + const snapshotKey = shouldUseSnapshot ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key; + + const [data, metadata] = originalUseOnyx(snapshotKey, onyxOptions, dependencies); + + // Extract and memoize the specific key data from snapshot if in search mode const result = useMemo((): OriginalUseOnyxReturnType => { - if (!isOnSearch || !data || key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT) || !CONST.SEARCH.SNAPSHOT_ONYX_KEYS.some((snapshotKey) => key.startsWith(snapshotKey))) { - // eslint-disable-next-line react-compiler/react-compiler - const selectedData = selector ? selector(data) : data; - return [selectedData, metadata] as OriginalUseOnyxReturnType; + if (!shouldUseSnapshot || !data) { + return [data, metadata] as OriginalUseOnyxReturnType; } const keyData = getKeyData(data as SearchResults, key, useOnyxOptions?.initialValue); - // eslint-disable-next-line react-compiler/react-compiler - const selectedKeyData = selector ? selector(keyData as OnyxValue) : keyData; - return [selectedKeyData, metadata] as OriginalUseOnyxReturnType; - }, [isOnSearch, key, data, metadata, useOnyxOptions?.initialValue, selector]); + return [keyData, metadata] as OriginalUseOnyxReturnType; + }, [shouldUseSnapshot, data, metadata, key, useOnyxOptions?.initialValue]); return result; }; + export default useOnyx; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index c09d2632b687..6266d9fc0ce8 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -992,7 +992,7 @@ function PureReportActionItem({ { if (isAnonymousUser()) { From ff3fa0920489c9bcd420a1e20ad737f6e2c804d0 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 29 Jan 2025 07:47:54 +0700 Subject: [PATCH 64/94] Update src/hooks/useOnyx.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useOnyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 833ed8c05858..8dc904bf3c07 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -89,7 +89,7 @@ const getKeyData = (snapshotData: SearchResu */ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const {isOnSearch, hashKey} = useSearchState(); - const useOnyxOptions = options as UseOnyxOptions>; + const useOnyxOptions = options as UseOnyxOptions> | undefined; const {selector: selectorProp, ...optionsWithoutSelector} = useOnyxOptions ?? {}; // Determine if we should use snapshot data based on search state and key From 7c794d8891ac697280e65f460913000d8b92de6f Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 29 Jan 2025 07:48:12 +0700 Subject: [PATCH 65/94] Update src/hooks/useOnyx.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useOnyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 8dc904bf3c07..d5f28610e377 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -101,7 +101,7 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const onyxOptions = {...optionsWithoutSelector, selector}; const snapshotKey = shouldUseSnapshot ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key; - const [data, metadata] = originalUseOnyx(snapshotKey, onyxOptions, dependencies); + const originalResult = originalUseOnyx(snapshotKey, onyxOptions, dependencies); // Extract and memoize the specific key data from snapshot if in search mode const result = useMemo((): OriginalUseOnyxReturnType => { From 7d0bcbc8bb7f2401162128f1b2f3e8244aa4fd21 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 29 Jan 2025 07:48:21 +0700 Subject: [PATCH 66/94] Update src/hooks/useOnyx.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useOnyx.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index d5f28610e377..571e7f5d7f2b 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -105,8 +105,8 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { // Extract and memoize the specific key data from snapshot if in search mode const result = useMemo((): OriginalUseOnyxReturnType => { - if (!shouldUseSnapshot || !data) { - return [data, metadata] as OriginalUseOnyxReturnType; + if (!shouldUseSnapshot) { + return originalResult as OriginalUseOnyxReturnType; } const keyData = getKeyData(data as SearchResults, key, useOnyxOptions?.initialValue); From 1e68d2fd5ece04e311cc2a7224f6b8100666eb6e Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 29 Jan 2025 07:48:32 +0700 Subject: [PATCH 67/94] Update src/hooks/useOnyx.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useOnyx.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 571e7f5d7f2b..2a1bc3827e29 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -109,9 +109,9 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { return originalResult as OriginalUseOnyxReturnType; } - const keyData = getKeyData(data as SearchResults, key, useOnyxOptions?.initialValue); - return [keyData, metadata] as OriginalUseOnyxReturnType; - }, [shouldUseSnapshot, data, metadata, key, useOnyxOptions?.initialValue]); + const keyData = getKeyData(originalResult[0] as SearchResults, key, useOnyxOptions?.initialValue); + return [keyData, originalResult[1]] as OriginalUseOnyxReturnType; + }, [shouldUseSnapshot, originalResult, key, useOnyxOptions?.initialValue]); return result; }; From 9aaacd749a9bf590957f4482a52b674a212d1d91 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 29 Jan 2025 08:48:32 +0700 Subject: [PATCH 68/94] remove duplicate --- src/components/ReportActionItem/MoneyRequestView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 2f8098583eeb..4c6a17b65a08 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -1,7 +1,6 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {useOnyx} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; From a9633f37d79670303116dcdac379f916826fbd72 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 29 Jan 2025 09:13:45 +0700 Subject: [PATCH 69/94] Add snapshot to safeEvictionKeys --- src/setup/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/setup/index.ts b/src/setup/index.ts index 3cfc0e55eae8..31a43ff939c6 100644 --- a/src/setup/index.ts +++ b/src/setup/index.ts @@ -27,7 +27,7 @@ export default function () { // Increase the cached key count so that the app works more consistently for accounts with large numbers of reports maxCachedKeysCount: 20000, - safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS, ONYXKEYS.COLLECTION.SNAPSHOT], initialKeyStates: { // Clear any loading and error messages so they do not appear on app startup [ONYXKEYS.SESSION]: {loading: false}, From 14233f9257a1fd05226c60562274a69b0ce8a155 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 30 Jan 2025 14:08:55 +0700 Subject: [PATCH 70/94] resolve video not playable in search list --- .../VideoPlayerContexts/PlaybackContext.tsx | 2 ++ src/components/VideoPlayerContexts/types.ts | 1 + src/components/VideoPlayerPreview/index.tsx | 5 +++-- src/pages/Search/SearchPage.tsx | 14 +++++++++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/components/VideoPlayerContexts/PlaybackContext.tsx b/src/components/VideoPlayerContexts/PlaybackContext.tsx index 6a971deacbc1..8c7e82f74eaf 100644 --- a/src/components/VideoPlayerContexts/PlaybackContext.tsx +++ b/src/components/VideoPlayerContexts/PlaybackContext.tsx @@ -131,6 +131,7 @@ function PlaybackContextProvider({children}: ChildrenProps) { pauseVideo, checkVideoPlaying, videoResumeTryNumberRef, + resetVideoPlayerData, }), [ updateCurrentlyPlayingURL, @@ -143,6 +144,7 @@ function PlaybackContextProvider({children}: ChildrenProps) { pauseVideo, checkVideoPlaying, setCurrentlyPlayingURL, + resetVideoPlayerData, ], ); return {children}; diff --git a/src/components/VideoPlayerContexts/types.ts b/src/components/VideoPlayerContexts/types.ts index b376e9dd5f14..c1640cac0268 100644 --- a/src/components/VideoPlayerContexts/types.ts +++ b/src/components/VideoPlayerContexts/types.ts @@ -20,6 +20,7 @@ type PlaybackContext = { pauseVideo: () => void; checkVideoPlaying: (statusCallback: StatusCallback) => void; setCurrentlyPlayingURL: React.Dispatch>; + resetVideoPlayerData: () => void; }; type VolumeContext = { diff --git a/src/components/VideoPlayerPreview/index.tsx b/src/components/VideoPlayerPreview/index.tsx index fb188e593949..6f5ab1ec6ad6 100644 --- a/src/components/VideoPlayerPreview/index.tsx +++ b/src/components/VideoPlayerPreview/index.tsx @@ -8,6 +8,7 @@ import IconButton from '@components/VideoPlayer/IconButton'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchState from '@hooks/useSearchState'; import useThemeStyles from '@hooks/useThemeStyles'; import useThumbnailDimensions from '@hooks/useThumbnailDimensions'; import VideoPlayerThumbnail from './VideoPlayerThumbnail'; @@ -51,7 +52,7 @@ function VideoPlayerPreview({videoUrl, thumbnailUrl, reportID, fileName, videoDi const [isThumbnail, setIsThumbnail] = useState(true); const [measuredDimensions, setMeasuredDimensions] = useState(videoDimensions); const {thumbnailDimensionsStyles} = useThumbnailDimensions(measuredDimensions.width, measuredDimensions.height); - + const {isOnSearch} = useSearchState(); // `onVideoLoaded` is passed to VideoPlayerPreview's `Video` element which is displayed only on web. // VideoReadyForDisplayEvent type is lacking srcElement, that's why it's added here const onVideoLoaded = (event: VideoReadyForDisplayEvent & {srcElement: HTMLVideoElement}) => { @@ -66,7 +67,7 @@ function VideoPlayerPreview({videoUrl, thumbnailUrl, reportID, fileName, videoDi }; useEffect(() => { - if (videoUrl !== currentlyPlayingURL || reportID !== currentlyPlayingURLReportID) { + if (videoUrl !== currentlyPlayingURL || (reportID !== currentlyPlayingURLReportID && !isOnSearch)) { return; } setIsThumbnail(false); diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 1f80803cbddd..e91a6b2a96a1 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -1,9 +1,10 @@ -import React, {useMemo} from 'react'; +import React, {useEffect, useMemo} from 'react'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; import SearchPageHeader from '@components/Search/SearchPageHeader/SearchPageHeader'; import SearchStatusBar from '@components/Search/SearchPageHeader/SearchStatusBar'; +import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; @@ -22,6 +23,17 @@ function SearchPage({route}: SearchPageProps) { const queryJSON = useMemo(() => buildSearchQueryJSON(q), [q]); const handleOnBackButtonPress = () => Navigation.goBack(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: buildCannedSearchQuery()})); + const {resetVideoPlayerData} = usePlaybackContext(); + + // Handles video player cleanup: + // 1. On mount: Resets player if navigating from report screen + // 2. On unmount: Stops video when leaving this screen + useEffect(() => { + resetVideoPlayerData(); + return () => { + resetVideoPlayerData(); + }; + }, []); // On small screens this page is not displayed, the configuration is in the file: src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx // To avoid calling hooks in the Search component when this page isn't visible, we return null here. From b552942f3112963e3a0a0aef9eb9bdf22add1888 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 30 Jan 2025 14:21:14 +0700 Subject: [PATCH 71/94] resolve lint warning --- src/components/VideoPlayerPreview/index.tsx | 2 +- src/pages/Search/SearchPage.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/VideoPlayerPreview/index.tsx b/src/components/VideoPlayerPreview/index.tsx index 6f5ab1ec6ad6..03ce41ad2713 100644 --- a/src/components/VideoPlayerPreview/index.tsx +++ b/src/components/VideoPlayerPreview/index.tsx @@ -71,7 +71,7 @@ function VideoPlayerPreview({videoUrl, thumbnailUrl, reportID, fileName, videoDi return; } setIsThumbnail(false); - }, [currentlyPlayingURL, currentlyPlayingURLReportID, updateCurrentlyPlayingURL, videoUrl, reportID]); + }, [currentlyPlayingURL, currentlyPlayingURLReportID, updateCurrentlyPlayingURL, videoUrl, reportID, isOnSearch]); return ( diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index e91a6b2a96a1..60b7fa9b3ad4 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -33,6 +33,7 @@ function SearchPage({route}: SearchPageProps) { return () => { resetVideoPlayerData(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // On small screens this page is not displayed, the configuration is in the file: src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx From 0145b82efdc9e4e820369b8ee6967d9f80d90d9b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 30 Jan 2025 14:36:13 +0700 Subject: [PATCH 72/94] skip compiler warning --- src/pages/Search/SearchPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 60b7fa9b3ad4..a91a23d320ec 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -33,6 +33,7 @@ function SearchPage({route}: SearchPageProps) { return () => { resetVideoPlayerData(); }; + // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From 85b32946760c0c7b6c27dc9c2cb31bc5a9aa4d53 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 30 Jan 2025 16:51:04 +0700 Subject: [PATCH 73/94] mock ConfirmedRoute in AppTest --- tests/actions/AppTest.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/actions/AppTest.ts b/tests/actions/AppTest.ts index 3de64b78ed5e..62b6b490e856 100644 --- a/tests/actions/AppTest.ts +++ b/tests/actions/AppTest.ts @@ -8,6 +8,8 @@ import getOnyxValue from '../utils/getOnyxValue'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +jest.mock('@src/components/ConfirmedRoute.tsx'); + OnyxUpdateManager(); describe('actions/App', () => { From 39363bd2e0ba97ec5788ede7e4a41957dd7c05ef Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 31 Jan 2025 10:45:32 +0700 Subject: [PATCH 74/94] if there is selector, don't use snapshot in result --- src/components/EReceiptThumbnail.tsx | 2 +- src/hooks/useOnyx.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/EReceiptThumbnail.tsx b/src/components/EReceiptThumbnail.tsx index 4b0c0caa1035..2d6a6bc04ecd 100644 --- a/src/components/EReceiptThumbnail.tsx +++ b/src/components/EReceiptThumbnail.tsx @@ -1,6 +1,6 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {getTransactionDetails} from '@libs/ReportUtils'; diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 2a1bc3827e29..3eded646a1e4 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -105,7 +105,8 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { // Extract and memoize the specific key data from snapshot if in search mode const result = useMemo((): OriginalUseOnyxReturnType => { - if (!shouldUseSnapshot) { + // if it has selector, we wouldn't need to use snapshot here + if (!shouldUseSnapshot || selector) { return originalResult as OriginalUseOnyxReturnType; } From 0a78c2e2d20dc6a69a838a78347097ebc73c9af8 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 3 Feb 2025 10:03:59 +0700 Subject: [PATCH 75/94] isOnSearch true for attachment modal case --- src/hooks/useSearchState.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index f99d04275306..28316fa9b86d 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -4,20 +4,24 @@ import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigat import type {AuthScreensParamList} from '@libs/Navigation/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import SCREENS from '@src/SCREENS'; +import CONST from '@src/CONST'; -type SearchResult = { +type SearchStateResult = { isOnSearch: boolean; hashKey?: string; + isSearchAttachmentModal?: boolean; }; /** * Hook to manage search state based on route parameters * Returns search status and hash for query tracking */ -const useSearchState = (): SearchResult => { +const useSearchState = (): SearchStateResult => { // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. - const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; - const {q} = route?.params ?? {}; + // const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; + const route = useContext(NavigationRouteContext); + const {q, type} = (route?.params as { q?: string; type?: string }) ?? { q: undefined, type: undefined }; + const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH ; return useMemo(() => { if (!route) { @@ -26,7 +30,7 @@ const useSearchState = (): SearchResult => { const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: string}); const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; - const isOnSearch = (route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey; + const isOnSearch = ((route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey) || isSearchAttachmentModal; return {hashKey, isOnSearch}; }, [q, route]); From cc2bf64acc9be2bca99866a855cdabaadc71dc06 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 3 Feb 2025 11:24:53 +0700 Subject: [PATCH 76/94] limit search page video reset to only non narrow, add isOnSearch condition to shouldUseSharedVideoElement --- src/components/Attachments/AttachmentView/index.tsx | 6 ++++-- src/pages/Search/SearchPage.tsx | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Attachments/AttachmentView/index.tsx b/src/components/Attachments/AttachmentView/index.tsx index f6d6ba447af3..e3937fd3bc17 100644 --- a/src/components/Attachments/AttachmentView/index.tsx +++ b/src/components/Attachments/AttachmentView/index.tsx @@ -2,7 +2,7 @@ import {Str} from 'expensify-common'; import React, {memo, useContext, useEffect, useState} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import AttachmentCarouselPagerContext from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import type {Attachment, AttachmentSource} from '@components/Attachments/types'; import DistanceEReceipt from '@components/DistanceEReceipt'; @@ -31,6 +31,7 @@ import AttachmentViewPdf from './AttachmentViewPdf'; import AttachmentViewVideo from './AttachmentViewVideo'; import DefaultAttachmentView from './DefaultAttachmentView'; import HighResolutionInfo from './HighResolutionInfo'; +import useSearchState from '@hooks/useSearchState'; type AttachmentViewProps = Attachment & { /** Whether this view is the active screen */ @@ -121,6 +122,7 @@ function AttachmentView({ const [hasPDFFailedToLoad, setHasPDFFailedToLoad] = useState(false); const isVideo = (typeof source === 'string' && Str.isVideo(source)) || (file?.name && Str.isVideo(file.name)); const isUsedInCarousel = !!attachmentCarouselPagerContext?.pagerRef; + const { isOnSearch } = useSearchState(); useEffect(() => { if (!isFocused && !(file && isUsedInAttachmentModal)) { @@ -297,7 +299,7 @@ function AttachmentView({ return ( diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 27a388ede384..797137820c36 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -28,9 +28,16 @@ function SearchPage({route}: SearchPageProps) { // Handles video player cleanup: // 1. On mount: Resets player if navigating from report screen // 2. On unmount: Stops video when leaving this screen + // in narrow layout, the reset will be handled by the attachment modal, so we don't need to do it here to preserve autoplay useEffect(() => { + if(shouldUseNarrowLayout){ + return; + } resetVideoPlayerData(); return () => { + if(shouldUseNarrowLayout){ + return; + } resetVideoPlayerData(); }; // eslint-disable-next-line react-compiler/react-compiler From c953afe0c1fda960fef8740f952dbb71d5c85f90 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 3 Feb 2025 11:34:35 +0700 Subject: [PATCH 77/94] prettier --- src/components/Attachments/AttachmentView/index.tsx | 6 +++--- src/hooks/useSearchState.ts | 6 +++--- src/pages/Search/SearchPage.tsx | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Attachments/AttachmentView/index.tsx b/src/components/Attachments/AttachmentView/index.tsx index e3937fd3bc17..73a413a3d924 100644 --- a/src/components/Attachments/AttachmentView/index.tsx +++ b/src/components/Attachments/AttachmentView/index.tsx @@ -2,7 +2,6 @@ import {Str} from 'expensify-common'; import React, {memo, useContext, useEffect, useState} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; import AttachmentCarouselPagerContext from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import type {Attachment, AttachmentSource} from '@components/Attachments/types'; import DistanceEReceipt from '@components/DistanceEReceipt'; @@ -15,6 +14,8 @@ import Text from '@components/Text'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useOnyx from '@hooks/useOnyx'; +import useSearchState from '@hooks/useSearchState'; import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; @@ -31,7 +32,6 @@ import AttachmentViewPdf from './AttachmentViewPdf'; import AttachmentViewVideo from './AttachmentViewVideo'; import DefaultAttachmentView from './DefaultAttachmentView'; import HighResolutionInfo from './HighResolutionInfo'; -import useSearchState from '@hooks/useSearchState'; type AttachmentViewProps = Attachment & { /** Whether this view is the active screen */ @@ -122,7 +122,7 @@ function AttachmentView({ const [hasPDFFailedToLoad, setHasPDFFailedToLoad] = useState(false); const isVideo = (typeof source === 'string' && Str.isVideo(source)) || (file?.name && Str.isVideo(file.name)); const isUsedInCarousel = !!attachmentCarouselPagerContext?.pagerRef; - const { isOnSearch } = useSearchState(); + const {isOnSearch} = useSearchState(); useEffect(() => { if (!isFocused && !(file && isUsedInAttachmentModal)) { diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index 28316fa9b86d..ad8805339907 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -3,8 +3,8 @@ import {useContext, useMemo} from 'react'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; -import SCREENS from '@src/SCREENS'; import CONST from '@src/CONST'; +import SCREENS from '@src/SCREENS'; type SearchStateResult = { isOnSearch: boolean; @@ -20,8 +20,8 @@ const useSearchState = (): SearchStateResult => { // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. // const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; const route = useContext(NavigationRouteContext); - const {q, type} = (route?.params as { q?: string; type?: string }) ?? { q: undefined, type: undefined }; - const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH ; + const {q, type} = (route?.params as {q?: string; type?: string}) ?? {q: undefined, type: undefined}; + const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; return useMemo(() => { if (!route) { diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 797137820c36..cebf021d4922 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -30,12 +30,12 @@ function SearchPage({route}: SearchPageProps) { // 2. On unmount: Stops video when leaving this screen // in narrow layout, the reset will be handled by the attachment modal, so we don't need to do it here to preserve autoplay useEffect(() => { - if(shouldUseNarrowLayout){ + if (shouldUseNarrowLayout) { return; } resetVideoPlayerData(); return () => { - if(shouldUseNarrowLayout){ + if (shouldUseNarrowLayout) { return; } resetVideoPlayerData(); From 76d21fe5acbd0e7925157914f824ff8a366a9059 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Mon, 3 Feb 2025 11:42:34 +0700 Subject: [PATCH 78/94] lint fix --- src/hooks/useOnyx.ts | 9 +++++++-- src/hooks/useSearchState.ts | 8 +++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 3eded646a1e4..75adfcaea1f1 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -96,7 +96,12 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const shouldUseSnapshot = isOnSearch && !key.startsWith(ONYXKEYS.COLLECTION.SNAPSHOT) && CONST.SEARCH.SNAPSHOT_ONYX_KEYS.some((snapshotKey) => key.startsWith(snapshotKey)); // Create selector function that handles both regular and snapshot data - const selector = selectorProp ? (data: OnyxValue | undefined) => selectorProp(shouldUseSnapshot ? getKeyData(data as SearchResults, key) : data) : undefined; + const selector = useMemo(() => { + if (!selectorProp) { + return undefined; + } + return (data: OnyxValue | undefined) => selectorProp(shouldUseSnapshot ? getKeyData(data as SearchResults, key) : data); + }, [selectorProp, shouldUseSnapshot, key]); const onyxOptions = {...optionsWithoutSelector, selector}; const snapshotKey = shouldUseSnapshot ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key; @@ -112,7 +117,7 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { const keyData = getKeyData(originalResult[0] as SearchResults, key, useOnyxOptions?.initialValue); return [keyData, originalResult[1]] as OriginalUseOnyxReturnType; - }, [shouldUseSnapshot, originalResult, key, useOnyxOptions?.initialValue]); + }, [shouldUseSnapshot, originalResult, key, useOnyxOptions?.initialValue, selector]); return result; }; diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index ad8805339907..e1ed8a68f797 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -1,7 +1,5 @@ import {NavigationRouteContext} from '@react-navigation/native'; import {useContext, useMemo} from 'react'; -import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {AuthScreensParamList} from '@libs/Navigation/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; @@ -9,7 +7,6 @@ import SCREENS from '@src/SCREENS'; type SearchStateResult = { isOnSearch: boolean; hashKey?: string; - isSearchAttachmentModal?: boolean; }; /** @@ -21,9 +18,10 @@ const useSearchState = (): SearchStateResult => { // const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; const route = useContext(NavigationRouteContext); const {q, type} = (route?.params as {q?: string; type?: string}) ?? {q: undefined, type: undefined}; - const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; return useMemo(() => { + const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; + if (!route) { return {isOnSearch: false, hashKey: undefined}; } @@ -33,7 +31,7 @@ const useSearchState = (): SearchStateResult => { const isOnSearch = ((route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey) || isSearchAttachmentModal; return {hashKey, isOnSearch}; - }, [q, route]); + }, [q, type, route]); }; export default useSearchState; From 438995508b3012db6644628e353c70695145d13b Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 5 Feb 2025 09:08:15 +0700 Subject: [PATCH 79/94] Use UseOnyxOptions type from react-native-onyx --- src/hooks/useOnyx.ts | 45 +------------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 75adfcaea1f1..3f08b6fb210e 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -1,54 +1,11 @@ import {useMemo} from 'react'; import {useOnyx as originalUseOnyx} from 'react-native-onyx'; -import type {OnyxCollection, OnyxEntry, OnyxKey, OnyxValue} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, UseOnyxOptions} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchResults} from '@src/types/onyx'; import useSearchState from './useSearchState'; -type BaseUseOnyxOptions = { - /** - * Determines if this key in this subscription is safe to be evicted. - */ - canEvict?: boolean; - - /** - * If set to `false`, then no data will be prefilled into the component. - */ - initWithStoredValues?: boolean; - - /** - * If set to `true`, data will be retrieved from cache during the first render even if there is a pending merge for the key. - */ - allowStaleData?: boolean; - - /** - * If set to `false`, the connection won't be reused between other subscribers that are listening to the same Onyx key - * with the same connect configurations. - */ - reuseConnection?: boolean; -}; - -type UseOnyxInitialValueOption = { - /** - * This value will be returned by the hook on the first render while the data is being read from Onyx. - */ - initialValue?: TInitialValue; -}; - -type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; - -type UseOnyxSelectorOption = { - /** - * This will be used to subscribe to a subset of an Onyx key's data. - * Using this setting can have very positive performance benefits because the component will only re-render - * when the subset of data changes. - */ - selector?: UseOnyxSelector; -}; - -type UseOnyxOptions = BaseUseOnyxOptions & UseOnyxInitialValueOption & UseOnyxSelectorOption; - type OriginalUseOnyx = typeof originalUseOnyx; type OriginalUseOnyxReturnType = ReturnType; From 867efb3b6a412a26b4684d8d9c20231d6a7258ef Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 5 Feb 2025 10:45:18 +0700 Subject: [PATCH 80/94] add hashKey in route param to make attachment able to determine the snapshot for the previewed attachment --- src/ROUTES.ts | 6 +++++- src/components/AttachmentContext.ts | 2 ++ .../Attachments/AttachmentCarousel/index.tsx | 2 +- .../HTMLRenderers/VideoRenderer.tsx | 4 ++-- src/hooks/useSearchState.ts | 11 ++++++----- src/libs/Navigation/types.ts | 1 + src/pages/home/report/PureReportActionItem.tsx | 6 +++--- src/pages/home/report/ReportAttachments.tsx | 2 ++ 8 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 87664b718974..216e58203ca4 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -361,14 +361,18 @@ const ROUTES = { isAuthTokenRequired?: boolean, fileName?: string, attachmentLink?: string, + hashKey?: number, ) => { const reportParam = reportID ? `&reportID=${reportID}` : ''; const accountParam = accountID ? `&accountID=${accountID}` : ''; const authTokenParam = isAuthTokenRequired ? '&isAuthTokenRequired=true' : ''; const fileNameParam = fileName ? `&fileName=${fileName}` : ''; const attachmentLinkParam = attachmentLink ? `&attachmentLink=${attachmentLink}` : ''; + const hashKeyParam = hashKey ? `&hashKey=${hashKey}` : ''; - return `attachment?source=${encodeURIComponent(url)}&type=${type as string}${reportParam}${accountParam}${authTokenParam}${fileNameParam}${attachmentLinkParam}` as const; + return `attachment?source=${encodeURIComponent(url)}&type=${ + type as string + }${reportParam}${accountParam}${authTokenParam}${fileNameParam}${attachmentLinkParam}${hashKeyParam}` as const; }, }, REPORT_PARTICIPANTS: { diff --git a/src/components/AttachmentContext.ts b/src/components/AttachmentContext.ts index 4ed6bdc9084f..0c3308ae75e5 100644 --- a/src/components/AttachmentContext.ts +++ b/src/components/AttachmentContext.ts @@ -6,12 +6,14 @@ type AttachmentContextProps = { type?: ValueOf; reportID?: string; accountID?: number; + hashKey?: number; }; const AttachmentContext = createContext({ type: undefined, reportID: undefined, accountID: undefined, + hashKey: undefined, }); AttachmentContext.displayName = 'AttachmentContext'; diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 50caaac3dd81..bc33e9cc6167 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -5,13 +5,13 @@ import type {ListRenderItemInfo} from 'react-native'; import {Keyboard, PixelRatio, View} from 'react-native'; import type {ComposedGesture, GestureType} from 'react-native-gesture-handler'; import {Gesture, GestureDetector} from 'react-native-gesture-handler'; -import {useOnyx} from 'react-native-onyx'; import Animated, {scrollTo, useAnimatedRef, useSharedValue} from 'react-native-reanimated'; import type {Attachment, AttachmentSource} from '@components/Attachments/types'; import BlockingView from '@components/BlockingViews/BlockingView'; import * as Illustrations from '@components/Icon/Illustrations'; import {useFullScreenContext} from '@components/VideoPlayerContexts/FullScreenContext'; import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/VideoRenderer.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/VideoRenderer.tsx index ad7ea87f4c9b..0cde2123ceb2 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/VideoRenderer.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/VideoRenderer.tsx @@ -32,7 +32,7 @@ function VideoRenderer({tnode, key}: VideoRendererProps) { {({report}) => ( - {({accountID, type}) => ( + {({accountID, type, hashKey}) => ( diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index e1ed8a68f797..ec246fae4cfc 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -6,7 +6,7 @@ import SCREENS from '@src/SCREENS'; type SearchStateResult = { isOnSearch: boolean; - hashKey?: string; + hashKey?: number; }; /** @@ -17,7 +17,7 @@ const useSearchState = (): SearchStateResult => { // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. // const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; const route = useContext(NavigationRouteContext); - const {q, type} = (route?.params as {q?: string; type?: string}) ?? {q: undefined, type: undefined}; + const {q, type, hashKey: hashKeyFromRoute} = (route?.params as {q?: string; type?: string; hashKey?: number}) ?? {q: undefined, type: undefined, hashKey: undefined}; return useMemo(() => { const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; @@ -26,12 +26,13 @@ const useSearchState = (): SearchStateResult => { return {isOnSearch: false, hashKey: undefined}; } - const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: string}); - const hashKey = queryJSON?.hash ? String(queryJSON.hash) : undefined; + const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: number}); + // for attachment modal the hashKey is passed through route params, fallback to it if not found in queryJSON + const hashKey = queryJSON?.hash ? queryJSON.hash : hashKeyFromRoute ?? undefined; const isOnSearch = ((route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey) || isSearchAttachmentModal; return {hashKey, isOnSearch}; - }, [q, type, route]); + }, [q, type, route, hashKeyFromRoute]); }; export default useSearchState; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index f57c4c3f5715..aac7da3406d8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1743,6 +1743,7 @@ type AuthScreensParamList = CentralPaneScreensParamList & isAuthTokenRequired?: string; fileName?: string; attachmentLink?: string; + hashKey?: number; }; [SCREENS.PROFILE_AVATAR]: { accountID: string; diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 2359f36ff2b6..4ced1d2a459b 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -397,7 +397,7 @@ function PureReportActionItem({ [action.reportActionID, action.message, updateHiddenAttachments], ); - const {isOnSearch} = useSearchState(); + const {isOnSearch, hashKey} = useSearchState(); const onClose = () => { let transactionID; if (isMoneyRequestAction(action)) { @@ -570,10 +570,10 @@ function PureReportActionItem({ const attachmentContextValue = useMemo(() => { if (isOnSearch) { - return {type: CONST.ATTACHMENT_TYPE.SEARCH}; + return {type: CONST.ATTACHMENT_TYPE.SEARCH, hashKey}; } return {reportID, type: CONST.ATTACHMENT_TYPE.REPORT}; - }, [reportID, isOnSearch]); + }, [reportID, isOnSearch, hashKey]); const mentionReportContextValue = useMemo(() => ({currentReportID: reportID}), [reportID]); const actionableItemButtons: ActionableItem[] = useMemo(() => { diff --git a/src/pages/home/report/ReportAttachments.tsx b/src/pages/home/report/ReportAttachments.tsx index dfac22b23f06..1e99a89f0f8c 100644 --- a/src/pages/home/report/ReportAttachments.tsx +++ b/src/pages/home/report/ReportAttachments.tsx @@ -16,6 +16,7 @@ type ReportAttachmentsProps = PlatformStackScreenProps Date: Wed, 5 Feb 2025 11:57:22 +0700 Subject: [PATCH 81/94] add hashKey to dependency --- src/pages/home/report/ReportAttachments.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportAttachments.tsx b/src/pages/home/report/ReportAttachments.tsx index 1e99a89f0f8c..bddc05892d6a 100644 --- a/src/pages/home/report/ReportAttachments.tsx +++ b/src/pages/home/report/ReportAttachments.tsx @@ -41,7 +41,7 @@ function ReportAttachments({route}: ReportAttachmentsProps) { ); Navigation.navigate(routeToNavigate); }, - [reportID, type, accountID], + [reportID, type, accountID, hashKey], ); return ( From 766ca0abc81fb3d91615e7e179a4d6bcd496cbf3 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 5 Feb 2025 13:56:22 +0700 Subject: [PATCH 82/94] waitForBatchedUpdates since the correct value shown at the last render --- tests/unit/ReportActionItemSingleTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index e0bf06be1609..26fa2b0d5584 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -70,7 +70,7 @@ describe('ReportActionItemSingle', () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; await setup(); - await waitFor(() => { + await waitForBatchedUpdates(() => { expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeOnTheScreen(); }); }); From 37040df2db5e1f29c6879b79fde2cc16e2d91ba6 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 5 Feb 2025 14:09:07 +0700 Subject: [PATCH 83/94] fix incorrect waitForBatchedUpdates usage --- tests/unit/ReportActionItemSingleTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index 26fa2b0d5584..2bc6d79294dc 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -70,7 +70,7 @@ describe('ReportActionItemSingle', () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; await setup(); - await waitForBatchedUpdates(() => { + waitForBatchedUpdates().then(() => { expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeOnTheScreen(); }); }); From 0739db9ae7422e12f93d0a6ef2445a5b5b25f7d7 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 5 Feb 2025 17:19:06 +0700 Subject: [PATCH 84/94] revert not working tes change --- tests/unit/ReportActionItemSingleTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index 2bc6d79294dc..e0bf06be1609 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -70,7 +70,7 @@ describe('ReportActionItemSingle', () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; await setup(); - waitForBatchedUpdates().then(() => { + await waitFor(() => { expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeOnTheScreen(); }); }); From 012e168c41712f6f8678f9761b21e26ab0c753da Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 6 Feb 2025 08:54:46 +0700 Subject: [PATCH 85/94] prettier --- src/components/MapView/MapView.tsx | 2 +- src/components/MapView/MapViewImpl.website.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 0efdd1998ee5..36ccc8d19c8c 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -5,9 +5,9 @@ import {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, import {View} from 'react-native'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; -import useOnyx from '@hooks/useOnyx'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import Text from '@components/Text'; +import useOnyx from '@hooks/useOnyx'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {clearUserLocation, setUserLocation} from '@libs/actions/UserLocation'; diff --git a/src/components/MapView/MapViewImpl.website.tsx b/src/components/MapView/MapViewImpl.website.tsx index 01e859aedc66..0a3bbf57c9f7 100644 --- a/src/components/MapView/MapViewImpl.website.tsx +++ b/src/components/MapView/MapViewImpl.website.tsx @@ -11,8 +11,8 @@ import Map, {Marker} from 'react-map-gl'; import {View} from 'react-native'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; -import useOnyx from '@hooks/useOnyx'; import {PressableWithoutFeedback} from '@components/Pressable'; +import useOnyx from '@hooks/useOnyx'; import usePrevious from '@hooks/usePrevious'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; From 4f06062dcf50b0daa68760965be4c73aa03c656d Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 6 Feb 2025 09:54:18 +0700 Subject: [PATCH 86/94] move test rendered report action after setup --- tests/unit/ReportActionItemSingleTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index e0bf06be1609..43c6b929f4ff 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -54,7 +54,6 @@ describe('ReportActionItemSingle', () => { }; function setup() { - LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); const policyCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.POLICY, [fakePolicy], (item) => item.id); return waitForBatchedUpdates().then(() => @@ -70,6 +69,7 @@ describe('ReportActionItemSingle', () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; await setup(); + LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); await waitFor(() => { expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeOnTheScreen(); }); From 1597c1c73610df49ab84fe9755bd9d9d611384ee Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 6 Feb 2025 11:24:00 +0700 Subject: [PATCH 87/94] fix missing render in test --- tests/unit/ReportActionItemSingleTest.ts | 25 +++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/unit/ReportActionItemSingleTest.ts b/tests/unit/ReportActionItemSingleTest.ts index 43c6b929f4ff..f8a29e87af82 100644 --- a/tests/unit/ReportActionItemSingleTest.ts +++ b/tests/unit/ReportActionItemSingleTest.ts @@ -55,30 +55,33 @@ describe('ReportActionItemSingle', () => { function setup() { const policyCollectionDataSet = toCollectionDataSet(ONYXKEYS.COLLECTION.POLICY, [fakePolicy], (item) => item.id); - - return waitForBatchedUpdates().then(() => - Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...policyCollectionDataSet, - }), - ); + return waitForBatchedUpdates() + .then(() => + Onyx.multiSet({ + [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails, + [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, + ...policyCollectionDataSet, + }), + ) + .then(() => { + LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); + }); } it('renders secondary Avatar properly', async () => { const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon'; await setup(); - LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction); await waitFor(() => { expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeOnTheScreen(); }); }); - it('renders Person information', () => { + it('renders Person information', async () => { const [expectedPerson] = fakeReportAction.person ?? []; - return setup().then(() => { + await setup(); + await waitFor(() => { expect(screen.getByText(expectedPerson.text ?? '')).toBeOnTheScreen(); }); }); From b884be86661e1fd119b6c2dd8742e772b90606b1 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Tue, 11 Feb 2025 09:21:00 +0700 Subject: [PATCH 88/94] resolve NewChatPageTest error --- tests/ui/NewChatPageTest.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/NewChatPageTest.tsx b/tests/ui/NewChatPageTest.tsx index 837f59bf3af4..bd500635f969 100644 --- a/tests/ui/NewChatPageTest.tsx +++ b/tests/ui/NewChatPageTest.tsx @@ -15,6 +15,7 @@ import {fakePersonalDetails} from '../utils/LHNTestUtils'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; jest.mock('@react-navigation/native'); +jest.mock('@components/ConfirmedRoute.tsx'); describe('NewChatPage', () => { beforeAll(() => { From e1232ed630a003579bf6cfb53d83d8aa1e1a2c21 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 12 Feb 2025 10:34:04 +0700 Subject: [PATCH 89/94] Resolve conflic, move 'IN' feature to reportactionsingle --- .../home/report/ReportActionItemSingle.tsx | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 7b8af9ec374c..7d35e9838294 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -9,11 +9,13 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import SubscriptAvatar from '@components/SubscriptAvatar'; import Text from '@components/Text'; +import TextLink from '@components/TextLink'; import Tooltip from '@components/Tooltip'; import UserDetailsTooltip from '@components/UserDetailsTooltip'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; +import useSearchState from '@hooks/useSearchState'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -36,11 +38,13 @@ import { isPolicyExpenseChat, isTripRoom as isTripRoomReportUtils, } from '@libs/ReportUtils'; +import variables from '@styles/variables'; 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 {Icon} from '@src/types/onyx/OnyxCommon'; +import type {SearchReportAction} from '@src/types/onyx/SearchResults'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; @@ -72,6 +76,9 @@ type ReportActionItemSingleProps = Partial & { /** If the action is being actived */ isActive?: boolean; + + /** Callback to be called on onPress */ + onPress?: () => void; }; const showUserDetails = (accountID: number | undefined) => { @@ -96,6 +103,7 @@ function ReportActionItemSingle({ iouReport, isHovered = false, isActive = false, + onPress = undefined, }: ReportActionItemSingleProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -120,6 +128,7 @@ function ReportActionItemSingle({ const displayAllActors = isReportPreviewAction && !isTripRoom && !isPolicyExpenseChat(report); const isInvoiceReport = isInvoiceReportUtils(iouReport ?? null); const isWorkspaceActor = isInvoiceReport || (isPolicyExpenseChat(report) && (!actorAccountID || displayAllActors)); + const {isOnSearch} = useSearchState(); let avatarSource = avatar; let avatarId: number | string | undefined = actorAccountID; @@ -280,8 +289,10 @@ function ReportActionItemSingle({ const statusText = status?.text ?? ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; - return ( - + const actionWrapper = (content: React.ReactNode) => {content}; + + const reportActionContent = ( + <> {children} - + + ); + + if (!isOnSearch) { + return actionWrapper(reportActionContent); + } + + return actionWrapper( + + + {translate('common.in')}  + { + onPress?.(); + }} + numberOfLines={1} + > + {(action as SearchReportAction).reportName} + + + {reportActionContent} + , ); } From edbddd354bc4158564fb0a3f29ec10adc0992a77 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 12 Feb 2025 11:06:52 +0700 Subject: [PATCH 90/94] Update src/pages/home/report/ReportActionItem.tsx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/pages/home/report/ReportActionItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index fd28e4a4b603..6970b142c108 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -38,7 +38,7 @@ function ReportActionItem({action, report, ...props}: PureReportActionItemProps) // The app would crash due to subscribing to the entire report collection if parentReportID is an empty string. So we should have a fallback ID here. // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID || undefined}`); - const [personalDetails] = useOnyx(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const blockedFromConcierge = useBlockedFromConcierge(); const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID); const linkedReport = ReportUtils.isChatThread(report) ? parentReport : report; From 3e619f0d90c044d46699f2dd2840c0668d80edc5 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 12 Feb 2025 11:07:09 +0700 Subject: [PATCH 91/94] Update src/hooks/useSearchState.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useSearchState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index ec246fae4cfc..3064e9c6f2a2 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -26,7 +26,7 @@ const useSearchState = (): SearchStateResult => { return {isOnSearch: false, hashKey: undefined}; } - const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: number}); + const queryJSON = q ? buildSearchQueryJSON(q) : ({} as Partial); // for attachment modal the hashKey is passed through route params, fallback to it if not found in queryJSON const hashKey = queryJSON?.hash ? queryJSON.hash : hashKeyFromRoute ?? undefined; const isOnSearch = ((route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey) || isSearchAttachmentModal; From 2f915baf6ff95ee7b6de67d4c2cadffba9261b3a Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 12 Feb 2025 12:02:20 +0700 Subject: [PATCH 92/94] fix isOnSearch based on new route change, fix lint and prettier --- src/hooks/useSearchState.ts | 12 +++++++++--- src/pages/Search/SearchPage.tsx | 2 +- tests/navigation/ResizeScreenTests.tsx | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index ec246fae4cfc..ce1c8e360a32 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -4,6 +4,12 @@ import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; +type SearchRouteParams = { + q?: string; + type?: string; + hashKey?: number; +}; + type SearchStateResult = { isOnSearch: boolean; hashKey?: number; @@ -15,9 +21,8 @@ type SearchStateResult = { */ const useSearchState = (): SearchStateResult => { // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. - // const route = useContext(NavigationRouteContext) as PlatformStackRouteProp; const route = useContext(NavigationRouteContext); - const {q, type, hashKey: hashKeyFromRoute} = (route?.params as {q?: string; type?: string; hashKey?: number}) ?? {q: undefined, type: undefined, hashKey: undefined}; + const { q, type, hashKey: hashKeyFromRoute } = (route?.params as SearchRouteParams) ?? {}; return useMemo(() => { const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; @@ -26,10 +31,11 @@ const useSearchState = (): SearchStateResult => { return {isOnSearch: false, hashKey: undefined}; } + const queryJSON = q ? buildSearchQueryJSON(q) : ({} as {hash?: number}); // for attachment modal the hashKey is passed through route params, fallback to it if not found in queryJSON const hashKey = queryJSON?.hash ? queryJSON.hash : hashKeyFromRoute ?? undefined; - const isOnSearch = ((route?.name === SCREENS.SEARCH.CENTRAL_PANE || route?.name === SCREENS.SEARCH.BOTTOM_TAB) && !!hashKey) || isSearchAttachmentModal; + const isOnSearch = (route?.name === SCREENS.SEARCH.ROOT && !!hashKey) || isSearchAttachmentModal; return {hashKey, isOnSearch}; }, [q, type, route, hashKeyFromRoute]); diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 898becbd4aee..1e90d0a294da 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -1,4 +1,4 @@ -import React, {useMemo, useEffect} from 'react'; +import React, {useEffect, useMemo} from 'react'; import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderGap from '@components/HeaderGap'; diff --git a/tests/navigation/ResizeScreenTests.tsx b/tests/navigation/ResizeScreenTests.tsx index 04bd7d72b76b..08a4a6e0c639 100644 --- a/tests/navigation/ResizeScreenTests.tsx +++ b/tests/navigation/ResizeScreenTests.tsx @@ -89,4 +89,4 @@ describe('Resize screen', () => { expect(rootStateAfterResize?.routes.at(1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); expect(rootStateAfterResize?.index).toBe(1); }); -}); \ No newline at end of file +}); From cacdf58a9a8abba4e141fcb494693d944416e96a Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 12 Feb 2025 14:01:40 +0700 Subject: [PATCH 93/94] resolve conflict fix vertical padding for search --- src/hooks/useSearchState.ts | 4 +-- .../home/report/ReportActionItemSingle.tsx | 36 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hooks/useSearchState.ts b/src/hooks/useSearchState.ts index e1e93c972612..055c7b8274df 100644 --- a/src/hooks/useSearchState.ts +++ b/src/hooks/useSearchState.ts @@ -1,9 +1,9 @@ import {NavigationRouteContext} from '@react-navigation/native'; import {useContext, useMemo} from 'react'; +import type {SearchQueryJSON} from '@components/Search/types'; import {buildSearchQueryJSON} from '@libs/SearchQueryUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; -import { SearchQueryJSON } from '@components/Search/types'; type SearchRouteParams = { q?: string; @@ -23,7 +23,7 @@ type SearchStateResult = { const useSearchState = (): SearchStateResult => { // We are using these contexts directly instead of useRoute, because those will throw an error if used outside a navigator. const route = useContext(NavigationRouteContext); - const { q, type, hashKey: hashKeyFromRoute } = (route?.params as SearchRouteParams) ?? {}; + const {q, type, hashKey: hashKeyFromRoute} = (route?.params as SearchRouteParams) ?? {}; return useMemo(() => { const isSearchAttachmentModal = route?.name === SCREENS.ATTACHMENTS && type === CONST.ATTACHMENT_TYPE.SEARCH; diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 7d35e9838294..7641728ff065 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -289,8 +289,6 @@ function ReportActionItemSingle({ const statusText = status?.text ?? ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; - const actionWrapper = (content: React.ReactNode) => {content}; - const reportActionContent = ( <> {reportActionContent}; } - return actionWrapper( - - - {translate('common.in')}  - { - onPress?.(); - }} - numberOfLines={1} - > - {(action as SearchReportAction).reportName} - + return ( + + + + {translate('common.in')}  + { + onPress?.(); + }} + numberOfLines={1} + > + {(action as SearchReportAction).reportName} + + + {reportActionContent} - {reportActionContent} - , + ); } From 22b5a8c44f131e3fd20b53ef442c5eb8e1239fb4 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 12 Feb 2025 14:05:48 +0700 Subject: [PATCH 94/94] Update src/hooks/useOnyx.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fábio Henriques --- src/hooks/useOnyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useOnyx.ts b/src/hooks/useOnyx.ts index 3f08b6fb210e..ae78bf1b979c 100644 --- a/src/hooks/useOnyx.ts +++ b/src/hooks/useOnyx.ts @@ -60,7 +60,7 @@ const useOnyx: OriginalUseOnyx = (key, options, dependencies) => { return (data: OnyxValue | undefined) => selectorProp(shouldUseSnapshot ? getKeyData(data as SearchResults, key) : data); }, [selectorProp, shouldUseSnapshot, key]); - const onyxOptions = {...optionsWithoutSelector, selector}; + const onyxOptions: UseOnyxOptions> = {...optionsWithoutSelector, selector, allowDynamicKey: true}; const snapshotKey = shouldUseSnapshot ? (`${ONYXKEYS.COLLECTION.SNAPSHOT}${hashKey}` as OnyxKey) : key; const originalResult = originalUseOnyx(snapshotKey, onyxOptions, dependencies);