Skip to content

Commit

Permalink
Merge pull request #41835 from software-mansion-labs/brtqkr/mark-as-cash
Browse files Browse the repository at this point in the history
Add markAsCash button with wired up action for dismissing the rter violation
  • Loading branch information
yuwenmemon authored May 23, 2024
2 parents 2c9cc0a + 44c1473 commit 4bd72e4
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 26 deletions.
62 changes: 49 additions & 13 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import * as TransactionActions from '@userActions/Transaction';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -125,9 +126,10 @@ function MoneyReportHeader({

const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0 && !allHavePendingRTERViolation;
const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
const shouldShowMarkAsCashButton = isDraft && allHavePendingRTERViolation;
const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;
const shouldShowNextStep = !ReportUtils.isClosedExpenseReportWithNoExpenses(moneyRequestReport) && isFromPaidPolicy && !!nextStep?.message?.length && !allHavePendingRTERViolation;
const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep;
const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep || allHavePendingRTERViolation;
const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
const formattedAmount = CurrencyUtils.convertToDisplayString(reimbursableSpend, moneyRequestReport.currency);
const [nonHeldAmount, fullAmount] = ReportUtils.getNonHeldAndFullAmount(moneyRequestReport, policy);
Expand Down Expand Up @@ -169,6 +171,16 @@ function MoneyReportHeader({
setIsDeleteRequestModalVisible(false);
}, [moneyRequestReport?.reportID, requestParentReportAction, setIsDeleteRequestModalVisible]);

const markAsCash = useCallback(() => {
if (!requestParentReportAction) {
return;
}
const iouTransactionID = requestParentReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? requestParentReportAction.originalMessage?.IOUTransactionID ?? '' : '';
const reportID = transactionThreadReport?.reportID ?? '';

TransactionActions.markAsCash(iouTransactionID, reportID);
}, [requestParentReportAction, transactionThreadReport?.reportID]);

// 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 Down Expand Up @@ -249,20 +261,44 @@ function MoneyReportHeader({
/>
</View>
)}
{shouldShowMarkAsCashButton && !shouldUseNarrowLayout && (
<View style={[styles.pv2]}>
<Button
medium
success
text={translate('iou.markAsCash')}
style={[styles.pv2, styles.pr0]}
onPress={markAsCash}
/>
</View>
)}
</HeaderWithBackButton>
{allHavePendingRTERViolation && (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.pendingMatchWithCreditCardDescription')}
shouldShowBorderBottom
/>
<View>
{shouldShowMarkAsCashButton && shouldUseNarrowLayout && (
<View style={[styles.ph5, styles.pb3]}>
<Button
medium
success
text={translate('iou.markAsCash')}
style={[styles.w100, styles.pr0]}
onPress={markAsCash}
/>
</View>
)}
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.pendingMatchWithCreditCardDescription')}
shouldShowBorderBottom
/>
</View>
)}
<View style={isMoreContentShown ? [styles.dFlex, styles.flexColumn, styles.borderBottom] : []}>
{shouldShowSettlementButton && shouldUseNarrowLayout && (
Expand Down
42 changes: 38 additions & 4 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import * as TransactionActions from '@userActions/Transaction';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Policy, Report, ReportAction, ReportActions, Session, Transaction, TransactionViolations} from '@src/types/onyx';
import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage';
import type IconAsset from '@src/types/utils/IconAsset';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
Expand Down Expand Up @@ -86,13 +88,16 @@ function MoneyRequestHeader({
const moneyRequestReport = parentReport;
const isSettled = ReportUtils.isSettled(moneyRequestReport?.reportID);
const isApproved = ReportUtils.isReportApproved(moneyRequestReport);
const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport);
const isOnHold = TransactionUtils.isOnHold(transaction);
const {windowWidth} = useWindowDimensions();

// Only the requestor can take delete the expense, admins can only edit it.
const isActionOwner = typeof parentReportAction?.actorAccountID === 'number' && typeof session?.accountID === 'number' && parentReportAction.actorAccountID === session?.accountID;
const isPolicyAdmin = policy?.role === CONST.POLICY.ROLE.ADMIN;
const isApprover = ReportUtils.isMoneyRequestReport(moneyRequestReport) && moneyRequestReport?.managerID !== null && session?.accountID === moneyRequestReport?.managerID;
const hasAllPendingRTERViolations = TransactionUtils.allHavePendingRTERViolation([transaction?.transactionID ?? '']);
const shouldShowMarkAsCashButton = isDraft && hasAllPendingRTERViolations;

const deleteTransaction = useCallback(() => {
if (parentReportAction) {
Expand All @@ -107,6 +112,10 @@ function MoneyRequestHeader({
setIsDeleteModalVisible(false);
}, [parentReport?.reportID, parentReportAction, setIsDeleteModalVisible]);

const markAsCash = useCallback(() => {
TransactionActions.markAsCash(transaction?.transactionID ?? '', report.reportID);
}, [report.reportID, transaction?.transactionID]);

const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);

const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction);
Expand Down Expand Up @@ -143,12 +152,16 @@ function MoneyRequestHeader({
if (TransactionUtils.isExpensifyCardTransaction(transaction) && TransactionUtils.isPending(transaction)) {
return {title: getStatusIcon(Expensicons.CreditCardHourglass), description: translate('iou.transactionPendingDescription'), shouldShowBorderBottom: true};
}
if (TransactionUtils.hasPendingRTERViolation(TransactionUtils.getTransactionViolations(transaction?.transactionID ?? '', transactionViolations))) {
return {
title: getStatusIcon(Expensicons.Hourglass),
description: translate('iou.pendingMatchWithCreditCardDescription'),
shouldShowBorderBottom: true,
};
}
if (isScanning) {
return {title: getStatusIcon(Expensicons.ReceiptScan), description: translate('iou.receiptScanInProgressDescription'), shouldShowBorderBottom: true};
}
if (TransactionUtils.hasPendingRTERViolation(TransactionUtils.getTransactionViolations(transaction?.transactionID ?? '', transactionViolations))) {
return {title: getStatusIcon(Expensicons.Hourglass), description: translate('iou.pendingMatchWithCreditCardDescription'), shouldShowBorderBottom: true};
}
};

const statusBarProps = getStatusBarProps();
Expand Down Expand Up @@ -231,7 +244,28 @@ function MoneyRequestHeader({
policy={policy}
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={onBackButtonPress}
/>
>
{shouldShowMarkAsCashButton && !shouldUseNarrowLayout && (
<Button
success
medium
text={translate('iou.markAsCash')}
style={[styles.p0]}
onPress={markAsCash}
/>
)}
</HeaderWithBackButton>
{shouldShowMarkAsCashButton && shouldUseNarrowLayout && (
<View style={[styles.ph5, styles.pb3]}>
<Button
medium
success
text={translate('iou.markAsCash')}
style={[styles.w100, styles.pr0]}
onPress={markAsCash}
/>
</View>
)}
{statusBarProps && (
<MoneyRequestHeaderStatusBar
title={statusBarProps.title}
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ export default {
deleteReceipt: 'Delete receipt',
pendingMatchWithCreditCard: 'Receipt pending match with credit card.',
pendingMatchWithCreditCardDescription: 'Receipt pending match with credit card. Mark as cash to ignore and request payment.',
markAsCash: 'Mark as cash',
routePending: 'Route pending...',
receiptScanning: 'Receipt scanning...',
receiptScanInProgress: 'Receipt scan in progress.',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ export default {
deleteReceipt: 'Eliminar recibo',
pendingMatchWithCreditCard: 'Recibo pendiente de adjuntar con la tarjeta de crédito.',
pendingMatchWithCreditCardDescription: 'Recibo pendiente de adjuntar con tarjeta de crédito. Marca como efectivo para ignorar y solicitar pago.',
markAsCash: 'Marcar como efectivo',
routePending: 'Ruta pendiente...',
receiptIssuesFound: (count: number) => `${count === 1 ? 'Problema encontrado' : 'Problemas encontrados'}`,
fieldPending: 'Pendiente...',
Expand Down
14 changes: 10 additions & 4 deletions src/libs/actions/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {buildOptimisticDismissedViolationReportAction} from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {RecentWaypoint, ReportActions, Transaction, TransactionViolation} from '@src/types/onyx';
import type {RecentWaypoint, ReportActions, Transaction, TransactionViolation, TransactionViolations} from '@src/types/onyx';
import type {OnyxData} from '@src/types/onyx/Request';
import type {WaypointCollection} from '@src/types/onyx/Transaction';

Expand All @@ -33,6 +33,12 @@ Onyx.connect({
},
});

let allTransactionViolations: TransactionViolations = [];
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
callback: (val) => (allTransactionViolations = val ?? []),
});

function createInitialWaypoints(transactionID: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {
comment: {
Expand Down Expand Up @@ -265,7 +271,7 @@ function clearError(transactionID: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {errors: null, errorFields: {route: null}});
}

function markAsCash(transactionID: string, transactionThreadReportID: string, existingViolations: TransactionViolation[]) {
function markAsCash(transactionID: string, transactionThreadReportID: string) {
const optimisticReportAction = buildOptimisticDismissedViolationReportAction({
reason: 'manual',
violationName: CONST.VIOLATIONS.RTER,
Expand All @@ -279,7 +285,7 @@ function markAsCash(transactionID: string, transactionThreadReportID: string, ex
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
value: existingViolations.filter((violation: TransactionViolation) => violation.name !== CONST.VIOLATIONS.RTER),
value: allTransactionViolations.filter((violation: TransactionViolation) => violation.name !== CONST.VIOLATIONS.RTER),
},
// Optimistically adding the system message indicating we dismissed the violation
{
Expand All @@ -293,7 +299,7 @@ function markAsCash(transactionID: string, transactionThreadReportID: string, ex
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
value: existingViolations,
value: allTransactionViolations,
},
{
onyxMethod: Onyx.METHOD.MERGE,
Expand Down
10 changes: 5 additions & 5 deletions src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ function ReportScreen({
/>
);

const transactionThreadReportID = useMemo(
() => ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, reportActions ?? [], false, isOffline),
[report.reportID, reportActions, isOffline],
);

if (isSingleTransactionView) {
headerView = (
<MoneyRequestHeader
Expand All @@ -356,11 +361,6 @@ function ReportScreen({
);
}

const transactionThreadReportID = useMemo(
() => ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, reportActions ?? [], false, isOffline),
[report.reportID, reportActions, isOffline],
);

useEffect(() => {
if (!transactionThreadReportID || !route.params.reportActionID) {
return;
Expand Down

0 comments on commit 4bd72e4

Please sign in to comment.