diff --git a/surfsense_web/components/report-panel/report-panel.tsx b/surfsense_web/components/report-panel/report-panel.tsx index 3d48fb8c5..291873b40 100644 --- a/surfsense_web/components/report-panel/report-panel.tsx +++ b/surfsense_web/components/report-panel/report-panel.tsx @@ -140,6 +140,14 @@ export function ReportPanelContent({ setActiveReportId(reportId); }, [reportId]); + // Clear copied state after 2 seconds + useEffect(() => { + if (copied) { + const timer = setTimeout(() => setCopied(false), 2000); + return () => clearTimeout(timer); + } + }, [copied]); + // Fetch report content (re-runs when activeReportId changes for version switching) useEffect(() => { let cancelled = false; @@ -197,7 +205,6 @@ export function ReportPanelContent({ try { await navigator.clipboard.writeText(currentMarkdown); setCopied(true); - setTimeout(() => setCopied(false), 2000); } catch (err) { console.error("Failed to copy:", err); } diff --git a/surfsense_web/components/ui/animated-tabs.tsx b/surfsense_web/components/ui/animated-tabs.tsx index 43ae82121..52e2342c9 100644 --- a/surfsense_web/components/ui/animated-tabs.tsx +++ b/surfsense_web/components/ui/animated-tabs.tsx @@ -306,7 +306,8 @@ const TabsList = forwardRef< }, [updateActiveIndicator]); useEffect(() => { - requestAnimationFrame(updateActiveIndicator); + const frameId = requestAnimationFrame(updateActiveIndicator); + return () => cancelAnimationFrame(frameId); }, [updateActiveIndicator]); const scrollTabToCenter = useCallback((index: number) => { diff --git a/surfsense_web/hooks/use-api-key.ts b/surfsense_web/hooks/use-api-key.ts index 0c595b420..873eebe24 100644 --- a/surfsense_web/hooks/use-api-key.ts +++ b/surfsense_web/hooks/use-api-key.ts @@ -15,6 +15,14 @@ export function useApiKey(): UseApiKeyReturn { const [copied, setCopied] = useState(false); const [isLoading, setIsLoading] = useState(true); + // Clear copied state after 2 seconds + useEffect(() => { + if (copied) { + const timer = setTimeout(() => setCopied(false), 2000); + return () => clearTimeout(timer); + } + }, [copied]); + useEffect(() => { // Load API key from localStorage const loadApiKey = () => { @@ -41,9 +49,6 @@ export function useApiKey(): UseApiKeyReturn { if (success) { setCopied(true); toast.success("API key copied to clipboard"); - setTimeout(() => { - setCopied(false); - }, 2000); } else { toast.error("Failed to copy API key"); }