Skip to content

Commit afb4a2b

Browse files
authored
Merge pull request #91946 from callstack-internal/perf/extract-money-report-transaction-thread
perf: extract money report transaction thread into context
2 parents 998484c + 3ee125b commit afb4a2b

9 files changed

Lines changed: 282 additions & 80 deletions

src/components/MoneyReportHeaderActions/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import {View} from 'react-native';
33
import type {ValueOf} from 'type-fest';
44
import type {ButtonWithDropdownMenuRef} from '@components/ButtonWithDropdownMenu/types';
55
import MoneyReportHeaderPrimaryAction from '@components/MoneyReportHeaderPrimaryAction';
6+
import {useMoneyReportTransactionThread} from '@components/MoneyReportTransactionThreadContext';
67
import {useSearchSelectionActions, useSearchSelectionContext} from '@components/Search/SearchContext';
78
import useExportAgainModal from '@hooks/useExportAgainModal';
89
import useOnyx from '@hooks/useOnyx';
910
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1011
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
1112
import useThemeStyles from '@hooks/useThemeStyles';
12-
import useTransactionThreadReport from '@hooks/useTransactionThreadReport';
1313
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
1414
import CONST from '@src/CONST';
1515
import ONYXKEYS from '@src/ONYXKEYS';
@@ -40,7 +40,7 @@ function MoneyReportHeaderActions({reportID, primaryAction, isReportInSearch, ba
4040
const [moneyRequestReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
4141
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(moneyRequestReport?.chatReportID)}`);
4242

43-
const {transactionThreadReportID} = useTransactionThreadReport(reportID);
43+
const {transactionThreadReportID} = useMoneyReportTransactionThread();
4444

4545
const {triggerExportOrConfirm} = useExportAgainModal(moneyRequestReport?.reportID, moneyRequestReport?.policyID);
4646

src/components/MoneyReportHeaderEducationalModals.tsx

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,17 @@ import type {ValueOf} from 'type-fest';
55
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
66
import useNetwork from '@hooks/useNetwork';
77
import useOnyx from '@hooks/useOnyx';
8-
import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
9-
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
108
import {setNameValuePair} from '@libs/actions/User';
119
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
12-
import {getAllNonDeletedTransactions} from '@libs/MoneyRequestReportUtils';
1310
import Navigation from '@libs/Navigation/Navigation';
14-
import {getFilteredReportActionsForReportView, getOneTransactionThreadReportID, getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
1511
import {changeMoneyRequestHoldStatus, rejectMoneyRequestReason} from '@libs/ReportUtils';
1612
import {dismissRejectUseExplanation} from '@userActions/IOU/RejectMoneyRequest';
1713
import CONST from '@src/CONST';
1814
import ONYXKEYS from '@src/ONYXKEYS';
1915
import ROUTES from '@src/ROUTES';
20-
import type * as OnyxTypes from '@src/types/onyx';
2116
import HoldOrRejectEducationalModal from './HoldOrRejectEducationalModal';
2217
import HoldSubmitterEducationalModal from './HoldSubmitterEducationalModal';
18+
import {useMoneyReportTransactionThread} from './MoneyReportTransactionThreadContext';
2319

2420
type RejectModalAction = ValueOf<
2521
typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.HOLD | typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT | typeof CONST.REPORT.TRANSACTION_SECONDARY_ACTIONS.REJECT_BULK
@@ -42,27 +38,9 @@ function MoneyReportHeaderEducationalModals({reportID, ref}: MoneyReportHeaderEd
4238
const {isOffline} = useNetwork();
4339
const [shouldFailAllRequests] = useOnyx(ONYXKEYS.NETWORK, {selector: shouldFailAllRequestsSelector});
4440

45-
// Fetch report data needed for educational modals
46-
const [moneyRequestReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
47-
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID}`);
48-
const {reportActions: unfilteredReportActions} = usePaginatedReportActions(moneyRequestReport?.reportID);
49-
const reportActions = getFilteredReportActionsForReportView(unfilteredReportActions);
50-
const {transactions: reportTransactions} = useTransactionsAndViolationsForReport(moneyRequestReport?.reportID);
5141
const {login: currentUserLogin, accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
5242

53-
// Derive transaction thread and parent action
54-
const nonDeletedTransactions = getAllNonDeletedTransactions(reportTransactions, reportActions, isOffline, true);
55-
const visibleTransactionsForThreadID = nonDeletedTransactions?.filter((t) => isOffline || t.pendingAction !== 'delete');
56-
const reportTransactionIDs = visibleTransactionsForThreadID?.map((t) => t.transactionID);
57-
const transactionThreadReportID = getOneTransactionThreadReportID(moneyRequestReport, chatReport, reportActions ?? [], isOffline, reportTransactionIDs);
58-
const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);
59-
60-
const requestParentReportAction =
61-
reportActions && transactionThreadReport?.parentReportActionID
62-
? reportActions.find((action): action is OnyxTypes.ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => action.reportActionID === transactionThreadReport.parentReportActionID)
63-
: null;
64-
65-
const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined;
43+
const {iouTransactionID, requestParentReportAction} = useMoneyReportTransactionThread();
6644
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(iouTransactionID)}`);
6745

6846
useImperativeHandle(ref, () => ({

src/components/MoneyReportHeaderModals.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import MoneyReportHeaderEducationalModals from './MoneyReportHeaderEducationalMo
1818
import type {MoneyReportHeaderEducationalModalsHandle, RejectModalAction} from './MoneyReportHeaderEducationalModals';
1919
import MoneyReportHeaderModalsContext from './MoneyReportHeaderModalsContext';
2020
import type {HoldMenuParams} from './MoneyReportHeaderModalsContext';
21+
import {MoneyReportTransactionThreadProvider} from './MoneyReportTransactionThreadContext';
2122
import ReportPDFDownloadModal from './ReportPDFDownloadModal';
2223

2324
type MoneyReportHeaderModalsProps = {
@@ -109,18 +110,20 @@ function MoneyReportHeaderModals({reportID, children}: MoneyReportHeaderModalsPr
109110

110111
return (
111112
<MoneyReportHeaderModalsContext.Provider value={contextValue}>
112-
{children}
113-
114-
<MoneyReportHeaderEducationalModals
115-
ref={educationalModalsRef}
116-
reportID={moneyRequestReport?.reportID}
117-
/>
118-
119-
<ReportPDFDownloadModal
120-
reportID={moneyRequestReport?.reportID}
121-
isVisible={isPDFModalVisible}
122-
onClose={() => setIsPDFModalVisible(false)}
123-
/>
113+
<MoneyReportTransactionThreadProvider reportID={moneyRequestReport?.reportID}>
114+
{children}
115+
116+
<MoneyReportHeaderEducationalModals
117+
ref={educationalModalsRef}
118+
reportID={moneyRequestReport?.reportID}
119+
/>
120+
121+
<ReportPDFDownloadModal
122+
reportID={moneyRequestReport?.reportID}
123+
isVisible={isPDFModalVisible}
124+
onClose={() => setIsPDFModalVisible(false)}
125+
/>
126+
</MoneyReportTransactionThreadProvider>
124127
</MoneyReportHeaderModalsContext.Provider>
125128
);
126129
}

src/components/MoneyReportHeaderMoreContent.tsx

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,21 @@ import {View} from 'react-native';
44
import type {OnyxEntry} from 'react-native-onyx';
55
import type {ValueOf} from 'type-fest';
66
import useMoneyReportHeaderStatusBar from '@hooks/useMoneyReportHeaderStatusBar';
7-
import useNetwork from '@hooks/useNetwork';
87
import useOnyx from '@hooks/useOnyx';
9-
import usePaginatedReportActions from '@hooks/usePaginatedReportActions';
10-
import useReportTransactionsCollection from '@hooks/useReportTransactionsCollection';
118
import useResponsiveLayout from '@hooks/useResponsiveLayout';
129
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
1310
import useThemeStyles from '@hooks/useThemeStyles';
1411
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
15-
import {getAllNonDeletedTransactions} from '@libs/MoneyRequestReportUtils';
1612
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
1713
import type {ReportsSplitNavigatorParamList, RightModalNavigatorParamList} from '@libs/Navigation/types';
18-
import {getFilteredReportActionsForReportView, getOneTransactionThreadReportID, getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
1914
import {isInvoiceReport as isInvoiceReportUtil} from '@libs/ReportUtils';
2015
import CONST from '@src/CONST';
2116
import ONYXKEYS from '@src/ONYXKEYS';
2217
import SCREENS from '@src/SCREENS';
2318
import type * as OnyxTypes from '@src/types/onyx';
2419
import MoneyReportHeaderNextStep from './MoneyReportHeaderNextStep';
2520
import MoneyReportHeaderStatusBarSection from './MoneyReportHeaderStatusBarSection';
21+
import {useMoneyReportTransactionThread} from './MoneyReportTransactionThreadContext';
2622
import MoneyRequestReportNavigation from './MoneyRequestReportView/MoneyRequestReportNavigation';
2723

2824
type MoneyReportHeaderMoreContentProps = {
@@ -76,29 +72,13 @@ type MoneyReportHeaderMoreContentBodyProps = {
7672

7773
function MoneyReportHeaderMoreContentBody({moneyRequestReport, statusBarType, isReportInSearch, shouldShowNextStep}: MoneyReportHeaderMoreContentBodyProps) {
7874
const styles = useThemeStyles();
79-
const {isOffline} = useNetwork();
8075
const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout();
8176
const shouldDisplayNarrowVersion = shouldUseNarrowLayout || isMediumScreenWidth;
8277
const {isWideRHPDisplayedOnWideLayout, isSuperWideRHPDisplayedOnWideLayout} = useResponsiveLayoutOnWideRHP();
8378
const shouldDisplayNarrowMoreButton = !shouldDisplayNarrowVersion || isWideRHPDisplayedOnWideLayout || isSuperWideRHPDisplayedOnWideLayout;
8479

8580
const reportID = moneyRequestReport?.reportID;
86-
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID}`);
87-
88-
const {reportActions: unfilteredReportActions} = usePaginatedReportActions(reportID);
89-
const reportActions = getFilteredReportActionsForReportView(unfilteredReportActions);
90-
91-
const allReportTransactions = useReportTransactionsCollection(reportID);
92-
const nonDeletedTransactions = getAllNonDeletedTransactions(allReportTransactions, reportActions, isOffline, true);
93-
const visibleTransactionsForThreadID = nonDeletedTransactions?.filter((t) => isOffline || t.pendingAction !== 'delete');
94-
const reportTransactionIDs = visibleTransactionsForThreadID?.map((t) => t.transactionID);
95-
const transactionThreadReportID = getOneTransactionThreadReportID(moneyRequestReport, chatReport, reportActions ?? [], isOffline, reportTransactionIDs);
96-
const [transactionThreadReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`);
97-
98-
const requestParentReportAction =
99-
reportActions && transactionThreadReport?.parentReportActionID ? reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID) : null;
100-
101-
const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined;
81+
const {iouTransactionID} = useMoneyReportTransactionThread();
10282

10383
return (
10484
<View style={[styles.flexRow, styles.gap2, styles.justifyContentStart, styles.flexNoWrap, styles.ph5, styles.pb3]}>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React, {createContext, useContext} from 'react';
2+
import type {ReactNode} from 'react';
3+
import useOnyx from '@hooks/useOnyx';
4+
import useTransactionThreadReport from '@hooks/useTransactionThreadReport';
5+
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
6+
import {getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
7+
import type CONST from '@src/CONST';
8+
import ONYXKEYS from '@src/ONYXKEYS';
9+
import type * as OnyxTypes from '@src/types/onyx';
10+
11+
type MoneyReportTransactionThreadContextValue = {
12+
/** The transaction ID from the parent IOU report action */
13+
iouTransactionID: string | undefined;
14+
/** The parent IOU report action for the transaction thread */
15+
requestParentReportAction: OnyxTypes.ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> | null;
16+
/** The transaction thread report ID */
17+
transactionThreadReportID: string | undefined;
18+
/** Filtered report actions for the transaction thread */
19+
reportActions: OnyxTypes.ReportAction[];
20+
};
21+
22+
const defaultValue: MoneyReportTransactionThreadContextValue = {
23+
iouTransactionID: undefined,
24+
requestParentReportAction: null,
25+
transactionThreadReportID: undefined,
26+
reportActions: [],
27+
};
28+
29+
const MoneyReportTransactionThreadContext = createContext<MoneyReportTransactionThreadContextValue>(defaultValue);
30+
31+
type MoneyReportTransactionThreadProviderProps = {
32+
/** The money request report ID */
33+
reportID: string | undefined;
34+
/** The children */
35+
children: ReactNode;
36+
};
37+
38+
function MoneyReportTransactionThreadProvider({reportID, children}: MoneyReportTransactionThreadProviderProps) {
39+
const {transactionThreadReportID, transactionThreadReport, reportActions} = useTransactionThreadReport(reportID);
40+
const [reportActionsForParent] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(reportID)}`);
41+
42+
// Parent lookup uses the raw Onyx collection so Hold/Unhold still work when the parent IOU is
43+
// filtered from the report view (e.g. deleted money request) or outside the paginated window.
44+
const parentReportAction = transactionThreadReport?.parentReportActionID ? reportActionsForParent?.[transactionThreadReport.parentReportActionID] : undefined;
45+
const requestParentReportAction = isMoneyRequestAction(parentReportAction) ? parentReportAction : null;
46+
47+
const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined;
48+
49+
const value: MoneyReportTransactionThreadContextValue = {
50+
iouTransactionID,
51+
requestParentReportAction: requestParentReportAction ?? null,
52+
transactionThreadReportID,
53+
reportActions: reportActions ?? [],
54+
};
55+
56+
return <MoneyReportTransactionThreadContext.Provider value={value}>{children}</MoneyReportTransactionThreadContext.Provider>;
57+
}
58+
59+
function useMoneyReportTransactionThread() {
60+
return useContext(MoneyReportTransactionThreadContext);
61+
}
62+
63+
export default MoneyReportTransactionThreadContext;
64+
export {MoneyReportTransactionThreadProvider, useMoneyReportTransactionThread};

src/hooks/useExpenseActions.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {ValueOf} from 'type-fest';
88
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
99
import {ModalActions} from '@components/Modal/Global/ModalContext';
1010
import type {SecondaryActionEntry} from '@components/MoneyReportHeaderActions/types';
11+
import {useMoneyReportTransactionThread} from '@components/MoneyReportTransactionThreadContext';
1112
import {useSearchQueryContext, useSearchSelectionActions} from '@components/Search/SearchContext';
1213
import {duplicateReport as duplicateReportAction, duplicateExpenseTransaction as duplicateTransactionAction} from '@libs/actions/IOU/Duplicate';
1314
import {setupMergeTransactionDataAndNavigate} from '@libs/actions/MergeTransaction';
@@ -19,7 +20,7 @@ import Log from '@libs/Log';
1920
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
2021
import Navigation from '@libs/Navigation/Navigation';
2122
import {isPolicyAccessible} from '@libs/PolicyUtils';
22-
import {getIOUActionForTransactionID, getOriginalMessage, isMoneyRequestAction} from '@libs/ReportActionsUtils';
23+
import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
2324
import {
2425
canEditFieldOfMoneyRequest,
2526
canUserPerformWriteAction as canUserPerformWriteActionReportUtils,
@@ -64,7 +65,6 @@ import useReportIsArchived from './useReportIsArchived';
6465
import useTheme from './useTheme';
6566
import useThrottledButtonState from './useThrottledButtonState';
6667
import useTransactionsAndViolationsForReport from './useTransactionsAndViolationsForReport';
67-
import useTransactionThreadReport from './useTransactionThreadReport';
6868
import useTransactionViolations from './useTransactionViolations';
6969

7070
type UseExpenseActionsParams = {
@@ -99,7 +99,7 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic
9999
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getNonEmptyStringOnyxID(moneyRequestReport?.policyID)}`);
100100
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(moneyRequestReport?.chatReportID)}`);
101101

102-
const {transactionThreadReportID, transactionThreadReport, reportActions} = useTransactionThreadReport(reportID);
102+
const {iouTransactionID, requestParentReportAction, transactionThreadReportID, reportActions} = useMoneyReportTransactionThread();
103103

104104
const {transactions: reportTransactions} = useTransactionsAndViolationsForReport(moneyRequestReport?.reportID);
105105

@@ -113,11 +113,6 @@ function useExpenseActions({reportID, isReportInSearch = false, backTo, onDuplic
113113
}
114114

115115
const currentTransaction = transactions.at(0);
116-
const requestParentReportAction =
117-
reportActions?.find((action): action is OnyxTypes.ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => action.reportActionID === transactionThreadReport?.parentReportActionID) ??
118-
null;
119-
120-
const iouTransactionID = isMoneyRequestAction(requestParentReportAction) ? getOriginalMessage(requestParentReportAction)?.IOUTransactionID : undefined;
121116
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(iouTransactionID)}`);
122117
const [originalTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transaction?.comment?.originalTransactionID)}`);
123118
const {iouReport, chatReport: chatIOUReport, isChatIOUReportArchived} = useGetIOUReportFromReportAction(requestParentReportAction);

0 commit comments

Comments
 (0)