Skip to content

Commit 90cda7c

Browse files
authored
Merge pull request #31467 from dukenv0307/fix/31105
Remove receipt from carousel
2 parents 0e3a005 + 0efb1a5 commit 90cda7c

File tree

5 files changed

+42
-102
lines changed

5 files changed

+42
-102
lines changed

src/components/AttachmentModal.js

+14-12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ const propTypes = {
9090

9191
/** Denotes whether it is a workspace avatar or not */
9292
isWorkspaceAvatar: PropTypes.bool,
93+
94+
/** Whether it is a receipt attachment or not */
95+
isReceiptAttachment: PropTypes.bool,
9396
};
9497

9598
const defaultProps = {
@@ -107,6 +110,7 @@ const defaultProps = {
107110
onModalHide: () => {},
108111
onCarouselAttachmentChange: () => {},
109112
isWorkspaceAvatar: false,
113+
isReceiptAttachment: false,
110114
};
111115

112116
function AttachmentModal(props) {
@@ -118,7 +122,6 @@ function AttachmentModal(props) {
118122
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
119123
const [isDeleteReceiptConfirmModalVisible, setIsDeleteReceiptConfirmModalVisible] = useState(false);
120124
const [isAuthTokenRequired, setIsAuthTokenRequired] = useState(props.isAuthTokenRequired);
121-
const [isAttachmentReceipt, setIsAttachmentReceipt] = useState(null);
122125
const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState('');
123126
const [attachmentInvalidReason, setAttachmentInvalidReason] = useState(null);
124127
const [source, setSource] = useState(props.source);
@@ -154,7 +157,6 @@ function AttachmentModal(props) {
154157
(attachment) => {
155158
setSource(attachment.source);
156159
setFile(attachment.file);
157-
setIsAttachmentReceipt(attachment.isReceipt);
158160
setIsAuthTokenRequired(attachment.isAuthTokenRequired);
159161
onCarouselAttachmentChange(attachment);
160162
},
@@ -357,7 +359,7 @@ function AttachmentModal(props) {
357359
const sourceForAttachmentView = props.source || source;
358360

359361
const threeDotsMenuItems = useMemo(() => {
360-
if (!isAttachmentReceipt || !props.parentReport || !props.parentReportActions) {
362+
if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) {
361363
return [];
362364
}
363365
const menuItems = [];
@@ -392,17 +394,17 @@ function AttachmentModal(props) {
392394
}
393395
return menuItems;
394396
// eslint-disable-next-line react-hooks/exhaustive-deps
395-
}, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]);
397+
}, [props.isReceiptAttachment, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]);
396398

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

408410
return (
@@ -443,7 +445,7 @@ function AttachmentModal(props) {
443445
shouldOverlay
444446
/>
445447
<View style={styles.imageModalImageCenterContainer}>
446-
{!_.isEmpty(props.report) ? (
448+
{!_.isEmpty(props.report) && !props.isReceiptAttachment ? (
447449
<AttachmentCarousel
448450
report={props.report}
449451
onNavigate={onNavigate}
@@ -486,7 +488,7 @@ function AttachmentModal(props) {
486488
)}
487489
</SafeAreaConsumer>
488490
)}
489-
{isAttachmentReceipt && (
491+
{props.isReceiptAttachment && (
490492
<ConfirmModal
491493
title={translate('receipt.deleteReceipt')}
492494
isVisible={isDeleteReceiptConfirmModalVisible}
@@ -499,7 +501,7 @@ function AttachmentModal(props) {
499501
/>
500502
)}
501503
</Modal>
502-
{!isAttachmentReceipt && (
504+
{!props.isReceiptAttachment && (
503505
<ConfirmModal
504506
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
505507
onConfirm={closeConfirmModal}

src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js

+2-29
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import {Parser as HtmlParser} from 'htmlparser2';
2-
import lodashGet from 'lodash/get';
32
import _ from 'underscore';
4-
import * as ReceiptUtils from '@libs/ReceiptUtils';
53
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
6-
import * as TransactionUtils from '@libs/TransactionUtils';
74
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
85
import CONST from '@src/CONST';
96

107
/**
118
* Constructs the initial component state from report actions
129
* @param {Object} parentReportAction
1310
* @param {Object} reportActions
14-
* @param {Object} transaction
1511
* @returns {Array}
1612
*/
17-
function extractAttachmentsFromReport(parentReportAction, reportActions, transaction) {
13+
function extractAttachmentsFromReport(parentReportAction, reportActions) {
1814
const actions = [parentReportAction, ...ReportActionsUtils.getSortedReportActions(_.values(reportActions))];
1915
const attachments = [];
2016

@@ -33,39 +29,16 @@ function extractAttachmentsFromReport(parentReportAction, reportActions, transac
3329
source: tryResolveUrlFromApiRoot(expensifySource || attribs.src),
3430
isAuthTokenRequired: Boolean(expensifySource),
3531
file: {name: attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE]},
36-
isReceipt: false,
3732
hasBeenFlagged: attribs['data-flagged'] === 'true',
3833
});
3934
},
4035
});
4136

4237
_.forEach(actions, (action, key) => {
43-
if (!ReportActionsUtils.shouldReportActionBeVisible(action, key)) {
38+
if (!ReportActionsUtils.shouldReportActionBeVisible(action, key) || ReportActionsUtils.isMoneyRequestAction(action)) {
4439
return;
4540
}
4641

47-
// We're handling receipts differently here because receipt images are not
48-
// part of the report action message, the images are constructed client-side
49-
if (ReportActionsUtils.isMoneyRequestAction(action)) {
50-
const transactionID = lodashGet(action, ['originalMessage', 'IOUTransactionID']);
51-
if (!transactionID) {
52-
return;
53-
}
54-
55-
if (TransactionUtils.hasReceipt(transaction)) {
56-
const {image} = ReceiptUtils.getThumbnailAndImageURIs(transaction);
57-
const isLocalFile = typeof image === 'string' && _.some(CONST.ATTACHMENT_LOCAL_URL_PREFIX, (prefix) => image.startsWith(prefix));
58-
attachments.unshift({
59-
source: tryResolveUrlFromApiRoot(image),
60-
isAuthTokenRequired: !isLocalFile,
61-
file: {name: transaction.filename},
62-
isReceipt: true,
63-
transactionID,
64-
});
65-
return;
66-
}
67-
}
68-
6942
const decision = _.get(action, ['message', 0, 'moderationDecision', 'decision'], '');
7043
const hasBeenFlagged = decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN;
7144
const html = _.get(action, ['message', 0, 'html'], '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`);

src/components/Attachments/AttachmentCarousel/index.js

+3-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import lodashGet from 'lodash/get';
21
import React, {useCallback, useEffect, useRef, useState} from 'react';
32
import {FlatList, Keyboard, PixelRatio, View} from 'react-native';
43
import {withOnyx} from 'react-native-onyx';
@@ -28,7 +27,7 @@ const viewabilityConfig = {
2827
itemVisiblePercentThreshold: 95,
2928
};
3029

31-
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction}) {
30+
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate}) {
3231
const styles = useThemeStyles();
3332
const scrollRef = useRef(null);
3433

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

44-
const compareImage = useCallback(
45-
(attachment) => {
46-
if (attachment.isReceipt && isReceipt) {
47-
return attachment.transactionID === transaction.transactionID;
48-
}
49-
return attachment.source === source;
50-
},
51-
[source, isReceipt, transaction],
52-
);
42+
const compareImage = useCallback((attachment) => attachment.source === source, [source]);
5343

5444
useEffect(() => {
5545
const parentReportAction = parentReportActions[report.parentReportActionID];
56-
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction);
46+
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions);
5747

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

@@ -88,12 +78,10 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source,
8878
// to get the index of the current page
8979
const entry = _.first(viewableItems);
9080
if (!entry) {
91-
setIsReceipt(false);
9281
setActiveSource(null);
9382
return;
9483
}
9584

96-
setIsReceipt(entry.item.isReceipt);
9785
setPage(entry.index);
9886
setActiveSource(entry.item.source);
9987

@@ -241,15 +229,6 @@ export default compose(
241229
canEvict: false,
242230
},
243231
}),
244-
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
245-
withOnyx({
246-
transaction: {
247-
key: ({report, parentReportActions}) => {
248-
const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]);
249-
return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`;
250-
},
251-
},
252-
}),
253232
withLocalize,
254233
withWindowDimensions,
255234
)(AttachmentCarousel);

src/components/Attachments/AttachmentCarousel/index.native.js

+3-24
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import lodashGet from 'lodash/get';
21
import React, {useCallback, useEffect, useRef, useState} from 'react';
32
import {Keyboard, PixelRatio, View} from 'react-native';
43
import {withOnyx} from 'react-native-onyx';
@@ -18,7 +17,7 @@ import extractAttachmentsFromReport from './extractAttachmentsFromReport';
1817
import AttachmentCarouselPager from './Pager';
1918
import useCarouselArrows from './useCarouselArrows';
2019

21-
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction, onClose}) {
20+
function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, onClose}) {
2221
const styles = useThemeStyles();
2322
const pagerRef = useRef(null);
2423

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

33-
const compareImage = useCallback(
34-
(attachment) => {
35-
if (attachment.isReceipt && isReceipt) {
36-
return attachment.transactionID === transaction.transactionID;
37-
}
38-
return attachment.source === source;
39-
},
40-
[source, isReceipt, transaction],
41-
);
31+
const compareImage = useCallback((attachment) => attachment.source === source, [source]);
4232

4333
useEffect(() => {
4434
const parentReportAction = parentReportActions[report.parentReportActionID];
45-
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction);
35+
const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions);
4636

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

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

7969
setPage(newPageIndex);
80-
setIsReceipt(item.isReceipt);
8170
setActiveSource(item.source);
82-
8371
onNavigate(item);
8472
},
8573
[setShouldShowArrows, attachments, onNavigate],
@@ -186,14 +174,5 @@ export default compose(
186174
canEvict: false,
187175
},
188176
}),
189-
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
190-
withOnyx({
191-
transaction: {
192-
key: ({report, parentReportActions}) => {
193-
const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]);
194-
return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`;
195-
},
196-
},
197-
}),
198177
withLocalize,
199178
)(AttachmentCarousel);

src/components/ReportActionItem/ReportActionItemImage.js

+20-13
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@ import PropTypes from 'prop-types';
22
import React from 'react';
33
import {View} from 'react-native';
44
import _ from 'underscore';
5+
import AttachmentModal from '@components/AttachmentModal';
56
import EReceiptThumbnail from '@components/EReceiptThumbnail';
67
import Image from '@components/Image';
78
import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
89
import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
910
import ThumbnailImage from '@components/ThumbnailImage';
1011
import transactionPropTypes from '@components/transactionPropTypes';
1112
import useLocalize from '@hooks/useLocalize';
12-
import Navigation from '@libs/Navigation/Navigation';
1313
import * as TransactionUtils from '@libs/TransactionUtils';
1414
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
1515
import useThemeStyles from '@styles/useThemeStyles';
1616
import CONST from '@src/CONST';
17-
import ROUTES from '@src/ROUTES';
1817

1918
const propTypes = {
2019
/** thumbnail URI for the image */
@@ -47,11 +46,11 @@ const defaultProps = {
4746
*/
4847

4948
function ReportActionItemImage({thumbnail, image, enablePreviewModal, transaction, isLocalFile}) {
50-
const styles = useThemeStyles();
5149
const {translate} = useLocalize();
5250
const imageSource = tryResolveUrlFromApiRoot(image || '');
5351
const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || '');
5452
const isEReceipt = !_.isEmpty(transaction) && TransactionUtils.hasEReceipt(transaction);
53+
const styles = useThemeStyles();
5554

5655
let receiptImageComponent;
5756

@@ -83,17 +82,25 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio
8382
return (
8483
<ShowContextMenuContext.Consumer>
8584
{({report}) => (
86-
<PressableWithoutFocus
87-
style={[styles.noOutline, styles.w100, styles.h100]}
88-
onPress={() => {
89-
const route = ROUTES.REPORT_ATTACHMENTS.getRoute(report.reportID, imageSource);
90-
Navigation.navigate(route);
91-
}}
92-
role={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
93-
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
85+
<AttachmentModal
86+
headerTitle="Receipt"
87+
source={imageSource}
88+
isAuthTokenRequired={!isLocalFile}
89+
report={report}
90+
isReceiptAttachment
91+
allowToDownload
9492
>
95-
{receiptImageComponent}
96-
</PressableWithoutFocus>
93+
{({show}) => (
94+
<PressableWithoutFocus
95+
style={[styles.noOutline, styles.w100, styles.h100]}
96+
onPress={show}
97+
role={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
98+
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
99+
>
100+
{receiptImageComponent}
101+
</PressableWithoutFocus>
102+
)}
103+
</AttachmentModal>
97104
)}
98105
</ShowContextMenuContext.Consumer>
99106
);

0 commit comments

Comments
 (0)