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 24 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
30 changes: 27 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 haveAllPendingRTERViolation = TransactionUtils.haveAllPendingRTERViolation(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) && !haveAllPendingRTERViolation;

const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0;
const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0 && !haveAllPendingRTERViolation;
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) && !haveAllPendingRTERViolation}
shouldShowThreeDotsButton
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
Expand Down Expand Up @@ -241,6 +250,21 @@ function MoneyReportHeader({
</View>
)}
</HeaderWithBackButton>
{haveAllPendingRTERViolation && (
<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
additionalViewStyle={[styles.mr2]}
smelaa marked this conversation as resolved.
Show resolved Hide resolved
/>
)}
<View style={isMoreContentShown ? [styles.dFlex, styles.flexColumn, styles.borderBottom] : []}>
{shouldShowSettlementButton && shouldUseNarrowLayout && (
<View style={[styles.ph5, styles.pb2]}>
Expand Down
67 changes: 50 additions & 17 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
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';
import useWindowDimensions from '@hooks/useWindowDimensions';
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 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';
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';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import {ReceiptScan} from './Icon/Expensicons';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
import ProcessMoneyRequestHoldMenu from './ProcessMoneyRequestHoldMenu';

Expand All @@ -32,6 +36,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 @@ -56,19 +63,20 @@ type MoneyRequestHeaderProps = MoneyRequestHeaderOnyxProps & {
/** Method to trigger when pressing close button of the header */
onBackButtonPress: () => void;
};

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 @@ -97,7 +105,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 @@ -116,6 +123,21 @@ function MoneyRequestHeader({
}
};

const getPendingType = () => {
if (TransactionUtils.isExpensifyCardTransaction(transaction) && TransactionUtils.isPending(transaction)) {
return {pendingType: 'PENDING', pendingTitle: translate('iou.pending'), pendingDescription: translate('iou.transactionPendingText')};
smelaa marked this conversation as resolved.
Show resolved Hide resolved
}
if (isScanning) {
return {pendingType: 'SCANNING', pendingTitle: ReceiptScan, pendingDescription: translate('iou.receiptScanInProgressDescription')};
}
if (TransactionUtils.hasPendingRTERViolation(TransactionUtils.getTransactionViolations(transaction?.transactionID ?? '', transactionViolations))) {
return {pendingType: 'RTER', pendingTitle: Expensicons.Hourglass, pendingDescription: translate('iou.pendingMatchWithCreditCardDescription')};
}
return {};
};

const {pendingType, pendingTitle, pendingDescription} = getPendingType();

useEffect(() => {
if (canDeleteRequest) {
return;
Expand Down Expand Up @@ -180,7 +202,7 @@ function MoneyRequestHeader({
<>
<View style={[styles.pl0]}>
<HeaderWithBackButton
shouldShowBorderBottom={!isScanning && !isPending && !isOnHold}
shouldShowBorderBottom={!pendingType && !isOnHold}
shouldShowReportAvatarWithDisplay
shouldEnableDetailPageNavigation
shouldShowPinButton={false}
Expand All @@ -195,18 +217,23 @@ function MoneyRequestHeader({
shouldShowBackButton={shouldUseNarrowLayout}
onBackButtonPress={onBackButtonPress}
/>
{isPending && (
<MoneyRequestHeaderStatusBar
title={translate('iou.pending')}
description={translate('iou.transactionPendingText')}
shouldShowBorderBottom={!isScanning}
/>
)}
{isScanning && (
{pendingType && (
<MoneyRequestHeaderStatusBar
title={translate('iou.receiptStatusTitle')}
description={translate('iou.receiptStatusText')}
title={
typeof pendingTitle === 'string' ? (
pendingTitle
) : (
<Icon
src={pendingTitle}
height={variables.iconSizeSmall}
width={variables.iconSizeSmall}
fill={theme.textSupporting}
/>
)
smelaa marked this conversation as resolved.
Show resolved Hide resolved
}
description={pendingDescription}
shouldShowBorderBottom={!isOnHold}
additionalViewStyle={[styles.mr2]}
smelaa marked this conversation as resolved.
Show resolved Hide resolved
/>
)}
{isOnHold && (
Expand Down Expand Up @@ -241,7 +268,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 @@ -252,9 +279,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
25 changes: 17 additions & 8 deletions src/components/MoneyRequestHeaderStatusBar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type {ReactNode} from 'react';
import React from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useThemeStyles from '@hooks/useThemeStyles';
import Badge from './Badge';
import Text from './Text';

type MoneyRequestHeaderStatusBarProps = {
/** Title displayed in badge */
title: string;
title: string | ReactNode;

/** Banner Description */
description: string;
Expand All @@ -16,9 +18,12 @@ type MoneyRequestHeaderStatusBarProps = {

/** Whether we should use the danger theme color */
danger?: boolean;

/** Additional style for the banner */
additionalViewStyle?: StyleProp<ViewStyle>;
};

function MoneyRequestHeaderStatusBar({title, description, shouldShowBorderBottom, danger = false}: MoneyRequestHeaderStatusBarProps) {
function MoneyRequestHeaderStatusBar({title, description, shouldShowBorderBottom, danger = false, additionalViewStyle}: MoneyRequestHeaderStatusBarProps) {
const styles = useThemeStyles();
const borderBottomStyle = shouldShowBorderBottom ? styles.borderBottom : {};
return (
Expand All @@ -35,12 +40,16 @@ function MoneyRequestHeaderStatusBar({title, description, shouldShowBorderBottom
styles.headerStatusBarContainer,
]}
>
<View style={[styles.mr3]}>
<Badge
text={title}
badgeStyles={styles.ml0}
error={danger}
/>
<View style={additionalViewStyle ?? [styles.mr3]}>
{typeof title === 'string' ? (
<Badge
text={title}
badgeStyles={styles.ml0}
error={danger}
/>
) : (
<View>{title}</View>
)}
</View>
<View style={[styles.flexShrink1]}>
<Text style={[styles.textLabelSupporting]}>{description}</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {GestureResponderEvent} from 'react-native';
import ConfirmedRoute from '@components/ConfirmedRoute';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import {ReceiptScan} from '@components/Icon/Expensicons';
import MoneyRequestSkeletonView from '@components/MoneyRequestSkeletonView';
import MultipleAvatars from '@components/MultipleAvatars';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
Expand All @@ -28,6 +29,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import ViolationsUtils from '@libs/Violations/ViolationsUtils';
import variables from '@styles/variables';
import * as PaymentMethods from '@userActions/PaymentMethods';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -93,6 +95,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 @@ -319,6 +322,30 @@ function MoneyRequestPreviewContent({
</Text>
)}
</View>
{isScanning && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mt2]}>
<Icon
src={ReceiptScan}
height={variables.iconSizeExtraSmall}
width={variables.iconSizeExtraSmall}
fill={theme.textSupporting}
/>
<Text style={[styles.textLabel, styles.colorMuted, styles.ml1, styles.amountSplitPadding]}>{translate('iou.receiptScanInProgress')}</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
Loading
Loading