diff --git a/src/components/reports/ReportsTablePanel.tsx b/src/components/reports/ReportsTablePanel.tsx index e640f3a..61f576a 100644 --- a/src/components/reports/ReportsTablePanel.tsx +++ b/src/components/reports/ReportsTablePanel.tsx @@ -98,6 +98,7 @@ export function ReportsTablePanel({ openDay, onToggleDay, onExport, + exportState, labels, }: { data: TableReportResponse | null; @@ -105,6 +106,10 @@ export function ReportsTablePanel({ openDay: string | null; onToggleDay: (day: string) => void; onExport: (type: "excel" | "pdf") => void; + exportState: { + excel: { pending: boolean; cooldownSeconds: number }; + pdf: { pending: boolean; cooldownSeconds: number }; + }; labels: Record; }) { const { lang } = useTranslation(); @@ -117,18 +122,28 @@ export function ReportsTablePanel({ diff --git a/src/pages/Reports.tsx b/src/pages/Reports.tsx index feba7e8..2fd4aa3 100644 --- a/src/pages/Reports.tsx +++ b/src/pages/Reports.tsx @@ -96,6 +96,10 @@ export default function Reports() { const [dayDetails, setDayDetails] = useState(null); const [openDay, setOpenDay] = useState(null); const [isLoading, setIsLoading] = useState(false); + const [exportState, setExportState] = useState({ + excel: { pending: false, cooldownSeconds: 0 }, + pdf: { pending: false, cooldownSeconds: 0 }, + }); const canSelectUsers = canWorkspace(activeWorkspace?.my_role, WORKSPACE_MEMBERS_VIEW); @@ -188,12 +192,44 @@ export default function Reports() { } }; + useEffect(() => { + const interval = window.setInterval(() => { + setExportState((current) => ({ + excel: { + pending: current.excel.pending, + cooldownSeconds: Math.max(current.excel.cooldownSeconds - 1, 0), + }, + pdf: { + pending: current.pdf.pending, + cooldownSeconds: Math.max(current.pdf.cooldownSeconds - 1, 0), + }, + })); + }, 1000); + + return () => window.clearInterval(interval); + }, []); + const handleExport = async (type: "excel" | "pdf") => { if (!apiFilters) return; + if (exportState[type].pending || exportState[type].cooldownSeconds > 0) return; + + setExportState((current) => ({ + ...current, + [type]: { pending: true, cooldownSeconds: 0 }, + })); + try { await createReportExport(apiFilters, type, lang); + setExportState((current) => ({ + ...current, + [type]: { pending: false, cooldownSeconds: 60 }, + })); toast.success(t.reports?.exportQueued || "Export queued. You will receive a notification with the download link."); } catch { + setExportState((current) => ({ + ...current, + [type]: { pending: false, cooldownSeconds: 0 }, + })); toast.error(t.reports?.exportError || "Failed to queue report export."); } }; @@ -310,6 +346,7 @@ export default function Reports() { openDay={openDay} onToggleDay={(day) => void handleToggleDay(day)} onExport={(type) => void handleExport(type)} + exportState={exportState} labels={{ exportExcel: t.reports?.exportExcel || "Export Excel", exportPdf: t.reports?.exportPdf || "Export PDF",