From ba04c097ceda788585784b4d901eb81bdbfda441 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 12 May 2026 10:27:04 +0200 Subject: [PATCH 1/2] perf: narrow Onyx subs in InvoiceSenderField and ReportField --- .../sections/InvoiceSenderField.tsx | 35 +++++++++++-------- .../sections/ReportField.tsx | 17 +++++---- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx b/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx index e5603cdea9c8..ac6ecb4ef590 100644 --- a/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx +++ b/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx @@ -1,6 +1,6 @@ import {emailSelector} from '@selectors/Session'; import React from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import MenuItem from '@components/MenuItem'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -35,37 +35,42 @@ type InvoiceSenderFieldProps = { transaction: OnyxEntry; }; +const senderWorkspaceSelector = (policy: OnyxEntry) => (policy ? {id: policy.id, name: policy.name, avatarURL: policy.avatarURL} : undefined); + +const createCanUpdateSenderWorkspaceSelector = + (selectedParticipants: Participant[], currentUserLogin: string | undefined, isFromGlobalCreate: boolean) => + (policies: OnyxCollection): boolean => { + const isInvoiceRoomParticipant = selectedParticipants.some((participant) => participant.isInvoiceRoom); + return canSendInvoice(policies ?? null, currentUserLogin) && isFromGlobalCreate && !isInvoiceRoomParticipant; + }; + function InvoiceSenderField({selectedParticipants, isReadOnly, didConfirm, iouType, reportID, transaction}: InvoiceSenderFieldProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - // canSendInvoice needs the full policy collection to check all admin workspaces - const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + const senderPolicyID = selectedParticipants.find((participant) => participant.isSender)?.policyID; + + const [senderWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${senderPolicyID}`, {selector: senderWorkspaceSelector}); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); const isFromGlobalCreate = !!transaction?.isFromGlobalCreate; - const senderWorkspace = (() => { - const senderWorkspaceParticipant = selectedParticipants.find((participant) => participant.isSender); - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderWorkspaceParticipant?.policyID}`]; - })(); - - const canUpdateSenderWorkspace = (() => { - const isInvoiceRoomParticipant = selectedParticipants.some((participant) => participant.isInvoiceRoom); - return canSendInvoice(allPolicies, currentUserLogin) && isFromGlobalCreate && !isInvoiceRoomParticipant; - })(); + // canSendInvoice needs the full policy collection to check all admin workspaces + const [canUpdateSenderWorkspace] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { + selector: createCanUpdateSenderWorkspaceSelector(selectedParticipants, currentUserLogin, isFromGlobalCreate), + }); return ( { if (!transaction?.transactionID) { return; diff --git a/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx b/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx index c6756d307077..5985363fc005 100644 --- a/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx +++ b/src/components/MoneyRequestConfirmationList/sections/ReportField.tsx @@ -16,6 +16,9 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; +const createOutstandingReportsForPolicySelector = (policyID: string | undefined) => (derived: OnyxEntry) => + derived?.[policyID ?? CONST.DEFAULT_NUMBER_ID]; + type ReportFieldProps = { /** The selected participants */ selectedParticipants: Participant[]; @@ -50,8 +53,9 @@ function ReportField({selectedParticipants, iouType, reportID, reportActionID, a const {translate, localeCompare} = useLocalize(); const reportAttributes = useReportAttributes(); + const policyID = selectedParticipants?.at(0)?.policyID; const [reportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS); - const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID); + const [outstandingReportsForPolicy] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, {selector: createOutstandingReportsForPolicySelector(policyID)}); // Per-key report subscriptions instead of full COLLECTION.REPORT const [transactionReportEntry] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`); @@ -66,18 +70,13 @@ function ReportField({selectedParticipants, iouType, reportID, reportActionID, a * We need to check if the transaction report exists first in order to prevent the outstanding reports from being used. * Also we need to check if transaction report exists in outstanding reports in order to show a correct report name. */ - const policyID = selectedParticipants?.at(0)?.policyID; const shouldUseTransactionReport = (!!transactionReportEntry && isReportOutstanding(transactionReportEntry, policyID, undefined, false)) || isUnreported; const ownerAccountID = selectedParticipants?.at(0)?.ownerAccountID; - const availableOutstandingReports = getOutstandingReportsForUser( - policyID, - ownerAccountID, - outstandingReportsByPolicyID?.[policyID ?? CONST.DEFAULT_NUMBER_ID] ?? {}, - reportNameValuePairs, - false, - ).sort((a, b) => localeCompare(a?.reportName?.toLowerCase() ?? '', b?.reportName?.toLowerCase() ?? '')); + const availableOutstandingReports = getOutstandingReportsForUser(policyID, ownerAccountID, outstandingReportsForPolicy ?? {}, reportNameValuePairs, false).sort((a, b) => + localeCompare(a?.reportName?.toLowerCase() ?? '', b?.reportName?.toLowerCase() ?? ''), + ); const outstandingReportID = isPolicyExpenseChat ? (iouReportIDFromMain ?? availableOutstandingReports.at(0)?.reportID) : reportID; From 19f93d1d57f9540ad92751b44c007cc6a6f3a3a1 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 12 May 2026 13:58:17 +0200 Subject: [PATCH 2/2] fix: pass selector dependencies to useOnyx --- .../sections/InvoiceSenderField.tsx | 8 +++++--- .../MoneyRequestConfirmationList/sections/ReportField.tsx | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx b/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx index ac6ecb4ef590..ee822c9ad368 100644 --- a/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx +++ b/src/components/MoneyRequestConfirmationList/sections/InvoiceSenderField.tsx @@ -56,9 +56,11 @@ function InvoiceSenderField({selectedParticipants, isReadOnly, didConfirm, iouTy const isFromGlobalCreate = !!transaction?.isFromGlobalCreate; // canSendInvoice needs the full policy collection to check all admin workspaces - const [canUpdateSenderWorkspace] = useOnyx(ONYXKEYS.COLLECTION.POLICY, { - selector: createCanUpdateSenderWorkspaceSelector(selectedParticipants, currentUserLogin, isFromGlobalCreate), - }); + const [canUpdateSenderWorkspace] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: createCanUpdateSenderWorkspaceSelector(selectedParticipants, currentUserLogin, isFromGlobalCreate)}, [ + selectedParticipants, + currentUserLogin, + isFromGlobalCreate, + ]); return (