diff --git a/src/components/ReceiptEmptyState.tsx b/src/components/ReceiptEmptyState.tsx
index 2af8959c9a591..f0de5d901b184 100644
--- a/src/components/ReceiptEmptyState.tsx
+++ b/src/components/ReceiptEmptyState.tsx
@@ -1,11 +1,15 @@
import React, {useEffect, useRef} from 'react';
import {View} from 'react-native';
import type {StyleProp, ViewStyle} from 'react-native';
+import useFilesValidation from '@hooks/useFilesValidation';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import type {FileObject} from '@src/types/utils/Attachment';
+import AttachmentPicker from './AttachmentPicker';
import Icon from './Icon';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import ReceiptAlternativeMethods from './ReceiptAlternativeMethods';
@@ -34,6 +38,9 @@ type ReceiptEmptyStateProps = {
/** Whether it's displayed in Wide RHP */
isDisplayedInWideRHP?: boolean;
+
+ /** Callback to be called when a receipt is selected */
+ onReplaceReceipt?: (files: FileObject[]) => void;
};
// Returns an SVG icon indicating that the user should attach a receipt
@@ -46,12 +53,14 @@ function ReceiptEmptyState({
style,
onLoad,
isDisplayedInWideRHP = false,
+ onReplaceReceipt = () => {},
}: ReceiptEmptyStateProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const theme = useTheme();
const isLoadedRef = useRef(false);
const icons = useMemoizedLazyExpensifyIcons(['ReceiptPlaceholderPlus', 'Receipt']);
+ const {validateFiles, PDFValidationComponent, ErrorModal} = useFilesValidation(onReplaceReceipt);
const Wrapper = onPress ? PressableWithoutFeedback : View;
const containerStyle = [
@@ -73,42 +82,56 @@ function ReceiptEmptyState({
}, [onLoad]);
return (
-
-
-
-
-
- {!isThumbnail && (
-
- )}
+
+ {({openPicker}) => (
+ {
+ if (isDisplayedInWideRHP) {
+ openPicker({
+ onPicked: validateFiles,
+ });
+ return;
+ }
+ onPress?.();
+ }}
+ disabled={disabled}
+ disabledStyle={styles.cursorDefault}
+ style={containerStyle}
+ >
+ {PDFValidationComponent}
+ {ErrorModal}
+
+
+
+
+ {!isThumbnail && (
+
+ )}
+
+ {!isThumbnail && isDisplayedInWideRHP && (
+ <>
+ {translate('receipt.addAReceipt.phrase1')}
+ {translate('receipt.addAReceipt.phrase2')}
+ >
+ )}
+
- {!isThumbnail && isDisplayedInWideRHP && (
- <>
- {translate('receipt.addAReceipt.phrase1')}
- {translate('receipt.addAReceipt.phrase2')}
- >
- )}
-
-
- {isDisplayedInWideRHP && !disabled && }
-
+ {isDisplayedInWideRHP && !disabled && }
+
+ )}
+
);
}
diff --git a/src/components/ReportActionItem/MoneyRequestReceiptView.tsx b/src/components/ReportActionItem/MoneyRequestReceiptView.tsx
index a501a95b3e107..19a14dfe53a79 100644
--- a/src/components/ReportActionItem/MoneyRequestReceiptView.tsx
+++ b/src/components/ReportActionItem/MoneyRequestReceiptView.tsx
@@ -38,7 +38,7 @@ import {
} from '@libs/TransactionUtils';
import ViolationsUtils, {filterReceiptViolations} from '@libs/Violations/ViolationsUtils';
import Navigation from '@navigation/Navigation';
-import {cleanUpMoneyRequest} from '@userActions/IOU';
+import {cleanUpMoneyRequest, replaceReceipt} from '@userActions/IOU';
import {navigateToConciergeChatAndDeleteReport} from '@userActions/Report';
import {clearAllRelatedReportActionErrors} from '@userActions/ReportActions';
import {clearError, getLastModifiedExpense, revert} from '@userActions/Transaction';
@@ -47,6 +47,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction';
+import type {FileObject} from '@src/types/utils/Attachment';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import ReportActionItemImage from './ReportActionItemImage';
@@ -123,6 +124,7 @@ function MoneyRequestReceiptView({
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(linkedTransactionID)}`, {canBeMissing: true});
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${moneyRequestReport?.policyID}`, {canBeMissing: true});
+ const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${moneyRequestReport?.policyID}`, {canBeMissing: true});
const transactionViolations = useTransactionViolations(transaction?.transactionID);
const isDistanceRequest = isDistanceRequestTransactionUtils(transaction);
@@ -276,6 +278,20 @@ function MoneyRequestReceiptView({
);
+ const onReplaceReceipt = (files: FileObject[]) => {
+ if (files.length === 0) {
+ return;
+ }
+
+ const file = files.at(0);
+
+ if (!file || !linkedTransactionID) {
+ return;
+ }
+ const source = URL.createObjectURL(file as Blob);
+ replaceReceipt({transactionID: linkedTransactionID, file: file as File, source, transactionPolicy: policy, transactionPolicyCategories: policyCategories});
+ };
+
// For empty receipt should be fullHeight
// For the rest, expand to match the content
return (
@@ -308,6 +324,7 @@ function MoneyRequestReceiptView({
isInMoneyRequestView
style={receiptStyle}
isDisplayedInWideRHP={isDisplayedInWideRHP}
+ onReplaceReceipt={onReplaceReceipt}
/>
)}