feat(plugin-import-export): show delayed toast when export download takes time (#13126)

### What?

Added a delayed toast message to indicate when an export is being
processed, and disabled the download button unless the export form has
been modified.

### Why?

Previously, there was no feedback during longer export operations, which
could confuse users if the request took time to complete. Also, the
download button was always enabled, even when the form had not been
modified — which could lead to unnecessary exports.

### How?

- Introduced a 200ms delay before showing a "Your export is being
processed..." toast
- Automatically dismisses the toast once the download completes or fails
- Hooked into `useFormModified` to:
  - Track whether the export form has been changed
  - Disable the download button when the form is unmodified
  - Reset the modified state after triggering a download
This commit is contained in:
Patrik
2025-07-10 14:55:46 -04:00
committed by GitHub
parent f63dfad565
commit b3a994ed6f

View File

@@ -1,6 +1,15 @@
'use client'
import { Button, SaveButton, Translation, useConfig, useForm, useTranslation } from '@payloadcms/ui'
import {
Button,
SaveButton,
toast,
Translation,
useConfig,
useForm,
useFormModified,
useTranslation,
} from '@payloadcms/ui'
import React from 'react'
import type {
@@ -17,13 +26,24 @@ export const ExportSaveButton: React.FC = () => {
},
} = useConfig()
const { getData } = useForm()
const { getData, setModified } = useForm()
const modified = useFormModified()
const label = t('general:save')
const handleDownload = async () => {
let timeoutID: null | ReturnType<typeof setTimeout> = null
let toastID: null | number | string = null
try {
setModified(false) // Reset modified state
const data = getData()
// Set a timeout to show toast if the request takes longer than 200ms
timeoutID = setTimeout(() => {
toastID = toast.success('Your export is being processed...')
}, 200)
const response = await fetch(`${serverURL}${api}/exports/download`, {
body: JSON.stringify({
data,
@@ -35,6 +55,16 @@ export const ExportSaveButton: React.FC = () => {
method: 'POST',
})
// Clear the timeout if fetch completes quickly
if (timeoutID) {
clearTimeout(timeoutID)
}
// Dismiss the toast if it was shown
if (toastID) {
toast.dismiss(toastID)
}
if (!response.ok) {
throw new Error('Failed to download file')
}
@@ -63,13 +93,14 @@ export const ExportSaveButton: React.FC = () => {
URL.revokeObjectURL(url)
} catch (error) {
console.error('Error downloading file:', error)
toast.error('Error downloading file')
}
}
return (
<React.Fragment>
<SaveButton label={label}></SaveButton>
<Button onClick={handleDownload} size="medium" type="button">
<Button disabled={!modified} onClick={handleDownload} size="medium" type="button">
<Translation i18nKey="upload:download" t={t} />
</Button>
</React.Fragment>