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
1 change: 0 additions & 1 deletion src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,6 @@ const CONST = {
SUGGESTED_FOLLOWUPS: 'suggestedFollowups',
BULK_EDIT: 'bulkEdit',
BULK_EDIT_WORKSPACES: 'bulkEditWorkspaces',
NEW_MANUAL_EXPENSE_FLOW: 'newManualExpenseFlow',
SUBMIT_2026: 'submit2026',
DATE_BOUND_MILEAGE_RATE: 'dateBoundMileageRate',
BULK_SUBMIT_APPROVE_PAY: 'bulkSubmitApprovePay',
Expand Down
5 changes: 0 additions & 5 deletions src/components/MoneyRequestConfirmationFields/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ type ProviderProps = {
/** Whether we're editing an existing split expense */
isEditingSplitBill?: boolean;

/** Whether the new manual expense flow beta is enabled */
isNewManualExpenseFlowEnabled?: boolean;

/** Whether the surface is in a policy-expense chat */
isPolicyExpenseChat?: boolean;

Expand Down Expand Up @@ -73,7 +70,6 @@ function Provider({
isReadOnly = false,
didConfirm = false,
isEditingSplitBill = false,
isNewManualExpenseFlowEnabled = false,
isPolicyExpenseChat = false,
isDistanceRequest = false,
isPerDiemRequest = false,
Expand All @@ -94,7 +90,6 @@ function Provider({
isReadOnly,
didConfirm,
isEditingSplitBill,
isNewManualExpenseFlowEnabled,
isPolicyExpenseChat,
isDistanceRequest,
isPerDiemRequest,
Expand Down
1 change: 0 additions & 1 deletion src/components/MoneyRequestConfirmationFields/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ type ConfirmationFieldsContextValue = {
isReadOnly: boolean;
didConfirm: boolean;
isEditingSplitBill: boolean;
isNewManualExpenseFlowEnabled: boolean;
isPolicyExpenseChat: boolean;

// Mode — *what kind* of expense is being confirmed
Expand Down
17 changes: 2 additions & 15 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useIsInLandscapeMode from '@hooks/useIsInLandscapeMode';
import useLocalize from '@hooks/useLocalize';
import {MouseProvider} from '@hooks/useMouseContext';
import usePermissions from '@hooks/usePermissions';
import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
import usePolicyForTransaction from '@hooks/usePolicyForTransaction';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
Expand All @@ -16,7 +15,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {isCategoryDescriptionRequired} from '@libs/CategoryUtils';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import {isMovingTransactionFromTrackExpense as isMovingTransactionFromTrackExpenseUtil} from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import {hasEnabledOptions} from '@libs/OptionsListUtils';
import {isTaxTrackingEnabled} from '@libs/PolicyUtils';
import type {OptionData} from '@libs/ReportUtils';
Expand All @@ -32,7 +30,6 @@ import {
} from '@libs/TransactionUtils';
import type {IOUAction, IOUType} from '@src/CONST';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {Participant} from '@src/types/onyx/IOU';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
Expand Down Expand Up @@ -211,8 +208,6 @@ function MoneyRequestConfirmationList({
const transactionReport = useTransactionReportForConfirmation(transaction?.reportID);
const {policyForMovingExpenses, shouldSelectPolicy} = usePolicyForMovingExpenses();
const isMovingTransactionFromTrackExpense = isMovingTransactionFromTrackExpenseUtil(action);
const {isBetaEnabled} = usePermissions();
const isNewManualExpenseFlowEnabled = isBetaEnabled(CONST.BETAS.NEW_MANUAL_EXPENSE_FLOW);
const {isDelegateAccessRestricted} = useDelegateNoAccessState();
const {showDelegateNoAccessModal} = useDelegateNoAccessActions();
const isInLandscapeMode = useIsInLandscapeMode();
Expand Down Expand Up @@ -309,7 +304,7 @@ function MoneyRequestConfirmationList({
});

const isManualRequest = transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL;
const shouldForceTopEmptySections = isNewManualExpenseFlowEnabled && (iouType === CONST.IOU.TYPE.CREATE || isManualRequest || isScanRequest);
const shouldForceTopEmptySections = iouType === CONST.IOU.TYPE.CREATE || isManualRequest || isScanRequest;

const isFocused = useIsFocused();

Expand Down Expand Up @@ -372,7 +367,6 @@ function MoneyRequestConfirmationList({
receiptPath,
isDistanceRequestWithPendingRoute,
isPerDiemRequest,
isNewManualExpenseFlowEnabled,
});

const selectedParticipants = selectedParticipantsProp.filter((participant) => participant.selected);
Expand Down Expand Up @@ -429,13 +423,7 @@ function MoneyRequestConfirmationList({
return;
}

if (isNewManualExpenseFlowEnabled) {
onOpenParticipantPicker?.();
return;
}

const newIOUType = iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.TRACK ? CONST.IOU.TYPE.CREATE : iouType;
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(newIOUType, transactionID, transaction?.reportID, Navigation.getActiveRoute(), action));
onOpenParticipantPicker?.();
};

const {validate} = useConfirmationValidation({
Expand Down Expand Up @@ -465,7 +453,6 @@ function MoneyRequestConfirmationList({
isPerDiemRequest,
isTimeRequest,
routeError,
isNewManualExpenseFlowEnabled,
});

const confirm = buildConfirmAction({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,14 @@ type UseConfirmationCtaTextParams = {

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

/** Whether the new manual expense flow beta is enabled */
isNewManualExpenseFlowEnabled: boolean;
};

/**
* Computes the primary confirm button label for the Money Request confirmation flow.
*
* Picks between create / create-with-amount / split / invoice / next variants based on
* the IOU type, manual-expense-flow beta, bulk-expense count, and amount, returning a
* single-entry DropdownOption array shaped for the ButtonWithDropdownMenu consumer.
* Picks between create / split / invoice / next variants based on the IOU type and
* bulk-expense count, returning a single-entry DropdownOption array shaped for the
* ButtonWithDropdownMenu consumer.
*/
function useConfirmationCtaText({
expensesNumber,
Expand All @@ -60,13 +57,12 @@ function useConfirmationCtaText({
isTypeSplit,
isTypeRequest,
iouAmount,
iouType,
policy,
iouType,
formattedAmount,
receiptPath,
isDistanceRequestWithPendingRoute,
isPerDiemRequest,
isNewManualExpenseFlowEnabled,
}: UseConfirmationCtaTextParams): Array<DropdownOption<string>> {
const {translate} = useLocalize();

Expand All @@ -81,27 +77,14 @@ function useConfirmationCtaText({
}
} else if (isTypeTrackExpense) {
text = translate('iou.createExpense');
if (iouAmount !== 0 && !isNewManualExpenseFlowEnabled) {
text = translate('iou.createExpenseWithAmount', {amount: formattedAmount});
}
} else if (isTypeSplit && iouAmount === 0) {
text = translate('iou.splitExpense');
} else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute || isPerDiemRequest) {
text = translate('iou.createExpense');
if (iouAmount !== 0 && !isNewManualExpenseFlowEnabled) {
text = translate('iou.createExpenseWithAmount', {amount: formattedAmount});
}
} else if (isTypeSplit) {
text = translate('iou.splitAmount', formattedAmount);
if (isNewManualExpenseFlowEnabled) {
text = translate('iou.splitExpense');
}
} else if (iouAmount === 0) {
text = translate('iou.createExpense');
} else if (isNewManualExpenseFlowEnabled) {
text = translate('iou.createExpense');
text = translate('iou.splitExpense');
} else {
text = translate('iou.createExpenseWithAmount', {amount: formattedAmount});
text = translate('iou.createExpense');
}
return [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ type UseConfirmationValidationParams = {

/** Truthy when the route to the confirmation page has a known error */
routeError: string | null | undefined;

/** Whether the new manual expense flow is enabled */
isNewManualExpenseFlowEnabled: boolean;
};

/**
Expand Down Expand Up @@ -153,7 +150,6 @@ function useConfirmationValidation({
isPerDiemRequest,
isTimeRequest,
routeError,
isNewManualExpenseFlowEnabled,
}: UseConfirmationValidationParams): {validate: (paymentType?: PaymentMethodType) => ValidationResult | null} {
const {getCurrencyDecimals} = useCurrencyListActions();
const selectedParticipantsCount = selectedParticipants.length;
Expand All @@ -174,11 +170,10 @@ function useConfirmationValidation({
return {errorKey: 'common.error.invalidAmount'};
}
// isAmountSet only applies to manual expenses — scan, per diem, distance, and time set amount programmatically.
if (isNewManualExpenseFlowEnabled && transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL && !transaction?.isAmountSet) {
if (transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL && !transaction?.isAmountSet) {
return {errorKey: 'common.error.fieldRequired'};
}
if (
isNewManualExpenseFlowEnabled &&
transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL &&
transaction?.isAmountSet &&
!isScanRequestUtil(transaction) &&
Expand All @@ -189,8 +184,8 @@ function useConfirmationValidation({
) {
return {errorKey: 'common.error.invalidAmount'};
}
// The date is an inline required field in the new manual flow; block confirmation when the user cleared it.
if (isNewManualExpenseFlowEnabled && transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL && isCreatedMissing(transaction)) {
// The date is an inline required field in the manual flow; block confirmation when the user cleared it.
if (transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL && isCreatedMissing(transaction)) {
return {errorKey: 'common.error.fieldRequired'};
}
const merchantValue = iouMerchant ?? '';
Expand Down Expand Up @@ -248,10 +243,10 @@ function useConfirmationValidation({
return {errorKey: 'violations.taxOutOfPolicy'};
}

// In the new manual expense flow the tax amount is edited inline, so the standalone tax amount step's
// In the manual expense flow the tax amount is edited inline, so the standalone tax amount step's
// guard (tax amount can't exceed the tax computed from the rate and the expense amount) runs here.
// This also blocks creation when an invalid tax amount was persisted to the draft and then reloaded.
if (isNewManualExpenseFlowEnabled && shouldShowTax && !isDistanceRequest) {
if (shouldShowTax && !isDistanceRequest) {
const decimals = getCurrencyDecimals(iouCurrencyCode);
const maxTaxAmount = getCalculatedTaxAmount(policy, transaction, iouCurrencyCode, decimals);
const currentTaxAmount = convertToFrontendAmountAsString(Math.abs(getTaxAmount(transaction, false)), decimals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ type AmountFieldProps = {
distanceRateCurrency: string;
iouCurrencyCode: string | undefined;
isDistanceRequest: boolean;
isNewManualExpenseFlowEnabled: boolean;
didConfirm: boolean;
isReadOnly: boolean;
shouldShowTimeRequestFields: boolean;
Expand All @@ -58,7 +57,6 @@ function AmountField({
distanceRateCurrency,
iouCurrencyCode,
isDistanceRequest,
isNewManualExpenseFlowEnabled,
didConfirm,
isReadOnly,
shouldShowTimeRequestFields,
Expand Down Expand Up @@ -92,10 +90,7 @@ function AmountField({
const [isCurrencyPickerVisible, setIsCurrencyPickerVisible] = useState(false);

const isAmountFieldDisabled = didConfirm || isReadOnly || shouldShowTimeRequestFields || isDistanceRequest;
const firstParticipant = transactionSlice?.participants?.at(0);
const isP2P = isNewManualExpenseFlowEnabled
? isParticipantP2P(getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID).at(0))
: !!(firstParticipant?.accountID && !firstParticipant?.isPolicyExpenseChat);
const isP2P = isParticipantP2P(getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID).at(0));
// `common.error.fieldRequired` is shared with the date field, so only surface it on the amount input when the
// amount itself is the missing value.
const shouldShowAmountRequiredError = formError === 'common.error.fieldRequired' && !transactionSlice?.isAmountSet;
Expand All @@ -110,21 +105,20 @@ function AmountField({

const effectiveCurrency = isDistanceRequest ? distanceRateCurrency : (iouCurrencyCode ?? CONST.CURRENCY.USD);
const decimals = getCurrencyDecimals(effectiveCurrency);
// In the new manual expense flow the amount field starts empty (transaction.amount defaults to 0 before the user
// In the manual expense flow the amount field starts empty (transaction.amount defaults to 0 before the user
// touches it). Once the user explicitly sets an amount – including 0 – isAmountSet becomes true and we show the
// real value. This avoids showing "$0.00" as a pre-filled default. Scan and other non-manual flows populate
// amount programmatically and never set isAmountSet.
const shouldShowEmptyAmount = isNewManualExpenseFlowEnabled && !transactionSlice?.isAmountSet && transactionSlice?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL;
const shouldShowEmptyAmount = !transactionSlice?.isAmountSet && transactionSlice?.iouRequestType === CONST.IOU.REQUEST_TYPE.MANUAL;
const transactionAmount = shouldShowEmptyAmount ? '' : convertToFrontendAmountAsString(amount, decimals);
const allowNegative = shouldEnableNegative(report, policy, iouType, transactionSlice?.participants, isNewManualExpenseFlowEnabled);
const allowNegative = shouldEnableNegative(report, policy, iouType, transactionSlice?.participants);

// `autoFocus` on our TextInput only runs on mount. Closing and reopening the RHP often keeps the same mounted
// instance, so autofocus does not run again. We re-focus when the parent-owned participant picker closes
// (visible → hidden) so the amount input gains focus once the user selects a participant in the new manual
// expense flow. The setTimeout defers focus past the RHP entry / picker close animation so the input reliably
// receives focus.
// (visible → hidden) so the amount input gains focus once the user selects a participant. The setTimeout defers
// focus past the RHP entry / picker close animation so the input reliably receives focus.
useEffect(() => {
if (!autoFocus || isAmountFieldDisabled || !isNewManualExpenseFlowEnabled || isParticipantPickerVisible) {
if (!autoFocus || isAmountFieldDisabled || isParticipantPickerVisible) {
return;
}

Expand All @@ -136,7 +130,7 @@ function AmountField({
}
clearTimeout(focusTimeoutRef.current);
};
}, [autoFocus, isAmountFieldDisabled, isNewManualExpenseFlowEnabled, isParticipantPickerVisible]);
}, [autoFocus, isAmountFieldDisabled, isParticipantPickerVisible]);

const showCurrencyPicker = () => {
setIsCurrencyPickerVisible(true);
Expand Down Expand Up @@ -297,7 +291,7 @@ function AmountField({
value={effectiveCurrency}
onInputChange={updateCurrency}
/>
{isNewManualExpenseFlowEnabled && !isAmountFieldDisabled ? (
{!isAmountFieldDisabled ? (
<View style={[styles.mh4, styles.mv2]}>
<NumberWithSymbolForm
ref={amountInputRef}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type DateFieldProps = {
shouldDisplayFieldError: boolean;
didConfirm: boolean;
isReadOnly: boolean;
isNewManualExpenseFlowEnabled: boolean;
formError: string;
clearFormErrors: (errors: string[]) => void;
transactionID: string | undefined;
Expand All @@ -36,19 +35,7 @@ type DateFieldProps = {
reportActionID: string | undefined;
};

function DateField({
shouldDisplayFieldError,
didConfirm,
isReadOnly,
isNewManualExpenseFlowEnabled,
formError,
clearFormErrors,
transactionID,
action,
iouType,
reportID,
reportActionID,
}: DateFieldProps) {
function DateField({shouldDisplayFieldError, didConfirm, isReadOnly, formError, clearFormErrors, transactionID, action, iouType, reportID, reportActionID}: DateFieldProps) {
const {isEditingSplitBill} = useConfirmationFields();
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -107,7 +94,7 @@ function DateField({
}
};

if (isNewManualExpenseFlowEnabled && !isReadOnly) {
if (!isReadOnly) {
return (
<View style={[styles.mh4, styles.mb2]}>
<DatePicker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {descriptionStateSelector} from './selectors';
import useTransactionSelector from './useTransactionSelector';

type DescriptionFieldProps = {
isNewManualExpenseFlowEnabled: boolean;
isReadOnly: boolean;
didConfirm: boolean;
isDescriptionRequired: boolean;
Expand All @@ -36,19 +35,7 @@ type DescriptionFieldProps = {
onSubmitForm?: () => void;
};

function DescriptionField({
isNewManualExpenseFlowEnabled,
isReadOnly,
didConfirm,
isDescriptionRequired,
transactionID,
action,
iouType,
reportID,
reportActionID,
policy,
onSubmitForm,
}: DescriptionFieldProps) {
function DescriptionField({isReadOnly, didConfirm, isDescriptionRequired, transactionID, action, iouType, reportID, reportActionID, policy, onSubmitForm}: DescriptionFieldProps) {
const {isEditingSplitBill} = useConfirmationFields();
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -99,7 +86,7 @@ function DescriptionField({
<ShowContextMenuStateContext.Provider value={contextMenuStateValue}>
<ShowContextMenuActionsContext.Provider value={contextMenuActionsValue}>
<MentionReportContext.Provider value={mentionReportContextValue}>
{isNewManualExpenseFlowEnabled && !isReadOnly ? (
{!isReadOnly ? (
<View style={[styles.mh4, styles.mv2]}>
<TextInput
value={iouComment ?? ''}
Expand Down
Loading
Loading