Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CP Staging] Show delete option for requests on one transaction view #39449

Merged
merged 9 commits into from
Apr 2, 2024
72 changes: 70 additions & 2 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useMemo, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
Expand All @@ -8,13 +8,15 @@
import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as HeaderUtils from '@libs/HeaderUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
Expand All @@ -32,6 +34,9 @@

/** Session info for the currently logged in user. */
session: OnyxEntry<OnyxTypes.Session>;

/** The transaction thread report associated with the current report, if any */
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;
};

type MoneyReportHeaderProps = MoneyReportHeaderOnyxProps & {
Expand All @@ -40,14 +45,34 @@

/** The policy tied to the money request report */
policy: OnyxEntry<OnyxTypes.Policy>;

/** Array of report actions for the report */
reportActions: OnyxTypes.ReportAction[];

/** The reportID of the transaction thread report associated with this current report, if any */
// eslint-disable-next-line react/no-unused-prop-types
transactionThreadReportID?: string | null;
};

function MoneyReportHeader({session, policy, chatReport, nextStep, report: moneyRequestReport}: MoneyReportHeaderProps) {
function MoneyReportHeader({session, policy, chatReport, nextStep, report: moneyRequestReport, transactionThreadReport, reportActions}: MoneyReportHeaderProps) {
const styles = useThemeStyles();
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
NikkiWines marked this conversation as resolved.
Show resolved Hide resolved
const {translate} = useLocalize();
const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(moneyRequestReport);
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);
const parentReportAction = useMemo(() => {
NikkiWines marked this conversation as resolved.
Show resolved Hide resolved
if (!reportActions || !transactionThreadReport?.parentReportActionID) {
return null;
}
return reportActions.find((action) => action.reportActionID === transactionThreadReport.parentReportActionID ?? '0') as OnyxTypes.ReportAction;

Check failure on line 68 in src/components/MoneyReportHeader.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint

Use a ! assertion to more succinctly remove null and undefined from the type
}, [reportActions, transactionThreadReport?.parentReportActionID]);
const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction);

// Only the requestor can take delete the request, admins can only edit it.
NikkiWines marked this conversation as resolved.
Show resolved Hide resolved
const isActionOwner = typeof parentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && parentReportAction.actorAccountID === session?.accountID;
const canDeleteRequest =
isActionOwner && (ReportUtils.canAddOrDeleteTransactions(moneyRequestReport) || ReportUtils.isTrackExpenseReport(transactionThreadReport)) && !isDeletedParentAction;
const [isHoldMenuVisible, setIsHoldMenuVisible] = useState(false);
const [paymentType, setPaymentType] = useState<PaymentMethodType>();
const [requestType, setRequestType] = useState<'pay' | 'approve'>();
Expand Down Expand Up @@ -106,6 +131,19 @@
}
};

const deleteTransaction = useCallback(() => {
if (parentReportAction) {
const iouTransactionID = parentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction.originalMessage?.IOUTransactionID ?? '' : '';
if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) {
IOU.deleteTrackExpense(moneyRequestReport?.reportID ?? '', iouTransactionID, parentReportAction, true);
return;
}
IOU.deleteMoneyRequest(iouTransactionID, parentReportAction, true);
}

setIsDeleteModalVisible(false);
}, [moneyRequestReport?.reportID, parentReportAction, setIsDeleteModalVisible]);

// The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on
const isWaitingForSubmissionFromCurrentUser = useMemo(
() => chatReport?.isOwnPolicyExpenseChat && !policy?.harvesting?.enabled,
Expand All @@ -121,6 +159,23 @@
});
}

// If the report supports adding transactions to it, then it also supports deleting transactions from it.
if (canDeleteRequest && !isEmptyObject(transactionThreadReport)) {
threeDotsMenuItems.push({
icon: Expensicons.Trashcan,
text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}),
onSelected: () => setIsDeleteModalVisible(true),
});
}

useEffect(() => {
if (canDeleteRequest) {
return;
}

setIsDeleteModalVisible(false);
}, [canDeleteRequest]);

return (
<View style={[styles.pt0]}>
<HeaderWithBackButton
Expand Down Expand Up @@ -231,6 +286,16 @@
cancelText={translate('common.dismiss')}
danger
/>
<ConfirmModal
title={translate('iou.deleteRequest')}
isVisible={isDeleteModalVisible}
onConfirm={deleteTransaction}
onCancel={() => setIsDeleteModalVisible(false)}
prompt={translate('iou.deleteConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
danger
/>
</View>
);
}
Expand All @@ -244,6 +309,9 @@
nextStep: {
key: ({report}) => `${ONYXKEYS.COLLECTION.NEXT_STEP}${report.reportID}`,
},
transactionThreadReport: {
key: ({transactionThreadReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`,
},
session: {
key: ONYXKEYS.SESSION,
},
Expand Down
5 changes: 4 additions & 1 deletion src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -335,11 +335,14 @@ function ReportScreen({
);
}

const transactionThreadReportID = useMemo(() => ReportActionsUtils.getOneTransactionThreadReportID(reportActions ?? []), [reportActions]);
if (ReportUtils.isMoneyRequestReport(report)) {
headerView = (
<MoneyReportHeader
report={report}
policy={policy}
transactionThreadReportID={transactionThreadReportID}
reportActions={reportActions}
/>
);
}
Expand Down Expand Up @@ -659,7 +662,7 @@ function ReportScreen({
isLoadingNewerReportActions={reportMetadata?.isLoadingNewerReportActions}
isLoadingOlderReportActions={reportMetadata?.isLoadingOlderReportActions}
isReadyForCommentLinking={!shouldShowSkeleton}
transactionThreadReportID={ReportActionsUtils.getOneTransactionThreadReportID(reportActions ?? [])}
transactionThreadReportID={transactionThreadReportID}
/>
)}

Expand Down
Loading