diff --git a/src/components/ExportDownloadStatusManager.tsx b/src/components/ExportDownloadStatusManager.tsx new file mode 100644 index 000000000000..6ec31075c4f2 --- /dev/null +++ b/src/components/ExportDownloadStatusManager.tsx @@ -0,0 +1,59 @@ +import useOnyx from '@hooks/useOnyx'; + +import {clearExportDownload} from '@libs/actions/Export'; + +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +import React from 'react'; + +import ExportDownloadStatusModal from './ExportDownloadStatusModal'; + +/** + * Renders the queued export status modal for the whole app. It watches the export collection and shows the modal + * for the active export (preparing, ready, or failed). Because it is the single owner of the modal and reads + * straight from Onyx, a screen only has to start an export (which writes its record); this shows the progress, + * delivers the file when it is ready, and still surfaces it after a reload or once the screen that started it is + * gone. There is no per-screen modal to coordinate with. + */ +function ExportDownloadStatusManager() { + const [exportDownloads] = useOnyx(ONYXKEYS.COLLECTION.EXPORT_DOWNLOAD); + + // Skip Concierge hand-offs: once the user opts into Concierge delivery, the file (or the error) is delivered + // through the Concierge chat, so the modal has nothing left to show. Setting shouldSendFromConcierge is what + // closes the modal, and the worker deletes the record once it is done. + const activeEntry = Object.entries(exportDownloads ?? {}).find( + ([, exportDownload]) => + !exportDownload?.shouldSendFromConcierge && + (exportDownload?.state === CONST.EXPORT_DOWNLOAD.STATE.PREPARING || + exportDownload?.state === CONST.EXPORT_DOWNLOAD.STATE.READY || + exportDownload?.state === CONST.EXPORT_DOWNLOAD.STATE.FAILED), + ); + + if (!activeEntry) { + return null; + } + + const exportID = activeEntry[0].replace(ONYXKEYS.COLLECTION.EXPORT_DOWNLOAD, ''); + const exportDownload = activeEntry[1]; + + const handleClose = () => { + // The modal blocks dismissal while still preparing, so this is belt-and-suspenders. + if (exportDownload?.state === CONST.EXPORT_DOWNLOAD.STATE.PREPARING) { + return; + } + clearExportDownload(exportID, exportDownload); + }; + + return ( + + ); +} + +ExportDownloadStatusManager.displayName = 'ExportDownloadStatusManager'; + +export default ExportDownloadStatusManager; diff --git a/src/components/ExportDownloadStatusModal.tsx b/src/components/ExportDownloadStatusModal.tsx index 086291969a4a..1021e25a7069 100644 --- a/src/components/ExportDownloadStatusModal.tsx +++ b/src/components/ExportDownloadStatusModal.tsx @@ -2,7 +2,6 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useOpenConciergeAnywhere from '@hooks/useOpenConciergeAnywhere'; import usePreviousDefined from '@hooks/usePreviousDefined'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -64,7 +63,6 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E const receiptCount = displayedExport?.receiptCount; const failedReceiptCount = displayedExport?.failedReceiptCount ?? 0; 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; const isEmptyReceipts = isReady && exportType === CONST.EXPORT_DOWNLOAD.TYPE.RECEIPTS && receiptCount === 0; @@ -94,17 +92,11 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E const handleSendFromConcierge = () => { sendExportFileFromConcierge(exportID, displayedExport ?? undefined); }; - const {openConciergeAnywhere} = useOpenConciergeAnywhere(); - - const handleGoToConcierge = () => { - onClose(); - openConciergeAnywhere({forceConcierge: true}); - }; const handleDownloadFile = () => { downloadFile(); - // Clearing the export download is owned by the parent's onClose handler (it runs on every dismissal and - // skips the clear for the Concierge path). Clearing here too would queue a duplicate ClearExportDownload write. + // Clearing the export download is owned by the parent's onClose handler (it runs on every dismissal). + // Clearing here too would queue a duplicate ClearExportDownload write. onClose(); }; @@ -128,26 +120,6 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E ); } - if (isConcierge) { - return ( - <> - {translate('exportDownload.conciergeTitle')} - {translate('exportDownload.conciergeBody')} -