55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
"use client"
|
|
|
|
import { useState } from "react"
|
|
import { Button } from "@/shared/components/ui/button"
|
|
import { Download, Loader2 } from "lucide-react"
|
|
import { toast } from "sonner"
|
|
|
|
type ExportDataButtonProps = {
|
|
onExport: (filters?: Record<string, unknown>) => Promise<Blob>
|
|
fileName?: string
|
|
filters?: Record<string, unknown>
|
|
label?: string
|
|
}
|
|
|
|
export function ExportDataButton({
|
|
onExport,
|
|
fileName = "export",
|
|
filters,
|
|
label = "Export",
|
|
}: ExportDataButtonProps) {
|
|
const [isPending, setIsPending] = useState(false)
|
|
|
|
const handleExport = async () => {
|
|
setIsPending(true)
|
|
try {
|
|
const blob = await onExport(filters)
|
|
const url = URL.createObjectURL(blob)
|
|
const a = document.createElement("a")
|
|
a.href = url
|
|
a.download = `${fileName}.xlsx`
|
|
document.body.appendChild(a)
|
|
a.click()
|
|
document.body.removeChild(a)
|
|
URL.revokeObjectURL(url)
|
|
toast.success("Data exported successfully")
|
|
} catch (err: any) {
|
|
toast.error(err?.message ?? "Failed to export data")
|
|
} finally {
|
|
setIsPending(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Button
|
|
size="sm"
|
|
variant="outline"
|
|
disabled={isPending}
|
|
onClick={handleExport}
|
|
>
|
|
{isPending ? <Loader2 className="animate-spin" /> : <Download />}
|
|
{label}
|
|
</Button>
|
|
)
|
|
}
|