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

[CP Staging] Manually revert "Merge pull request #31467 from dukenv0307/fix/31105" #32516

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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,17 +1,21 @@
import {Parser as HtmlParser} from 'htmlparser2';
import lodashGet from 'lodash/get';
import _ from 'underscore';
import * as FileUtils from '@libs/fileDownload/FileUtils';
import * as ReceiptUtils from '@libs/ReceiptUtils';
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 @@ -28,20 +32,43 @@ function extractAttachmentsFromReport(parentReportAction, reportActions) {
// By iterating actions in chronological order and prepending each attachment
// we ensure correct order of attachments even across actions with multiple attachments.
attachments.unshift({
source,
reportActionID: attribs['data-id'],
source,
isAuthTokenRequired: Boolean(expensifySource),
file: {name: fileName},
isReceipt: false,
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
Loading