Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/components/MoneyRequestConfirmationFields/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand All @@ -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 = {
Expand All @@ -68,6 +96,13 @@ function Provider({
isEditingSplitBill,
isNewManualExpenseFlowEnabled,
isPolicyExpenseChat,
isDistanceRequest,
isPerDiemRequest,
isTimeRequest,
isTypeInvoice,
isManualDistanceRequest,
isOdometerDistanceRequest,
isGPSDistanceRequest,
};
return <ConfirmationFieldsContext.Provider value={value}>{children}</ConfirmationFieldsContext.Provider>;
}
Expand Down
9 changes: 9 additions & 0 deletions src/components/MoneyRequestConfirmationFields/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConfirmationFieldsContextValue | null>(null);
Expand Down
20 changes: 8 additions & 12 deletions src/components/MoneyRequestConfirmationListFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
>
<View style={isCompactMode ? styles.flex1 : undefined}>
<View>
<InvoiceSenderSection selectedParticipants={selectedParticipants} />
<DistanceMapSection
isDistanceRequest={expenseMode.isDistance}
isManualDistanceRequest={distanceFlags.isManualDistanceRequest}
isOdometerDistanceRequest={distanceFlags.isOdometerDistanceRequest}
/>
<DistanceMapSection />
<PerDiemSection
isPerDiemRequest={expenseMode.isPerDiem}
policy={policy}
shouldDisplayFieldError={errorState.shouldDisplayFieldError}
formError={errorState.formError}
Expand All @@ -179,10 +181,6 @@ function MoneyRequestConfirmationListFooter({

<ReceiptSection
policy={policy}
isPerDiemRequest={expenseMode.isPerDiem}
isDistanceRequest={expenseMode.isDistance}
isManualDistanceRequest={distanceFlags.isManualDistanceRequest}
isOdometerDistanceRequest={distanceFlags.isOdometerDistanceRequest}
isReceiptEditable={receiptOptions.isReceiptEditable ?? false}
shouldDisplayReceipt={receiptOptions.shouldDisplayReceipt}
isLoadingReceipt={receiptOptions.isLoadingReceipt ?? false}
Expand All @@ -203,8 +201,6 @@ function MoneyRequestConfirmationListFooter({
policy={policy}
policyTags={policyTags}
selectedParticipants={selectedParticipants}
expenseMode={expenseMode}
distanceFlags={distanceFlags}
distanceData={distanceData}
amountDisplay={amountDisplay}
requiredFlags={requiredFlags}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import ClassificationFields from './fieldGroups/ClassificationFields';
import computeFieldVisibility, {hasBelowShowMore} from './fieldGroups/fieldVisibility';
import SettingsFields from './fieldGroups/SettingsFields';
import TransactionDetailsFields from './fieldGroups/TransactionDetailsFields';
import type {AmountDisplay, CompactState, DistanceData, DistanceFlags, ErrorState, ExpenseMode, RequiredFlags, ToggleHandlers, VisibilityFlags} from './fieldGroupTypes';
import type {AmountDisplay, CompactState, DistanceData, ErrorState, RequiredFlags, ToggleHandlers, VisibilityFlags} from './fieldGroupTypes';
import useFooterDerivedFlags from './hooks/useFooterDerivedFlags';
import useFooterTagVisibility from './hooks/useFooterTagVisibility';

Expand All @@ -31,12 +31,6 @@ type ConfirmationFieldListProps = {
/** Selected participants (drives ReportField presentation) */
selectedParticipants: Participant[];

/** What kind of expense the surface is confirming */
expenseMode: ExpenseMode;

/** Distance-mode discriminators (only meaningful when expenseMode.isDistance) */
distanceFlags: DistanceFlags;

/** Distance-rate metadata */
distanceData: DistanceData;

Expand Down Expand Up @@ -66,8 +60,6 @@ function ConfirmationFieldList({
policy,
policyTags,
selectedParticipants,
expenseMode,
distanceFlags,
distanceData,
amountDisplay,
requiredFlags,
Expand All @@ -81,7 +73,7 @@ function ConfirmationFieldList({
const theme = useTheme();
const {translate} = useLocalize();
const icons = useMemoizedLazyExpensifyIcons(['Sparkles', 'DownArrow']);
const {action, iouType, transactionID, isReadOnly, isPolicyExpenseChat} = useConfirmationFields();
const {action, iouType, transactionID, isReadOnly, isPolicyExpenseChat, isDistanceRequest, isPerDiemRequest, isTimeRequest, isTypeInvoice} = useConfirmationFields();
const policyTagLists = getTagLists(policyTags);

const flags = useFooterDerivedFlags({
Expand All @@ -92,10 +84,10 @@ function ConfirmationFieldList({
policyTagLists,
isPolicyExpenseChat,
isReadOnly,
isDistanceRequest: expenseMode.isDistance,
isPerDiemRequest: expenseMode.isPerDiem,
isTimeRequest: expenseMode.isTime,
isTypeInvoice: expenseMode.isInvoice,
isDistanceRequest,
isPerDiemRequest,
isTimeRequest,
isTypeInvoice,
shouldShowSmartScanFields: visibilityFlags.shouldShowSmartScanFields,
});

Expand All @@ -109,7 +101,7 @@ function ConfirmationFieldList({
const fieldVisibility = computeFieldVisibility({
shouldShowSmartScanFields: visibilityFlags.shouldShowSmartScanFields,
shouldShowAmountField: visibilityFlags.shouldShowAmountField,
isDistanceRequest: expenseMode.isDistance,
isDistanceRequest,
shouldShowMerchant: visibilityFlags.shouldShowMerchant,
shouldShowTimeRequestFields: flags.shouldShowTimeRequestFields,
shouldShowCategories: visibilityFlags.shouldShowCategories,
Expand Down Expand Up @@ -141,7 +133,6 @@ function ConfirmationFieldList({

<TransactionDetailsFields
policy={policy}
distanceFlags={distanceFlags}
amountDisplay={amountDisplay}
distanceData={distanceData}
requiredFlags={requiredFlags}
Expand Down Expand Up @@ -175,7 +166,6 @@ function ConfirmationFieldList({
selectedParticipants={selectedParticipants}
shouldShowBillable={flags.shouldShowBillable}
shouldShowReimbursable={flags.shouldShowReimbursable}
isPerDiemRequest={expenseMode.isPerDiem}
toggleHandlers={toggleHandlers}
isCompactMode={compactState.isCompactMode}
fieldVisibility={fieldVisibility}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ type SettingsFieldsProps = {
/** Whether the reimbursable toggle should be displayed */
shouldShowReimbursable: boolean;

/** Whether the active transaction is a per-diem request */
isPerDiemRequest: boolean;

/** Toggle callbacks for billable/reimbursable */
toggleHandlers: ToggleHandlers;

Expand All @@ -34,8 +31,8 @@ type SettingsFieldsProps = {
* Gating ReportField behind `isPolicyExpenseChat` keeps its 5 Onyx subscriptions
* (including `COLLECTION.REPORT_NVP`) from instantiating on non-policy-expense flows.
*/
function SettingsFields({selectedParticipants, shouldShowBillable, shouldShowReimbursable, isPerDiemRequest, toggleHandlers, isCompactMode, fieldVisibility}: SettingsFieldsProps) {
const {action, iouType, transactionID, reportID, reportActionID, isReadOnly, isPolicyExpenseChat} = useConfirmationFields();
function SettingsFields({selectedParticipants, shouldShowBillable, shouldShowReimbursable, toggleHandlers, isCompactMode, fieldVisibility}: SettingsFieldsProps) {
const {action, iouType, transactionID, reportID, reportActionID, isReadOnly, isPolicyExpenseChat, isPerDiemRequest} = useConfirmationFields();

if (isCompactMode) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import DistanceField from '@components/MoneyRequestConfirmationList/sections/Dis
import MerchantField from '@components/MoneyRequestConfirmationList/sections/MerchantField';
import RateField from '@components/MoneyRequestConfirmationList/sections/RateField';
import TimeFields from '@components/MoneyRequestConfirmationList/sections/TimeFields';
import type {AmountDisplay, DistanceData, DistanceFlags, ErrorState, RequiredFlags} from '@components/MoneyRequestConfirmationListFooter/fieldGroupTypes';
import type {AmountDisplay, DistanceData, ErrorState, RequiredFlags} from '@components/MoneyRequestConfirmationListFooter/fieldGroupTypes';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import type * as OnyxTypes from '@src/types/onyx';
import type {FieldVisibility} from './fieldVisibility';
Expand All @@ -16,9 +16,6 @@ type TransactionDetailsFieldsProps = {
/** Active policy (read by Amount/Description/Rate/Merchant) */
policy: OnyxEntry<OnyxTypes.Policy>;

/** Distance-mode discriminators (manual / odometer / GPS) */
distanceFlags: DistanceFlags;

/** Pre-formatted amount values consumed by Amount/Attendee fields */
amountDisplay: AmountDisplay;

Expand Down Expand Up @@ -55,7 +52,6 @@ type TransactionDetailsFieldsProps = {

function TransactionDetailsFields({
policy,
distanceFlags,
amountDisplay,
distanceData,
requiredFlags,
Expand All @@ -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 (
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<OnyxTypes.Policy>;

Expand All @@ -22,15 +19,13 @@ type PerDiemSectionProps = {
formError: string;
};

type PerDiemSectionContentProps = Omit<PerDiemSectionProps, 'isPerDiemRequest'>;

/**
* 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;
}
Expand All @@ -43,7 +38,7 @@ function PerDiemSection({isPerDiemRequest, policy, shouldDisplayFieldError, form
);
}

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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,6 @@ type ReceiptSectionProps = {
/** Active policy (used to decide whether the receipt empty state should render) */
policy: OnyxEntry<OnyxTypes.Policy>;

/** 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;

Expand Down Expand Up @@ -61,10 +49,6 @@ type ReceiptSectionProps = {

function ReceiptSection({
policy,
isPerDiemRequest,
isDistanceRequest,
isManualDistanceRequest,
isOdometerDistanceRequest,
isReceiptEditable,
shouldDisplayReceipt,
isLoadingReceipt,
Expand All @@ -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});
Expand Down
Loading