Skip to content

Commit

Permalink
Merge pull request #55942 from Expensify/revert-53849-enabling-receip…
Browse files Browse the repository at this point in the history
…t-drop-inside-confirm-step

[CP Staging] Revert "Enabling Receipt drag and drop inside the confirmation step"

(cherry picked from commit dbc3de5)

(CP triggered by mountiny)
  • Loading branch information
mountiny authored and OSBotify committed Jan 29, 2025
1 parent 5c4b005 commit 87673ed
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 341 deletions.
2 changes: 1 addition & 1 deletion src/components/EReceiptThumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type IconSize = 'x-small' | 'small' | 'medium' | 'large';

type EReceiptThumbnailProps = {
/** TransactionID of the transaction this EReceipt corresponds to. */
transactionID?: string;
transactionID: string;

/** Border radius to be applied on the parent view. */
borderRadius?: number;
Expand Down
4 changes: 1 addition & 3 deletions src/components/MoneyRequestConfirmationListFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import {hasEnabledTags} from '@libs/TagsOptionsListUtils';
import {getTagForDisplay, getTaxAmount, getTaxName, isAmountMissing, isCreatedMissing, shouldShowAttendees as shouldShowAttendeesTransactionUtils} from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
import type {IOUAction, IOUType} from '@src/CONST';
import CONST from '@src/CONST';
import type {IOUAction, IOUType} from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
Expand Down Expand Up @@ -827,7 +827,6 @@ function MoneyRequestConfirmationListFooter({
? receiptThumbnailContent
: shouldShowReceiptEmptyState && (
<ReceiptEmptyState
transactionID={transactionID}
onPress={() => {
if (!transactionID) {
return;
Expand All @@ -837,7 +836,6 @@ function MoneyRequestConfirmationListFooter({
ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()),
);
}}
shouldAllowReceiptDrop
/>
))}
{primaryFields}
Expand Down
113 changes: 3 additions & 110 deletions src/components/ReceiptEmptyState.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,11 @@
import {Str} from 'expensify-common';
import React, {useState} from 'react';
import React from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {setMoneyRequestReceipt} from '@libs/actions/IOU';
import {resizeImageIfNeeded} from '@libs/fileDownload/FileUtils';
import {validateReceipt} from '@libs/ReceiptUtils';
import ReceiptDropUI from '@pages/iou/ReceiptDropUI';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import type {FileObject} from './AttachmentModal';
import ConfirmModal from './ConfirmModal';
import FullScreenLoadingIndicator from './FullscreenLoadingIndicator';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import PDFThumbnail from './PDFThumbnail';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';

type ReceiptEmptyStateProps = {
Expand All @@ -29,85 +18,13 @@ type ReceiptEmptyStateProps = {
disabled?: boolean;

isThumbnail?: boolean;

shouldAllowReceiptDrop?: boolean;

transactionID: string | undefined;
};

// Returns an SVG icon indicating that the user should attach a receipt
function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumbnail = false, shouldAllowReceiptDrop = false, transactionID}: ReceiptEmptyStateProps) {
function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumbnail = false}: ReceiptEmptyStateProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const theme = useTheme();
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState<TranslationPaths>();
const [attachmentInvalidReason, setAttachmentValidReason] = useState<TranslationPaths>();
const [pdfFile, setPdfFile] = useState<null | FileObject>(null);
const [isLoadingReceipt, setIsLoadingReceipt] = useState(false);

/**
* Sets the upload receipt error modal content when an invalid receipt is uploaded
*/
const setUploadReceiptError = (isInvalid: boolean, title: TranslationPaths, reason: TranslationPaths) => {
setIsAttachmentInvalid(isInvalid);
setAttachmentInvalidReasonTitle(title);
setAttachmentValidReason(reason);
setPdfFile(null);
};

const setReceipt = (originalFile: FileObject, isPdfValidated?: boolean) => {
validateReceipt(originalFile).then((result) => {
if (!result.isValid) {
if (result.title && result.reason) {
setUploadReceiptError(true, result.title, result.reason);
}
return;
}

// If we have a pdf file and if it is not validated then set the pdf file for validation and return
if (Str.isPDF(originalFile.name ?? '') && !isPdfValidated) {
setPdfFile(originalFile);
return;
}

// With the image size > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE, we use manipulateAsync to resize the image.
// It takes a long time so we should display a loading indicator while the resize image progresses.
if (Str.isImage(originalFile.name ?? '') && (originalFile?.size ?? 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {
setIsLoadingReceipt(true);
}

resizeImageIfNeeded(originalFile).then((file) => {
setIsLoadingReceipt(false);
const source = URL.createObjectURL(file as Blob);
if (transactionID) {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
setMoneyRequestReceipt(transactionID, source, file.name || '', true);
}
});
});
};

const hideReceiptModal = () => {
setIsAttachmentInvalid(false);
};

const PDFThumbnailView = pdfFile ? (
<PDFThumbnail
style={styles.invisiblePDF}
previewSourceURL={pdfFile.uri ?? ''}
onLoadSuccess={() => {
setPdfFile(null);
setReceipt(pdfFile, true);
}}
onPassword={() => {
setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.protectedPDFNotSupported');
}}
onLoadError={() => {
setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.errorWhileSelectingCorruptedAttachment');
}}
/>
) : null;

const Wrapper = onPress ? PressableWithoutFeedback : View;

Expand All @@ -121,14 +38,11 @@ function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumb
style={[
styles.alignItemsCenter,
styles.justifyContentCenter,
styles.moneyRequestImage,
styles.moneyRequestViewImage,
isThumbnail ? styles.moneyRequestAttachReceiptThumbnail : styles.moneyRequestAttachReceipt,
hasError && styles.borderColorDanger,
]}
>
{isLoadingReceipt && <FullScreenLoadingIndicator />}
{PDFThumbnailView}

<View>
<Icon
fill={theme.border}
Expand All @@ -145,27 +59,6 @@ function ReceiptEmptyState({hasError = false, onPress, disabled = false, isThumb
/>
)}
</View>

{shouldAllowReceiptDrop && !disabled && (
<ReceiptDropUI
onDrop={(e) => {
const file = e?.dataTransfer?.files[0];
if (file) {
file.uri = URL.createObjectURL(file);
setReceipt(file);
}
}}
/>
)}
<ConfirmModal
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
onConfirm={hideReceiptModal}
onCancel={hideReceiptModal}
isVisible={isAttachmentInvalid}
prompt={attachmentInvalidReason ? translate(attachmentInvalidReason) : ''}
confirmText={translate('common.close')}
shouldShowCancelButton={false}
/>
</Wrapper>
);
}
Expand Down
3 changes: 1 addition & 2 deletions src/components/ReceiptImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ function ReceiptImage({
isThumbnail
onPress={onPress}
disabled={!onPress}
transactionID={transactionID}
/>
);
}
Expand All @@ -133,7 +132,7 @@ function ReceiptImage({
return (
<View style={style ?? [styles.w100, styles.h100]}>
<EReceiptThumbnail
transactionID={transactionID}
transactionID={transactionID ?? '-1'}
iconSize={iconSize}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
Expand Down
21 changes: 10 additions & 11 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import * as Expensicons from '@components/Icon/Expensicons';
import MenuItem from '@components/MenuItem';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
Expand All @@ -16,15 +16,14 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import type {ViolationField} from '@hooks/useViolations';
import useViolations from '@hooks/useViolations';
import type {ViolationField} from '@hooks/useViolations';
import {convertToDisplayString} from '@libs/CurrencyUtils';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import {hasEnabledOptions} from '@libs/OptionsListUtils';
import {getTagLists, hasDependentTags, isTaxTrackingEnabled} from '@libs/PolicyUtils';
import {getThumbnailAndImageURIs} from '@libs/ReceiptUtils';
import {getOriginalMessage, isMoneyRequestAction, isPayAction} from '@libs/ReportActionsUtils';
import type {TransactionDetails} from '@libs/ReportUtils';
import {
canEditFieldOfMoneyRequest,
canEditMoneyRequest,
Expand All @@ -40,6 +39,7 @@ import {
isSettled as isSettledReportUtils,
isTrackExpenseReport,
} from '@libs/ReportUtils';
import type {TransactionDetails} from '@libs/ReportUtils';
import {hasEnabledTags} from '@libs/TagsOptionsListUtils';
import {
didReceiptScanSucceed as didReceiptScanSucceedTransactionUtils,
Expand Down Expand Up @@ -70,13 +70,13 @@ import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Report, Transaction, TransactionViolation, ViolationName} from '@src/types/onyx';
import type * as OnyxTypes from '@src/types/onyx';
import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction';
import ReportActionItemImage from './ReportActionItemImage';

type MoneyRequestViewProps = {
/** The report currently being looked at */
report: OnyxEntry<Report>;
report: OnyxEntry<OnyxTypes.Report>;

/** Whether we should display the animated banner above the component */
shouldShowAnimatedBackground: boolean;
Expand All @@ -88,17 +88,17 @@ type MoneyRequestViewProps = {
isFromReviewDuplicates?: boolean;

/** Updated transaction to show in duplicate transaction flow */
updatedTransaction?: OnyxEntry<Transaction>;
updatedTransaction?: OnyxEntry<OnyxTypes.Transaction>;
};

const receiptImageViolationNames: ViolationName[] = [
const receiptImageViolationNames: OnyxTypes.ViolationName[] = [
CONST.VIOLATIONS.RECEIPT_REQUIRED,
CONST.VIOLATIONS.RECEIPT_NOT_SMART_SCANNED,
CONST.VIOLATIONS.CASH_EXPENSE_WITH_NO_RECEIPT,
CONST.VIOLATIONS.SMARTSCAN_FAILED,
];

const receiptFieldViolationNames: ViolationName[] = [CONST.VIOLATIONS.MODIFIED_AMOUNT, CONST.VIOLATIONS.MODIFIED_DATE];
const receiptFieldViolationNames: OnyxTypes.ViolationName[] = [CONST.VIOLATIONS.MODIFIED_AMOUNT, CONST.VIOLATIONS.MODIFIED_DATE];

function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = false, updatedTransaction, isFromReviewDuplicates = false}: MoneyRequestViewProps) {
const styles = useThemeStyles();
Expand Down Expand Up @@ -219,7 +219,7 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals

const {getViolationsForField} = useViolations(transactionViolations ?? [], isReceiptBeingScanned || !isPaidGroupPolicy(report));
const hasViolations = useCallback(
(field: ViolationField, data?: TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string): boolean =>
(field: ViolationField, data?: OnyxTypes.TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string): boolean =>
getViolationsForField(field, data, policyHasDependentTags, tagValue).length > 0,
[getViolationsForField],
);
Expand Down Expand Up @@ -293,7 +293,7 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
const getPendingFieldAction = (fieldPath: TransactionPendingFieldsKey) => (pendingAction ? undefined : transaction?.pendingFields?.[fieldPath]);

const getErrorForField = useCallback(
(field: ViolationField, data?: TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string) => {
(field: ViolationField, data?: OnyxTypes.TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string) => {
// Checks applied when creating a new expense
// NOTE: receipt field can return multiple violations, so we need to handle it separately
const fieldChecks: Partial<Record<ViolationField, {isError: boolean; translationPath: TranslationPaths}>> = {
Expand Down Expand Up @@ -538,7 +538,6 @@ function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = fals
<ReceiptEmptyState
hasError={hasErrors}
disabled={!canEditReceipt}
transactionID={transaction?.transactionID}
onPress={() => {
if (!transaction?.transactionID || !report?.reportID) {
return;
Expand Down
Loading

0 comments on commit 87673ed

Please sign in to comment.