From 3df5903e1cf36cd6d5ba00697b3d5c0139a6af3f Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Fri, 29 May 2026 18:55:46 -0700 Subject: [PATCH] Move mobile pairing copy timer into handler (#3415) --- .../src/components/settings/MobilePane.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/components/settings/MobilePane.tsx b/src/renderer/src/components/settings/MobilePane.tsx index db297eccf74..89af31e34a1 100644 --- a/src/renderer/src/components/settings/MobilePane.tsx +++ b/src/renderer/src/components/settings/MobilePane.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import { toast } from 'sonner' import { Check, Copy, Maximize2, Smartphone, Trash2 } from 'lucide-react' import { Button } from '../ui/button' @@ -52,14 +52,14 @@ export function MobilePane(): React.JSX.Element { const [selectedAddress, setSelectedAddress] = useState(undefined) const [refreshingNetworkInterfaces, setRefreshingNetworkInterfaces] = useState(false) const [codeCopied, setCodeCopied] = useState(false) + const codeCopiedResetTimerRef = useRef(null) - useEffect(() => { - if (!codeCopied) { - return + const clearCodeCopiedResetTimer = useCallback((): void => { + if (codeCopiedResetTimerRef.current !== null) { + window.clearTimeout(codeCopiedResetTimerRef.current) + codeCopiedResetTimerRef.current = null } - const timeout = window.setTimeout(() => setCodeCopied(false), 2000) - return () => window.clearTimeout(timeout) - }, [codeCopied]) + }, []) const loadDevices = useCallback(async () => { try { @@ -103,6 +103,7 @@ export function MobilePane(): React.JSX.Element { setQrDataUrl(result.qrDataUrl) setPairingUrl(result.pairingUrl) setEndpoint(result.endpoint) + clearCodeCopiedResetTimer() setCodeCopied(false) void loadDevices() } else { @@ -114,7 +115,7 @@ export function MobilePane(): React.JSX.Element { setLoading(false) } }, - [loadDevices, selectedAddress] + [clearCodeCopiedResetTimer, loadDevices, selectedAddress] ) useEffect(() => { @@ -148,7 +149,12 @@ export function MobilePane(): React.JSX.Element { // (no transient activation, non-secure context). Use the main-process // IPC clipboard which the rest of the app uses everywhere. await window.api.ui.writeClipboardText(pairingUrl) + clearCodeCopiedResetTimer() setCodeCopied(true) + codeCopiedResetTimerRef.current = window.setTimeout(() => { + codeCopiedResetTimerRef.current = null + setCodeCopied(false) + }, 2000) } catch { toast.error('Failed to copy pairing code') }