11'use client' ;
22
3- import { useState , useRef } from 'react' ;
3+ import { useState , useRef , useEffect } from 'react' ;
44import { api } from '~/trpc/react' ;
55import { Button } from './ui/button' ;
66import { ContextualHelpIcon } from './ContextualHelpIcon' ;
@@ -11,6 +11,8 @@ export function ResyncButton() {
1111 const [ syncMessage , setSyncMessage ] = useState < string | null > ( null ) ;
1212 const hasReloadedRef = useRef < boolean > ( false ) ;
1313 const isUserInitiatedRef = useRef < boolean > ( false ) ;
14+ const reloadTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
15+ const messageTimeoutRef = useRef < NodeJS . Timeout | null > ( null ) ;
1416
1517 const resyncMutation = api . scripts . resyncScripts . useMutation ( {
1618 onSuccess : ( data ) => {
@@ -21,7 +23,16 @@ export function ResyncButton() {
2123 // Only reload if this was triggered by user action
2224 if ( isUserInitiatedRef . current && ! hasReloadedRef . current ) {
2325 hasReloadedRef . current = true ;
24- setTimeout ( ( ) => {
26+
27+ // Clear any existing reload timeout
28+ if ( reloadTimeoutRef . current ) {
29+ clearTimeout ( reloadTimeoutRef . current ) ;
30+ reloadTimeoutRef . current = null ;
31+ }
32+
33+ // Set new reload timeout
34+ reloadTimeoutRef . current = setTimeout ( ( ) => {
35+ reloadTimeoutRef . current = null ;
2536 window . location . reload ( ) ;
2637 } , 2000 ) ; // Wait 2 seconds to show the success message
2738 } else {
@@ -31,14 +42,26 @@ export function ResyncButton() {
3142 } else {
3243 setSyncMessage ( data . error ?? 'Failed to sync scripts' ) ;
3344 // Clear message after 3 seconds for errors
34- setTimeout ( ( ) => setSyncMessage ( null ) , 3000 ) ;
45+ if ( messageTimeoutRef . current ) {
46+ clearTimeout ( messageTimeoutRef . current ) ;
47+ }
48+ messageTimeoutRef . current = setTimeout ( ( ) => {
49+ setSyncMessage ( null ) ;
50+ messageTimeoutRef . current = null ;
51+ } , 3000 ) ;
3552 isUserInitiatedRef . current = false ;
3653 }
3754 } ,
3855 onError : ( error ) => {
3956 setIsResyncing ( false ) ;
4057 setSyncMessage ( `Error: ${ error . message } ` ) ;
41- setTimeout ( ( ) => setSyncMessage ( null ) , 3000 ) ;
58+ if ( messageTimeoutRef . current ) {
59+ clearTimeout ( messageTimeoutRef . current ) ;
60+ }
61+ messageTimeoutRef . current = setTimeout ( ( ) => {
62+ setSyncMessage ( null ) ;
63+ messageTimeoutRef . current = null ;
64+ } , 3000 ) ;
4265 isUserInitiatedRef . current = false ;
4366 } ,
4467 } ) ;
@@ -47,6 +70,12 @@ export function ResyncButton() {
4770 // Prevent multiple simultaneous sync operations
4871 if ( isResyncing ) return ;
4972
73+ // Clear any pending reload timeout
74+ if ( reloadTimeoutRef . current ) {
75+ clearTimeout ( reloadTimeoutRef . current ) ;
76+ reloadTimeoutRef . current = null ;
77+ }
78+
5079 // Mark as user-initiated before starting
5180 isUserInitiatedRef . current = true ;
5281 hasReloadedRef . current = false ;
@@ -55,6 +84,23 @@ export function ResyncButton() {
5584 resyncMutation . mutate ( ) ;
5685 } ;
5786
87+ // Cleanup on unmount - clear any pending timeouts
88+ useEffect ( ( ) => {
89+ return ( ) => {
90+ if ( reloadTimeoutRef . current ) {
91+ clearTimeout ( reloadTimeoutRef . current ) ;
92+ reloadTimeoutRef . current = null ;
93+ }
94+ if ( messageTimeoutRef . current ) {
95+ clearTimeout ( messageTimeoutRef . current ) ;
96+ messageTimeoutRef . current = null ;
97+ }
98+ // Reset refs on unmount
99+ hasReloadedRef . current = false ;
100+ isUserInitiatedRef . current = false ;
101+ } ;
102+ } , [ ] ) ;
103+
58104 return (
59105 < div className = "flex flex-col sm:flex-row sm:items-center gap-3" >
60106 < div className = "text-sm text-muted-foreground font-medium" >
0 commit comments