diff --git a/src/CONST.ts b/src/CONST.ts index 2e2608d773ae..d93158e3088c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2335,6 +2335,7 @@ const CONST = { PRIVATE_NOTES: 'privateNotes', DELETE: 'delete', MARK_AS_INCOMPLETE: 'markAsIncomplete', + CANCEL_PAYMENT: 'cancelPayment', UNAPPROVE: 'unapprove', }, EDIT_REQUEST_FIELD: { diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 80ad2890afaa..6777bbf6c269 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -99,7 +99,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const canAllowSettlement = ReportUtils.hasUpdatedTotal(moneyRequestReport, policy); const policyType = policy?.type; const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport); - const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const navigateBackToAfterDelete = useRef(); const hasScanningReceipt = ReportUtils.getTransactionsWithReceipts(moneyRequestReport?.reportID).some((t) => TransactionUtils.isReceiptBeingScanned(t)); @@ -108,14 +107,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea // allTransactions in TransactionUtils might have stale data const hasOnlyHeldExpenses = ReportUtils.hasOnlyHeldExpenses(moneyRequestReport.reportID, transactions); - const cancelPayment = useCallback(() => { - if (!chatReport) { - return; - } - IOU.cancelPayment(moneyRequestReport, chatReport); - setIsConfirmModalVisible(false); - }, [moneyRequestReport, chatReport]); - const shouldShowPayButton = useMemo(() => IOU.canIOUBePaid(moneyRequestReport, chatReport, policy), [moneyRequestReport, chatReport, policy]); const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(moneyRequestReport, chatReport, policy), [moneyRequestReport, chatReport, policy]); @@ -371,17 +362,6 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea transactionCount={transactionIDs.length} /> )} - setIsConfirmModalVisible(false)} - prompt={translate('iou.cancelPaymentConfirmation')} - confirmText={translate('iou.cancelPayment')} - cancelText={translate('common.dismiss')} - danger - shouldEnableNewFocusManagement - /> , chatReport: OnyxTypes.Report) { + if (isEmptyObject(expenseReport)) { + return; + } + const optimisticReportAction = ReportUtils.buildOptimisticCancelPaymentReportAction(expenseReport.reportID, -(expenseReport.total ?? 0), expenseReport.currency ?? ''); const policy = PolicyUtils.getPolicy(chatReport.policyID); const isFree = policy && policy.type === CONST.POLICY.TYPE.FREE; diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index 2939c64ca958..d36761703d01 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -109,6 +109,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD const [isLastMemberLeavingGroupModalVisible, setIsLastMemberLeavingGroupModalVisible] = useState(false); const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); + const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? '-1'}`], [policies, report?.policyID]); const isPolicyAdmin = useMemo(() => PolicyUtils.isPolicyAdmin(policy), [policy]); const isPolicyEmployee = useMemo(() => PolicyUtils.isPolicyEmployee(report?.policyID ?? '-1', policies), [report?.policyID, policies]); @@ -263,6 +264,21 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD const shouldShowWriteCapability = !isMoneyRequestReport; const shouldShowMenuItem = shouldShowNotificationPref || shouldShowWriteCapability || (!!report?.visibility && report.chatType !== CONST.REPORT.CHAT_TYPE.INVOICE); + const isPayer = ReportUtils.isPayer(session, moneyRequestReport); + const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID ?? '-1'); + + const shouldShowCancelPaymentButton = caseID === CASES.MONEY_REPORT && isPayer && isSettled && ReportUtils.isExpenseReport(moneyRequestReport); + const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${moneyRequestReport?.chatReportID ?? '-1'}`); + + const cancelPayment = useCallback(() => { + if (!chatReport) { + return; + } + + IOU.cancelPayment(moneyRequestReport, chatReport); + setIsConfirmModalVisible(false); + }, [moneyRequestReport, chatReport]); + const menuItems: ReportDetailsPageMenuItem[] = useMemo(() => { const items: ReportDetailsPageMenuItem[] = []; @@ -356,6 +372,16 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD } } + if (shouldShowCancelPaymentButton) { + items.push({ + key: CONST.REPORT_DETAILS_MENU_ITEM.CANCEL_PAYMENT, + icon: Expensicons.Trashcan, + translationKey: 'iou.cancelPayment', + isAnonymousAction: false, + action: () => setIsConfirmModalVisible(true), + }); + } + if (shouldShowLeaveButton) { items.push({ key: CONST.REPORT_DETAILS_MENU_ITEM.LEAVE_ROOM, @@ -403,6 +429,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD isCanceledTaskReport, shouldShowLeaveButton, activeChatMembers.length, + shouldShowCancelPaymentButton, isPolicyAdmin, session, leaveChat, @@ -710,6 +737,17 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD confirmText={translate('common.leave')} cancelText={translate('common.cancel')} /> + setIsConfirmModalVisible(false)} + prompt={translate('iou.cancelPaymentConfirmation')} + confirmText={translate('iou.cancelPayment')} + cancelText={translate('common.dismiss')} + danger + shouldEnableNewFocusManagement + />