Skip to content

Commit b3a994e

Browse files
authored
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
1 parent f63dfad commit b3a994e

File tree

1 file changed

+34
-3
lines changed
  • packages/plugin-import-export/src/components/ExportSaveButton

1 file changed

+34
-3
lines changed

packages/plugin-import-export/src/components/ExportSaveButton/index.tsx

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
'use client'
22

3-
import { Button, SaveButton, Translation, useConfig, useForm, useTranslation } from '@payloadcms/ui'
3+
import {
4+
Button,
5+
SaveButton,
6+
toast,
7+
Translation,
8+
useConfig,
9+
useForm,
10+
useFormModified,
11+
useTranslation,
12+
} from '@payloadcms/ui'
413
import React from 'react'
514

615
import type {
@@ -17,13 +26,24 @@ export const ExportSaveButton: React.FC = () => {
1726
},
1827
} = useConfig()
1928

20-
const { getData } = useForm()
29+
const { getData, setModified } = useForm()
30+
const modified = useFormModified()
2131

2232
const label = t('general:save')
2333

2434
const handleDownload = async () => {
35+
let timeoutID: null | ReturnType<typeof setTimeout> = null
36+
let toastID: null | number | string = null
37+
2538
try {
39+
setModified(false) // Reset modified state
2640
const data = getData()
41+
42+
// Set a timeout to show toast if the request takes longer than 200ms
43+
timeoutID = setTimeout(() => {
44+
toastID = toast.success('Your export is being processed...')
45+
}, 200)
46+
2747
const response = await fetch(`${serverURL}${api}/exports/download`, {
2848
body: JSON.stringify({
2949
data,
@@ -35,6 +55,16 @@ export const ExportSaveButton: React.FC = () => {
3555
method: 'POST',
3656
})
3757

58+
// Clear the timeout if fetch completes quickly
59+
if (timeoutID) {
60+
clearTimeout(timeoutID)
61+
}
62+
63+
// Dismiss the toast if it was shown
64+
if (toastID) {
65+
toast.dismiss(toastID)
66+
}
67+
3868
if (!response.ok) {
3969
throw new Error('Failed to download file')
4070
}
@@ -63,13 +93,14 @@ export const ExportSaveButton: React.FC = () => {
6393
URL.revokeObjectURL(url)
6494
} catch (error) {
6595
console.error('Error downloading file:', error)
96+
toast.error('Error downloading file')
6697
}
6798
}
6899

69100
return (
70101
<React.Fragment>
71102
<SaveButton label={label}></SaveButton>
72-
<Button onClick={handleDownload} size="medium" type="button">
103+
<Button disabled={!modified} onClick={handleDownload} size="medium" type="button">
73104
<Translation i18nKey="upload:download" t={t} />
74105
</Button>
75106
</React.Fragment>

0 commit comments

Comments
 (0)