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} /> )}