Skip to content

Commit

Permalink
Merge pull request #32516 from Expensify/neil-fix-distance-eReceipt
Browse files Browse the repository at this point in the history
[CP Staging] Manually revert "Merge pull request #31467 from dukenv0307/fix/31105"

(cherry picked from commit 62ef87a)
  • Loading branch information
neil-marcellini authored and OSBotify committed Dec 5, 2023
1 parent 5985d73 commit d184851
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 42 deletions.
26 changes: 12 additions & 14 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@ const propTypes = {

/** Denotes whether it is a workspace avatar or not */
isWorkspaceAvatar: PropTypes.bool,

/** Whether it is a receipt attachment or not */
isReceiptAttachment: PropTypes.bool,
};

const defaultProps = {
Expand All @@ -110,7 +107,6 @@ const defaultProps = {
onModalHide: () => {},
onCarouselAttachmentChange: () => {},
isWorkspaceAvatar: false,
isReceiptAttachment: false,
};

function AttachmentModal(props) {
Expand All @@ -122,6 +118,7 @@ function AttachmentModal(props) {
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
const [isDeleteReceiptConfirmModalVisible, setIsDeleteReceiptConfirmModalVisible] = useState(false);
const [isAuthTokenRequired, setIsAuthTokenRequired] = useState(props.isAuthTokenRequired);
const [isAttachmentReceipt, setIsAttachmentReceipt] = useState(null);
const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState('');
const [attachmentInvalidReason, setAttachmentInvalidReason] = useState(null);
const [source, setSource] = useState(props.source);
Expand Down Expand Up @@ -157,6 +154,7 @@ function AttachmentModal(props) {
(attachment) => {
setSource(attachment.source);
setFile(attachment.file);
setIsAttachmentReceipt(attachment.isReceipt);
setIsAuthTokenRequired(attachment.isAuthTokenRequired);
onCarouselAttachmentChange(attachment);
},
Expand Down Expand Up @@ -359,7 +357,7 @@ function AttachmentModal(props) {
const sourceForAttachmentView = props.source || source;

const threeDotsMenuItems = useMemo(() => {
if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) {
if (!isAttachmentReceipt || !props.parentReport || !props.parentReportActions) {
return [];
}
const menuItems = [];
Expand Down Expand Up @@ -394,17 +392,17 @@ function AttachmentModal(props) {
}
return menuItems;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.isReceiptAttachment, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]);
}, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]);

// There are a few things that shouldn't be set until we absolutely know if the file is a receipt or an attachment.
// props.isReceiptAttachment will be null until its certain what the file is, in which case it will then be true|false.
// isAttachmentReceipt will be null until its certain what the file is, in which case it will then be true|false.
let headerTitle = props.headerTitle;
let shouldShowDownloadButton = false;
let shouldShowThreeDotsButton = false;
if (!_.isNull(props.isReceiptAttachment)) {
headerTitle = translate(props.isReceiptAttachment ? 'common.receipt' : 'common.attachment');
shouldShowDownloadButton = props.allowDownload && isDownloadButtonReadyToBeShown && !props.isReceiptAttachment && !isOffline;
shouldShowThreeDotsButton = props.isReceiptAttachment && isModalOpen;
if (!_.isNull(isAttachmentReceipt)) {
headerTitle = translate(isAttachmentReceipt ? 'common.receipt' : 'common.attachment');
shouldShowDownloadButton = props.allowDownload && isDownloadButtonReadyToBeShown && !isAttachmentReceipt && !isOffline;
shouldShowThreeDotsButton = isAttachmentReceipt && isModalOpen;
}

return (
Expand Down Expand Up @@ -445,7 +443,7 @@ function AttachmentModal(props) {
shouldOverlay
/>
<View style={styles.imageModalImageCenterContainer}>
{!_.isEmpty(props.report) && !props.isReceiptAttachment ? (
{!_.isEmpty(props.report) ? (
<AttachmentCarousel
report={props.report}
onNavigate={onNavigate}
Expand Down Expand Up @@ -488,7 +486,7 @@ function AttachmentModal(props) {
)}
</SafeAreaConsumer>
)}
{props.isReceiptAttachment && (
{isAttachmentReceipt && (
<ConfirmModal
title={translate('receipt.deleteReceipt')}
isVisible={isDeleteReceiptConfirmModalVisible}
Expand All @@ -501,7 +499,7 @@ function AttachmentModal(props) {
/>
)}
</Modal>
{!props.isReceiptAttachment && (
{!isAttachmentReceipt && (
<ConfirmModal
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
onConfirm={closeConfirmModal}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import {Parser as HtmlParser} from 'htmlparser2';
import lodashGet from 'lodash/get';
import _ from 'underscore';
<<<<<<< HEAD
=======
import * as FileUtils from '@libs/fileDownload/FileUtils';
import * as ReceiptUtils from '@libs/ReceiptUtils';
>>>>>>> 62ef87a (Merge pull request #32516 from Expensify/neil-fix-distance-eReceipt)
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import CONST from '@src/CONST';

/**
* Constructs the initial component state from report actions
* @param {Object} parentReportAction
* @param {Object} reportActions
* @param {Object} transaction
* @returns {Array}
*/
function extractAttachmentsFromReport(parentReportAction, reportActions) {
function extractAttachmentsFromReport(parentReportAction, reportActions, transaction) {
const actions = [parentReportAction, ...ReportActionsUtils.getSortedReportActions(_.values(reportActions))];
const attachments = [];

Expand All @@ -26,19 +34,48 @@ function extractAttachmentsFromReport(parentReportAction, reportActions) {
// we ensure correct order of attachments even across actions with multiple attachments.
attachments.unshift({
reportActionID: attribs['data-id'],
<<<<<<< HEAD
source: tryResolveUrlFromApiRoot(expensifySource || attribs.src),
isAuthTokenRequired: Boolean(expensifySource),
file: {name: attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE]},
=======
source,
isAuthTokenRequired: Boolean(expensifySource),
file: {name: fileName},
isReceipt: false,
>>>>>>> 62ef87a (Merge pull request #32516 from Expensify/neil-fix-distance-eReceipt)
hasBeenFlagged: attribs['data-flagged'] === 'true',
});
},
});

_.forEach(actions, (action, key) => {
if (!ReportActionsUtils.shouldReportActionBeVisible(action, key) || ReportActionsUtils.isMoneyRequestAction(action)) {
if (!ReportActionsUtils.shouldReportActionBeVisible(action, key)) {
return;
}

// We're handling receipts differently here because receipt images are not
// part of the report action message, the images are constructed client-side
if (ReportActionsUtils.isMoneyRequestAction(action)) {
const transactionID = lodashGet(action, ['originalMessage', 'IOUTransactionID']);
if (!transactionID) {
return;
}

if (TransactionUtils.hasReceipt(transaction)) {
const {image} = ReceiptUtils.getThumbnailAndImageURIs(transaction);
const isLocalFile = typeof image === 'string' && _.some(CONST.ATTACHMENT_LOCAL_URL_PREFIX, (prefix) => image.startsWith(prefix));
attachments.unshift({
source: tryResolveUrlFromApiRoot(image),
isAuthTokenRequired: !isLocalFile,
file: {name: transaction.filename},
isReceipt: true,
transactionID,
});
return;
}
}

const decision = _.get(action, ['message', 0, 'moderationDecision', 'decision'], '');
const hasBeenFlagged = decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN;
const html = _.get(action, ['message', 0, 'html'], '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`);
Expand Down
27 changes: 24 additions & 3 deletions src/components/Attachments/AttachmentCarousel/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import lodashGet from 'lodash/get';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {FlatList, Keyboard, PixelRatio, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -27,7 +28,7 @@ const viewabilityConfig = {
itemVisiblePercentThreshold: 95,
};

function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate}) {
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction}) {
const styles = useThemeStyles();
const scrollRef = useRef(null);

Expand All @@ -38,12 +39,21 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source,
const [attachments, setAttachments] = useState([]);
const [activeSource, setActiveSource] = useState(source);
const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows();
const [isReceipt, setIsReceipt] = useState(false);

const compareImage = useCallback((attachment) => attachment.source === source, [source]);
const compareImage = useCallback(
(attachment) => {
if (attachment.isReceipt && isReceipt) {
return attachment.transactionID === transaction.transactionID;
}
return attachment.source === source;
},
[source, isReceipt, transaction],
);

useEffect(() => {
const parentReportAction = parentReportActions[report.parentReportActionID];
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions);
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction);

const initialPage = _.findIndex(attachmentsFromReport, compareImage);

Expand Down Expand Up @@ -78,10 +88,12 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source,
// to get the index of the current page
const entry = _.first(viewableItems);
if (!entry) {
setIsReceipt(false);
setActiveSource(null);
return;
}

setIsReceipt(entry.item.isReceipt);
setPage(entry.index);
setActiveSource(entry.item.source);

Expand Down Expand Up @@ -229,6 +241,15 @@ export default compose(
canEvict: false,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
transaction: {
key: ({report, parentReportActions}) => {
const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]);
return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`;
},
},
}),
withLocalize,
withWindowDimensions,
)(AttachmentCarousel);
27 changes: 24 additions & 3 deletions src/components/Attachments/AttachmentCarousel/index.native.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import lodashGet from 'lodash/get';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {Keyboard, PixelRatio, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
Expand All @@ -17,7 +18,7 @@ import extractAttachmentsFromReport from './extractAttachmentsFromReport';
import AttachmentCarouselPager from './Pager';
import useCarouselArrows from './useCarouselArrows';

function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, onClose}) {
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction, onClose}) {
const styles = useThemeStyles();
const pagerRef = useRef(null);

Expand All @@ -27,12 +28,21 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source,
const [activeSource, setActiveSource] = useState(source);
const [isPinchGestureRunning, setIsPinchGestureRunning] = useState(true);
const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows();
const [isReceipt, setIsReceipt] = useState(false);

const compareImage = useCallback((attachment) => attachment.source === source, [source]);
const compareImage = useCallback(
(attachment) => {
if (attachment.isReceipt && isReceipt) {
return attachment.transactionID === transaction.transactionID;
}
return attachment.source === source;
},
[source, isReceipt, transaction],
);

useEffect(() => {
const parentReportAction = parentReportActions[report.parentReportActionID];
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions);
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction);

const initialPage = _.findIndex(attachmentsFromReport, compareImage);

Expand Down Expand Up @@ -67,7 +77,9 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source,
const item = attachments[newPageIndex];

setPage(newPageIndex);
setIsReceipt(item.isReceipt);
setActiveSource(item.source);

onNavigate(item);
},
[setShouldShowArrows, attachments, onNavigate],
Expand Down Expand Up @@ -174,5 +186,14 @@ export default compose(
canEvict: false,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
transaction: {
key: ({report, parentReportActions}) => {
const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]);
return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`;
},
},
}),
withLocalize,
)(AttachmentCarousel);
33 changes: 13 additions & 20 deletions src/components/ReportActionItem/ReportActionItemImage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import AttachmentModal from '@components/AttachmentModal';
import EReceiptThumbnail from '@components/EReceiptThumbnail';
import Image from '@components/Image';
import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
import ThumbnailImage from '@components/ThumbnailImage';
import transactionPropTypes from '@components/transactionPropTypes';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import useThemeStyles from '@styles/useThemeStyles';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

const propTypes = {
/** thumbnail URI for the image */
Expand Down Expand Up @@ -46,11 +47,11 @@ const defaultProps = {
*/

function ReportActionItemImage({thumbnail, image, enablePreviewModal, transaction, isLocalFile}) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const imageSource = tryResolveUrlFromApiRoot(image || '');
const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || '');
const isEReceipt = !_.isEmpty(transaction) && TransactionUtils.hasEReceipt(transaction);
const styles = useThemeStyles();

let receiptImageComponent;

Expand Down Expand Up @@ -82,25 +83,17 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio
return (
<ShowContextMenuContext.Consumer>
{({report}) => (
<AttachmentModal
headerTitle="Receipt"
source={imageSource}
isAuthTokenRequired={!isLocalFile}
report={report}
isReceiptAttachment
allowToDownload
<PressableWithoutFocus
style={[styles.noOutline, styles.w100, styles.h100]}
onPress={() => {
const route = ROUTES.REPORT_ATTACHMENTS.getRoute(report.reportID, imageSource);
Navigation.navigate(route);
}}
role={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
>
{({show}) => (
<PressableWithoutFocus
style={[styles.noOutline, styles.w100, styles.h100]}
onPress={show}
role={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
>
{receiptImageComponent}
</PressableWithoutFocus>
)}
</AttachmentModal>
{receiptImageComponent}
</PressableWithoutFocus>
)}
</ShowContextMenuContext.Consumer>
);
Expand Down

0 comments on commit d184851

Please sign in to comment.