@@ -25,9 +25,14 @@ export const GameTimer: FC<GameTimerProps> = ({
2525} ) => {
2626 const [ timeLeft , setTimeLeft ] = useState ( TIMER_DURATION ) ;
2727 const [ isExpired , setIsExpired ] = useState ( false ) ;
28+ const [ isStopped , setIsStopped ] = useState ( false ) ;
2829 const [ showSpies , setShowSpies ] = useState ( false ) ;
2930
3031 useEffect ( ( ) => {
32+ if ( isStopped ) {
33+ return ;
34+ }
35+
3136 if ( timeLeft <= 0 ) {
3237 setIsExpired ( true ) ;
3338 return ;
@@ -44,19 +49,21 @@ export const GameTimer: FC<GameTimerProps> = ({
4449 } , 1000 ) ;
4550
4651 return ( ) => clearInterval ( interval ) ;
47- } , [ timeLeft ] ) ;
52+ } , [ timeLeft , isStopped ] ) ;
4853
4954 const minutes = Math . floor ( timeLeft / 60 ) ;
5055 const seconds = timeLeft % 60 ;
5156 const formattedTime = `${ minutes } :${ seconds . toString ( ) . padStart ( 2 , '0' ) } ` ;
5257
5358 const getTimerColor = ( ) => {
54- if ( isExpired ) return ' text-destructive' ;
55- if ( timeLeft <= 30 ) return ' text-destructive' ;
56- if ( timeLeft <= 60 ) return ' text-warning' ;
57- return ' text-foreground' ;
59+ if ( isExpired || isStopped ) return " text-destructive" ;
60+ if ( timeLeft <= 30 ) return " text-destructive" ;
61+ if ( timeLeft <= 60 ) return " text-warning" ;
62+ return " text-foreground" ;
5863 } ;
5964
65+ const isFinished = isExpired || isStopped ;
66+
6067 const spies = playerRoles . filter ( ( player ) => player . isSpy ) ;
6168
6269 return (
@@ -65,7 +72,9 @@ export const GameTimer: FC<GameTimerProps> = ({
6572 < div className = "text-center" >
6673 < h2 className = "mb-2 font-bold text-2xl" > { dict . timer . title } </ h2 >
6774 < p className = "text-muted-foreground" >
68- { isExpired ? dict . timer . timeUpDescription : dict . timer . description }
75+ { isFinished
76+ ? dict . timer . timeUpDescription
77+ : dict . timer . description }
6978 </ p >
7079 </ div >
7180
@@ -74,26 +83,32 @@ export const GameTimer: FC<GameTimerProps> = ({
7483 'flex h-64 w-64 items-center justify-center rounded-full border-4 shadow-lg transition-colors' ,
7584 getTimerColor ( ) ,
7685 {
77- ' animate-pulse border-destructive' : isExpired ,
78- ' border-destructive' : timeLeft <= 30 && ! isExpired ,
79- ' border-warning' : timeLeft > 30 && timeLeft <= 60 ,
80- ' border-border' : timeLeft > 60 ,
86+ " animate-pulse border-destructive" : isExpired ,
87+ " border-destructive" : ( timeLeft <= 30 && ! isFinished ) || isStopped ,
88+ " border-warning" : timeLeft > 30 && timeLeft <= 60 && ! isFinished ,
89+ " border-border" : timeLeft > 60 && ! isFinished ,
8190 } ,
8291 ) } >
8392 < div className = "text-center" >
8493 < div className = { cn ( 'font-bold text-6xl' , getTimerColor ( ) ) } >
8594 { formattedTime }
8695 </ div >
87- { isExpired && (
96+ { isFinished && (
8897 < div className = "mt-2 font-semibold text-xl" >
89- { dict . timer . timeUp }
98+ { isExpired ? dict . timer . timeUp : dict . timer . stopped }
9099 </ div >
91100 ) }
92101 </ div >
93102 </ div >
103+
104+ { ! isFinished && (
105+ < Button variant = "outline" onClick = { ( ) => setIsStopped ( true ) } >
106+ { dict . timer . stopTimer }
107+ </ Button >
108+ ) }
94109 </ div >
95110
96- { isExpired && (
111+ { isFinished && (
97112 < div className = "flex flex-col items-center gap-4" >
98113 { showSpies && (
99114 < div className = "rounded-lg border bg-card p-6 shadow-lg" >
0 commit comments