From f6886c81e2af484f4f5600ab7caf7986b2565f87 Mon Sep 17 00:00:00 2001 From: Test Date: Tue, 9 Jun 2026 13:28:00 +0200 Subject: [PATCH 1/2] refactor: move footer mode flags into ConfirmationFieldsContext --- .../Provider.tsx | 35 +++++++++++++++++++ .../MoneyRequestConfirmationFields/context.ts | 9 +++++ .../MoneyRequestConfirmationListFooter.tsx | 20 +++++------ .../ConfirmationFieldList.tsx | 24 ++++--------- .../fieldGroups/SettingsFields.tsx | 7 ++-- .../fieldGroups/TransactionDetailsFields.tsx | 27 +++++++++----- .../sections/DistanceMapSection.tsx | 22 ++++-------- .../sections/PerDiemSection.tsx | 11 +++--- .../sections/ReceiptSection.tsx | 18 +--------- 9 files changed, 90 insertions(+), 83 deletions(-) diff --git a/src/components/MoneyRequestConfirmationFields/Provider.tsx b/src/components/MoneyRequestConfirmationFields/Provider.tsx index b6955067f613..e023dda0ce57 100644 --- a/src/components/MoneyRequestConfirmationFields/Provider.tsx +++ b/src/components/MoneyRequestConfirmationFields/Provider.tsx @@ -38,6 +38,27 @@ type ProviderProps = { /** Whether the surface is in a policy-expense chat */ isPolicyExpenseChat?: boolean; + /** Whether the active transaction is a distance request */ + isDistanceRequest?: boolean; + + /** Whether the active transaction is a per-diem request */ + isPerDiemRequest?: boolean; + + /** Whether the active transaction is a time request */ + isTimeRequest?: boolean; + + /** Whether the surface is confirming an invoice */ + isTypeInvoice?: boolean; + + /** Whether the active transaction is a manual distance request */ + isManualDistanceRequest?: boolean; + + /** Whether the active transaction is an odometer-driven distance request */ + isOdometerDistanceRequest?: boolean; + + /** Whether the active transaction is a GPS distance request */ + isGPSDistanceRequest?: boolean; + /** Block components rendered inside the Provider */ children: ReactNode; }; @@ -54,6 +75,13 @@ function Provider({ isEditingSplitBill = false, isNewManualExpenseFlowEnabled = false, isPolicyExpenseChat = false, + isDistanceRequest = false, + isPerDiemRequest = false, + isTimeRequest = false, + isTypeInvoice = false, + isManualDistanceRequest = false, + isOdometerDistanceRequest = false, + isGPSDistanceRequest = false, children, }: ProviderProps) { const value = { @@ -68,6 +96,13 @@ function Provider({ isEditingSplitBill, isNewManualExpenseFlowEnabled, isPolicyExpenseChat, + isDistanceRequest, + isPerDiemRequest, + isTimeRequest, + isTypeInvoice, + isManualDistanceRequest, + isOdometerDistanceRequest, + isGPSDistanceRequest, }; return {children}; } diff --git a/src/components/MoneyRequestConfirmationFields/context.ts b/src/components/MoneyRequestConfirmationFields/context.ts index d8af3e8d262f..2ece24c6f7a5 100644 --- a/src/components/MoneyRequestConfirmationFields/context.ts +++ b/src/components/MoneyRequestConfirmationFields/context.ts @@ -22,6 +22,15 @@ type ConfirmationFieldsContextValue = { isEditingSplitBill: boolean; isNewManualExpenseFlowEnabled: boolean; isPolicyExpenseChat: boolean; + + // Mode — *what kind* of expense is being confirmed + isDistanceRequest: boolean; + isPerDiemRequest: boolean; + isTimeRequest: boolean; + isTypeInvoice: boolean; + isManualDistanceRequest: boolean; + isOdometerDistanceRequest: boolean; + isGPSDistanceRequest: boolean; }; const ConfirmationFieldsContext = createContext(null); diff --git a/src/components/MoneyRequestConfirmationListFooter.tsx b/src/components/MoneyRequestConfirmationListFooter.tsx index dd74469f0333..792156c73f50 100644 --- a/src/components/MoneyRequestConfirmationListFooter.tsx +++ b/src/components/MoneyRequestConfirmationListFooter.tsx @@ -160,17 +160,19 @@ function MoneyRequestConfirmationListFooter({ isEditingSplitBill={isEditingSplitBill} isNewManualExpenseFlowEnabled={isNewManualExpenseFlowEnabled} isPolicyExpenseChat={isPolicyExpenseChat} + isDistanceRequest={expenseMode.isDistance} + isPerDiemRequest={expenseMode.isPerDiem} + isTimeRequest={expenseMode.isTime} + isTypeInvoice={expenseMode.isInvoice} + isManualDistanceRequest={distanceFlags.isManualDistanceRequest} + isOdometerDistanceRequest={distanceFlags.isOdometerDistanceRequest} + isGPSDistanceRequest={distanceFlags.isGPSDistanceRequest} > - + ; - /** Distance-mode discriminators (manual / odometer / GPS) */ - distanceFlags: DistanceFlags; - /** Pre-formatted amount values consumed by Amount/Attendee fields */ amountDisplay: AmountDisplay; @@ -55,7 +52,6 @@ type TransactionDetailsFieldsProps = { function TransactionDetailsFields({ policy, - distanceFlags, amountDisplay, distanceData, requiredFlags, @@ -68,7 +64,20 @@ function TransactionDetailsFields({ onSubmitForm, isParticipantPickerVisible, }: TransactionDetailsFieldsProps) { - const {action, iouType, transactionID, reportID, reportActionID, isReadOnly, didConfirm, isNewManualExpenseFlowEnabled, isPolicyExpenseChat} = useConfirmationFields(); + const { + action, + iouType, + transactionID, + reportID, + reportActionID, + isReadOnly, + didConfirm, + isNewManualExpenseFlowEnabled, + isPolicyExpenseChat, + isManualDistanceRequest, + isOdometerDistanceRequest, + isGPSDistanceRequest, + } = useConfirmationFields(); const shouldAutoFocusAmountField = !canUseTouchScreen(); return ( @@ -135,9 +144,9 @@ function TransactionDetailsFields({ distance={distanceData.distance} unit={distanceData.unit} rate={distanceData.rate} - isManualDistanceRequest={distanceFlags.isManualDistanceRequest} - isOdometerDistanceRequest={distanceFlags.isOdometerDistanceRequest} - isGPSDistanceRequest={distanceFlags.isGPSDistanceRequest} + isManualDistanceRequest={isManualDistanceRequest} + isOdometerDistanceRequest={isOdometerDistanceRequest} + isGPSDistanceRequest={isGPSDistanceRequest} isReadOnly={isReadOnly} didConfirm={didConfirm} transactionID={transactionID} diff --git a/src/components/MoneyRequestConfirmationListFooter/sections/DistanceMapSection.tsx b/src/components/MoneyRequestConfirmationListFooter/sections/DistanceMapSection.tsx index 8f1858fee2f0..05b5d187f40b 100644 --- a/src/components/MoneyRequestConfirmationListFooter/sections/DistanceMapSection.tsx +++ b/src/components/MoneyRequestConfirmationListFooter/sections/DistanceMapSection.tsx @@ -8,24 +8,14 @@ import shouldShowDistanceMap from '@components/MoneyRequestConfirmationListFoote import useThemeStyles from '@hooks/useThemeStyles'; import type {Transaction} from '@src/types/onyx'; -type DistanceMapSectionProps = { - /** Whether the active transaction is a distance request (gate for showing the map) */ - isDistanceRequest: boolean; - - /** Whether the active transaction is a manual distance request (suppresses the map) */ - isManualDistanceRequest: boolean; - - /** Whether the active transaction is an odometer-driven distance request (suppresses the map) */ - isOdometerDistanceRequest: boolean; -}; - /** - * Two-level guard: the outer component uses the prop-only portion of `shouldShowDistanceMap`'s - * gate (no transaction reads) to short-circuit on every non-distance / manual / odometer flow. - * The inner component is the only place that subscribes to the transaction slice, so flows where - * the map can never render avoid the extra Onyx subscriptions. + * Two-level guard: the outer component uses the context-level discriminators (no transaction reads) + * to short-circuit on every non-distance / manual / odometer flow. The inner component is the only + * place that subscribes to the transaction slice, so flows where the map can never render avoid the + * extra Onyx subscriptions. */ -function DistanceMapSection({isDistanceRequest, isManualDistanceRequest, isOdometerDistanceRequest}: DistanceMapSectionProps) { +function DistanceMapSection() { + const {isDistanceRequest, isManualDistanceRequest, isOdometerDistanceRequest} = useConfirmationFields(); if (!isDistanceRequest || isManualDistanceRequest || isOdometerDistanceRequest) { return null; } diff --git a/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx b/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx index d48bbf3da51d..b662fa82b919 100644 --- a/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx +++ b/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx @@ -9,9 +9,6 @@ import CONST from '@src/CONST'; import type * as OnyxTypes from '@src/types/onyx'; type PerDiemSectionProps = { - /** Whether the active transaction is a per-diem request (gate for rendering this section) */ - isPerDiemRequest: boolean; - /** Active policy (used to resolve the per-diem custom unit) */ policy: OnyxEntry; @@ -22,15 +19,15 @@ type PerDiemSectionProps = { formError: string; }; -type PerDiemSectionContentProps = Omit; +type PerDiemSectionContentProps = PerDiemSectionProps; /** - * Two-level guard: the outer component checks the prop-level gate (`isPerDiemRequest` + action) + * Two-level guard: the outer component checks the context-level gate (`isPerDiemRequest` + action) * without subscribing to anything. The inner component is the only place that subscribes to the * transaction slice, so non-per-diem flows avoid the extra Onyx subscriptions. */ -function PerDiemSection({isPerDiemRequest, policy, shouldDisplayFieldError, formError}: PerDiemSectionProps) { - const {action} = useConfirmationFields(); +function PerDiemSection({policy, shouldDisplayFieldError, formError}: PerDiemSectionProps) { + const {action, isPerDiemRequest} = useConfirmationFields(); if (!isPerDiemRequest || action === CONST.IOU.ACTION.SUBMIT) { return null; } diff --git a/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx b/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx index 23b0c893149b..f9cfb6769e59 100644 --- a/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx +++ b/src/components/MoneyRequestConfirmationListFooter/sections/ReceiptSection.tsx @@ -22,18 +22,6 @@ type ReceiptSectionProps = { /** Active policy (used to decide whether the receipt empty state should render) */ policy: OnyxEntry; - /** Whether the active transaction is a per-diem request */ - isPerDiemRequest: boolean; - - /** Whether the active transaction is a distance request (suppresses receipt area unless manual/odometer) */ - isDistanceRequest: boolean; - - /** Whether the active transaction is a manual distance request */ - isManualDistanceRequest: boolean; - - /** Whether the active transaction is an odometer-driven distance request */ - isOdometerDistanceRequest: boolean; - /** Whether the receipt can be replaced */ isReceiptEditable: boolean; @@ -61,10 +49,6 @@ type ReceiptSectionProps = { function ReceiptSection({ policy, - isPerDiemRequest, - isDistanceRequest, - isManualDistanceRequest, - isOdometerDistanceRequest, isReceiptEditable, shouldDisplayReceipt, isLoadingReceipt, @@ -77,7 +61,7 @@ function ReceiptSection({ const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); const isInLandscapeMode = useIsInLandscapeMode(); - const {action, iouType, transactionID, reportID, isReadOnly} = useConfirmationFields(); + const {action, iouType, transactionID, reportID, isReadOnly, isPerDiemRequest, isDistanceRequest, isManualDistanceRequest, isOdometerDistanceRequest} = useConfirmationFields(); const transaction = useTransactionSelector(transactionID, receiptSliceSelector); const receiptSource = useReceiptThumbnailSource({transaction, receiptPath, receiptFilename}); From 30181491f8bf0e044ec33851554156ce42e5c5fd Mon Sep 17 00:00:00 2001 From: Test Date: Thu, 11 Jun 2026 11:14:42 +0200 Subject: [PATCH 2/2] drop redundant alias --- .../sections/PerDiemSection.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx b/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx index b662fa82b919..d29ca31f60c3 100644 --- a/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx +++ b/src/components/MoneyRequestConfirmationListFooter/sections/PerDiemSection.tsx @@ -19,8 +19,6 @@ type PerDiemSectionProps = { formError: string; }; -type PerDiemSectionContentProps = PerDiemSectionProps; - /** * Two-level guard: the outer component checks the context-level gate (`isPerDiemRequest` + action) * without subscribing to anything. The inner component is the only place that subscribes to the @@ -40,7 +38,7 @@ function PerDiemSection({policy, shouldDisplayFieldError, formError}: PerDiemSec ); } -function PerDiemSectionContent({policy, shouldDisplayFieldError, formError}: PerDiemSectionContentProps) { +function PerDiemSectionContent({policy, shouldDisplayFieldError, formError}: PerDiemSectionProps) { const {action, iouType, transactionID, reportID, isReadOnly, didConfirm} = useConfirmationFields(); const transaction = useTransactionSelector(transactionID, perDiemSliceSelector);