diff --git a/src/libs/tryResolveUrlFromApiRoot.ts b/src/libs/tryResolveUrlFromApiRoot.ts index 69609cc2e933..eeaab85b0a7f 100644 --- a/src/libs/tryResolveUrlFromApiRoot.ts +++ b/src/libs/tryResolveUrlFromApiRoot.ts @@ -1,6 +1,7 @@ import type {ImageSourcePropType} from 'react-native'; import Config from '@src/CONFIG'; import type {ReceiptSource} from '@src/types/onyx/Transaction'; +import proxyConfig from '../../config/proxyConfig'; import {getApiRoot} from './ApiUtils'; // Absolute URLs (`/` or `//`) should be resolved from API ROOT @@ -29,6 +30,13 @@ function tryResolveUrlFromApiRoot(url: string | ImageSourcePropType | ReceiptSou return url; } const apiRoot = getApiRoot({shouldUseSecure: false}); + + // When using the staging web proxy, the URL might already include the `/staging/` proxy path. + // In that case, do not replace the leading `/` again, as it would create `/staging/staging/...`. + if (apiRoot === proxyConfig.STAGING && url.startsWith(apiRoot)) { + return url; + } + return url.replace(ORIGIN_PATTERN, apiRoot); } diff --git a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/AttachmentStateContextProvider.tsx b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/AttachmentStateContextProvider.tsx index 1a1dbaf47465..e18b5f2349bc 100644 --- a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/AttachmentStateContextProvider.tsx +++ b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/AttachmentStateContextProvider.tsx @@ -47,7 +47,7 @@ function AttachmentStateContextProvider({children}: Props) { setAttachmentLoadedState({}); }, []); - const isAttachmentLoaded = useCallback((key: AttachmentSource) => attachmentLoaded?.[convertSourceToString(key)] !== false, [attachmentLoaded]); + const isAttachmentLoaded = useCallback((key: AttachmentSource) => attachmentLoaded?.[convertSourceToString(key)] === true, [attachmentLoaded]); const value = useMemo(() => ({setAttachmentLoaded, clearAttachmentLoaded, isAttachmentLoaded}), [setAttachmentLoaded, clearAttachmentLoaded, isAttachmentLoaded]); return {children}; } diff --git a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx index 8fa1914a8808..f3d98dad539e 100644 --- a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx +++ b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/index.tsx @@ -6,7 +6,7 @@ import ActivityIndicator from '@components/ActivityIndicator'; import AttachmentCarousel from '@components/Attachments/AttachmentCarousel'; import {AttachmentCarouselPagerActionsContext, AttachmentCarouselPagerStateContext} from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext'; import type {AttachmentCarouselPagerActionsContextType, AttachmentCarouselPagerStateContextType} from '@components/Attachments/AttachmentCarousel/Pager/types'; -import AttachmentView from '@components/Attachments/AttachmentView'; +import AttachmentView, {checkIsFileImage} from '@components/Attachments/AttachmentView'; import useAttachmentErrors from '@components/Attachments/AttachmentView/useAttachmentErrors'; import type {Attachment} from '@components/Attachments/types'; import BlockingView from '@components/BlockingViews/BlockingView'; @@ -99,6 +99,7 @@ function AttachmentModalBaseContent({ const [transactionFromOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transactionID)}`); const transaction = transactionProp ?? transactionFromOnyx; const [currentAttachmentLink, setCurrentAttachmentLink] = useState(attachmentLink); + const [currentPreviewSource, setCurrentPreviewSource] = useState(); const bottomSafeAreaPaddingStyle = useBottomSafeSafeAreaPaddingStyle({ addBottomSafeAreaPadding: true, addOfflineIndicatorBottomSafeAreaPadding: true, @@ -135,6 +136,7 @@ function AttachmentModalBaseContent({ (attachment: Attachment) => { setSource(attachment.source); setFile(attachment.file); + setCurrentPreviewSource(attachment.previewSource); setIsAuthTokenRequiredState(attachment.isAuthTokenRequired ?? false); onCarouselAttachmentChange(attachment); setCurrentAttachmentLink(attachment?.attachmentLink ?? ''); @@ -188,19 +190,22 @@ function AttachmentModalBaseContent({ const {isAttachmentLoaded} = useContext(AttachmentStateContext); const isEReceipt = transaction && !hasReceiptSource(transaction) && hasEReceipt(transaction); + const isFileImage = typeof source !== 'function' && checkIsFileImage(source, fileToDisplay?.name); + const isSourceLoaded = isAttachmentLoaded?.(source) || (!!currentPreviewSource && isAttachmentLoaded?.(currentPreviewSource)); const shouldShowDownloadButton = useMemo(() => { const isValidContext = !isEmptyObject(report) || type === CONST.ATTACHMENT_TYPE.SEARCH || shouldAllowDownloadOutsideReportContext; if (!isValidContext || isErrorInAttachment(source) || isEReceipt) { return false; } - return !!onDownloadAttachment && isDownloadButtonReadyToBeShown && !shouldShowNotFoundPage && !isOffline && !isLocalSource && isAttachmentLoaded?.(source); + return !!onDownloadAttachment && isDownloadButtonReadyToBeShown && !shouldShowNotFoundPage && !isOffline && !isLocalSource && (!isFileImage || isSourceLoaded); }, [ - isAttachmentLoaded, isDownloadButtonReadyToBeShown, isErrorInAttachment, + isFileImage, isLocalSource, isOffline, + isSourceLoaded, onDownloadAttachment, report, shouldAllowDownloadOutsideReportContext,