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

[Violations - Pending Receipts] Display the rter Violation with the Pending Pattern #40354

Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
5f1d0b8
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 17, 2024
68d480d
Display rter violation in MoneyRequestHeader & ReportPreview
smelaa Apr 17, 2024
3409d9c
Display rter violations in MoneyReportHeader
smelaa Apr 17, 2024
a350cda
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 18, 2024
5275089
Fix util function
smelaa Apr 18, 2024
046dbc2
Add rter violation information to MoneyRequestPreviewContent header
smelaa Apr 18, 2024
a13a1f7
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 24, 2024
68b9e49
Mocking data
smelaa Apr 24, 2024
aea3766
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 24, 2024
07d3bc5
Disable eslint on mocking data
smelaa Apr 26, 2024
3de40c1
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 26, 2024
c20119d
Move message from header to footer
smelaa Apr 29, 2024
306fc8f
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa Apr 29, 2024
8f00196
Fix eslint error
smelaa Apr 29, 2024
7a89a59
Styling fixes
smelaa May 6, 2024
82e2fd5
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa May 6, 2024
c47e30b
Fixes after merging with main
smelaa May 6, 2024
81d200e
Styling
smelaa May 7, 2024
937d677
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa May 7, 2024
8d72c93
Eslint
smelaa May 7, 2024
8463360
Eslint
smelaa May 7, 2024
c4cdb4b
Addressing review comments
smelaa May 8, 2024
03fb6ee
Remove mocking data
smelaa May 8, 2024
5560114
Eslint
smelaa May 8, 2024
6524120
Merge branch 'brtqkr/pending-and-scanning/38688' into smelaa/pending-…
smelaa May 8, 2024
a3d217e
Address review comments
smelaa May 8, 2024
c4da3cc
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa May 9, 2024
f48a9c4
Merge branch 'brtqkr/pending-and-scanning/38688' into smelaa/pending-…
smelaa May 10, 2024
34b43dc
Update Spanish translations
smelaa May 10, 2024
8e8bd95
Merge branch 'main' into smelaa/pending-and-scanning/39533
smelaa May 13, 2024
75d88b1
Address review comments
smelaa May 13, 2024
48b387c
Rename variables & change icon color
smelaa May 13, 2024
e5670c0
Fix a type & rename function
smelaa May 14, 2024
e90103f
Create icon & description getter functions
smelaa May 14, 2024
4920af0
Move types declaration to ReportUtils
smelaa May 14, 2024
7da3c45
Address review comments
smelaa May 14, 2024
027b40e
Address review comments
smelaa May 15, 2024
40f471c
Reuse MoneyRequestHeaderStatusBar
smelaa May 15, 2024
1855b01
Add JSDoc comment
smelaa May 15, 2024
02d87f4
Do not display next step banner in case of pending rter violation
smelaa May 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as HeaderUtils from '@libs/HeaderUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -19,8 +22,10 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
import ProcessMoneyReportHoldMenu from './ProcessMoneyReportHoldMenu';
import SettlementButton from './SettlementButton';

Expand Down Expand Up @@ -71,6 +76,7 @@ function MoneyReportHeader({
onBackButtonPress,
}: MoneyReportHeaderProps) {
const styles = useThemeStyles();
const theme = useTheme();
const [isDeleteRequestModalVisible, setIsDeleteRequestModalVisible] = useState(false);
const {translate} = useLocalize();
const {windowWidth} = useWindowDimensions();
Expand Down Expand Up @@ -98,6 +104,9 @@ function MoneyReportHeader({
const isDraft = ReportUtils.isOpenExpenseReport(moneyRequestReport);
const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);

const transactionIDs = TransactionUtils.getAllReportTransactions(moneyRequestReport?.reportID).map((transaction) => transaction.transactionID);
const hasAllPendingRTERViolation = TransactionUtils.hasAllPendingRTERViolations(transactionIDs);
smelaa marked this conversation as resolved.
Show resolved Hide resolved

const cancelPayment = useCallback(() => {
if (!chatReport) {
return;
Expand All @@ -112,9 +121,9 @@ function MoneyReportHeader({

const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport);

const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(moneyRequestReport) && (shouldShowPayButton || shouldShowApproveButton);
const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(moneyRequestReport) && (shouldShowPayButton || shouldShowApproveButton) && !hasAllPendingRTERViolation;
smelaa marked this conversation as resolved.
Show resolved Hide resolved

const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0;
const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0 && !hasAllPendingRTERViolation;
smelaa marked this conversation as resolved.
Show resolved Hide resolved
const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;
const shouldShowNextStep = !ReportUtils.isClosedExpenseReportWithNoExpenses(moneyRequestReport) && isFromPaidPolicy && !!nextStep?.message?.length;
Expand Down Expand Up @@ -203,7 +212,7 @@ function MoneyReportHeader({
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={onBackButtonPress}
// Shows border if no buttons or next steps are showing below the header
shouldShowBorderBottom={!(shouldShowAnyButton && shouldUseNarrowLayout) && !(shouldShowNextStep && !shouldUseNarrowLayout)}
shouldShowBorderBottom={!(shouldShowAnyButton && shouldUseNarrowLayout) && !(shouldShowNextStep && !shouldUseNarrowLayout) && !hasAllPendingRTERViolation}
smelaa marked this conversation as resolved.
Show resolved Hide resolved
shouldShowThreeDotsButton
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
Expand Down Expand Up @@ -241,6 +250,20 @@ function MoneyReportHeader({
</View>
)}
</HeaderWithBackButton>
{hasAllPendingRTERViolation && (
smelaa marked this conversation as resolved.
Show resolved Hide resolved
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.textSupporting}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the fill color betheme.icon ? cc @dubielzyk-expensify

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I think it should. Based on that #39533 (comment)

I have changed it here and the other places to theme.icon. I was misled because theme.textSupporting wa used for icons of different violations somewhere else in the code.

/>
}
description={translate('iou.pendingMatchWithCreditCardDescription')}
shouldShowBorderBottom
/>
)}
<View style={isMoreContentShown ? [styles.dFlex, styles.flexColumn, styles.borderBottom] : []}>
{shouldShowSettlementButton && shouldUseNarrowLayout && (
<View style={[styles.ph5, styles.pb2]}>
Expand Down
123 changes: 90 additions & 33 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback, useEffect, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -16,7 +16,7 @@ import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Policy, Report, ReportAction, ReportActions, Session, Transaction} from '@src/types/onyx';
import type {Policy, Report, ReportAction, ReportActions, Session, Transaction, TransactionViolations} from '@src/types/onyx';
import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
Expand All @@ -35,6 +35,9 @@ type MoneyRequestHeaderOnyxProps = {
/** All the data for the transaction */
transaction: OnyxEntry<Transaction>;

/** The violations of the transaction */
transactionViolations: OnyxCollection<TransactionViolations>;

/** All report actions */
// eslint-disable-next-line react/no-unused-prop-types
parentReportActions: OnyxEntry<ReportActions>;
Expand All @@ -60,19 +63,76 @@ type MoneyRequestHeaderProps = MoneyRequestHeaderOnyxProps & {
onBackButtonPress: () => void;
};

type PendingType = 'PENDING' | 'SCANNING' | 'RTER';

type MoneyRequestHeaderPendingStatusBarProps = {pendingType: PendingType; shouldShowBorderBottom: boolean};

function MoneyRequestHeaderPendingStatusBar({pendingType, shouldShowBorderBottom}: MoneyRequestHeaderPendingStatusBarProps) {
smelaa marked this conversation as resolved.
Show resolved Hide resolved
const theme = useTheme();
const {translate} = useLocalize();

if (pendingType === 'PENDING') {
return (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.CreditCardHourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.transactionPendingDescription')}
shouldShowBorderBottom={shouldShowBorderBottom}
/>
);
}

if (pendingType === 'SCANNING') {
return (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.ReceiptScan}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.receiptScanInProgressDescription')}
shouldShowBorderBottom={shouldShowBorderBottom}
/>
);
}

return (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.textSupporting}
/>
}
description={translate('iou.pendingMatchWithCreditCardDescription')}
shouldShowBorderBottom={shouldShowBorderBottom}
/>
);
}
function MoneyRequestHeader({
session,
parentReport,
report,
parentReportAction,
transactionViolations,
transaction,
shownHoldUseExplanation = false,
policy,
shouldUseNarrowLayout = false,
onBackButtonPress,
}: MoneyRequestHeaderProps) {
const styles = useThemeStyles();
const theme = useTheme();
const {translate} = useLocalize();
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
const [shouldShowHoldMenu, setShouldShowHoldMenu] = useState(false);
Expand Down Expand Up @@ -101,7 +161,6 @@ function MoneyRequestHeader({
}, [parentReport?.reportID, parentReportAction, setIsDeleteModalVisible]);

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

const isDeletedParentAction = ReportActionsUtils.isDeletedAction(parentReportAction);
const canHoldOrUnholdRequest = !isSettled && !isApproved && !isDeletedParentAction;
Expand All @@ -120,6 +179,20 @@ function MoneyRequestHeader({
}
};

const getPendingType: () => PendingType | undefined = () => {
if (TransactionUtils.isExpensifyCardTransaction(transaction) && TransactionUtils.isPending(transaction)) {
return 'PENDING';
smelaa marked this conversation as resolved.
Show resolved Hide resolved
}
if (isScanning) {
return 'SCANNING';
smelaa marked this conversation as resolved.
Show resolved Hide resolved
}
if (TransactionUtils.hasPendingRTERViolation(TransactionUtils.getTransactionViolations(transaction?.transactionID ?? '', transactionViolations))) {
return 'RTER';
smelaa marked this conversation as resolved.
Show resolved Hide resolved
}
};

const pendingType = getPendingType();

useEffect(() => {
if (canDeleteRequest) {
return;
Expand Down Expand Up @@ -184,7 +257,7 @@ function MoneyRequestHeader({
<>
<View style={[styles.pl0]}>
<HeaderWithBackButton
shouldShowBorderBottom={!isScanning && !isPending && !isOnHold}
shouldShowBorderBottom={!pendingType && !isOnHold}
shouldShowReportAvatarWithDisplay
shouldEnableDetailPageNavigation
shouldShowPinButton={false}
Expand All @@ -199,32 +272,10 @@ function MoneyRequestHeader({
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={onBackButtonPress}
/>
{isPending && (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.CreditCardHourglass}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.transactionPendingDescription')}
shouldShowBorderBottom={!isScanning}
/>
)}
{isScanning && (
<MoneyRequestHeaderStatusBar
title={
<Icon
src={Expensicons.ReceiptScan}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.icon}
/>
}
description={translate('iou.receiptScanInProgressDescription')}
shouldShowBorderBottom
{pendingType && (
<MoneyRequestHeaderPendingStatusBar
pendingType={pendingType}
shouldShowBorderBottom={!isOnHold}
/>
)}
{isOnHold && (
Expand Down Expand Up @@ -259,7 +310,7 @@ function MoneyRequestHeader({

MoneyRequestHeader.displayName = 'MoneyRequestHeader';

const MoneyRequestHeaderWithTransaction = withOnyx<MoneyRequestHeaderProps, Pick<MoneyRequestHeaderOnyxProps, 'transaction' | 'shownHoldUseExplanation'>>({
const MoneyRequestHeaderWithTransaction = withOnyx<MoneyRequestHeaderProps, Pick<MoneyRequestHeaderOnyxProps, 'transactionViolations' | 'transaction' | 'shownHoldUseExplanation'>>({
transaction: {
key: ({report, parentReportActions}) => {
const parentReportAction = (report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : {}) as ReportAction & OriginalMessageIOU;
Expand All @@ -270,9 +321,15 @@ const MoneyRequestHeaderWithTransaction = withOnyx<MoneyRequestHeaderProps, Pick
key: ONYXKEYS.NVP_HOLD_USE_EXPLAINED,
initWithStoredValues: true,
},
transactionViolations: {
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
},
})(MoneyRequestHeader);

export default withOnyx<Omit<MoneyRequestHeaderProps, 'transaction' | 'shownHoldUseExplanation'>, Omit<MoneyRequestHeaderOnyxProps, 'transaction' | 'shownHoldUseExplanation'>>({
export default withOnyx<
Omit<MoneyRequestHeaderProps, 'transactionViolations' | 'transaction' | 'shownHoldUseExplanation'>,
Omit<MoneyRequestHeaderOnyxProps, 'transactionViolations' | 'transaction' | 'shownHoldUseExplanation'>
>({
session: {
key: ONYXKEYS.SESSION,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function MoneyRequestPreviewContent({
const isCardTransaction = TransactionUtils.isCardTransaction(transaction);
const isSettled = ReportUtils.isSettled(iouReport?.reportID);
const isDeleted = action?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
const hasPendingUI = TransactionUtils.hasPendingUI(transaction, TransactionUtils.getTransactionViolations(transaction?.transactionID ?? '', transactionViolations));
const isFullySettled = isSettled && !isSettlementOrApprovalPartial;
const isFullyApproved = ReportUtils.isReportApproved(iouReport) && !isSettlementOrApprovalPartial;
const shouldShowRBR = hasNoticeTypeViolations || hasViolations || hasFieldErrors || (!isFullySettled && !isFullyApproved && isOnHold);
Expand Down Expand Up @@ -334,6 +335,19 @@ function MoneyRequestPreviewContent({
<Text style={[styles.textMicroSupporting, styles.ml1, styles.amountSplitPadding]}>{translate('iou.transactionPending')}</Text>
</View>
)}
{!isScanning && hasPendingUI && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2]}>
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeExtraSmall}
width={variables.iconSizeExtraSmall}
fill={theme.textSupporting}
/>
<Text style={[styles.textLabel, styles.colorMuted, styles.ml1, styles.amountSplitPadding]}>
{translate('iou.pendingMatchWithCreditCard')}
</Text>
</View>
)}
</View>
</View>
</View>
Expand Down
19 changes: 17 additions & 2 deletions src/components/ReportActionItem/ReportPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ function ReportPreview({
const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)) || ReportUtils.hasActionsWithErrors(iouReportID);
const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3);
const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction));
const showRTERViolationMessage =
allTransactions.length === 1 && TransactionUtils.hasPendingUI(allTransactions[0], TransactionUtils.getTransactionViolations(allTransactions[0].transactionID, transactionViolations));
smelaa marked this conversation as resolved.
Show resolved Hide resolved

let formattedMerchant = numberOfRequests === 1 ? TransactionUtils.getMerchant(allTransactions[0]) : null;
const formattedDescription = numberOfRequests === 1 ? TransactionUtils.getDescription(allTransactions[0]) : null;
Expand All @@ -148,7 +150,7 @@ function ReportPreview({
formattedMerchant = null;
}

const shouldShowSubmitButton = isOpenExpenseReport && reimbursableSpend !== 0;
const shouldShowSubmitButton = isOpenExpenseReport && reimbursableSpend !== 0 && !showRTERViolationMessage;
const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(iouReport);

// The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on
Expand Down Expand Up @@ -210,7 +212,7 @@ function ReportPreview({

const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport);

const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(iouReport) && (shouldShowPayButton || shouldShowApproveButton);
const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(iouReport) && (shouldShowPayButton || shouldShowApproveButton) && !showRTERViolationMessage;

const shouldPromptUserToAddBankAccount = ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID);
const shouldShowRBR = !iouSettled && hasErrors;
Expand Down Expand Up @@ -314,6 +316,19 @@ function ReportPreview({
</View>
</View>
)}
{showRTERViolationMessage && (
<View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter]}>
<Icon
src={Expensicons.Hourglass}
height={variables.iconSizeExtraSmall}
width={variables.iconSizeExtraSmall}
fill={theme.textSupporting}
/>
<Text style={[styles.textLabel, styles.colorMuted, styles.ml1, styles.amountSplitPadding]}>
{translate('iou.pendingMatchWithCreditCard')}
</Text>
</View>
)}
{shouldShowScanningSubtitle && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2]}>
<Icon
Expand Down
Loading
Loading