diff --git a/cspell.json b/cspell.json index 80ef1951f2c2..8e4d47c57f00 100644 --- a/cspell.json +++ b/cspell.json @@ -516,6 +516,7 @@ "creditamount", "creditcards", "crios", + "csvexport", "csvg", "customairshipextender", "customfield", diff --git a/src/components/ExportDownloadStatusModal.tsx b/src/components/ExportDownloadStatusModal.tsx index be5b2d107d97..a030222b4d1b 100644 --- a/src/components/ExportDownloadStatusModal.tsx +++ b/src/components/ExportDownloadStatusModal.tsx @@ -1,17 +1,22 @@ -import {hasSeenTourSelector} from '@selectors/Onboarding'; import React, {useEffect} from 'react'; import {View} from 'react-native'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePreviousDefined from '@hooks/usePreviousDefined'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; +import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL'; +import {isMobileSafari} from '@libs/Browser'; +import {getOldDotURLFromEnvironment} from '@libs/Environment/Environment'; import fileDownload from '@libs/fileDownload'; +import Navigation from '@libs/Navigation/Navigation'; +import addTrailingForwardSlash from '@libs/UrlUtils'; import {clearExportDownload, sendExportFileFromConcierge} from '@userActions/Export'; -import {navigateToConciergeChat} from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import ActivityIndicator from './ActivityIndicator'; import Button from './Button'; import Modal from './Modal'; @@ -37,30 +42,44 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E // isSmallScreenWidth is needed here because the modal type depends on actual screen width, not layout mode // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {isSmallScreenWidth} = useResponsiveLayout(); - const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); + const {login: currentUserLogin} = useCurrentUserPersonalDetails(); + const {environment} = useEnvironment(); const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); - const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED); - const [betas] = useOnyx(ONYXKEYS.BETAS); - const [isSelfTourViewed] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector}); + const [encryptedAuthToken] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.encryptedAuthToken}); const [exportDownload] = useOnyx(`${ONYXKEYS.COLLECTION.EXPORT_DOWNLOAD}${exportID}`); const displayedExport = usePreviousDefined(exportDownload); const state = displayedExport?.state; const shouldSendFromConcierge = displayedExport?.shouldSendFromConcierge; - const downloadURL = displayedExport?.downloadURL; + const fileName = displayedExport?.fileName; const isPreparing = state === CONST.EXPORT_DOWNLOAD.STATE.PREPARING && !shouldSendFromConcierge; const isConcierge = !!shouldSendFromConcierge; const isReady = state === CONST.EXPORT_DOWNLOAD.STATE.READY; const isFailed = state === CONST.EXPORT_DOWNLOAD.STATE.FAILED; + // Build the secure download URL the same way downloadReportPDF does, so the host always follows + // the app's current environment (instead of the env baked into a backend-built URL) and authenticates + // via the encryptedAuthToken — no separate OldDot sign-in needed. + const downloadFile = () => { + if (!fileName || !currentUserLogin) { + return; + } + const baseURL = addTrailingForwardSlash(getOldDotURLFromEnvironment(environment)); + const isCSV = fileName.endsWith('.csv'); + const secureType = isCSV ? 'csvexport' : 'pdfreport'; + const url = `${baseURL}secure?secureType=${secureType}&filename=${encodeURIComponent(fileName)}&downloadName=${encodeURIComponent(fileName)}&email=${encodeURIComponent(currentUserLogin)}`; + fileDownload(translate, addEncryptedAuthTokenToURL(url, encryptedAuthToken ?? '', true), fileName, '', isMobileSafari()); + }; + useEffect(() => { - if (!isReady || !downloadURL || shouldSendFromConcierge) { + if (!isReady || !fileName || shouldSendFromConcierge) { return; } - fileDownload(translate, downloadURL); - }, [isReady, downloadURL, translate, shouldSendFromConcierge]); + downloadFile(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isReady, fileName, shouldSendFromConcierge]); const handleSendFromConcierge = () => { sendExportFileFromConcierge(exportID, displayedExport ?? undefined); @@ -68,14 +87,9 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E const handleGoToConcierge = () => { onClose(); - navigateToConciergeChat(conciergeReportID, introSelected, currentUserAccountID, isSelfTourViewed, betas); - }; - - const handleDownloadFile = () => { - if (!downloadURL) { - return; + if (conciergeReportID) { + Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID: conciergeReportID})); } - fileDownload(translate, downloadURL); }; const handleClose = () => { @@ -89,15 +103,15 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E if (isPreparing) { return ( <> - - {translate('exportDownload.preparingTitle')} - {translate('exportDownload.preparingBody')} + + {translate('exportDownload.preparingTitle')} + + + {translate('exportDownload.preparingBody')}