diff --git a/src/components/AnimatedSubmitButton/index.tsx b/src/components/AnimatedSubmitButton/index.tsx
index 945d5333fc9b9..5e1d0e14363a2 100644
--- a/src/components/AnimatedSubmitButton/index.tsx
+++ b/src/components/AnimatedSubmitButton/index.tsx
@@ -1,3 +1,4 @@
+import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import type {View} from 'react-native';
import Animated, {Keyframe, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
@@ -5,9 +6,12 @@ import {scheduleOnRN} from 'react-native-worklets';
import Button from '@components/Button';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
+import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
+import {isSubmitAndClose} from '@libs/PolicyUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import type WithSentryLabel from '@src/types/utils/SentryLabel';
type AnimatedSubmitButtonProps = WithSentryLabel & {
@@ -28,11 +32,16 @@ type AnimatedSubmitButtonProps = WithSentryLabel & {
// Whether the button should be disabled
isDisabled?: boolean;
+
+ // The policy ID for the report, used to check approval mode
+ policyID?: string;
};
-function AnimatedSubmitButton({success, text, onPress, isSubmittingAnimationRunning, onAnimationFinish, isDisabled, sentryLabel}: AnimatedSubmitButtonProps) {
+function AnimatedSubmitButton({success, text, onPress, isSubmittingAnimationRunning, onAnimationFinish, isDisabled, sentryLabel, policyID}: AnimatedSubmitButtonProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
+ const [animationPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
const isAnimationRunning = isSubmittingAnimationRunning;
const buttonDuration = isSubmittingAnimationRunning ? CONST.ANIMATION_SUBMIT_DURATION : CONST.ANIMATION_SUBMITTED_DURATION;
const gap = styles.expenseAndReportPreviewTextButtonContainer.gap;
@@ -120,7 +129,7 @@ function AnimatedSubmitButton({success, text, onPress, isSubmittingAnimationRunn
>
);
}
diff --git a/src/components/LHNOptionsList/types.ts b/src/components/LHNOptionsList/types.ts
index abed19c3267ce..ae7c7514c4a17 100644
--- a/src/components/LHNOptionsList/types.ts
+++ b/src/components/LHNOptionsList/types.ts
@@ -153,6 +153,9 @@ type OptionRowLHNProps = {
/** The concierge report ID from Onyx */
conciergeReportID: OnyxEntry;
+
+ /** Whether the report's policy has approvals disabled (submit and close) */
+ isApprovalDisabledForReport?: boolean;
};
type RenderItemProps = {item: Report; index: number};
diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index 592b92a82d2cd..bd69324e2edcd 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -1,7 +1,7 @@
import {useRoute} from '@react-navigation/native';
import {isUserValidatedSelector} from '@selectors/Account';
import {shouldFailAllRequestsSelector} from '@selectors/Network';
-import {hasSeenTourSelector} from '@selectors/Onboarding';
+import {hasSeenTourSelector, isTrackIntentUserSelector} from '@selectors/Onboarding';
import passthroughPolicyTagListSelector from '@selectors/PolicyTagList';
import {validTransactionDraftsSelector} from '@selectors/TransactionDraft';
import truncate from 'lodash/truncate';
@@ -70,7 +70,7 @@ import {
} from '@libs/NextStepUtils';
import type {KYCFlowEvent, TriggerKYCFlow} from '@libs/PaymentUtils';
import {handleUnvalidatedAccount, selectPaymentType} from '@libs/PaymentUtils';
-import {getConnectedIntegration, getValidConnectedIntegration, hasDynamicExternalWorkflow, isPolicyAccessible, sortPoliciesByName} from '@libs/PolicyUtils';
+import {getConnectedIntegration, getValidConnectedIntegration, hasDynamicExternalWorkflow, isPolicyAccessible, isSubmitAndClose, sortPoliciesByName} from '@libs/PolicyUtils';
import {
getFilteredReportActionsForReportView,
getIOUActionForTransactionID,
@@ -366,6 +366,10 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
const [downloadErrorModalVisible, setDownloadErrorModalVisible] = useState(false);
const [isPDFModalVisible, setIsPDFModalVisible] = useState(false);
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
+ const shouldUseMarkAsDoneCopy = isTrackIntentUser && isSubmitAndClose(policy);
+ const submitButtonText = shouldUseMarkAsDoneCopy ? translate('common.markAsDone') : translate('common.submit');
+ const approveButtonText = shouldUseMarkAsDoneCopy ? translate('common.markAsDone') : translate('iou.approve');
const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID);
const currentTransaction = transactions.at(0);
const [originalIOUTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(currentTransaction?.comment?.originalTransactionID)}`);
@@ -1340,7 +1344,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
const actions: Array & Pick> = [];
if (hasSubmitAction && !shouldBlockSubmit) {
actions.push({
- text: translate('common.submit'),
+ text: submitButtonText,
icon: expensifyIcons.Send,
value: CONST.REPORT.PRIMARY_ACTIONS.SUBMIT,
onSelected: () => handleSubmitReport(true),
@@ -1348,7 +1352,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
}
if (hasApproveAction && !isBlockSubmitDueToPreventSelfApproval) {
actions.push({
- text: translate('iou.approve'),
+ text: approveButtonText,
icon: expensifyIcons.ThumbsUp,
value: CONST.REPORT.PRIMARY_ACTIONS.APPROVE,
onSelected: () => {
@@ -1397,6 +1401,8 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
expensifyIcons.Send,
expensifyIcons.ThumbsUp,
kycWallRef,
+ approveButtonText,
+ submitButtonText,
]);
const connectedIntegrationName = connectedIntegration
@@ -1472,7 +1478,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
},
[CONST.REPORT.SECONDARY_ACTIONS.SUBMIT]: {
value: CONST.REPORT.SECONDARY_ACTIONS.SUBMIT,
- text: translate('common.submit'),
+ text: submitButtonText,
icon: expensifyIcons.Send,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.SUBMIT,
onSelected: () => {
@@ -1497,7 +1503,7 @@ function MoneyReportHeader({reportID: reportIDProp, shouldDisplayBackButton = fa
},
},
[CONST.REPORT.SECONDARY_ACTIONS.APPROVE]: {
- text: translate('iou.approve'),
+ text: approveButtonText,
icon: expensifyIcons.ThumbsUp,
value: CONST.REPORT.SECONDARY_ACTIONS.APPROVE,
sentryLabel: CONST.SENTRY_LABEL.MORE_MENU.APPROVE,
diff --git a/src/components/MoneyReportHeaderPrimaryAction/ApprovePrimaryAction.tsx b/src/components/MoneyReportHeaderPrimaryAction/ApprovePrimaryAction.tsx
index bda557fcb9bbc..fb0c7cf43352a 100644
--- a/src/components/MoneyReportHeaderPrimaryAction/ApprovePrimaryAction.tsx
+++ b/src/components/MoneyReportHeaderPrimaryAction/ApprovePrimaryAction.tsx
@@ -1,8 +1,10 @@
+import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React from 'react';
import Button from '@components/Button';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
+import {isSubmitAndClose} from '@libs/PolicyUtils';
import {getNextApproverAccountID, isReportOwner} from '@libs/ReportUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
@@ -19,7 +21,9 @@ function ApprovePrimaryAction({reportID, startApprovedAnimation, onHoldMenuOpen}
const [moneyRequestReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${getNonEmptyStringOnyxID(moneyRequestReport?.policyID)}`);
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
+ const shouldUseMarkAsDoneCopy = isTrackIntentUser && isSubmitAndClose(policy);
const nextApproverAccountID = getNextApproverAccountID(moneyRequestReport);
const isSubmitterSameAsNextApprover =
isReportOwner(moneyRequestReport) && (nextApproverAccountID === moneyRequestReport?.ownerAccountID || moneyRequestReport?.managerID === moneyRequestReport?.ownerAccountID);
@@ -31,7 +35,7 @@ function ApprovePrimaryAction({reportID, startApprovedAnimation, onHoldMenuOpen}
);
diff --git a/src/components/MoneyReportHeaderPrimaryAction/SubmitPrimaryAction.tsx b/src/components/MoneyReportHeaderPrimaryAction/SubmitPrimaryAction.tsx
index 6709240afffce..f154c73f70957 100644
--- a/src/components/MoneyReportHeaderPrimaryAction/SubmitPrimaryAction.tsx
+++ b/src/components/MoneyReportHeaderPrimaryAction/SubmitPrimaryAction.tsx
@@ -1,3 +1,4 @@
+import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React from 'react';
import AnimatedSubmitButton from '@components/AnimatedSubmitButton';
import {useSearchStateContext} from '@components/Search/SearchContext';
@@ -13,6 +14,7 @@ import useStrictPolicyRules from '@hooks/useStrictPolicyRules';
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
import {search} from '@libs/actions/Search';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
+import {isSubmitAndClose} from '@libs/PolicyUtils';
import {getFilteredReportActionsForReportView} from '@libs/ReportActionsUtils';
import {getNextApproverAccountID, hasViolations as hasViolationsReportUtils, isReportOwner, shouldBlockSubmitDueToStrictPolicyRules} from '@libs/ReportUtils';
import {hasAnyPendingRTERViolation as hasAnyPendingRTERViolationTransactionUtils} from '@libs/TransactionUtils';
@@ -42,6 +44,7 @@ function SubmitPrimaryAction({reportID, isSubmittingAnimationRunning, stopAnimat
const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED);
const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
const [allTransactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
const isASAPSubmitBetaEnabled = isBetaEnabled(CONST.BETAS.ASAP_SUBMIT);
const {reportActions: unfilteredReportActions} = usePaginatedReportActions(moneyRequestReport?.reportID);
@@ -69,6 +72,7 @@ function SubmitPrimaryAction({reportID, isSubmittingAnimationRunning, stopAnimat
transactions,
);
const shouldBlockSubmit = isBlockSubmitDueToStrictPolicyRules || isBlockSubmitDueToPreventSelfApproval;
+ const shouldUseMarkAsDoneCopy = isTrackIntentUser && isSubmitAndClose(policy);
const {currentSearchQueryJSON, currentSearchKey, currentSearchResults} = useSearchStateContext();
const shouldCalculateTotals = useSearchShouldCalculateTotals(currentSearchKey, currentSearchQueryJSON?.hash, true);
@@ -107,7 +111,7 @@ function SubmitPrimaryAction({reportID, isSubmittingAnimationRunning, stopAnimat
return (
isOffline || t.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
@@ -64,7 +67,7 @@ function SubmitActionButton({iouReportID, chatReportID, isSubmittingAnimationRun
return (
{
confirmPendingRTERAndProceed(() => {
submitReport({
@@ -85,6 +88,7 @@ function SubmitActionButton({iouReportID, chatReportID, isSubmittingAnimationRun
isSubmittingAnimationRunning={isSubmittingAnimationRunning}
onAnimationFinish={stopAnimation}
sentryLabel={CONST.SENTRY_LABEL.REPORT_PREVIEW.SUBMIT_BUTTON}
+ policyID={iouReport?.policyID}
/>
);
}
diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx
index 1ddcf6fb7662e..384b5dd91b1fc 100644
--- a/src/components/ReportWelcomeText.tsx
+++ b/src/components/ReportWelcomeText.tsx
@@ -1,3 +1,4 @@
+import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
@@ -54,6 +55,7 @@ function ReportWelcomeText({report, policy}: ReportWelcomeTextProps) {
const [invoiceReceiverPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`);
const isReportArchived = useReportIsArchived(report?.reportID);
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
const isConciergeChat = isConciergeChatReport(report, conciergeReportID);
const isChatRoom = isChatRoomReportUtils(report);
const isSelfDM = isSelfDMReportUtils(report);
@@ -124,6 +126,7 @@ function ReportWelcomeText({report, policy}: ReportWelcomeTextProps) {
reportDetailsLink,
shouldShowUsePlusButtonText,
additionalText,
+ isTrackIntentUser: !!isTrackIntentUser,
});
return (
diff --git a/src/components/Search/SearchList/ListItem/ActionCell/index.tsx b/src/components/Search/SearchList/ListItem/ActionCell/index.tsx
index 1ab70eeac6ea1..ad76a75aaa7da 100644
--- a/src/components/Search/SearchList/ListItem/ActionCell/index.tsx
+++ b/src/components/Search/SearchList/ListItem/ActionCell/index.tsx
@@ -1,9 +1,13 @@
+import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React from 'react';
import Button from '@components/Button';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
+import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
+import {isSubmitAndClose} from '@libs/PolicyUtils';
import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
import actionTranslationsMap from './actionTranslationsMap';
import PayActionCell from './PayActionCell';
@@ -38,6 +42,8 @@ function ActionCell({
const {translate} = useLocalize();
const styles = useThemeStyles();
const {isOffline} = useNetwork();
+ const [isTrackIntentUser] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED, {selector: isTrackIntentUserSelector});
+ const [actionCellPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
const shouldUseViewAction = action === CONST.SEARCH.ACTION_TYPES.VIEW || action === CONST.SEARCH.ACTION_TYPES.PAID || action === CONST.SEARCH.ACTION_TYPES.DONE;
@@ -78,7 +84,8 @@ function ActionCell({
);
}
- const text = translate(actionTranslationsMap[action]);
+ const shouldUseMarkAsDone = isTrackIntentUser && isSubmitAndClose(actionCellPolicy) && action === CONST.SEARCH.ACTION_TYPES.SUBMIT;
+ const text = shouldUseMarkAsDone ? translate('common.done') : translate(actionTranslationsMap[action]);
return (