From 1fc9a0dfcd2965d7c8a0b4b784887870d1c72c84 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 21 May 2025 20:58:13 +0200 Subject: [PATCH 01/25] refactor: remove the consumer from DropZoneUI --- src/components/DropZoneUI.tsx | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/components/DropZoneUI.tsx b/src/components/DropZoneUI.tsx index e20405499793..4e69e09c4dc0 100644 --- a/src/components/DropZoneUI.tsx +++ b/src/components/DropZoneUI.tsx @@ -3,14 +3,10 @@ import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; import type IconAsset from '@src/types/utils/IconAsset'; -import DragAndDropConsumer from './DragAndDrop/Consumer'; import Icon from './Icon'; import Text from './Text'; type DropZoneUIProps = { - /** Callback to execute when a file is dropped. */ - onDrop: (event: DragEvent) => void; - /** Icon to display in the drop zone */ icon: IconAsset; @@ -27,27 +23,25 @@ type DropZoneUIProps = { dropInnerWrapperStyles?: StyleProp; }; -function DropZoneUI({onDrop, icon, dropTitle, dropStyles, dropTextStyles, dropInnerWrapperStyles}: DropZoneUIProps) { +function DropZoneUI({icon, dropTitle, dropStyles, dropTextStyles, dropInnerWrapperStyles}: DropZoneUIProps) { const styles = useThemeStyles(); return ( - - - - {/* TODO: display dropInnerWrapper styles only when hovered over - will be done in Stage 4 (two zones) */} - - - - - {dropTitle} + + + {/* TODO: display dropInnerWrapper styles only when hovered over - will be done in Stage 4 (two zones) */} + + + + {dropTitle} - + ); } From dab3b748078bd81c0a3a68bc70e6da15129af770 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 22 May 2025 21:03:33 +0200 Subject: [PATCH 02/25] feat: create dual dropzone, refactor the hook --- src/components/DragAndDrop/Consumer/index.tsx | 3 + src/components/DragAndDrop/Consumer/types.ts | 2 +- src/components/{ => DropZone}/DropZoneUI.tsx | 21 +++++-- src/components/DropZone/DropZoneWrapper.tsx | 39 ++++++++++++ src/components/DropZone/DualDropZone.tsx | 59 +++++++++++++++++++ src/hooks/useDragAndDrop/index.ts | 20 ++++++- src/hooks/useDragAndDrop/types.ts | 2 + src/pages/Search/SearchPage.tsx | 2 +- .../ReportActionCompose.tsx | 14 ++--- .../step/IOURequestStepConfirmation.tsx | 21 ++++--- .../request/step/IOURequestStepScan/index.tsx | 31 +++++++--- src/styles/index.ts | 1 - 12 files changed, 177 insertions(+), 38 deletions(-) rename src/components/{ => DropZone}/DropZoneUI.tsx (64%) create mode 100644 src/components/DropZone/DropZoneWrapper.tsx create mode 100644 src/components/DropZone/DualDropZone.tsx diff --git a/src/components/DragAndDrop/Consumer/index.tsx b/src/components/DragAndDrop/Consumer/index.tsx index 7cd557608450..0b05e7d6b453 100644 --- a/src/components/DragAndDrop/Consumer/index.tsx +++ b/src/components/DragAndDrop/Consumer/index.tsx @@ -7,6 +7,9 @@ function DragAndDropConsumer({children, onDrop}: DragAndDropConsumerProps) { const {isDraggingOver, setOnDropHandler, dropZoneID} = useContext(DragAndDropContext); useEffect(() => { + if (!onDrop) { + return; + } setOnDropHandler?.(onDrop); }, [onDrop, setOnDropHandler]); diff --git a/src/components/DragAndDrop/Consumer/types.ts b/src/components/DragAndDrop/Consumer/types.ts index 03bdee3f23d8..57d134849d74 100644 --- a/src/components/DragAndDrop/Consumer/types.ts +++ b/src/components/DragAndDrop/Consumer/types.ts @@ -5,7 +5,7 @@ type DragAndDropConsumerProps = { children: ReactNode; /** Function to execute when an item is dropped in the drop zone. */ - onDrop: (event: DragEvent) => void; + onDrop?: (event: DragEvent) => void; }; export default DragAndDropConsumerProps; diff --git a/src/components/DropZoneUI.tsx b/src/components/DropZone/DropZoneUI.tsx similarity index 64% rename from src/components/DropZoneUI.tsx rename to src/components/DropZone/DropZoneUI.tsx index 4e69e09c4dc0..cdf31197f8dd 100644 --- a/src/components/DropZoneUI.tsx +++ b/src/components/DropZone/DropZoneUI.tsx @@ -1,10 +1,10 @@ import React from 'react'; import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import {View} from 'react-native'; +import Icon from '@components/Icon'; +import Text from '@components/Text'; import useThemeStyles from '@hooks/useThemeStyles'; import type IconAsset from '@src/types/utils/IconAsset'; -import Icon from './Icon'; -import Text from './Text'; type DropZoneUIProps = { /** Icon to display in the drop zone */ @@ -21,16 +21,25 @@ type DropZoneUIProps = { /** Custom styles for the inner wrapper of the drop zone */ dropInnerWrapperStyles?: StyleProp; + + /** Whether the drop zone is currently being dragged over */ + isDraggingOver: boolean; }; -function DropZoneUI({icon, dropTitle, dropStyles, dropTextStyles, dropInnerWrapperStyles}: DropZoneUIProps) { +function DropZoneUI({isDraggingOver, icon, dropTitle, dropStyles, dropTextStyles, dropInnerWrapperStyles}: DropZoneUIProps) { const styles = useThemeStyles(); return ( - + - {/* TODO: display dropInnerWrapper styles only when hovered over - will be done in Stage 4 (two zones) */} - + void; + + /** Function to render the children */ + children: React.FC<{isDraggingOver: boolean}>; +}; + +function DropZoneWrapper({onDrop, children}: DropZoneWrapperProps) { + const styles = useThemeStyles(); + const dropZone = useRef(null); + + const {isDraggingOver} = useDragAndDrop({ + shouldAcceptDrop: (event) => !!event.dataTransfer?.types.some((type) => type === 'Files'), + onDrop, + shouldPropagate: false, + shouldHandleDragEvent: false, + dropZone: htmlDivElementRef(dropZone), + }); + + return ( + + {children({isDraggingOver})} + + ); +} + +export default DropZoneWrapper; diff --git a/src/components/DropZone/DualDropZone.tsx b/src/components/DropZone/DualDropZone.tsx new file mode 100644 index 000000000000..1cefdd68be50 --- /dev/null +++ b/src/components/DropZone/DualDropZone.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import {View} from 'react-native'; +import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; +import * as Expensicons from '@components/Icon/Expensicons'; +import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useThemeStyles from '@hooks/useThemeStyles'; +import DropZoneUI from './DropZoneUI'; +import DropZoneWrapper from './DropZoneWrapper'; + +type DropZoneProps = { + /** Whether the user is editing */ + isEditing: boolean; + + /** Callback to execute when a file is dropped */ + onAttachmentDrop: (event: DragEvent) => void; + + /** Callback to execute when a file is dropped */ + onReceiptDrop: (event: DragEvent) => void; +}; + +function DualDropZone({isEditing, onAttachmentDrop, onReceiptDrop}: DropZoneProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); + + return ( + + + + {({isDraggingOver}) => ( + + )} + + + {({isDraggingOver}) => ( + + )} + + + + ); +} + +export default DualDropZone; diff --git a/src/hooks/useDragAndDrop/index.ts b/src/hooks/useDragAndDrop/index.ts index b278039ee020..c009488f391b 100644 --- a/src/hooks/useDragAndDrop/index.ts +++ b/src/hooks/useDragAndDrop/index.ts @@ -13,7 +13,15 @@ const DROP_EVENT = 'drop'; /** * @param dropZone – ref to the dropZone component */ -const useDragAndDrop: UseDragAndDrop = ({dropZone, onDrop = () => {}, shouldAllowDrop = true, isDisabled = false, shouldAcceptDrop = () => true}) => { +const useDragAndDrop: UseDragAndDrop = ({ + dropZone, + onDrop = () => {}, + shouldAllowDrop = true, + isDisabled = false, + shouldAcceptDrop = () => true, + shouldHandleDragEvent = true, + shouldPropagate = true, +}) => { const isFocused = useIsFocused(); const [isDraggingOver, setIsDraggingOver] = useState(false); const {close: closePopover} = useContext(PopoverContext); @@ -29,6 +37,10 @@ const useDragAndDrop: UseDragAndDrop = ({dropZone, onDrop = () => {}, shouldAllo const handleDragEvent = useCallback( (event: DragEvent) => { + if (!shouldHandleDragEvent) { + return; + } + const shouldAcceptThisDrop = shouldAllowDrop && shouldAcceptDrop(event); if (shouldAcceptThisDrop && event.type === DRAG_ENTER_EVENT) { @@ -44,7 +56,7 @@ const useDragAndDrop: UseDragAndDrop = ({dropZone, onDrop = () => {}, shouldAllo event.dataTransfer.effectAllowed = effect; } }, - [shouldAllowDrop, shouldAcceptDrop, closePopover], + [shouldHandleDragEvent, shouldAllowDrop, shouldAcceptDrop, closePopover], ); /** @@ -57,7 +69,9 @@ const useDragAndDrop: UseDragAndDrop = ({dropZone, onDrop = () => {}, shouldAllo } event.preventDefault(); - event.stopPropagation(); + if (shouldPropagate) { + event.stopPropagation(); + } switch (event.type) { case DRAG_OVER_EVENT: diff --git a/src/hooks/useDragAndDrop/types.ts b/src/hooks/useDragAndDrop/types.ts index 78859783ee36..19fccfd60999 100644 --- a/src/hooks/useDragAndDrop/types.ts +++ b/src/hooks/useDragAndDrop/types.ts @@ -4,6 +4,8 @@ type DragAndDropParams = { shouldAllowDrop?: boolean; isDisabled?: boolean; shouldAcceptDrop?: (event: DragEvent) => boolean; + shouldPropagate?: boolean; + shouldHandleDragEvent?: boolean; }; type DragAndDropResult = { diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index b7a5be57f772..1032631f7ed0 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -7,7 +7,7 @@ import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import DecisionModal from '@components/DecisionModal'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; -import DropZoneUI from '@components/DropZoneUI'; +import DropZoneUI from '@components/DropZone/DropZoneUI'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import * as Expensicons from '@components/Icon/Expensicons'; import PDFThumbnail from '@components/PDFThumbnail'; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 91c34d0d063a..080047f1c492 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -9,10 +9,9 @@ import {runOnUI, useSharedValue} from 'react-native-reanimated'; import type {Emoji} from '@assets/emojis/types'; import type {FileObject} from '@components/AttachmentModal'; import AttachmentModal from '@components/AttachmentModal'; -import DropZoneUI from '@components/DropZoneUI'; +import DualDropZone from '@components/DropZone/DualDropZone'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; import ExceededCommentLength from '@components/ExceededCommentLength'; -import * as Expensicons from '@components/Icon/Expensicons'; import ImportedStateIndicator from '@components/ImportedStateIndicator'; import type {Mention} from '@components/MentionSuggestions'; import OfflineIndicator from '@components/OfflineIndicator'; @@ -488,8 +487,9 @@ function ReportActionCompose({ /> {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} {canUseMultiFilesDragAndDrop ? ( - { + { if (isAttachmentPreviewActive) { return; } @@ -499,11 +499,7 @@ function ReportActionCompose({ displayFileInModal(data); } }} - icon={Expensicons.MessageInABottle} - dropTitle={translate('dropzone.addAttachments')} - dropStyles={styles.attachmentDropOverlay} - dropTextStyles={styles.attachmentDropText} - dropInnerWrapperStyles={styles.attachmentDropInnerWrapper} + onReceiptDrop={() => {}} /> ) : ( { const file = e?.dataTransfer?.files[0]; if (file) { @@ -1027,12 +1028,16 @@ function IOURequestStepConfirmation({ setReceiptOnDrop(file); } }} - icon={Expensicons.ReplaceReceipt} - dropStyles={styles.receiptDropOverlay} - dropTitle={translate('dropzone.replaceReceipt')} - dropTextStyles={styles.receiptDropText} - dropInnerWrapperStyles={styles.receiptDropInnerWrapper} - /> + > + + ) : ( { diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 351af8bda97f..d38da3cf7ff0 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -16,8 +16,9 @@ import AttachmentPicker from '@components/AttachmentPicker'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; import CopyTextToClipboard from '@components/CopyTextToClipboard'; +import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; import {DragAndDropContext} from '@components/DragAndDrop/Provider'; -import DropZoneUI from '@components/DropZoneUI'; +import DropZoneUI from '@components/DropZone/DropZoneUI'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -334,7 +335,15 @@ function IOURequestStepScan({ }, [initialTransaction, reportID]); const createTransaction = useCallback( - (files: ReceiptFile[], participant: Participant, gpsPoints?: GpsPoint, policyParams?: {policy: OnyxEntry}, billable?: boolean) => { + ( + files: ReceiptFile[], + participant: Participant, + gpsPoints?: GpsPoint, + policyParams?: { + policy: OnyxEntry; + }, + billable?: boolean, + ) => { files.forEach((receiptFile: ReceiptFile, index) => { const transaction = transactions.find((item) => item.transactionID === receiptFile.transactionID); const receipt: Receipt = receiptFile.file; @@ -951,7 +960,7 @@ function IOURequestStepScan({ {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} {canUseMultiFilesDragAndDrop ? ( - { const file = e?.dataTransfer?.files[0]; if (file) { @@ -959,12 +968,16 @@ function IOURequestStepScan({ setReceiptAndNavigate(file); } }} - icon={isEditing ? Expensicons.ReplaceReceipt : Expensicons.SmartScan} - dropStyles={styles.receiptDropOverlay} - dropTitle={isEditing ? translate('dropzone.replaceReceipt') : translate('dropzone.scanReceipts')} - dropTextStyles={styles.receiptDropText} - dropInnerWrapperStyles={styles.receiptDropInnerWrapper} - /> + > + + ) : ( { diff --git a/src/styles/index.ts b/src/styles/index.ts index 656b1edfccd3..2f335e337ba0 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3993,7 +3993,6 @@ const styles = (theme: ThemeColors) => dropInnerWrapper: { borderWidth: 2, - flex: 1, borderStyle: 'dashed', }, From 6211f2dafd5627592a6c6deb14c7674ae7674fce Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 23 May 2025 10:15:03 +0200 Subject: [PATCH 03/25] refactor: create validation hook --- .../useActiveElementRole/useFileValidation.ts | 62 +++++++++++++ src/pages/Search/SearchPage.tsx | 89 +++++++------------ 2 files changed, 95 insertions(+), 56 deletions(-) create mode 100644 src/hooks/useActiveElementRole/useFileValidation.ts diff --git a/src/hooks/useActiveElementRole/useFileValidation.ts b/src/hooks/useActiveElementRole/useFileValidation.ts new file mode 100644 index 000000000000..480c4cc77d53 --- /dev/null +++ b/src/hooks/useActiveElementRole/useFileValidation.ts @@ -0,0 +1,62 @@ +import {Str} from 'expensify-common'; +import {useState} from 'react'; +import type {FileObject} from '@components/AttachmentModal'; +import {resizeImageIfNeeded, validateReceipt} from '@libs/fileDownload/FileUtils'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; + +function useFileValidation() { + const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); + const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState(); + const [attachmentInvalidReason, setAttachmentValidReason] = useState(); + const [pdfFile, setPdfFile] = useState(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 validateAndResizeFile = (originalFile: FileObject, setReceiptAndNavigate: (file: FileObject) => void, isPdfValidated?: boolean) => { + validateReceipt(originalFile, setUploadReceiptError).then((isFileValid) => { + if (!isFileValid) { + 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 > 24MB, 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((resizedFile) => { + setIsLoadingReceipt(false); + setReceiptAndNavigate(resizedFile); + }); + }); + }; + + return { + validateAndResizeFile, + isAttachmentInvalid, + setIsAttachmentInvalid, + attachmentInvalidReason, + attachmentInvalidReasonTitle, + setUploadReceiptError, + pdfFile, + setPdfFile, + isLoadingReceipt, + }; +} + +export default useFileValidation; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 1032631f7ed0..f729604d423d 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -1,4 +1,3 @@ -import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import type {FileObject} from '@components/AttachmentModal'; @@ -6,6 +5,7 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import DecisionModal from '@components/DecisionModal'; +import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; import DropZoneUI from '@components/DropZone/DropZoneUI'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; @@ -19,6 +19,7 @@ import SearchPageHeader from '@components/Search/SearchPageHeader/SearchPageHead import SearchStatusBar from '@components/Search/SearchPageHeader/SearchStatusBar'; import type {PaymentData, SearchParams} from '@components/Search/types'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; +import useFileValidation from '@hooks/useActiveElementRole/useFileValidation'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; @@ -38,7 +39,6 @@ import { search, unholdMoneyRequestOnSearch, } from '@libs/actions/Search'; -import {resizeImageIfNeeded, validateReceipt} from '@libs/fileDownload/FileUtils'; import {navigateToParticipantPage} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -49,7 +49,6 @@ import {buildCannedSearchQuery, buildSearchQueryJSON} from '@libs/SearchQueryUti import variables from '@styles/variables'; import {initMoneyRequest, setMoneyRequestReceipt} from '@userActions/IOU'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -75,12 +74,17 @@ function SearchPage({route}: SearchPageProps) { const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false); const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false); const [isDownloadExportModalVisible, setIsDownloadExportModalVisible] = useState(false); - // TODO: to be refactored in step 3 - const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); - const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState(); - const [attachmentInvalidReason, setAttachmentValidReason] = useState(); - const [pdfFile, setPdfFile] = useState(null); - const [isLoadingReceipt, setIsLoadingReceipt] = useState(false); + const { + validateAndResizeFile, + setIsAttachmentInvalid, + isAttachmentInvalid, + attachmentInvalidReason, + attachmentInvalidReasonTitle, + setUploadReceiptError, + pdfFile, + setPdfFile, + isLoadingReceipt, + } = useFileValidation(); const {q, name} = route.params; @@ -106,17 +110,6 @@ function SearchPage({route}: SearchPageProps) { const {status, hash} = queryJSON ?? {}; const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); - // TODO: to be refactored in step 3 - /** - * 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); - }; - // TODO: to be refactored in step 3 const getConfirmModalPrompt = () => { if (!attachmentInvalidReason) { @@ -400,35 +393,17 @@ function SearchPage({route}: SearchPageProps) { setIsAttachmentInvalid(false); }; - // TODO: to be refactored in step 3 - const setReceiptAndNavigate = (originalFile: FileObject, isPdfValidated?: boolean) => { - validateReceipt(originalFile, setUploadReceiptError).then((isFileValid) => { - if (!isFileValid) { - 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; - } + const saveFileAndInitMoneyRequest = (file: FileObject) => { + const source = URL.createObjectURL(file as Blob); + const newReportID = generateReportID(); + initMoneyRequest(newReportID, undefined, true, undefined, CONST.IOU.REQUEST_TYPE.SCAN); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, source, file.name || '', true); + navigateToParticipantPage(CONST.IOU.TYPE.CREATE, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, newReportID); + }; - // With the image size > 24MB, 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((resizedFile) => { - setIsLoadingReceipt(false); - // Store the receipt on the transaction object in Onyx - const source = URL.createObjectURL(resizedFile as Blob); - const newReportID = generateReportID(); - initMoneyRequest(newReportID, undefined, true, undefined, CONST.IOU.REQUEST_TYPE.SCAN); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, source, resizedFile.name || '', true); - navigateToParticipantPage(CONST.IOU.TYPE.CREATE, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, newReportID); - }); - }); + const setReceiptAndNavigate = (originalFile: FileObject, isPdfValidated?: boolean) => { + validateAndResizeFile(originalFile, saveFileAndInitMoneyRequest, isPdfValidated); }; const initScanRequest = (e: DragEvent) => { @@ -595,14 +570,16 @@ function SearchPage({route}: SearchPageProps) { lastNonEmptySearchResults={lastNonEmptySearchResults} handleSearch={handleSearchAction} /> - + + + Date: Fri, 23 May 2025 12:14:27 +0200 Subject: [PATCH 04/25] feat: minor improvements --- src/components/DropZone/DualDropZone.tsx | 4 +- src/libs/fileDownload/FileUtils.ts | 11 +++ src/pages/Search/SearchPage.tsx | 14 +--- .../ReportActionCompose.tsx | 75 ++++++++++++++++++- 4 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/components/DropZone/DualDropZone.tsx b/src/components/DropZone/DualDropZone.tsx index 1cefdd68be50..d7ace964cd43 100644 --- a/src/components/DropZone/DualDropZone.tsx +++ b/src/components/DropZone/DualDropZone.tsx @@ -22,11 +22,11 @@ type DropZoneProps = { function DualDropZone({isEditing, onAttachmentDrop, onReceiptDrop}: DropZoneProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout(); return ( - + {({isDraggingOver}) => ( { + if (!attachmentInvalidReason) { + return ''; + } + if (attachmentInvalidReason === 'attachmentPicker.sizeExceededWithLimit') { + return translateLocal(attachmentInvalidReason, {maxUploadSizeInMB: CONST.API_ATTACHMENT_VALIDATIONS.RECEIPT_MAX_SIZE / (1024 * 1024)}); + } + return translateLocal(attachmentInvalidReason); +}; + export { showGeneralErrorAlert, showSuccessAlert, @@ -400,4 +410,5 @@ export { resizeImageIfNeeded, createFile, validateReceipt, + getConfirmModalPrompt }; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index f729604d423d..10d7c2eb5503 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -54,6 +54,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {SearchResults} from '@src/types/onyx'; import SearchPageNarrow from './SearchPageNarrow'; +import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; type SearchPageProps = PlatformStackScreenProps; @@ -110,17 +111,6 @@ function SearchPage({route}: SearchPageProps) { const {status, hash} = queryJSON ?? {}; const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); - // TODO: to be refactored in step 3 - const getConfirmModalPrompt = () => { - if (!attachmentInvalidReason) { - return ''; - } - if (attachmentInvalidReason === 'attachmentPicker.sizeExceededWithLimit') { - return translate(attachmentInvalidReason, {maxUploadSizeInMB: CONST.API_ATTACHMENT_VALIDATIONS.RECEIPT_MAX_SIZE / (1024 * 1024)}); - } - return translate(attachmentInvalidReason); - }; - const headerButtonsOptions = useMemo(() => { if (selectedTransactionsKeys.length === 0 || !status || !hash) { return []; @@ -587,7 +577,7 @@ function SearchPage({route}: SearchPageProps) { onConfirm={hideReceiptModal} onCancel={hideReceiptModal} isVisible={isAttachmentInvalid} - prompt={getConfirmModalPrompt()} + prompt={getConfirmModalPrompt(attachmentInvalidReason)} confirmText={translate('common.close')} shouldShowCancelButton={false} /> diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 080047f1c492..06dfc7b9684b 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -9,6 +9,7 @@ import {runOnUI, useSharedValue} from 'react-native-reanimated'; import type {Emoji} from '@assets/emojis/types'; import type {FileObject} from '@components/AttachmentModal'; import AttachmentModal from '@components/AttachmentModal'; +import ConfirmModal from '@components/ConfirmModal'; import DualDropZone from '@components/DropZone/DualDropZone'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; import ExceededCommentLength from '@components/ExceededCommentLength'; @@ -17,6 +18,8 @@ import type {Mention} from '@components/MentionSuggestions'; import OfflineIndicator from '@components/OfflineIndicator'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {usePersonalDetails} from '@components/OnyxProvider'; +import PDFThumbnail from '@components/PDFThumbnail'; +import useFileValidation from '@hooks/useActiveElementRole/useFileValidation'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebounce from '@hooks/useDebounce'; import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength'; @@ -30,15 +33,18 @@ import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import DomUtils from '@libs/DomUtils'; import {getDraftComment} from '@libs/DraftCommentUtils'; +import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; import getModalState from '@libs/getModalState'; +import {navigateToParticipantPage} from '@libs/IOUUtils'; import Performance from '@libs/Performance'; -import {canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, getReportRecipientAccountIDs} from '@libs/ReportUtils'; +import {canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, generateReportID, getReportRecipientAccountIDs} from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime'; import ReportDropUI from '@pages/home/report/ReportDropUI'; import ReportTypingIndicator from '@pages/home/report/ReportTypingIndicator'; import {hideEmojiPicker, isActive as isActiveEmojiPickerAction} from '@userActions/EmojiPickerAction'; +import {initMoneyRequest, setMoneyRequestReceipt} from '@userActions/IOU'; import {addAttachment as addAttachmentReportActions, setIsComposerFullSize} from '@userActions/Report'; import Timing from '@userActions/Timing'; import {isBlockedFromConcierge as isBlockedFromConciergeUserAction} from '@userActions/User'; @@ -124,6 +130,17 @@ function ReportActionCompose({ // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled const {canUseMultiFilesDragAndDrop} = usePermissions(); + const { + validateAndResizeFile, + setIsAttachmentInvalid, + isAttachmentInvalid, + attachmentInvalidReason, + attachmentInvalidReasonTitle, + setUploadReceiptError, + pdfFile, + setPdfFile, + } = useFileValidation(); + /** * Updates the Highlight state of the composer */ @@ -395,6 +412,50 @@ function ReportActionCompose({ [isComposerFullSize, reportID, debouncedValidate], ); + // TODO: to be refactored in step 3 + const hideReceiptModal = () => { + setIsAttachmentInvalid(false); + }; + + const saveFileAndInitMoneyRequest = (file: FileObject) => { + const source = URL.createObjectURL(file as Blob); + const newReportID = generateReportID(); + initMoneyRequest(newReportID, undefined, true, undefined, CONST.IOU.REQUEST_TYPE.SCAN); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, source, file.name || '', true); + navigateToParticipantPage(CONST.IOU.TYPE.CREATE, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, newReportID); + }; + + const setReceiptAndNavigate = (originalFile: FileObject, isPdfValidated?: boolean) => { + validateAndResizeFile(originalFile, saveFileAndInitMoneyRequest, isPdfValidated); + }; + + const initScanRequest = (e: DragEvent) => { + const file = e?.dataTransfer?.files[0]; + if (file) { + file.uri = URL.createObjectURL(file); + setReceiptAndNavigate(file); + } + }; + + // TODO: to be refactored in step 3 + const PDFThumbnailView = pdfFile ? ( + { + setPdfFile(null); + setReceiptAndNavigate(pdfFile, true); + }} + onPassword={() => { + setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.protectedPDFNotSupported'); + }} + onLoadError={() => { + setUploadReceiptError(true, 'attachmentPicker.attachmentError', 'attachmentPicker.errorWhileSelectingCorruptedAttachment'); + }} + /> + ) : null; + return ( @@ -417,6 +478,7 @@ function ReportActionCompose({ !!exceededMaxLength && styles.borderColorDanger, ]} > + {PDFThumbnailView} {}} + onReceiptDrop={initScanRequest} /> ) : ( + Date: Fri, 23 May 2025 13:00:48 +0200 Subject: [PATCH 05/25] feat: do not display dualDropzone in rooms --- .../ReportActionCompose.tsx | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 06dfc7b9684b..55386520b72e 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -10,9 +10,12 @@ import type {Emoji} from '@assets/emojis/types'; import type {FileObject} from '@components/AttachmentModal'; import AttachmentModal from '@components/AttachmentModal'; import ConfirmModal from '@components/ConfirmModal'; +import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; +import DropZoneUI from '@components/DropZone/DropZoneUI'; import DualDropZone from '@components/DropZone/DualDropZone'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; import ExceededCommentLength from '@components/ExceededCommentLength'; +import * as Expensicons from '@components/Icon/Expensicons'; import ImportedStateIndicator from '@components/ImportedStateIndicator'; import type {Mention} from '@components/MentionSuggestions'; import OfflineIndicator from '@components/OfflineIndicator'; @@ -37,7 +40,7 @@ import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; import getModalState from '@libs/getModalState'; import {navigateToParticipantPage} from '@libs/IOUUtils'; import Performance from '@libs/Performance'; -import {canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, generateReportID, getReportRecipientAccountIDs} from '@libs/ReportUtils'; +import {canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, generateReportID, getReportRecipientAccountIDs, isChatRoom} from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime'; @@ -130,16 +133,8 @@ function ReportActionCompose({ // TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled const {canUseMultiFilesDragAndDrop} = usePermissions(); - const { - validateAndResizeFile, - setIsAttachmentInvalid, - isAttachmentInvalid, - attachmentInvalidReason, - attachmentInvalidReasonTitle, - setUploadReceiptError, - pdfFile, - setPdfFile, - } = useFileValidation(); + const {validateAndResizeFile, setIsAttachmentInvalid, isAttachmentInvalid, attachmentInvalidReason, attachmentInvalidReasonTitle, setUploadReceiptError, pdfFile, setPdfFile} = + useFileValidation(); /** * Updates the Highlight state of the composer @@ -207,6 +202,7 @@ function ReportActionCompose({ const includesConcierge = useMemo(() => chatIncludesConcierge({participants: report?.participants}), [report?.participants]); const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); + const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report), [report]); // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { @@ -548,7 +544,7 @@ function ReportActionCompose({ didHideComposerInput={didHideComposerInput} /> {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} - {canUseMultiFilesDragAndDrop ? ( + {!!canUseMultiFilesDragAndDrop && shouldDisplayDualDropZone && ( { @@ -563,7 +559,27 @@ function ReportActionCompose({ }} onReceiptDrop={initScanRequest} /> - ) : ( + )} + {!!canUseMultiFilesDragAndDrop && !shouldDisplayDualDropZone && ( + { + if (isAttachmentPreviewActive) { + return; + } + const data = event.dataTransfer?.files[0]; + if (data) { + data.uri = URL.createObjectURL(data); + displayFileInModal(data); + } + }} + > + + + )} + {!canUseMultiFilesDragAndDrop && ( { if (isAttachmentPreviewActive) { From 5673adfe2e3c8ace0caaa9c0fcfbfd27eba7ef98 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 23 May 2025 15:10:03 +0200 Subject: [PATCH 06/25] fix: display dual dropzone only for selected chats --- .../ReportActionCompose/ReportActionCompose.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index e4679ea72e18..f2ee079e5807 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -40,7 +40,17 @@ import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; import getModalState from '@libs/getModalState'; import {navigateToParticipantPage} from '@libs/IOUUtils'; import Performance from '@libs/Performance'; -import {canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, getReportRecipientAccountIDs} from '@libs/ReportUtils'; +import { + canShowReportRecipientLocalTime, + chatIncludesChronos, + chatIncludesConcierge, + generateReportID, + getReportRecipientAccountIDs, + isAdminRoom, + isAnnounceRoom, + isChatRoom, + isUserCreatedPolicyRoom, +} from '@libs/ReportUtils'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime'; import ReportDropUI from '@pages/home/report/ReportDropUI'; @@ -201,7 +211,7 @@ function ReportActionCompose({ const includesConcierge = useMemo(() => chatIncludesConcierge({participants: report?.participants}), [report?.participants]); const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); - const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report), [report]); + const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report), [report]); // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { From a4a30275a49f43973a70d655a443c62297bff0bb Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 23 May 2025 16:30:00 +0200 Subject: [PATCH 07/25] fix: lint --- src/hooks/useDragAndDrop/index.ts | 2 +- src/libs/fileDownload/FileUtils.ts | 2 +- src/pages/Search/SearchPage.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/useDragAndDrop/index.ts b/src/hooks/useDragAndDrop/index.ts index c009488f391b..051d7f92cc06 100644 --- a/src/hooks/useDragAndDrop/index.ts +++ b/src/hooks/useDragAndDrop/index.ts @@ -104,7 +104,7 @@ const useDragAndDrop: UseDragAndDrop = ({ break; } }, - [isFocused, isDisabled, shouldAcceptDrop, isDraggingOver, onDrop, handleDragEvent], + [isFocused, isDisabled, shouldAcceptDrop, shouldPropagate, handleDragEvent, isDraggingOver, onDrop], ); useEffect(() => { diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 5ada4eaf7895..593e3ea78cdd 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -410,5 +410,5 @@ export { resizeImageIfNeeded, createFile, validateReceipt, - getConfirmModalPrompt + getConfirmModalPrompt, }; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 624d8abf657f..dbbbbdddc9a5 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -39,6 +39,7 @@ import { search, unholdMoneyRequestOnSearch, } from '@libs/actions/Search'; +import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; import {navigateToParticipantPage} from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -54,7 +55,6 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {SearchResults} from '@src/types/onyx'; import SearchPageNarrow from './SearchPageNarrow'; -import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; type SearchPageProps = PlatformStackScreenProps; From 02a2e298748ce4c17243e48c026b16ca8bb6f314 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 27 May 2025 10:22:09 +0200 Subject: [PATCH 08/25] feat: create logic for replacing receipt --- .../ReportActionCompose.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index f2ee079e5807..bf361b8a7864 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -49,6 +49,7 @@ import { isAdminRoom, isAnnounceRoom, isChatRoom, + isReportTransactionThread, isUserCreatedPolicyRoom, } from '@libs/ReportUtils'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; @@ -212,6 +213,7 @@ function ReportActionCompose({ const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report), [report]); + const isTransactionThreadView = isReportTransactionThread(report); // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { @@ -433,11 +435,19 @@ function ReportActionCompose({ validateAndResizeFile(originalFile, saveFileAndInitMoneyRequest, isPdfValidated); }; - const initScanRequest = (e: DragEvent) => { + const replaceReceipt = (file: FileObject) => { + console.log(file); + }; + + const handleAddingReceipt = (e: DragEvent) => { const file = e?.dataTransfer?.files[0]; if (file) { file.uri = URL.createObjectURL(file); - setReceiptAndNavigate(file); + if (isTransactionThreadView) { + replaceReceipt(file); + } else { + setReceiptAndNavigate(file); + } } }; @@ -553,7 +563,7 @@ function ReportActionCompose({ {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} {!!canUseMultiFilesDragAndDrop && shouldDisplayDualDropZone && ( { if (isAttachmentPreviewActive) { return; @@ -564,7 +574,7 @@ function ReportActionCompose({ displayFileInModal(data); } }} - onReceiptDrop={initScanRequest} + onReceiptDrop={handleAddingReceipt} /> )} {!!canUseMultiFilesDragAndDrop && !shouldDisplayDualDropZone && ( From c848b39d42491c73ab6b2d41cf09f3d5a9b1d677 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 27 May 2025 18:39:28 +0200 Subject: [PATCH 09/25] fix: add missing styles --- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index a17f1fdd36bd..b488356b9d59 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -610,6 +610,10 @@ function ReportActionCompose({ )} From b2d7b34e104ac87160e75cee7ccc7cdc4a76c1a1 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 27 May 2025 19:01:25 +0200 Subject: [PATCH 10/25] fix: show scan receipts when no receipt attached --- .../ReportActionCompose/ReportActionCompose.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index b488356b9d59..0d639f10d798 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -53,7 +53,7 @@ import { isReportTransactionThread, isUserCreatedPolicyRoom, } from '@libs/ReportUtils'; -import {getTransactionID} from '@libs/TransactionUtils'; +import {getTransactionID, hasReceipt as hasReceiptTransactionUtils} from '@libs/TransactionUtils'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime'; import ReportDropUI from '@pages/home/report/ReportDropUI'; @@ -216,8 +216,12 @@ function ReportActionCompose({ const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report), [report]); - const isTransactionThreadView = isReportTransactionThread(report); - const transactionID = getTransactionID(reportID); + const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]); + const transactionID = useMemo(() => getTransactionID(reportID), [reportID]); + + const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, {canBeMissing: true}); + + const hasReceipt = useMemo(() => hasReceiptTransactionUtils(transaction), [transaction]); // Placeholder to display in the chat input. const inputPlaceholder = useMemo(() => { @@ -580,7 +584,7 @@ function ReportActionCompose({ {/* TODO: remove canUseMultiFilesDragAndDrop check after the feature is enabled */} {!!canUseMultiFilesDragAndDrop && shouldDisplayDualDropZone && ( { if (isAttachmentPreviewActive) { return; From ed3c91e4e72999d0e0ccdb4e80122c15da6f2fc9 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 27 May 2025 19:18:06 +0200 Subject: [PATCH 11/25] fix: lint --- src/pages/Search/SearchPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index f64ce529da2c..f58e5c899286 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -20,7 +20,6 @@ import SearchStatusBar from '@components/Search/SearchPageHeader/SearchStatusBar import type {PaymentData, SearchParams} from '@components/Search/types'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useFileValidation from '@hooks/useActiveElementRole/useFileValidation'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; From 3fddda263975c3984134f06fc1e37afa0cffb7b0 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 28 May 2025 19:05:14 +0200 Subject: [PATCH 12/25] feat: change opacity when dragging over --- src/components/DropZone/DualDropZone.tsx | 4 +-- src/pages/Search/SearchPage.tsx | 2 +- .../request/step/IOURequestStepScan/index.tsx | 2 +- src/styles/index.ts | 26 ++++++++++++------- src/styles/theme/themes/dark.ts | 2 ++ src/styles/theme/themes/light.ts | 2 ++ src/styles/theme/types.ts | 2 ++ 7 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/components/DropZone/DualDropZone.tsx b/src/components/DropZone/DualDropZone.tsx index d7ace964cd43..f4e1e75fd7ea 100644 --- a/src/components/DropZone/DualDropZone.tsx +++ b/src/components/DropZone/DualDropZone.tsx @@ -33,7 +33,7 @@ function DualDropZone({isEditing, onAttachmentDrop, onReceiptDrop}: DropZoneProp isDraggingOver={isDraggingOver} icon={Expensicons.MessageInABottle} dropTitle={translate('dropzone.addAttachments')} - dropStyles={styles.attachmentDropOverlay} + dropStyles={styles.attachmentDropOverlay(isDraggingOver)} dropTextStyles={styles.attachmentDropText} dropInnerWrapperStyles={styles.attachmentDropInnerWrapper} /> @@ -45,7 +45,7 @@ function DualDropZone({isEditing, onAttachmentDrop, onReceiptDrop}: DropZoneProp isDraggingOver={isDraggingOver} icon={isEditing ? Expensicons.ReplaceReceipt : Expensicons.SmartScan} dropTitle={translate(isEditing ? 'dropzone.replaceReceipt' : 'dropzone.scanReceipts')} - dropStyles={styles.receiptDropOverlay} + dropStyles={styles.receiptDropOverlay(isDraggingOver)} dropTextStyles={styles.receiptDropText} dropInnerWrapperStyles={styles.receiptDropInnerWrapper} /> diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index f58e5c899286..67995ef2f1f8 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -572,7 +572,7 @@ function SearchPage({route}: SearchPageProps) { isDraggingOver icon={Expensicons.SmartScan} dropTitle={translate('dropzone.scanReceipts')} - dropStyles={styles.receiptDropOverlay} + dropStyles={styles.receiptDropOverlay()} dropTextStyles={styles.receiptDropText} dropInnerWrapperStyles={styles.receiptDropInnerWrapper} /> diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index b866d8ab7aff..747e88ffc8da 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -953,7 +953,7 @@ function IOURequestStepScan({ }, rootNavigatorContainerStyles: (isSmallScreenWidth: boolean) => - ({marginLeft: isSmallScreenWidth ? 0 : variables.sideBarWithLHBWidth + variables.navigationTabBarSize, flex: 1} satisfies ViewStyle), - RHPNavigatorContainerNavigatorContainerStyles: (isSmallScreenWidth: boolean) => ({marginLeft: isSmallScreenWidth ? 0 : variables.sideBarWidth, flex: 1} satisfies ViewStyle), + ({ + marginLeft: isSmallScreenWidth ? 0 : variables.sideBarWithLHBWidth + variables.navigationTabBarSize, + flex: 1, + } satisfies ViewStyle), + RHPNavigatorContainerNavigatorContainerStyles: (isSmallScreenWidth: boolean) => + ({ + marginLeft: isSmallScreenWidth ? 0 : variables.sideBarWidth, + flex: 1, + } satisfies ViewStyle), avatarInnerTextChat: { color: theme.text, @@ -3999,9 +4006,10 @@ const styles = (theme: ThemeColors) => backgroundColor: theme.fileDropUIBG, }, - attachmentDropOverlay: { - backgroundColor: theme.attachmentDropUIBG, - }, + attachmentDropOverlay: (isActive?: boolean) => ({ + backgroundColor: isActive ? theme.attachmentDropUIBGActive : theme.attachmentDropUIBG, + transition: 'background-color 0.2s ease-in', + }), attachmentDropText: { color: theme.textAttachmentDropZone, @@ -4011,10 +4019,10 @@ const styles = (theme: ThemeColors) => borderColor: theme.attachmentDropBorderColor, }, - receiptDropOverlay: { - backgroundColor: theme.receiptDropUIBG, - zIndex: 2, - }, + receiptDropOverlay: (isActive?: boolean) => ({ + backgroundColor: isActive ? theme.receiptDropUIBGActive : theme.receiptDropUIBG, + transition: 'background-color 0.2s ease-in', + }), receiptDropText: { color: theme.textReceiptDropZone, diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts index 59c0672771b3..17e4c2e84919 100644 --- a/src/styles/theme/themes/dark.ts +++ b/src/styles/theme/themes/dark.ts @@ -73,8 +73,10 @@ const darkTheme = { dropWrapperBG: 'rgba(26, 61, 50, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.7)', attachmentDropBorderColor: colors.blue100, receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 0.7)', receiptDropBorderColor: colors.green100, checkBox: colors.green400, imageCropBackgroundColor: colors.productDark700, diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts index cbc063e17fdf..d4ded108ed31 100644 --- a/src/styles/theme/themes/light.ts +++ b/src/styles/theme/themes/light.ts @@ -73,8 +73,10 @@ const lightTheme = { dropWrapperBG: 'rgba(235, 230, 223, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.7)', attachmentDropBorderColor: colors.blue100, receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 0.7)', receiptDropBorderColor: colors.green100, checkBox: colors.green400, imageCropBackgroundColor: colors.productLight700, diff --git a/src/styles/theme/types.ts b/src/styles/theme/types.ts index c0061ce7a198..d761dc85c446 100644 --- a/src/styles/theme/types.ts +++ b/src/styles/theme/types.ts @@ -78,8 +78,10 @@ type ThemeColors = { dropWrapperBG: Color; fileDropUIBG: Color; attachmentDropUIBG: Color; + attachmentDropUIBGActive: Color; attachmentDropBorderColor: Color; receiptDropUIBG: Color; + receiptDropUIBGActive: Color; receiptDropBorderColor: Color; checkBox: Color; imageCropBackgroundColor: Color; From 93f5bde490839d4186923a79800dd47591bffe51 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 29 May 2025 11:57:12 +0200 Subject: [PATCH 13/25] fix: resolve conflicts --- .../ReportActionCompose/ReportActionCompose.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 0d639f10d798..257a791f6fc3 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -39,13 +39,11 @@ import DomUtils from '@libs/DomUtils'; import {getDraftComment} from '@libs/DraftCommentUtils'; import {getConfirmModalPrompt} from '@libs/fileDownload/FileUtils'; import getModalState from '@libs/getModalState'; -import {navigateToParticipantPage} from '@libs/IOUUtils'; import Performance from '@libs/Performance'; import { canShowReportRecipientLocalTime, chatIncludesChronos, chatIncludesConcierge, - generateReportID, getReportRecipientAccountIDs, isAdminRoom, isAnnounceRoom, @@ -55,16 +53,18 @@ import { } from '@libs/ReportUtils'; import {getTransactionID, hasReceipt as hasReceiptTransactionUtils} from '@libs/TransactionUtils'; import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside'; +import Navigation from '@navigation/Navigation'; import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime'; import ReportDropUI from '@pages/home/report/ReportDropUI'; import ReportTypingIndicator from '@pages/home/report/ReportTypingIndicator'; import {hideEmojiPicker, isActive as isActiveEmojiPickerAction} from '@userActions/EmojiPickerAction'; -import {initMoneyRequest, replaceReceipt, setMoneyRequestReceipt} from '@userActions/IOU'; +import {initMoneyRequest, replaceReceipt, setMoneyRequestParticipantsFromReport, setMoneyRequestReceipt} from '@userActions/IOU'; import {addAttachment as addAttachmentReportActions, setIsComposerFullSize} from '@userActions/Report'; import Timing from '@userActions/Timing'; import {isBlockedFromConcierge as isBlockedFromConciergeUserAction} from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -444,15 +444,16 @@ function ReportActionCompose({ const saveFileAndInitMoneyRequest = (file: FileObject) => { const source = URL.createObjectURL(file as Blob); - const newReportID = generateReportID(); if (isTransactionThreadView && transactionID) { replaceReceipt({transactionID, file: file as File, source}); } else { - initMoneyRequest(newReportID, undefined, true, undefined, CONST.IOU.REQUEST_TYPE.SCAN); + initMoneyRequest(reportID, undefined, false, undefined, CONST.IOU.REQUEST_TYPE.SCAN); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, source, file.name || '', true); - navigateToParticipantPage(CONST.IOU.TYPE.CREATE, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, newReportID); + setMoneyRequestParticipantsFromReport(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report).then(() => { + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, CONST.IOU.TYPE.SUBMIT, CONST.IOU.OPTIMISTIC_TRANSACTION_ID, reportID)); + }); } }; @@ -615,7 +616,7 @@ function ReportActionCompose({ icon={Expensicons.MessageInABottle} isDraggingOver dropTitle={translate('dropzone.addAttachments')} - dropStyles={styles.attachmentDropOverlay} + dropStyles={styles.attachmentDropOverlay()} dropTextStyles={styles.attachmentDropText} dropInnerWrapperStyles={styles.attachmentDropInnerWrapper} /> From 5cb870c7f4ee13ef9f0745213ffdfc2ae6f8f436 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 29 May 2025 09:39:18 +0200 Subject: [PATCH 14/25] fix: change active styles --- src/pages/Search/SearchPage.tsx | 2 +- .../report/ReportActionCompose/ReportActionCompose.tsx | 2 +- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 2 +- src/pages/iou/request/step/IOURequestStepScan/index.tsx | 2 +- src/styles/theme/themes/dark.ts | 8 ++++---- src/styles/theme/themes/light.ts | 8 ++++---- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 67995ef2f1f8..6380dc4d3764 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -572,7 +572,7 @@ function SearchPage({route}: SearchPageProps) { isDraggingOver icon={Expensicons.SmartScan} dropTitle={translate('dropzone.scanReceipts')} - dropStyles={styles.receiptDropOverlay()} + dropStyles={styles.receiptDropOverlay(true)} dropTextStyles={styles.receiptDropText} dropInnerWrapperStyles={styles.receiptDropInnerWrapper} /> diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 257a791f6fc3..5e82a9aba07c 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -616,7 +616,7 @@ function ReportActionCompose({ icon={Expensicons.MessageInABottle} isDraggingOver dropTitle={translate('dropzone.addAttachments')} - dropStyles={styles.attachmentDropOverlay()} + dropStyles={styles.attachmentDropOverlay(true)} dropTextStyles={styles.attachmentDropText} dropInnerWrapperStyles={styles.attachmentDropInnerWrapper} /> diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 50f385dc8aa9..ce0cfd966afb 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1047,7 +1047,7 @@ function IOURequestStepConfirmation({ Date: Thu, 29 May 2025 15:22:19 +0200 Subject: [PATCH 15/25] fix: change gap between dropzones --- src/components/DropZone/DropZoneUI.tsx | 7 +++++-- src/components/DropZone/DualDropZone.tsx | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/DropZone/DropZoneUI.tsx b/src/components/DropZone/DropZoneUI.tsx index cdf31197f8dd..bd35714b1520 100644 --- a/src/components/DropZone/DropZoneUI.tsx +++ b/src/components/DropZone/DropZoneUI.tsx @@ -22,15 +22,18 @@ type DropZoneUIProps = { /** Custom styles for the inner wrapper of the drop zone */ dropInnerWrapperStyles?: StyleProp; + /** Custom styles for the drop wrapper */ + dropWrapperStyles?: StyleProp; + /** Whether the drop zone is currently being dragged over */ isDraggingOver: boolean; }; -function DropZoneUI({isDraggingOver, icon, dropTitle, dropStyles, dropTextStyles, dropInnerWrapperStyles}: DropZoneUIProps) { +function DropZoneUI({isDraggingOver, icon, dropTitle, dropStyles, dropTextStyles, dropWrapperStyles, dropInnerWrapperStyles}: DropZoneUIProps) { const styles = useThemeStyles(); return ( - + - + {({isDraggingOver}) => ( )} From bd081e976b16d6ccce8ac96698ea8b7fce00eea3 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 30 May 2025 10:20:53 +0200 Subject: [PATCH 16/25] fix: style improvements --- src/components/DropZone/DropZoneUI.tsx | 14 ++------------ src/components/DropZone/DualDropZone.tsx | 6 ++---- src/pages/Search/SearchPage.tsx | 3 +-- .../ReportActionCompose/ReportActionCompose.tsx | 3 +-- .../request/step/IOURequestStepConfirmation.tsx | 3 +-- .../iou/request/step/IOURequestStepScan/index.tsx | 3 +-- src/styles/index.ts | 15 ++++++++------- src/styles/theme/themes/dark.ts | 14 ++++++++------ src/styles/theme/themes/light.ts | 14 ++++++++------ src/styles/theme/types.ts | 2 ++ 10 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/components/DropZone/DropZoneUI.tsx b/src/components/DropZone/DropZoneUI.tsx index bd35714b1520..ac5dcd56f912 100644 --- a/src/components/DropZone/DropZoneUI.tsx +++ b/src/components/DropZone/DropZoneUI.tsx @@ -24,25 +24,15 @@ type DropZoneUIProps = { /** Custom styles for the drop wrapper */ dropWrapperStyles?: StyleProp; - - /** Whether the drop zone is currently being dragged over */ - isDraggingOver: boolean; }; -function DropZoneUI({isDraggingOver, icon, dropTitle, dropStyles, dropTextStyles, dropWrapperStyles, dropInnerWrapperStyles}: DropZoneUIProps) { +function DropZoneUI({icon, dropTitle, dropStyles, dropTextStyles, dropWrapperStyles, dropInnerWrapperStyles}: DropZoneUIProps) { const styles = useThemeStyles(); return ( - + {({isDraggingOver}) => ( )} @@ -45,12 +44,11 @@ function DualDropZone({isEditing, onAttachmentDrop, onReceiptDrop}: DropZoneProp {({isDraggingOver}) => ( )} diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 6380dc4d3764..7f50b9cee297 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -569,12 +569,11 @@ function SearchPage({route}: SearchPageProps) { /> diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 0a7b4cf0c053..6d8372997d38 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -613,11 +613,10 @@ function ReportActionCompose({ > )} diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 361d1b9917ef..0e465c0127e1 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -1045,12 +1045,11 @@ function IOURequestStepConfirmation({ }} > ) : ( diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index 9076bbd350ed..de718c8b1b12 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -944,12 +944,11 @@ function IOURequestStepScan({ }} > ) : ( diff --git a/src/styles/index.ts b/src/styles/index.ts index 569f959eda77..c2992a9b0e9c 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3989,7 +3989,6 @@ const styles = (theme: ThemeColors) => dropWrapper: { zIndex: 2, - backgroundColor: theme.dropWrapperBG, }, dropInnerWrapper: { @@ -4015,9 +4014,10 @@ const styles = (theme: ThemeColors) => color: theme.textAttachmentDropZone, }, - attachmentDropInnerWrapper: { - borderColor: theme.attachmentDropBorderColor, - }, + attachmentDropInnerWrapper: (isActive?: boolean) => ({ + borderColor: isActive ? theme.attachmentDropBorderColorActive : theme.attachmentDropBorderColor, + transition: '0.2s ease-in', + }), receiptDropOverlay: (isActive?: boolean) => ({ backgroundColor: isActive ? theme.receiptDropUIBGActive : theme.receiptDropUIBG, @@ -4028,9 +4028,10 @@ const styles = (theme: ThemeColors) => color: theme.textReceiptDropZone, }, - receiptDropInnerWrapper: { - borderColor: theme.receiptDropBorderColor, - }, + receiptDropInnerWrapper: (isActive?: boolean) => ({ + borderColor: isActive ? theme.receiptDropBorderColorActive : theme.receiptDropBorderColor, + transition: '0.2s ease-in', + }), isDraggingOver: { backgroundColor: theme.fileDropUIBG, diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts index 7697ba4851c0..01ed443968a5 100644 --- a/src/styles/theme/themes/dark.ts +++ b/src/styles/theme/themes/dark.ts @@ -72,12 +72,14 @@ const darkTheme = { dropUIBG: 'rgba(6,27,9,0.92)', dropWrapperBG: 'rgba(26, 61, 50, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', - attachmentDropUIBG: 'rgba(90, 176, 255, 0.7)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.9)', - attachmentDropBorderColor: colors.blue100, - receiptDropUIBG: 'rgba(3, 212, 124, 0.7)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 0.9)', - receiptDropBorderColor: colors.green100, + attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.96)', + attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', + attachmentDropBorderColorActive: colors.blue100, + receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 0.96)', + receiptDropBorderColor: 'rgba(177, 242, 214, 0)', + receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, imageCropBackgroundColor: colors.productDark700, fallbackIconColor: colors.green700, diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts index 88236b5d1257..5c6663170a90 100644 --- a/src/styles/theme/themes/light.ts +++ b/src/styles/theme/themes/light.ts @@ -72,12 +72,14 @@ const lightTheme = { dropUIBG: 'rgba(252, 251, 249, 0.92)', dropWrapperBG: 'rgba(235, 230, 223, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', - attachmentDropUIBG: 'rgba(90, 176, 255, 0.7)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.9)', - attachmentDropBorderColor: colors.blue100, - receiptDropUIBG: 'rgba(3, 212, 124, 0.7)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 0.9)', - receiptDropBorderColor: colors.green100, + attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.96)', + attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', + attachmentDropBorderColorActive: colors.blue100, + receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 0.96)', + receiptDropBorderColor: 'rgba(177, 242, 214, 0)', + receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, imageCropBackgroundColor: colors.productLight700, fallbackIconColor: colors.green700, diff --git a/src/styles/theme/types.ts b/src/styles/theme/types.ts index d761dc85c446..349ad3e9e7bb 100644 --- a/src/styles/theme/types.ts +++ b/src/styles/theme/types.ts @@ -80,9 +80,11 @@ type ThemeColors = { attachmentDropUIBG: Color; attachmentDropUIBGActive: Color; attachmentDropBorderColor: Color; + attachmentDropBorderColorActive: Color; receiptDropUIBG: Color; receiptDropUIBGActive: Color; receiptDropBorderColor: Color; + receiptDropBorderColorActive: Color; checkBox: Color; imageCropBackgroundColor: Color; fallbackIconColor: Color; From 5d4e3702fb222e369d0c00590f8d908d0cda2dcf Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 30 May 2025 15:33:10 +0200 Subject: [PATCH 17/25] fix: style improvements --- src/styles/theme/themes/dark.ts | 4 ++-- src/styles/theme/themes/light.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts index 01ed443968a5..3971e44dae33 100644 --- a/src/styles/theme/themes/dark.ts +++ b/src/styles/theme/themes/dark.ts @@ -73,11 +73,11 @@ const darkTheme = { dropWrapperBG: 'rgba(26, 61, 50, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.96)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 1)', attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', attachmentDropBorderColorActive: colors.blue100, receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 0.96)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 1)', receiptDropBorderColor: 'rgba(177, 242, 214, 0)', receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts index 5c6663170a90..4714c41eb7b8 100644 --- a/src/styles/theme/themes/light.ts +++ b/src/styles/theme/themes/light.ts @@ -73,11 +73,11 @@ const lightTheme = { dropWrapperBG: 'rgba(235, 230, 223, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.96)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 1)', attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', attachmentDropBorderColorActive: colors.blue100, receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 0.96)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 1)', receiptDropBorderColor: 'rgba(177, 242, 214, 0)', receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, From b53573ea4b25de6fc8cfa8947611b406cb048334 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 30 May 2025 19:25:36 +0200 Subject: [PATCH 18/25] fix: minor fix --- src/styles/theme/themes/dark.ts | 8 ++++---- src/styles/theme/themes/light.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts index 3971e44dae33..66071bdc9723 100644 --- a/src/styles/theme/themes/dark.ts +++ b/src/styles/theme/themes/dark.ts @@ -72,12 +72,12 @@ const darkTheme = { dropUIBG: 'rgba(6,27,9,0.92)', dropWrapperBG: 'rgba(26, 61, 50, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', - attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 1)', + attachmentDropUIBG: 'rgba(90, 176, 255, 0.8)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 96)', attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', attachmentDropBorderColorActive: colors.blue100, - receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 1)', + receiptDropUIBG: 'rgba(3, 212, 124, 0.8)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 96)', receiptDropBorderColor: 'rgba(177, 242, 214, 0)', receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts index 4714c41eb7b8..1598f200c251 100644 --- a/src/styles/theme/themes/light.ts +++ b/src/styles/theme/themes/light.ts @@ -72,12 +72,12 @@ const lightTheme = { dropUIBG: 'rgba(252, 251, 249, 0.92)', dropWrapperBG: 'rgba(235, 230, 223, 0.72)', fileDropUIBG: 'rgba(3, 212, 124, 0.84)', - attachmentDropUIBG: 'rgba(90, 176, 255, 0.9)', - attachmentDropUIBGActive: 'rgba(90, 176, 255, 1)', + attachmentDropUIBG: 'rgba(90, 176, 255, 0.8)', + attachmentDropUIBGActive: 'rgba(90, 176, 255, 0.96)', attachmentDropBorderColor: 'rgba(176, 217, 255, 0)', attachmentDropBorderColorActive: colors.blue100, - receiptDropUIBG: 'rgba(3, 212, 124, 0.9)', - receiptDropUIBGActive: 'rgba(3, 212, 124, 1)', + receiptDropUIBG: 'rgba(3, 212, 124, 0.8)', + receiptDropUIBGActive: 'rgba(3, 212, 124, 0.96)', receiptDropBorderColor: 'rgba(177, 242, 214, 0)', receiptDropBorderColorActive: colors.green100, checkBox: colors.green400, From 1823b28adbf9265715292e6174f7096762f91c95 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 2 Jun 2025 14:56:24 +0200 Subject: [PATCH 19/25] fix: change prop name --- src/components/DropZone/DropZoneWrapper.tsx | 2 +- src/hooks/useDragAndDrop/index.ts | 6 +++--- src/hooks/useDragAndDrop/types.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/DropZone/DropZoneWrapper.tsx b/src/components/DropZone/DropZoneWrapper.tsx index dbe55bd70ca0..c56b9369e427 100644 --- a/src/components/DropZone/DropZoneWrapper.tsx +++ b/src/components/DropZone/DropZoneWrapper.tsx @@ -21,7 +21,7 @@ function DropZoneWrapper({onDrop, children}: DropZoneWrapperProps) { const {isDraggingOver} = useDragAndDrop({ shouldAcceptDrop: (event) => !!event.dataTransfer?.types.some((type) => type === 'Files'), onDrop, - shouldPropagate: false, + shouldStopPropagation: false, shouldHandleDragEvent: false, dropZone: htmlDivElementRef(dropZone), }); diff --git a/src/hooks/useDragAndDrop/index.ts b/src/hooks/useDragAndDrop/index.ts index 051d7f92cc06..536a33c4c98a 100644 --- a/src/hooks/useDragAndDrop/index.ts +++ b/src/hooks/useDragAndDrop/index.ts @@ -20,7 +20,7 @@ const useDragAndDrop: UseDragAndDrop = ({ isDisabled = false, shouldAcceptDrop = () => true, shouldHandleDragEvent = true, - shouldPropagate = true, + shouldStopPropagation = true, }) => { const isFocused = useIsFocused(); const [isDraggingOver, setIsDraggingOver] = useState(false); @@ -69,7 +69,7 @@ const useDragAndDrop: UseDragAndDrop = ({ } event.preventDefault(); - if (shouldPropagate) { + if (shouldStopPropagation) { event.stopPropagation(); } @@ -104,7 +104,7 @@ const useDragAndDrop: UseDragAndDrop = ({ break; } }, - [isFocused, isDisabled, shouldAcceptDrop, shouldPropagate, handleDragEvent, isDraggingOver, onDrop], + [isFocused, isDisabled, shouldAcceptDrop, shouldStopPropagation, handleDragEvent, isDraggingOver, onDrop], ); useEffect(() => { diff --git a/src/hooks/useDragAndDrop/types.ts b/src/hooks/useDragAndDrop/types.ts index 19fccfd60999..ac1ef4e49db5 100644 --- a/src/hooks/useDragAndDrop/types.ts +++ b/src/hooks/useDragAndDrop/types.ts @@ -4,7 +4,7 @@ type DragAndDropParams = { shouldAllowDrop?: boolean; isDisabled?: boolean; shouldAcceptDrop?: (event: DragEvent) => boolean; - shouldPropagate?: boolean; + shouldStopPropagation?: boolean; shouldHandleDragEvent?: boolean; }; From b99ff477227e9cad80ead39a78359c2b9fbf1e46 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 2 Jun 2025 15:09:36 +0200 Subject: [PATCH 20/25] fix: do not show dual dropzone in concierge chat and invoice report --- .../report/ReportActionCompose/ReportActionCompose.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 6d8372997d38..7319189e4551 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -48,6 +48,8 @@ import { isAdminRoom, isAnnounceRoom, isChatRoom, + isConciergeChatReport, + isInvoiceReport, isReportTransactionThread, isUserCreatedPolicyRoom, } from '@libs/ReportUtils'; @@ -215,7 +217,10 @@ function ReportActionCompose({ const includesConcierge = useMemo(() => chatIncludesConcierge({participants: report?.participants}), [report?.participants]); const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); - const shouldDisplayDualDropZone = useMemo(() => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report), [report]); + const shouldDisplayDualDropZone = useMemo( + () => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report) && !isConciergeChatReport(report) && !isInvoiceReport(report), + [report], + ); const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]); const transactionID = useMemo(() => getTransactionID(reportID), [reportID]); From 9c442ae0faa7d331402060d9c0cb848a7291bda8 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 4 Jun 2025 16:08:54 +0200 Subject: [PATCH 21/25] fix: typecheck --- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index beb55a2a47bb..ef8b21974b62 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -453,7 +453,7 @@ function ReportActionCompose({ if (isTransactionThreadView && transactionID) { replaceReceipt({transactionID, file: file as File, source}); } else { - initMoneyRequest(reportID, undefined, false, undefined, CONST.IOU.REQUEST_TYPE.SCAN); + initMoneyRequest({reportID, newIouRequestType: CONST.IOU.REQUEST_TYPE.SCAN}); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, source, file.name || '', true); setMoneyRequestParticipantsFromReport(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, report).then(() => { @@ -625,7 +625,7 @@ function ReportActionCompose({ /> )} - {!canUseMultiFilesDragAndDrop && ( + {!isBetaEnabled(CONST.BETAS.NEWDOT_MULTI_FILES_DRAG_AND_DROP) && ( { if (isAttachmentPreviewActive) { From 1de30ab96e5d62e0895bbbd68016cbf605d37449 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 4 Jun 2025 17:06:58 +0200 Subject: [PATCH 22/25] fix: apply suggestion Co-authored-by: Getabalew <75031127+getusha@users.noreply.github.com> --- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index ef8b21974b62..4f60ece89d1b 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -218,7 +218,7 @@ function ReportActionCompose({ const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); const shouldDisplayDualDropZone = useMemo( - () => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report) && !isConciergeChatReport(report) && !isInvoiceReport(report), + () => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report) && !isConciergeChatReport(report) && !isInvoiceReport(report) && !isGroupChat(report), [report], ); const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]); From 0874e8df94f8451757e0830daa95eaf3b866d220 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 4 Jun 2025 17:26:55 +0200 Subject: [PATCH 23/25] fix: add missing import --- .../ReportActionCompose/ReportActionCompose.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 4f60ece89d1b..a77c0b39d78b 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -48,7 +48,7 @@ import { isAdminRoom, isAnnounceRoom, isChatRoom, - isConciergeChatReport, + isConciergeChatReport, isGroupChat, isInvoiceReport, isReportTransactionThread, isUserCreatedPolicyRoom, @@ -218,7 +218,14 @@ function ReportActionCompose({ const userBlockedFromConcierge = useMemo(() => isBlockedFromConciergeUserAction(blockedFromConcierge), [blockedFromConcierge]); const isBlockedFromConcierge = useMemo(() => includesConcierge && userBlockedFromConcierge, [includesConcierge, userBlockedFromConcierge]); const shouldDisplayDualDropZone = useMemo( - () => !isChatRoom(report) && !isUserCreatedPolicyRoom(report) && !isAnnounceRoom(report) && !isAdminRoom(report) && !isConciergeChatReport(report) && !isInvoiceReport(report) && !isGroupChat(report), + () => + !isChatRoom(report) && + !isUserCreatedPolicyRoom(report) && + !isAnnounceRoom(report) && + !isAdminRoom(report) && + !isConciergeChatReport(report) && + !isInvoiceReport(report) && + !isGroupChat(report), [report], ); const isTransactionThreadView = useMemo(() => isReportTransactionThread(report), [report]); From 8e4adc2e91dfbc16ec6bdf127a82c37f661d2cd8 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 4 Jun 2025 17:45:58 +0200 Subject: [PATCH 24/25] fix: prettier --- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index a77c0b39d78b..13227704d532 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -48,7 +48,8 @@ import { isAdminRoom, isAnnounceRoom, isChatRoom, - isConciergeChatReport, isGroupChat, + isConciergeChatReport, + isGroupChat, isInvoiceReport, isReportTransactionThread, isUserCreatedPolicyRoom, From bd85b948771031d38d5a88754016ba652442c167 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Sun, 8 Jun 2025 19:38:06 +0200 Subject: [PATCH 25/25] fix: move hook out from a wrong folder --- src/hooks/{useActiveElementRole => }/useFileValidation.ts | 0 src/pages/Search/SearchPage.tsx | 2 +- .../home/report/ReportActionCompose/ReportActionCompose.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/hooks/{useActiveElementRole => }/useFileValidation.ts (100%) diff --git a/src/hooks/useActiveElementRole/useFileValidation.ts b/src/hooks/useFileValidation.ts similarity index 100% rename from src/hooks/useActiveElementRole/useFileValidation.ts rename to src/hooks/useFileValidation.ts diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 8ca278ae37c2..8c307e45a7bb 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -19,7 +19,7 @@ import type {SearchHeaderOptionValue} from '@components/Search/SearchPageHeader/ import SearchPageHeader from '@components/Search/SearchPageHeader/SearchPageHeader'; import type {PaymentData, SearchParams} from '@components/Search/types'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; -import useFileValidation from '@hooks/useActiveElementRole/useFileValidation'; +import useFileValidation from '@hooks/useFileValidation'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 13227704d532..6adca7d80153 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -23,9 +23,9 @@ import OfflineIndicator from '@components/OfflineIndicator'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {usePersonalDetails} from '@components/OnyxProvider'; import PDFThumbnail from '@components/PDFThumbnail'; -import useFileValidation from '@hooks/useActiveElementRole/useFileValidation'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebounce from '@hooks/useDebounce'; +import useFileValidation from '@hooks/useFileValidation'; import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength'; import useHandleExceedMaxTaskTitleLength from '@hooks/useHandleExceedMaxTaskTitleLength'; import useLocalize from '@hooks/useLocalize';