mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-04 16:13:23 +00:00
fix(frontend): guard CopyButton against concurrent copies
The button is disabled once isCopied is true, but copy() is now async, so isCopied and the disabled prop only catch up after it resolves. Clicks landing inside that window both passed the guard and started a write. Nothing leaked, since the existing clearTimeout already handled the duplicate timer, but the window did not exist before copy-to-clipboard 4 made the call async. A ref cleared in finally closes it. Raised by CodeRabbit on #2762. 598 tests pass, build and lint unchanged.
This commit is contained in:
1 parent
88b4d89b4f
commit
4cc603db89
1 file changed
+7
-1
@@ -35,6 +35,9 @@ export default function CopyButton({
|
||||
const { t } = useTranslation();
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
const timeoutIdRef = useRef<number | null>(null);
|
||||
// `copy` is async, so `isCopied` and the disabled prop only catch up after it
|
||||
// resolves. Guard that window so rapid clicks cannot start a second write.
|
||||
const copyInFlightRef = useRef(false);
|
||||
|
||||
const iconWrapperClasses = clsx(
|
||||
'flex items-center justify-center rounded-full transition-colors duration-150 ease-in-out',
|
||||
@@ -72,7 +75,8 @@ export default function CopyButton({
|
||||
: t('conversation.copy');
|
||||
|
||||
const handleCopy = useCallback(async () => {
|
||||
if (isCopied) return;
|
||||
if (isCopied || copyInFlightRef.current) return;
|
||||
copyInFlightRef.current = true;
|
||||
|
||||
try {
|
||||
const success = await copy(textToCopy);
|
||||
@@ -92,6 +96,8 @@ export default function CopyButton({
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to copy text:', error);
|
||||
} finally {
|
||||
copyInFlightRef.current = false;
|
||||
}
|
||||
}, [textToCopy, copiedDuration, isCopied]);
|
||||
|
||||
|
||||
Reference in new issue
Block a user