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

[Wave 8 - ECard Transactions] Show EReceipts in ReportPreviews and Attachment View #29474

Merged
merged 17 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,7 @@ const CONST = {
MAKE_REQUEST_WITH_SIDE_EFFECTS: 'makeRequestWithSideEffects',
},

ERECEIPT_PATH: 'eReceipt/',
grgia marked this conversation as resolved.
Show resolved Hide resolved
ERECEIPT_COLORS: {
YELLOW: 'Yellow',
ICE: 'Ice',
Expand Down
5 changes: 5 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ export default {
I_AM_A_TEACHER: 'teachersunite/i-am-a-teacher',
INTRO_SCHOOL_PRINCIPAL: 'teachersunite/intro-school-principal',

ERECEIPT: {
route: 'eReceipt/:transactionID',
getRoute: (transactionID: string) => `eReceipt/${transactionID}`,
},

WORKSPACE_NEW: 'workspace/new',
WORKSPACE_NEW_ROOM: 'workspace/new-room',
WORKSPACE_INITIAL: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function extractAttachmentsFromReport(report, reportActions) {

const transaction = TransactionUtils.getTransaction(transactionID);
if (TransactionUtils.hasReceipt(transaction)) {
const {image} = ReceiptUtils.getThumbnailAndImageURIs(transaction.receipt.source, transaction.filename);
const {image} = ReceiptUtils.getThumbnailAndImageURIs(transaction);
attachments.unshift({
source: tryResolveUrlFromApiRoot(image),
isAuthTokenRequired: true,
Expand Down
11 changes: 11 additions & 0 deletions src/components/Attachments/AttachmentView/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import addEncryptedAuthTokenToURL from '../../../libs/addEncryptedAuthTokenToURL
import * as StyleUtils from '../../../styles/StyleUtils';
import {attachmentViewPropTypes, attachmentViewDefaultProps} from './propTypes';
import useNetwork from '../../../hooks/useNetwork';
import CONST from '../../../CONST';
import EReceipt from '../../EReceipt';

const propTypes = {
...attachmentViewPropTypes,
Expand Down Expand Up @@ -92,6 +94,15 @@ function AttachmentView({
);
}

if (_.isString(source) && source.startsWith(CONST.ERECEIPT_PATH)) {
const transactionIDFromURL = source.split(CONST.ERECEIPT_PATH)[1];
return (
<View style={[styles.flex1, styles.justifyContentCenter, styles.alignItemsCenter]}>
<EReceipt transactionID={transactionIDFromURL} />
</View>
);
}

// Check both source and file.name since PDFs dragged into the text field
// will appear with a source that is a blob
if ((_.isString(source) && Str.isPDF(source)) || (file && Str.isPDF(file.name || translate('attachmentView.unknownFilename')))) {
Expand Down
3 changes: 1 addition & 2 deletions src/components/MoneyRequestConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,7 @@ function MoneyRequestConfirmationList(props) {
);
}, [confirm, props.bankAccountRoute, props.iouCurrencyCode, props.iouType, props.isReadOnly, props.policyID, selectedParticipants, splitOrRequestOptions, translate, formError]);

const {image: receiptImage, thumbnail: receiptThumbnail} =
props.receiptPath && props.receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(props.receiptPath, props.receiptFilename) : {};
const {image: receiptImage, thumbnail: receiptThumbnail} = props.receiptPath && props.receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction) : {};
Copy link
Contributor

Choose a reason for hiding this comment

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

This caused a regression in #29855 , When creating a money request, the receipt image details are not saved in the transaction. Instead, they are stored in the IOU object. As a result, a placeholder is shown instead of the receipt image.


return (
<OptionsSelector
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReportActionItem/MoneyRequestPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ function MoneyRequestPreview(props) {
!_.isEmpty(requestMerchant) && !props.isBillSplit && requestMerchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && requestMerchant !== CONST.TRANSACTION.DEFAULT_MERCHANT;
const shouldShowDescription = !_.isEmpty(description) && !shouldShowMerchant;

const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction.receipt.source, props.transaction.filename || '')] : [];
const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction)] : [];

const getSettledMessage = () => {
if (isExpensifyCardTransaction || isDistanceRequest) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReportActionItem/MoneyRequestView.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should
let receiptURIs;
let hasErrors = false;
if (hasReceipt) {
receiptURIs = ReceiptUtils.getThumbnailAndImageURIs(transaction.receipt.source, transaction.filename);
receiptURIs = ReceiptUtils.getThumbnailAndImageURIs(transaction);
hasErrors = canEdit && TransactionUtils.hasMissingSmartscanFields(transaction);
}

Expand Down
15 changes: 14 additions & 1 deletion src/components/ReportActionItem/ReportActionItemImage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import styles from '../../styles/styles';
import Image from '../Image';
import ThumbnailImage from '../ThumbnailImage';
Expand All @@ -10,6 +11,7 @@ import {ShowContextMenuContext} from '../ShowContextMenuContext';
import Navigation from '../../libs/Navigation/Navigation';
import PressableWithoutFocus from '../Pressable/PressableWithoutFocus';
import useLocalize from '../../hooks/useLocalize';
import EReceiptThumbnail from '../EReceiptThumbnail';

const propTypes = {
/** thumbnail URI for the image */
Expand Down Expand Up @@ -38,7 +40,9 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal}) {
const imageSource = tryResolveUrlFromApiRoot(image || '');
const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || '');

const receiptImageComponent = thumbnail ? (
const isEReceipt = imageSource.startsWith(CONST.ERECEIPT_PATH);
grgia marked this conversation as resolved.
Show resolved Hide resolved

let receiptImageComponent = thumbnail ? (
<ThumbnailImage
previewSourceURL={thumbnailSource}
style={[styles.w100, styles.h100]}
Expand All @@ -52,6 +56,15 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal}) {
/>
);

if (isEReceipt) {
const transactionIDFromURL = imageSource.split(CONST.ERECEIPT_PATH)[1];
receiptImageComponent = (
<View style={[styles.w100, styles.h100]}>
<EReceiptThumbnail transactionID={transactionIDFromURL} />
</View>
);
}

if (enablePreviewModal) {
return (
<ShowContextMenuContext.Consumer>
Expand Down
5 changes: 3 additions & 2 deletions src/components/ReportActionItem/ReportPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ function ReportPreview(props) {
const hasReceipts = transactionsWithReceipts.length > 0;
const isScanning = hasReceipts && ReportUtils.areAllRequestsBeingSmartScanned(props.iouReportID, props.action);
const hasErrors = hasReceipts && ReportUtils.hasMissingSmartscanFields(props.iouReportID);
const lastThreeTransactionsWithReceipts = ReportUtils.getReportPreviewDisplayTransactions(props.action);
const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, ({receipt, filename}) => ReceiptUtils.getThumbnailAndImageURIs(receipt.source, filename || ''));

const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3);
const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, (transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction));

const hasOnlyOneReceiptRequest = numberOfRequests === 1 && hasReceipts;
const previewSubtitle = hasOnlyOneReceiptRequest
Expand Down
3 changes: 2 additions & 1 deletion src/libs/CardUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ function getCardDescription(cardID: number) {
return '';
}
const cardDescriptor = card.state === CONST.EXPENSIFY_CARD.STATE.NOT_ACTIVATED ? Localize.translateLocal('cardTransactions.notActivated') : card.lastFourPAN;
return `${card.bank} - ${cardDescriptor}`;
const result = cardDescriptor ? `${card.bank} - ${cardDescriptor}` : `${card.bank}`;
return result;
grgia marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
17 changes: 14 additions & 3 deletions src/libs/ReceiptUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import ReceiptHTML from '../../assets/images/receipt-html.png';
import ReceiptDoc from '../../assets/images/receipt-doc.png';
import ReceiptGeneric from '../../assets/images/receipt-generic.png';
import ReceiptSVG from '../../assets/images/receipt-svg.png';
import {Transaction} from '../types/onyx';
import ROUTES from '../ROUTES';

type ThumbnailAndImageURI = {
image: ImageSourcePropType | string;
Expand All @@ -20,12 +22,21 @@ type FileNameAndExtension = {
/**
* Grab the appropriate receipt image and thumbnail URIs based on file type
*
* @param path URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg
* @param filename of uploaded image or last part of remote URI
* @param transaction
*/
function getThumbnailAndImageURIs(path: string, filename: string): ThumbnailAndImageURI {
function getThumbnailAndImageURIs(transaction: Transaction): ThumbnailAndImageURI {
// URI to image, i.e. blob:new.expensify.com/9ef3a018-4067-47c6-b29f-5f1bd35f213d or expensify.com/receipts/w_e616108497ef940b7210ec6beb5a462d01a878f4.jpg
const path = transaction?.receipt?.source ?? '';
// filename of uploaded image or last part of remote URI
const filename = transaction?.filename ?? '';
const isReceiptImage = Str.isImage(filename);

const hasEReceipt = transaction?.hasEReceipt;

if (hasEReceipt) {
return {thumbnail: null, image: ROUTES.ERECEIPT.getRoute(transaction.transactionID)};
}

// For local files, we won't have a thumbnail yet
if (isReceiptImage && (path.startsWith('blob:') || path.startsWith('file:'))) {
return {thumbnail: null, image: path};
Expand Down
24 changes: 0 additions & 24 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3756,29 +3756,6 @@ function getParticipantsIDs(report) {
return participants;
}

/**
* Get the last 3 transactions with receipts of an IOU report that will be displayed on the report preview
*
* @param {Object} reportPreviewAction
* @returns {Object}
*/
function getReportPreviewDisplayTransactions(reportPreviewAction) {
const transactionIDs = lodashGet(reportPreviewAction, ['childRecentReceiptTransactionIDs']);
return _.reduce(
_.keys(transactionIDs),
(transactions, transactionID) => {
if (transactionIDs[transactionID] !== null) {
const transaction = TransactionUtils.getTransaction(transactionID);
if (TransactionUtils.hasReceipt(transaction)) {
transactions.push(transaction);
}
}
return transactions;
},
[],
);
}

/**
* Return iou report action display message
*
Expand Down Expand Up @@ -3966,7 +3943,6 @@ export {
canEditMoneyRequest,
buildTransactionThread,
areAllRequestsBeingSmartScanned,
getReportPreviewDisplayTransactions,
getTransactionsWithReceipts,
hasMissingSmartscanFields,
getIOUReportActionDisplayMessage,
Expand Down
16 changes: 8 additions & 8 deletions src/libs/TransactionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,15 @@ function buildOptimisticTransaction(
};
}

/**
* Check if the transaction has an Ereceipt
*/
function hasEreceipt(transaction: Transaction | undefined | null): boolean {
grgia marked this conversation as resolved.
Show resolved Hide resolved
return !!transaction?.hasEReceipt;
}

function hasReceipt(transaction: Transaction | undefined | null): boolean {
return !!transaction?.receipt?.state;
return !!transaction?.receipt?.state || hasEreceipt(transaction);
grgia marked this conversation as resolved.
Show resolved Hide resolved
}

function areRequiredFieldsEmpty(transaction: Transaction): boolean {
Expand Down Expand Up @@ -332,13 +339,6 @@ function hasRoute(transaction: Transaction): boolean {
return !!transaction?.routes?.route0?.geometry?.coordinates;
}

/**
* Check if the transaction has an Ereceipt
*/
function hasEreceipt(transaction: Transaction): boolean {
return !!transaction?.hasEReceipt;
}

/**
* Get the transactions related to a report preview with receipts
* Get the details linked to the IOU reportAction
Expand Down
Loading
Loading