diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 659178870646..de139c7f9886 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -52,8 +52,8 @@ import { buildOptimisticNextStepForDEWOffline, buildOptimisticNextStepForDynamicExternalWorkflowApproveError, buildOptimisticNextStepForDynamicExternalWorkflowSubmitError, - buildOptimisticNextStepForPreventSelfApprovalsEnabled, buildOptimisticNextStepForStrictPolicyRuleViolations, + getReportNextStep, } from '@libs/NextStepUtils'; import type {KYCFlowEvent, TriggerKYCFlow} from '@libs/PaymentUtils'; import {selectPaymentType} from '@libs/PaymentUtils'; @@ -508,7 +508,7 @@ function MoneyReportHeader({ hasDuplicates || shouldShowMarkAsResolved; - let optimisticNextStep = isBlockSubmitDueToPreventSelfApproval ? buildOptimisticNextStepForPreventSelfApprovalsEnabled() : nextStep; + let optimisticNextStep = getReportNextStep(nextStep, moneyRequestReport, transactions, policy, allTransactionViolations, email ?? '', accountID); // Check for DEW submit/approve failed or pending - show appropriate next step if (isDEWPolicy && (moneyRequestReport?.statusNum === CONST.REPORT.STATUS_NUM.OPEN || moneyRequestReport?.statusNum === CONST.REPORT.STATUS_NUM.SUBMITTED)) { diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts index bd3e8188563f..bb0a71ae14c6 100644 --- a/src/libs/NextStepUtils.ts +++ b/src/libs/NextStepUtils.ts @@ -1,10 +1,10 @@ import {addMonths, format, isPast, setDate} from 'date-fns'; import {Str} from 'expensify-common'; -import type {OnyxEntry} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import CONST from '@src/CONST'; -import type {Policy, Report, ReportNextStepDeprecated} from '@src/types/onyx'; +import type {Policy, Report, ReportNextStepDeprecated, Transaction, TransactionViolations} from '@src/types/onyx'; import type {ReportNextStep} from '@src/types/onyx/Report'; import type {Message} from '@src/types/onyx/ReportNextStepDeprecated'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; @@ -20,8 +20,11 @@ import { getPersonalDetailsForAccountID, isExpenseReport, isInvoiceReport, + isOpenExpenseReport, isPayer, + isReportOwner, } from './ReportUtils'; +import {hasSubmissionBlockingViolations} from './TransactionUtils'; type BuildNextStepNewParams = { report: OnyxEntry; @@ -318,6 +321,30 @@ function buildOptimisticNextStepForPreventSelfApprovalsEnabled() { return optimisticNextStep; } +function buildOptimisticFixIssueNextStep() { + const optimisticNextStep: ReportNextStepDeprecated = { + type: 'neutral', + icon: CONST.NEXT_STEP.ICONS.HOURGLASS, + message: [ + { + text: 'Waiting for ', + }, + { + text: `you`, + type: 'strong', + }, + { + text: ' to ', + }, + { + text: 'fix the issue(s)', + }, + ], + }; + + return optimisticNextStep; +} + function buildOptimisticNextStepForStrictPolicyRuleViolations() { const optimisticNextStep: ReportNextStepDeprecated = { type: 'alert', @@ -332,6 +359,39 @@ function buildOptimisticNextStepForStrictPolicyRuleViolations() { return optimisticNextStep; } +function getReportNextStep( + currentNextStep: ReportNextStepDeprecated | undefined, + moneyRequestReport: OnyxEntry, + transactions: Array>, + policy: OnyxEntry, + transactionViolations: OnyxCollection, + currentUserEmail: string, + currentUserAccountID: number, +) { + const nextApproverAccountID = getNextApproverAccountID(moneyRequestReport); + + if ( + isOpenExpenseReport(moneyRequestReport) && + transactions.length > 0 && + transactions.every( + (transaction) => !!transaction && hasSubmissionBlockingViolations(transaction, transactionViolations, currentUserEmail, currentUserAccountID, moneyRequestReport, policy), + ) + ) { + return buildOptimisticFixIssueNextStep(); + } + + const isSubmitterSameAsNextApprover = + isReportOwner(moneyRequestReport) && (nextApproverAccountID === moneyRequestReport?.ownerAccountID || moneyRequestReport?.managerID === moneyRequestReport?.ownerAccountID); + + // When prevent self-approval is enabled & the current user is submitter AND they're submitting to themselves, we need to show the optimistic next step + // We should always show this optimistic message for policies with preventSelfApproval + // to avoid any flicker during transitions between online/offline states + if (isSubmitterSameAsNextApprover && policy?.preventSelfApproval) { + return buildOptimisticNextStepForPreventSelfApprovalsEnabled(); + } + + return currentNextStep; +} function buildOptimisticNextStepForDynamicExternalWorkflowSubmitError(iconFill?: string) { const optimisticNextStep: ReportNextStepDeprecated = { type: 'alert', @@ -745,6 +805,7 @@ function buildNextStepNew(params: BuildNextStepNewParams): ReportNextStepDepreca } export { + getReportNextStep, buildNextStepMessage, buildOptimisticNextStep, parseMessage,