Files
1a57cb25a0 Async CSV export (#3330)
* add export for address txs

* transfer all export from page to dialog

* remove old route and components

* improve file name and fix loading state of icon button

* basic implementation

* refetch item status

* status indicator for download items

* changes for multichain

* handle too many requests for downloads error

* update button styles and spacing

* fix tests

* disable async export for multichain

* Fix CSV export cancel flow and stabilize context updates

Applied via @cursor push command

* test and review fixes

* design fixes

* refactor file names

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-03-02 15:51:50 +02:00

87 lines
2.8 KiB
TypeScript

import { chakra, Flex } from '@chakra-ui/react';
import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import type { FormFields } from './types';
import dayjs from 'lib/date/dayjs';
import { Button } from 'toolkit/chakra/button';
import { DialogBody, DialogContent, DialogHeader, DialogRoot } from 'toolkit/chakra/dialog';
import type { OnOpenChangeHandler } from 'toolkit/hooks/useDisclosure';
import CsvExportFormDateField from './CsvExportFormDateField';
interface Props {
children: React.ReactNode;
open: boolean;
onOpenChange: OnOpenChangeHandler;
onFormSubmit: (data: FormFields) => Promise<void>;
onCancel: () => void;
isAsyncDownload?: boolean;
}
const CsvExportDialog = ({ open, onOpenChange, onFormSubmit, onCancel, children, isAsyncDownload }: Props) => {
const formApi = useForm<FormFields>({
mode: 'onBlur',
defaultValues: {
from_period: dayjs().subtract(1, 'day').format('YYYY-MM-DDTHH:mm'),
to_period: dayjs().format('YYYY-MM-DDTHH:mm'),
},
});
const { handleSubmit, formState } = formApi;
const handleOpenChange: OnOpenChangeHandler = React.useCallback(({ open }) => {
if (formState.isSubmitting && !open) {
const confirm = window.confirm('Are you sure you want to close the dialog? The export will be cancelled.');
if (!confirm) {
return;
}
onCancel();
}
onOpenChange({ open });
}, [ onOpenChange, formState.isSubmitting, onCancel ]);
return (
<DialogRoot open={ open } onOpenChange={ handleOpenChange } size={{ lgDown: 'full', lg: 'md' }}>
<DialogContent>
<FormProvider { ...formApi }>
<chakra.form
noValidate
onSubmit={ handleSubmit(onFormSubmit) }
>
<DialogHeader>
Export data to CSV file
</DialogHeader>
<DialogBody>
{ children }
<Flex
columnGap={ 3 }
rowGap={ 3 }
mt={ 6 }
flexDir={{ base: 'column', lg: 'row' }}
alignItems={{ base: 'flex-start', lg: 'center' }}
w="100%"
>
<CsvExportFormDateField name="from_period" formApi={ formApi }/>
<CsvExportFormDateField name="to_period" formApi={ formApi }/>
</Flex>
<Button
variant="solid"
type="submit"
mt={ 6 }
loading={ formState.isSubmitting }
disabled={ Boolean(formState.errors.from_period || formState.errors.to_period) }
>
{ isAsyncDownload ? 'Generate CSV' : 'Download' }
</Button>
</DialogBody>
</chakra.form>
</FormProvider>
</DialogContent>
</DialogRoot>
);
};
export default React.memo(CsvExportDialog);